@@ -51,6 +51,35 @@ static const char EDXRetpolineName[] = "__llvm_retpoline_edx";
5151static const char EDIRetpolineName[] = " __llvm_retpoline_edi" ;
5252
5353namespace {
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+
5483class X86IndirectThunks : public MachineFunctionPass {
5584public:
5685 static char ID;
@@ -60,7 +89,7 @@ class X86IndirectThunks : public MachineFunctionPass {
6089 StringRef getPassName () const override { return " X86 Indirect Thunks" ; }
6190
6291 bool doInitialization (Module &M) override ;
63- bool runOnMachineFunction (MachineFunction &F ) override ;
92+ bool runOnMachineFunction (MachineFunction &MF ) override ;
6493
6594 void getAnalysisUsage (AnalysisUsage &AU) const override {
6695 MachineFunctionPass::getAnalysisUsage (AU);
@@ -69,78 +98,39 @@ class X86IndirectThunks : public MachineFunctionPass {
6998 }
7099
71100private:
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+ }
83118};
84119
85120} // end anonymous namespace
86121
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);
89129}
90130
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;
144134 if (Is64Bit) {
145135 assert (MF.getName () == " __llvm_retpoline_r11" &&
146136 " Should only have an r11 thunk on 64-bit targets" );
@@ -155,7 +145,7 @@ bool X86IndirectThunks::runOnMachineFunction(MachineFunction &MF) {
155145 // .Lr11_call_target:
156146 // movq %r11, (%rsp)
157147 // retq
158- populateThunk (MF, X86::R11) ;
148+ ThunkReg = X86::R11;
159149 } else {
160150 // For 32-bit targets we need to emit a collection of thunks for various
161151 // possible scratch registers as well as a fallback that uses EDI, which is
@@ -185,67 +175,18 @@ bool X86IndirectThunks::runOnMachineFunction(MachineFunction &MF) {
185175 // movl %edi, (%esp)
186176 // retl
187177 if (MF.getName () == EAXRetpolineName)
188- populateThunk (MF, X86::EAX) ;
178+ ThunkReg = X86::EAX;
189179 else if (MF.getName () == ECXRetpolineName)
190- populateThunk (MF, X86::ECX) ;
180+ ThunkReg = X86::ECX;
191181 else if (MF.getName () == EDXRetpolineName)
192- populateThunk (MF, X86::EDX) ;
182+ ThunkReg = X86::EDX;
193183 else if (MF.getName () == EDIRetpolineName)
194- populateThunk (MF, X86::EDI) ;
184+ ThunkReg = X86::EDI;
195185 else
196186 llvm_unreachable (" Invalid thunk name on x86-32!" );
197187 }
198188
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 ();
249190 // Grab the entry MBB and erase any other blocks. O0 codegen appears to
250191 // generate two bbs for the entry block.
251192 MachineBasicBlock *Entry = &MF.front ();
@@ -264,7 +205,7 @@ void X86IndirectThunks::populateThunk(MachineFunction &MF,
264205 const unsigned CallOpc = Is64Bit ? X86::CALL64pcrel32 : X86::CALLpcrel32;
265206 const unsigned RetOpc = Is64Bit ? X86::RETQ : X86::RETL;
266207
267- Entry->addLiveIn (Reg );
208+ Entry->addLiveIn (ThunkReg );
268209 BuildMI (Entry, DebugLoc (), TII->get (CallOpc)).addSym (TargetSym);
269210
270211 // The MIR verifier thinks that the CALL in the entry block will fall through
@@ -286,10 +227,101 @@ void X86IndirectThunks::populateThunk(MachineFunction &MF,
286227 CaptureSpec->setHasAddressTaken ();
287228 CaptureSpec->addSuccessor (CaptureSpec);
288229
289- CallTarget->addLiveIn (Reg );
230+ CallTarget->addLiveIn (ThunkReg );
290231 CallTarget->setHasAddressTaken ();
291232 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+
293241 CallTarget->back ().setPreInstrSymbol (MF, TargetSym);
294242 BuildMI (CallTarget, DebugLoc (), TII->get (RetOpc));
295243}
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