@@ -51,6 +51,35 @@ static const char EDXRetpolineName[] = "__llvm_retpoline_edx";
51
51
static const char EDIRetpolineName[] = " __llvm_retpoline_edi" ;
52
52
53
53
namespace {
54
+ template <typename Derived> class ThunkInserter {
55
+ Derived &getDerived () { return *static_cast <Derived *>(this ); }
56
+
57
+ protected:
58
+ bool InsertedThunks;
59
+ void doInitialization (Module &M) {}
60
+ void createThunkFunction (MachineModuleInfo &MMI, StringRef Name);
61
+
62
+ public:
63
+ void init (Module &M) {
64
+ InsertedThunks = false ;
65
+ getDerived ().doInitialization (M);
66
+ }
67
+ // return `true` if `MMI` or `MF` was modified
68
+ bool run (MachineModuleInfo &MMI, MachineFunction &MF);
69
+ };
70
+
71
+ struct RetpolineThunkInserter : ThunkInserter<RetpolineThunkInserter> {
72
+ const char *getThunkPrefix () { return RetpolineNamePrefix; }
73
+ bool mayUseThunk (const MachineFunction &MF) {
74
+ const auto &STI = MF.getSubtarget <X86Subtarget>();
75
+ return (STI.useRetpolineIndirectCalls () ||
76
+ STI.useRetpolineIndirectBranches ()) &&
77
+ !STI.useRetpolineExternalThunk ();
78
+ }
79
+ void insertThunks (MachineModuleInfo &MMI);
80
+ void populateThunk (MachineFunction &MF);
81
+ };
82
+
54
83
class X86IndirectThunks : public MachineFunctionPass {
55
84
public:
56
85
static char ID;
@@ -60,7 +89,7 @@ class X86IndirectThunks : public MachineFunctionPass {
60
89
StringRef getPassName () const override { return " X86 Indirect Thunks" ; }
61
90
62
91
bool doInitialization (Module &M) override ;
63
- bool runOnMachineFunction (MachineFunction &F ) override ;
92
+ bool runOnMachineFunction (MachineFunction &MF ) override ;
64
93
65
94
void getAnalysisUsage (AnalysisUsage &AU) const override {
66
95
MachineFunctionPass::getAnalysisUsage (AU);
@@ -69,78 +98,39 @@ class X86IndirectThunks : public MachineFunctionPass {
69
98
}
70
99
71
100
private:
72
- MachineModuleInfo *MMI = nullptr ;
73
- const TargetMachine *TM = nullptr ;
74
- bool Is64Bit = false ;
75
- const X86Subtarget *STI = nullptr ;
76
- const X86InstrInfo *TII = nullptr ;
77
-
78
- bool InsertedThunks = false ;
79
-
80
- void createThunkFunction (Module &M, StringRef Name);
81
- void insertRegReturnAddrClobber (MachineBasicBlock &MBB, Register Reg);
82
- void populateThunk (MachineFunction &MF, Register Reg);
101
+ std::tuple<RetpolineThunkInserter> TIs;
102
+
103
+ // FIXME: When LLVM moves to C++17, these can become folds
104
+ template <typename ... ThunkInserterT>
105
+ static void initTIs (Module &M,
106
+ std::tuple<ThunkInserterT...> &ThunkInserters) {
107
+ (void )std::initializer_list<int >{
108
+ (std::get<ThunkInserterT>(ThunkInserters).init (M), 0 )...};
109
+ }
110
+ template <typename ... ThunkInserterT>
111
+ static bool runTIs (MachineModuleInfo &MMI, MachineFunction &MF,
112
+ std::tuple<ThunkInserterT...> &ThunkInserters) {
113
+ bool Modified = false ;
114
+ (void )std::initializer_list<int >{
115
+ Modified |= std::get<ThunkInserterT>(ThunkInserters).run (MMI, MF)...};
116
+ return Modified;
117
+ }
83
118
};
84
119
85
120
} // end anonymous namespace
86
121
87
- FunctionPass *llvm::createX86IndirectThunksPass () {
88
- return new X86IndirectThunks ();
122
+ void RetpolineThunkInserter::insertThunks (MachineModuleInfo &MMI) {
123
+ if (MMI.getTarget ().getTargetTriple ().getArch () == Triple::x86_64)
124
+ createThunkFunction (MMI, R11RetpolineName);
125
+ else
126
+ for (StringRef Name : {EAXRetpolineName, ECXRetpolineName, EDXRetpolineName,
127
+ EDIRetpolineName})
128
+ createThunkFunction (MMI, Name);
89
129
}
90
130
91
- char X86IndirectThunks::ID = 0 ;
92
-
93
- bool X86IndirectThunks::doInitialization (Module &M) {
94
- InsertedThunks = false ;
95
- return false ;
96
- }
97
-
98
- bool X86IndirectThunks::runOnMachineFunction (MachineFunction &MF) {
99
- LLVM_DEBUG (dbgs () << getPassName () << ' \n ' );
100
-
101
- TM = &MF.getTarget ();;
102
- STI = &MF.getSubtarget <X86Subtarget>();
103
- TII = STI->getInstrInfo ();
104
- Is64Bit = TM->getTargetTriple ().getArch () == Triple::x86_64;
105
-
106
- MMI = &getAnalysis<MachineModuleInfoWrapperPass>().getMMI ();
107
- Module &M = const_cast <Module &>(*MMI->getModule ());
108
-
109
- // If this function is not a thunk, check to see if we need to insert
110
- // a thunk.
111
- if (!MF.getName ().startswith (RetpolineNamePrefix)) {
112
- // If we've already inserted a thunk, nothing else to do.
113
- if (InsertedThunks)
114
- return false ;
115
-
116
- // Only add a thunk if one of the functions has the retpoline feature
117
- // enabled in its subtarget, and doesn't enable external thunks.
118
- // FIXME: Conditionalize on indirect calls so we don't emit a thunk when
119
- // nothing will end up calling it.
120
- // FIXME: It's a little silly to look at every function just to enumerate
121
- // the subtargets, but eventually we'll want to look at them for indirect
122
- // calls, so maybe this is OK.
123
- if ((!STI->useRetpolineIndirectCalls () &&
124
- !STI->useRetpolineIndirectBranches ()) ||
125
- STI->useRetpolineExternalThunk ())
126
- return false ;
127
-
128
- // Otherwise, we need to insert the thunk.
129
- // WARNING: This is not really a well behaving thing to do in a function
130
- // pass. We extract the module and insert a new function (and machine
131
- // function) directly into the module.
132
- if (Is64Bit)
133
- createThunkFunction (M, R11RetpolineName);
134
- else
135
- for (StringRef Name :
136
- {EAXRetpolineName, ECXRetpolineName, EDXRetpolineName,
137
- EDIRetpolineName})
138
- createThunkFunction (M, Name);
139
- InsertedThunks = true ;
140
- return true ;
141
- }
142
-
143
- // If this *is* a thunk function, we need to populate it with the correct MI.
131
+ void RetpolineThunkInserter::populateThunk (MachineFunction &MF) {
132
+ bool Is64Bit = MF.getTarget ().getTargetTriple ().getArch () == Triple::x86_64;
133
+ Register ThunkReg;
144
134
if (Is64Bit) {
145
135
assert (MF.getName () == " __llvm_retpoline_r11" &&
146
136
" Should only have an r11 thunk on 64-bit targets" );
@@ -155,7 +145,7 @@ bool X86IndirectThunks::runOnMachineFunction(MachineFunction &MF) {
155
145
// .Lr11_call_target:
156
146
// movq %r11, (%rsp)
157
147
// retq
158
- populateThunk (MF, X86::R11) ;
148
+ ThunkReg = X86::R11;
159
149
} else {
160
150
// For 32-bit targets we need to emit a collection of thunks for various
161
151
// possible scratch registers as well as a fallback that uses EDI, which is
@@ -185,67 +175,18 @@ bool X86IndirectThunks::runOnMachineFunction(MachineFunction &MF) {
185
175
// movl %edi, (%esp)
186
176
// retl
187
177
if (MF.getName () == EAXRetpolineName)
188
- populateThunk (MF, X86::EAX) ;
178
+ ThunkReg = X86::EAX;
189
179
else if (MF.getName () == ECXRetpolineName)
190
- populateThunk (MF, X86::ECX) ;
180
+ ThunkReg = X86::ECX;
191
181
else if (MF.getName () == EDXRetpolineName)
192
- populateThunk (MF, X86::EDX) ;
182
+ ThunkReg = X86::EDX;
193
183
else if (MF.getName () == EDIRetpolineName)
194
- populateThunk (MF, X86::EDI) ;
184
+ ThunkReg = X86::EDI;
195
185
else
196
186
llvm_unreachable (" Invalid thunk name on x86-32!" );
197
187
}
198
188
199
- return true ;
200
- }
201
-
202
- void X86IndirectThunks::createThunkFunction (Module &M, StringRef Name) {
203
- assert (Name.startswith (RetpolineNamePrefix) &&
204
- " Created a thunk with an unexpected prefix!" );
205
-
206
- LLVMContext &Ctx = M.getContext ();
207
- auto Type = FunctionType::get (Type::getVoidTy (Ctx), false );
208
- Function *F =
209
- Function::Create (Type, GlobalValue::LinkOnceODRLinkage, Name, &M);
210
- F->setVisibility (GlobalValue::HiddenVisibility);
211
- F->setComdat (M.getOrInsertComdat (Name));
212
-
213
- // Add Attributes so that we don't create a frame, unwind information, or
214
- // inline.
215
- AttrBuilder B;
216
- B.addAttribute (llvm::Attribute::NoUnwind);
217
- B.addAttribute (llvm::Attribute::Naked);
218
- F->addAttributes (llvm::AttributeList::FunctionIndex, B);
219
-
220
- // Populate our function a bit so that we can verify.
221
- BasicBlock *Entry = BasicBlock::Create (Ctx, " entry" , F);
222
- IRBuilder<> Builder (Entry);
223
-
224
- Builder.CreateRetVoid ();
225
-
226
- // MachineFunctions/MachineBasicBlocks aren't created automatically for the
227
- // IR-level constructs we already made. Create them and insert them into the
228
- // module.
229
- MachineFunction &MF = MMI->getOrCreateMachineFunction (*F);
230
- MachineBasicBlock *EntryMBB = MF.CreateMachineBasicBlock (Entry);
231
-
232
- // Insert EntryMBB into MF. It's not in the module until we do this.
233
- MF.insert (MF.end (), EntryMBB);
234
- }
235
-
236
- void X86IndirectThunks::insertRegReturnAddrClobber (MachineBasicBlock &MBB,
237
- Register Reg) {
238
- const unsigned MovOpc = Is64Bit ? X86::MOV64mr : X86::MOV32mr;
239
- const Register SPReg = Is64Bit ? X86::RSP : X86::ESP;
240
- addRegOffset (BuildMI (&MBB, DebugLoc (), TII->get (MovOpc)), SPReg, false , 0 )
241
- .addReg (Reg);
242
- }
243
-
244
- void X86IndirectThunks::populateThunk (MachineFunction &MF,
245
- Register Reg) {
246
- // Set MF properties. We never use vregs...
247
- MF.getProperties ().set (MachineFunctionProperties::Property::NoVRegs);
248
-
189
+ const TargetInstrInfo *TII = MF.getSubtarget <X86Subtarget>().getInstrInfo ();
249
190
// Grab the entry MBB and erase any other blocks. O0 codegen appears to
250
191
// generate two bbs for the entry block.
251
192
MachineBasicBlock *Entry = &MF.front ();
@@ -264,7 +205,7 @@ void X86IndirectThunks::populateThunk(MachineFunction &MF,
264
205
const unsigned CallOpc = Is64Bit ? X86::CALL64pcrel32 : X86::CALLpcrel32;
265
206
const unsigned RetOpc = Is64Bit ? X86::RETQ : X86::RETL;
266
207
267
- Entry->addLiveIn (Reg );
208
+ Entry->addLiveIn (ThunkReg );
268
209
BuildMI (Entry, DebugLoc (), TII->get (CallOpc)).addSym (TargetSym);
269
210
270
211
// The MIR verifier thinks that the CALL in the entry block will fall through
@@ -286,10 +227,101 @@ void X86IndirectThunks::populateThunk(MachineFunction &MF,
286
227
CaptureSpec->setHasAddressTaken ();
287
228
CaptureSpec->addSuccessor (CaptureSpec);
288
229
289
- CallTarget->addLiveIn (Reg );
230
+ CallTarget->addLiveIn (ThunkReg );
290
231
CallTarget->setHasAddressTaken ();
291
232
CallTarget->setAlignment (Align (16 ));
292
- insertRegReturnAddrClobber (*CallTarget, Reg);
233
+
234
+ // Insert return address clobber
235
+ const unsigned MovOpc = Is64Bit ? X86::MOV64mr : X86::MOV32mr;
236
+ const Register SPReg = Is64Bit ? X86::RSP : X86::ESP;
237
+ addRegOffset (BuildMI (CallTarget, DebugLoc (), TII->get (MovOpc)), SPReg, false ,
238
+ 0 )
239
+ .addReg (ThunkReg);
240
+
293
241
CallTarget->back ().setPreInstrSymbol (MF, TargetSym);
294
242
BuildMI (CallTarget, DebugLoc (), TII->get (RetOpc));
295
243
}
244
+
245
+ template <typename Derived>
246
+ void ThunkInserter<Derived>::createThunkFunction(MachineModuleInfo &MMI,
247
+ StringRef Name) {
248
+ assert (Name.startswith (getDerived ().getThunkPrefix ()) &&
249
+ " Created a thunk with an unexpected prefix!" );
250
+
251
+ Module &M = const_cast <Module &>(*MMI.getModule ());
252
+ LLVMContext &Ctx = M.getContext ();
253
+ auto Type = FunctionType::get (Type::getVoidTy (Ctx), false );
254
+ Function *F =
255
+ Function::Create (Type, GlobalValue::LinkOnceODRLinkage, Name, &M);
256
+ F->setVisibility (GlobalValue::HiddenVisibility);
257
+ F->setComdat (M.getOrInsertComdat (Name));
258
+
259
+ // Add Attributes so that we don't create a frame, unwind information, or
260
+ // inline.
261
+ AttrBuilder B;
262
+ B.addAttribute (llvm::Attribute::NoUnwind);
263
+ B.addAttribute (llvm::Attribute::Naked);
264
+ F->addAttributes (llvm::AttributeList::FunctionIndex, B);
265
+
266
+ // Populate our function a bit so that we can verify.
267
+ BasicBlock *Entry = BasicBlock::Create (Ctx, " entry" , F);
268
+ IRBuilder<> Builder (Entry);
269
+
270
+ Builder.CreateRetVoid ();
271
+
272
+ // MachineFunctions/MachineBasicBlocks aren't created automatically for the
273
+ // IR-level constructs we already made. Create them and insert them into the
274
+ // module.
275
+ MachineFunction &MF = MMI.getOrCreateMachineFunction (*F);
276
+ MachineBasicBlock *EntryMBB = MF.CreateMachineBasicBlock (Entry);
277
+
278
+ // Insert EntryMBB into MF. It's not in the module until we do this.
279
+ MF.insert (MF.end (), EntryMBB);
280
+ // Set MF properties. We never use vregs...
281
+ MF.getProperties ().set (MachineFunctionProperties::Property::NoVRegs);
282
+ }
283
+
284
+ template <typename Derived>
285
+ bool ThunkInserter<Derived>::run(MachineModuleInfo &MMI, MachineFunction &MF) {
286
+ // If MF is not a thunk, check to see if we need to insert a thunk.
287
+ if (!MF.getName ().startswith (getDerived ().getThunkPrefix ())) {
288
+ // If we've already inserted a thunk, nothing else to do.
289
+ if (InsertedThunks)
290
+ return false ;
291
+
292
+ // Only add a thunk if one of the functions has the corresponding feature
293
+ // enabled in its subtarget, and doesn't enable external thunks.
294
+ // FIXME: Conditionalize on indirect calls so we don't emit a thunk when
295
+ // nothing will end up calling it.
296
+ // FIXME: It's a little silly to look at every function just to enumerate
297
+ // the subtargets, but eventually we'll want to look at them for indirect
298
+ // calls, so maybe this is OK.
299
+ if (!getDerived ().mayUseThunk (MF))
300
+ return false ;
301
+
302
+ getDerived ().insertThunks (MMI);
303
+ InsertedThunks = true ;
304
+ return true ;
305
+ }
306
+
307
+ // If this *is* a thunk function, we need to populate it with the correct MI.
308
+ getDerived ().populateThunk (MF);
309
+ return true ;
310
+ }
311
+
312
+ FunctionPass *llvm::createX86IndirectThunksPass () {
313
+ return new X86IndirectThunks ();
314
+ }
315
+
316
+ char X86IndirectThunks::ID = 0 ;
317
+
318
+ bool X86IndirectThunks::doInitialization (Module &M) {
319
+ initTIs (M, TIs);
320
+ return false ;
321
+ }
322
+
323
+ bool X86IndirectThunks::runOnMachineFunction (MachineFunction &MF) {
324
+ LLVM_DEBUG (dbgs () << getPassName () << ' \n ' );
325
+ auto &MMI = getAnalysis<MachineModuleInfoWrapperPass>().getMMI ();
326
+ return runTIs (MMI, MF, TIs);
327
+ }
0 commit comments