63
63
// `bar.sync` instruction happen divergently.
64
64
//
65
65
// To work around this, we add an `exit` instruction before every `unreachable`,
66
- // as `ptxas` understands that exit terminates the CFG. Note that `trap` is not
67
- // equivalent, and only future versions of `ptxas` will model it like `exit`.
66
+ // as `ptxas` understands that exit terminates the CFG. We do only do this if
67
+ // `unreachable` is not lowered to `trap`, which has the same effect (although
68
+ // with current versions of `ptxas` only because it is emited as `trap; exit;`).
68
69
//
69
70
// ===----------------------------------------------------------------------===//
70
71
@@ -83,14 +84,19 @@ void initializeNVPTXLowerUnreachablePass(PassRegistry &);
83
84
84
85
namespace {
85
86
class NVPTXLowerUnreachable : public FunctionPass {
87
+ StringRef getPassName () const override ;
86
88
bool runOnFunction (Function &F) override ;
89
+ bool isLoweredToTrap (const UnreachableInst &I) const ;
87
90
88
91
public:
89
92
static char ID; // Pass identification, replacement for typeid
90
- NVPTXLowerUnreachable () : FunctionPass(ID) {}
91
- StringRef getPassName () const override {
92
- return " add an exit instruction before every unreachable" ;
93
- }
93
+ NVPTXLowerUnreachable (bool TrapUnreachable, bool NoTrapAfterNoreturn)
94
+ : FunctionPass(ID), TrapUnreachable(TrapUnreachable),
95
+ NoTrapAfterNoreturn (NoTrapAfterNoreturn) {}
96
+
97
+ private:
98
+ bool TrapUnreachable;
99
+ bool NoTrapAfterNoreturn;
94
100
};
95
101
} // namespace
96
102
@@ -99,12 +105,33 @@ char NVPTXLowerUnreachable::ID = 1;
99
105
INITIALIZE_PASS (NVPTXLowerUnreachable, " nvptx-lower-unreachable" ,
100
106
" Lower Unreachable" , false , false )
101
107
108
+ StringRef NVPTXLowerUnreachable::getPassName() const {
109
+ return " add an exit instruction before every unreachable" ;
110
+ }
111
+
112
+ // =============================================================================
113
+ // Returns whether a `trap` intrinsic should be emitted before I.
114
+ //
115
+ // This is a copy of the logic in SelectionDAGBuilder::visitUnreachable().
116
+ // =============================================================================
117
+ bool NVPTXLowerUnreachable::isLoweredToTrap (const UnreachableInst &I) const {
118
+ if (!TrapUnreachable)
119
+ return false ;
120
+ if (!NoTrapAfterNoreturn)
121
+ return true ;
122
+ const CallInst *Call = dyn_cast_or_null<CallInst>(I.getPrevNode ());
123
+ return Call && Call->doesNotReturn ();
124
+ }
125
+
102
126
// =============================================================================
103
127
// Main function for this pass.
104
128
// =============================================================================
105
129
bool NVPTXLowerUnreachable::runOnFunction (Function &F) {
106
130
if (skipFunction (F))
107
131
return false ;
132
+ // Early out iff isLoweredToTrap() always returns true.
133
+ if (TrapUnreachable && !NoTrapAfterNoreturn)
134
+ return false ;
108
135
109
136
LLVMContext &C = F.getContext ();
110
137
FunctionType *ExitFTy = FunctionType::get (Type::getVoidTy (C), false );
@@ -114,13 +141,16 @@ bool NVPTXLowerUnreachable::runOnFunction(Function &F) {
114
141
for (auto &BB : F)
115
142
for (auto &I : BB) {
116
143
if (auto unreachableInst = dyn_cast<UnreachableInst>(&I)) {
117
- Changed = true ;
144
+ if (isLoweredToTrap (*unreachableInst))
145
+ continue ; // trap is emitted as `trap; exit;`.
118
146
CallInst::Create (ExitFTy, Exit, " " , unreachableInst);
147
+ Changed = true ;
119
148
}
120
149
}
121
150
return Changed;
122
151
}
123
152
124
- FunctionPass *llvm::createNVPTXLowerUnreachablePass () {
125
- return new NVPTXLowerUnreachable ();
153
+ FunctionPass *llvm::createNVPTXLowerUnreachablePass (bool TrapUnreachable,
154
+ bool NoTrapAfterNoreturn) {
155
+ return new NVPTXLowerUnreachable (TrapUnreachable, NoTrapAfterNoreturn);
126
156
}
0 commit comments