mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
The ownership kind is Any for trivial types, or Owned otherwise, but whether a type is trivial or not will soon depend on the resilience expansion. This means that a SILModule now uniques two SILUndefs per type instead of one, and serialization uses two distinct sentinel IDs for this purpose as well. For now, the resilience expansion is not actually used here, so this change is NFC, other than changing the module format.
186 lines
6.8 KiB
C++
186 lines
6.8 KiB
C++
//===--- BugReducerTester.cpp ---------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
///
|
|
/// \file
|
|
///
|
|
/// This pass is a testing pass for sil-bug-reducer. It asserts when it visits a
|
|
/// function that calls a function specified by an llvm::cl::opt.
|
|
///
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "swift/SIL/SILBuilder.h"
|
|
#include "swift/SIL/SILFunction.h"
|
|
#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h"
|
|
#include "swift/SIL/SILInstruction.h"
|
|
#include "swift/SIL/ApplySite.h"
|
|
#include "swift/SIL/SILLocation.h"
|
|
#include "swift/SIL/SILUndef.h"
|
|
#include "swift/SILOptimizer/PassManager/Passes.h"
|
|
#include "swift/SILOptimizer/PassManager/Transforms.h"
|
|
#include "llvm/Support/CommandLine.h"
|
|
|
|
using namespace swift;
|
|
|
|
static llvm::cl::opt<std::string> FunctionTarget(
|
|
"bug-reducer-tester-target-func",
|
|
llvm::cl::desc("Function that when called by an apply should cause "
|
|
"BugReducerTester to blow up or miscompile if the pass "
|
|
"visits the apply"));
|
|
|
|
namespace {
|
|
enum class FailureKind {
|
|
OptimizerCrasher,
|
|
RuntimeMiscompile,
|
|
RuntimeCrasher,
|
|
None
|
|
};
|
|
} // end anonymous namespace
|
|
|
|
static llvm::cl::opt<FailureKind> TargetFailureKind(
|
|
"bug-reducer-tester-failure-kind",
|
|
llvm::cl::desc("The type of failure to perform"),
|
|
llvm::cl::values(
|
|
clEnumValN(FailureKind::OptimizerCrasher, "opt-crasher",
|
|
"Crash the optimizer when we see the specified apply"),
|
|
clEnumValN(FailureKind::RuntimeMiscompile, "miscompile",
|
|
"Delete the target function call to cause a runtime "
|
|
"miscompile that is not a crasher"),
|
|
clEnumValN(FailureKind::RuntimeCrasher, "runtime-crasher",
|
|
"Delete the target function call to cause a runtime "
|
|
"miscompile that is not a crasher")),
|
|
llvm::cl::init(FailureKind::None));
|
|
|
|
|
|
LLVM_ATTRIBUTE_NOINLINE
|
|
void THIS_TEST_IS_EXPECTED_TO_CRASH_HERE() {
|
|
llvm_unreachable("Found the target!");
|
|
}
|
|
|
|
namespace {
|
|
|
|
class BugReducerTester : public SILFunctionTransform {
|
|
|
|
// We only want to cause 1 miscompile.
|
|
bool CausedError = false;
|
|
StringRef RuntimeCrasherFunctionName = "bug_reducer_runtime_crasher_func";
|
|
|
|
SILFunction *getRuntimeCrasherFunction() {
|
|
assert(TargetFailureKind == FailureKind::RuntimeCrasher);
|
|
llvm::SmallVector<SILResultInfo, 1> ResultInfoArray;
|
|
auto EmptyTupleCanType = getFunction()
|
|
->getModule()
|
|
.Types.getEmptyTupleType()
|
|
.getASTType();
|
|
ResultInfoArray.push_back(
|
|
SILResultInfo(EmptyTupleCanType, ResultConvention::Unowned));
|
|
auto FuncType = SILFunctionType::get(
|
|
nullptr, SILFunctionType::ExtInfo(SILFunctionType::Representation::Thin,
|
|
false /*isPseudoGeneric*/,
|
|
false /*noescape*/),
|
|
SILCoroutineKind::None, ParameterConvention::Direct_Unowned,
|
|
ArrayRef<SILParameterInfo>(), ArrayRef<SILYieldInfo>(),
|
|
ResultInfoArray, None, getFunction()->getModule().getASTContext());
|
|
|
|
SILOptFunctionBuilder FunctionBuilder(*this);
|
|
SILFunction *F = FunctionBuilder.getOrCreateSharedFunction(
|
|
RegularLocation::getAutoGeneratedLocation(), RuntimeCrasherFunctionName,
|
|
FuncType, IsBare, IsNotTransparent, IsSerialized, ProfileCounter(),
|
|
IsNotThunk, IsNotDynamic);
|
|
if (F->isDefinition())
|
|
return F;
|
|
|
|
// Create a new block.
|
|
SILBasicBlock *BB = F->createBasicBlock();
|
|
|
|
// Insert a builtin int trap. Then return F.
|
|
SILBuilder B(BB);
|
|
B.createBuiltinTrap(RegularLocation::getAutoGeneratedLocation());
|
|
B.createUnreachable(ArtificialUnreachableLocation());
|
|
return F;
|
|
}
|
|
|
|
void run() override {
|
|
// If we don't have a target function or we already caused a miscompile,
|
|
// just return.
|
|
if (FunctionTarget.empty() || CausedError)
|
|
return;
|
|
assert(TargetFailureKind != FailureKind::None);
|
|
for (auto &BB : *getFunction()) {
|
|
for (auto II = BB.begin(), IE = BB.end(); II != IE;) {
|
|
// Skip try_apply. We do not support them for now.
|
|
if (isa<TryApplyInst>(&*II)) {
|
|
++II;
|
|
continue;
|
|
}
|
|
|
|
auto FAS = FullApplySite::isa(&*II);
|
|
if (!FAS) {
|
|
++II;
|
|
continue;
|
|
}
|
|
|
|
auto *FRI = dyn_cast<FunctionRefInst>(FAS.getCallee());
|
|
if (!FRI ||
|
|
!FRI->getReferencedFunction()->getName().equals(FunctionTarget)) {
|
|
++II;
|
|
continue;
|
|
}
|
|
|
|
// Ok, we found the Apply that we want! If we are asked to crash, crash
|
|
// here.
|
|
if (TargetFailureKind == FailureKind::OptimizerCrasher)
|
|
THIS_TEST_IS_EXPECTED_TO_CRASH_HERE();
|
|
|
|
// Otherwise, if we are asked to perform a runtime time miscompile,
|
|
// delete the apply target.
|
|
if (TargetFailureKind == FailureKind::RuntimeMiscompile) {
|
|
// Ok, we need to insert a runtime miscompile. Move II to
|
|
// the next instruction and then replace its current value
|
|
// with undef.
|
|
auto *Inst = cast<SingleValueInstruction>(&*II);
|
|
Inst->replaceAllUsesWith(SILUndef::get(Inst->getType(), *getFunction()));
|
|
Inst->eraseFromParent();
|
|
|
|
// Mark that we found the miscompile and return so we do not try to
|
|
// visit any more instructions in this function.
|
|
CausedError = true;
|
|
return;
|
|
}
|
|
|
|
assert(TargetFailureKind == FailureKind::RuntimeCrasher);
|
|
// Finally, if we reach this point we are being asked to replace the
|
|
// given apply with a new apply that calls the crasher func.
|
|
auto Loc = RegularLocation::getAutoGeneratedLocation();
|
|
SILFunction *RuntimeCrasherFunc = getRuntimeCrasherFunction();
|
|
llvm::dbgs() << "Runtime Crasher Func!\n";
|
|
RuntimeCrasherFunc->dump();
|
|
SILBuilder B(II);
|
|
B.createApply(Loc, B.createFunctionRef(Loc, RuntimeCrasherFunc),
|
|
SubstitutionMap(),
|
|
ArrayRef<SILValue>(), false /*NoThrow*/);
|
|
|
|
auto *Inst = cast<SingleValueInstruction>(&*II);
|
|
++II;
|
|
Inst->replaceAllUsesWith(SILUndef::get(Inst->getType(), *getFunction()));
|
|
Inst->eraseFromParent();
|
|
|
|
CausedError = true;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
SILTransform *swift::createBugReducerTester() { return new BugReducerTester(); }
|