Skip to content

Commit 4c49e00

Browse files
committed
Verifier: in the swift verifier call the bridged C++ verificationFailure function in case of a failure
This brings all the nice verifier features to the swift verifier, like printing the surrounding instructions in case of a failure, etc.
1 parent 95bd329 commit 4c49e00

File tree

7 files changed

+86
-41
lines changed

7 files changed

+86
-41
lines changed

SwiftCompilerSources/Sources/Optimizer/Utilities/Verifier.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,12 @@ private protocol VerifyableInstruction : Instruction {
1717
func verify(_ context: FunctionPassContext)
1818
}
1919

20-
private func require(_ condition: Bool, _ message: @autoclosure () -> String) {
20+
private func require(_ condition: Bool, _ message: @autoclosure () -> String, atInstruction: Instruction? = nil) {
2121
if !condition {
22-
fatalError(message())
22+
let msg = message()
23+
msg._withBridgedStringRef { stringRef in
24+
verifierError(stringRef, atInstruction.bridged, Optional<Argument>.none.bridged)
25+
}
2326
}
2427
}
2528

SwiftCompilerSources/Sources/SIL/Argument.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,12 @@ extension BridgedArgument {
550550
public var functionArgument: FunctionArgument { obj.getAs(FunctionArgument.self) }
551551
}
552552

553+
extension Optional where Wrapped == Argument {
554+
public var bridged: OptionalBridgedArgument {
555+
OptionalBridgedArgument(obj: self?.bridged.obj)
556+
}
557+
}
558+
553559
extension BridgedArgumentConvention {
554560
var convention: ArgumentConvention {
555561
switch self {

include/swift/SIL/SILBridging.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1070,6 +1070,14 @@ struct BridgedArgument {
10701070

10711071
struct OptionalBridgedArgument {
10721072
OptionalSwiftObject obj;
1073+
1074+
#ifdef USED_IN_CPP_SOURCE
1075+
swift::SILArgument * _Nullable unbridged() const {
1076+
if (!obj)
1077+
return nullptr;
1078+
return static_cast<swift::SILArgument *>(obj);
1079+
}
1080+
#endif
10731081
};
10741082

10751083
struct OptionalBridgedBasicBlock {

include/swift/SIL/SILModule.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,6 +1059,11 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const SILModule &M){
10591059
return OS;
10601060
}
10611061

1062+
void verificationFailure(const Twine &complaint,
1063+
const SILInstruction *atInstruction,
1064+
const SILArgument *atArgument,
1065+
const std::function<void()> &extraContext);
1066+
10621067
inline bool SILOptions::supportsLexicalLifetimes(const SILModule &mod) const {
10631068
switch (mod.getStage()) {
10641069
case SILStage::Raw:

include/swift/SILOptimizer/OptimizerBridging.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,8 @@ BridgedDynamicCastResult classifyDynamicCastBridged(BridgedType sourceTy, Bridge
386386

387387
BridgedDynamicCastResult classifyDynamicCastBridged(BridgedInstruction inst);
388388

389+
void verifierError(BridgedStringRef message, OptionalBridgedInstruction atInstruction, OptionalBridgedArgument atArgument);
390+
389391
//===----------------------------------------------------------------------===//
390392
// Pass registration
391393
//===----------------------------------------------------------------------===//

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 53 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,58 @@ static llvm::cl::opt<bool> AllowCriticalEdges("allow-critical-edges",
9494
llvm::cl::init(true));
9595
extern llvm::cl::opt<bool> SILPrintDebugInfo;
9696

97+
void swift::verificationFailure(const Twine &complaint,
98+
const SILInstruction *atInstruction,
99+
const SILArgument *atArgument,
100+
const std::function<void()> &extraContext) {
101+
const SILFunction *f = nullptr;
102+
StringRef funcName = "?";
103+
if (atInstruction) {
104+
f = atInstruction->getFunction();
105+
funcName = f->getName();
106+
} else if (atArgument) {
107+
f = atArgument->getFunction();
108+
funcName = f->getName();
109+
}
110+
if (ContinueOnFailure) {
111+
llvm::dbgs() << "Begin Error in function " << funcName << "\n";
112+
}
113+
114+
llvm::dbgs() << "SIL verification failed: " << complaint << "\n";
115+
if (extraContext)
116+
extraContext();
117+
118+
if (atInstruction) {
119+
llvm::dbgs() << "Verifying instruction:\n";
120+
atInstruction->printInContext(llvm::dbgs());
121+
} else if (atArgument) {
122+
llvm::dbgs() << "Verifying argument:\n";
123+
atArgument->printInContext(llvm::dbgs());
124+
}
125+
if (ContinueOnFailure) {
126+
llvm::dbgs() << "End Error in function " << funcName << "\n";
127+
return;
128+
}
129+
130+
if (f) {
131+
llvm::dbgs() << "In function:\n";
132+
f->print(llvm::dbgs());
133+
if (DumpModuleOnFailure) {
134+
// Don't do this by default because modules can be _very_ large.
135+
llvm::dbgs() << "In module:\n";
136+
f->getModule().print(llvm::dbgs());
137+
}
138+
}
139+
140+
// We abort by default because we want to always crash in
141+
// the debugger.
142+
if (AbortOnFailure)
143+
abort();
144+
else
145+
exit(1);
146+
}
147+
148+
97149
// The verifier is basically all assertions, so don't compile it with NDEBUG to
98150
// prevent release builds from triggering spurious unused variable warnings.
99151

@@ -922,45 +974,7 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
922974
const std::function<void()> &extraContext = nullptr) {
923975
if (condition) return;
924976

925-
StringRef funcName;
926-
if (CurInstruction)
927-
funcName = CurInstruction->getFunction()->getName();
928-
else if (CurArgument)
929-
funcName = CurArgument->getFunction()->getName();
930-
if (ContinueOnFailure) {
931-
llvm::dbgs() << "Begin Error in function " << funcName << "\n";
932-
}
933-
934-
llvm::dbgs() << "SIL verification failed: " << complaint << "\n";
935-
if (extraContext)
936-
extraContext();
937-
938-
if (CurInstruction) {
939-
llvm::dbgs() << "Verifying instruction:\n";
940-
CurInstruction->printInContext(llvm::dbgs());
941-
} else if (CurArgument) {
942-
llvm::dbgs() << "Verifying argument:\n";
943-
CurArgument->printInContext(llvm::dbgs());
944-
}
945-
if (ContinueOnFailure) {
946-
llvm::dbgs() << "End Error in function " << funcName << "\n";
947-
return;
948-
}
949-
950-
llvm::dbgs() << "In function:\n";
951-
F.print(llvm::dbgs());
952-
if (DumpModuleOnFailure) {
953-
// Don't do this by default because modules can be _very_ large.
954-
llvm::dbgs() << "In module:\n";
955-
F.getModule().print(llvm::dbgs());
956-
}
957-
958-
// We abort by default because we want to always crash in
959-
// the debugger.
960-
if (AbortOnFailure)
961-
abort();
962-
else
963-
exit(1);
977+
verificationFailure(complaint, CurInstruction, CurArgument, extraContext);
964978
}
965979
#define require(condition, complaint) \
966980
_require(bool(condition), complaint ": " #condition)

lib/SILOptimizer/PassManager/PassManager.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2177,3 +2177,10 @@ void BridgedBuilder::destroyCapturedArgs(BridgedInstruction partialApply) const
21772177
assert(false && "`destroyCapturedArgs` must only be called on a `partial_apply` on stack!");
21782178
}
21792179
}
2180+
2181+
void verifierError(BridgedStringRef message,
2182+
OptionalBridgedInstruction atInstruction,
2183+
OptionalBridgedArgument atArgument) {
2184+
Twine msg(message.unbridged());
2185+
verificationFailure(msg, atInstruction.unbridged(), atArgument.unbridged(), /*extraContext=*/nullptr);
2186+
}

0 commit comments

Comments
 (0)