1- // ===---- IndirectThunks.h - Indirect Thunk Base Class ------- ---*- C++ -*-===//
1+ // ===---- IndirectThunks.h - Indirect thunk insertion helpers ---*- C++ -*-===//
22//
33// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44// See https://llvm.org/LICENSE.txt for license information.
77// ===----------------------------------------------------------------------===//
88// /
99// / \file
10- // / Contains a base class for Passes that inject an MI thunk.
10+ // / Contains a base ThunkInserter class that simplifies injection of MI thunks
11+ // / as well as a default implementation of MachineFunctionPass wrapping
12+ // / several `ThunkInserter`s for targets to extend.
1113// /
1214// ===----------------------------------------------------------------------===//
1315
1416#ifndef LLVM_CODEGEN_INDIRECTTHUNKS_H
1517#define LLVM_CODEGEN_INDIRECTTHUNKS_H
1618
1719#include " llvm/CodeGen/MachineFunction.h"
20+ #include " llvm/CodeGen/MachineFunctionPass.h"
1821#include " llvm/CodeGen/MachineModuleInfo.h"
1922#include " llvm/IR/IRBuilder.h"
2023#include " llvm/IR/Module.h"
2124
2225namespace llvm {
2326
27+ // / This class assists in inserting MI thunk functions into the module and
28+ // / rewriting the existing machine functions to call these thunks.
29+ // /
30+ // / One of the common cases is implementing security mitigations that involve
31+ // / replacing some machine code patterns with calls to special thunk functions.
32+ // /
33+ // / Inserting a module pass late in the codegen pipeline may increase memory
34+ // / usage, as it serializes the transformations and forces preceding passes to
35+ // / produce machine code for all functions before running the module pass.
36+ // / For that reason, ThunkInserter can be driven by a MachineFunctionPass by
37+ // / passing one MachineFunction at a time to its `run(MMI, MF)` method.
38+ // / Then, the derived class should
39+ // / * call createThunkFunction from its insertThunks method exactly once for
40+ // / each of the thunk functions to be inserted
41+ // / * populate the thunk in its populateThunk method
42+ // /
43+ // / Note that if some other pass is responsible for rewriting the functions,
44+ // / the insertThunks method may simply create all possible thunks at once,
45+ // / probably postponed until the first occurrence of possibly affected MF.
46+ // /
47+ // / Alternatively, insertThunks method can rewrite MF by itself and only insert
48+ // / the thunks being called. In that case InsertedThunks variable can be used
49+ // / to track which thunks were already inserted.
50+ // /
51+ // / In any case, the thunk function has to be inserted on behalf of some other
52+ // / function and then populated on its own "iteration" later - this is because
53+ // / MachineFunctionPass will see the newly created functions, but they first
54+ // / have to go through the preceding passes from the same pass manager,
55+ // / possibly even through the instruction selector.
56+ //
57+ // FIXME Maybe implement a documented and less surprising way of modifying
58+ // the module from a MachineFunctionPass that is restricted to inserting
59+ // completely new functions to the module.
2460template <typename Derived, typename InsertedThunksTy = bool >
2561class ThunkInserter {
2662 Derived &getDerived () { return *static_cast <Derived *>(this ); }
2763
28- protected:
2964 // A variable used to track whether (and possible which) thunks have been
3065 // inserted so far. InsertedThunksTy is usually a bool, but can be other types
3166 // to represent more than one type of thunk. Requires an |= operator to
3267 // accumulate results.
3368 InsertedThunksTy InsertedThunks;
34- void doInitialization (Module &M) {}
69+
70+ protected:
71+ // Interface for subclasses to use.
72+
73+ // / Create an empty thunk function.
74+ // /
75+ // / The new function will eventually be passed to populateThunk. If multiple
76+ // / thunks are created, populateThunk can distinguish them by their names.
3577 void createThunkFunction (MachineModuleInfo &MMI, StringRef Name,
3678 bool Comdat = true , StringRef TargetAttrs = " " );
3779
80+ protected:
81+ // Interface for subclasses to implement.
82+ //
83+ // Note: all functions are non-virtual and are called via getDerived().
84+ // Note: only doInitialization() has an implementation.
85+
86+ // / Initializes thunk inserter.
87+ void doInitialization (Module &M) {}
88+
89+ // / Returns common prefix for thunk function's names.
90+ const char *getThunkPrefix (); // undefined
91+
92+ // / Checks if MF may use thunks (true - maybe, false - definitely not).
93+ bool mayUseThunk (const MachineFunction &MF); // undefined
94+
95+ // / Rewrites the function if necessary, returns the set of thunks added.
96+ InsertedThunksTy insertThunks (MachineModuleInfo &MMI, MachineFunction &MF,
97+ InsertedThunksTy ExistingThunks); // undefined
98+
99+ // / Populate the thunk function with instructions.
100+ // /
101+ // / If multiple thunks are created, the content that must be inserted in the
102+ // / thunk function body should be derived from the MF's name.
103+ // /
104+ // / Depending on the preceding passes in the pass manager, by the time
105+ // / populateThunk is called, MF may have a few target-specific instructions
106+ // / (such as a single MBB containing the return instruction).
107+ void populateThunk (MachineFunction &MF); // undefined
108+
38109public:
39110 void init (Module &M) {
40111 InsertedThunks = InsertedThunksTy{};
@@ -53,7 +124,7 @@ void ThunkInserter<Derived, InsertedThunksTy>::createThunkFunction(
53124
54125 Module &M = const_cast <Module &>(*MMI.getModule ());
55126 LLVMContext &Ctx = M.getContext ();
56- auto Type = FunctionType::get (Type::getVoidTy (Ctx), false );
127+ auto * Type = FunctionType::get (Type::getVoidTy (Ctx), false );
57128 Function *F = Function::Create (Type,
58129 Comdat ? GlobalValue::LinkOnceODRLinkage
59130 : GlobalValue::InternalLinkage,
@@ -95,19 +166,15 @@ bool ThunkInserter<Derived, InsertedThunksTy>::run(MachineModuleInfo &MMI,
95166 MachineFunction &MF) {
96167 // If MF is not a thunk, check to see if we need to insert a thunk.
97168 if (!MF.getName ().starts_with (getDerived ().getThunkPrefix ())) {
98- // Only add a thunk if one of the functions has the corresponding feature
99- // enabled in its subtarget, and doesn't enable external thunks. The target
100- // can use InsertedThunks to detect whether relevant thunks have already
101- // been inserted.
102- // FIXME: Conditionalize on indirect calls so we don't emit a thunk when
103- // nothing will end up calling it.
104- // FIXME: It's a little silly to look at every function just to enumerate
105- // the subtargets, but eventually we'll want to look at them for indirect
106- // calls, so maybe this is OK.
107- if (!getDerived ().mayUseThunk (MF, InsertedThunks))
169+ // Only add thunks if one of the functions may use them.
170+ if (!getDerived ().mayUseThunk (MF))
108171 return false ;
109172
110- InsertedThunks |= getDerived ().insertThunks (MMI, MF);
173+ // The target can use InsertedThunks to detect whether relevant thunks
174+ // have already been inserted.
175+ // FIXME: Provide the way for insertThunks to notify us whether it changed
176+ // the MF, instead of conservatively assuming it did.
177+ InsertedThunks |= getDerived ().insertThunks (MMI, MF, InsertedThunks);
111178 return true ;
112179 }
113180
@@ -116,6 +183,40 @@ bool ThunkInserter<Derived, InsertedThunksTy>::run(MachineModuleInfo &MMI,
116183 return true ;
117184}
118185
186+ // / Basic implementation of MachineFunctionPass wrapping one or more
187+ // / `ThunkInserter`s passed as type parameters.
188+ template <typename ... Inserters>
189+ class ThunkInserterPass : public MachineFunctionPass {
190+ protected:
191+ std::tuple<Inserters...> TIs;
192+
193+ ThunkInserterPass (char &ID) : MachineFunctionPass(ID) {}
194+
195+ public:
196+ bool doInitialization (Module &M) override {
197+ initTIs (M, TIs);
198+ return false ;
199+ }
200+
201+ bool runOnMachineFunction (MachineFunction &MF) override {
202+ auto &MMI = getAnalysis<MachineModuleInfoWrapperPass>().getMMI ();
203+ return runTIs (MMI, MF, TIs);
204+ }
205+
206+ private:
207+ template <typename ... ThunkInserterT>
208+ static void initTIs (Module &M,
209+ std::tuple<ThunkInserterT...> &ThunkInserters) {
210+ (..., std::get<ThunkInserterT>(ThunkInserters).init (M));
211+ }
212+
213+ template <typename ... ThunkInserterT>
214+ static bool runTIs (MachineModuleInfo &MMI, MachineFunction &MF,
215+ std::tuple<ThunkInserterT...> &ThunkInserters) {
216+ return (0 | ... | std::get<ThunkInserterT>(ThunkInserters).run (MMI, MF));
217+ }
218+ };
219+
119220} // namespace llvm
120221
121222#endif
0 commit comments