LLVM 20.0.0git
IndirectThunks.h
Go to the documentation of this file.
1//===---- IndirectThunks.h - Indirect thunk insertion helpers ---*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8///
9/// \file
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.
13///
14//===----------------------------------------------------------------------===//
15
16#ifndef LLVM_CODEGEN_INDIRECTTHUNKS_H
17#define LLVM_CODEGEN_INDIRECTTHUNKS_H
18
22#include "llvm/IR/IRBuilder.h"
23#include "llvm/IR/Module.h"
24
25namespace llvm {
26
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.
60template <typename Derived, typename InsertedThunksTy = bool>
62 Derived &getDerived() { return *static_cast<Derived *>(this); }
63
64 // A variable used to track whether (and possible which) thunks have been
65 // inserted so far. InsertedThunksTy is usually a bool, but can be other types
66 // to represent more than one type of thunk. Requires an |= operator to
67 // accumulate results.
68 InsertedThunksTy InsertedThunks;
69
70protected:
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.
78 bool Comdat = true, StringRef TargetAttrs = "");
79
80protected:
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.
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.
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
109public:
110 void init(Module &M) {
111 InsertedThunks = InsertedThunksTy{};
112 getDerived().doInitialization(M);
113 }
114 // return `true` if `MMI` or `MF` was modified
115 bool run(MachineModuleInfo &MMI, MachineFunction &MF);
116};
117
118template <typename Derived, typename InsertedThunksTy>
121 StringRef TargetAttrs) {
122 assert(Name.starts_with(getDerived().getThunkPrefix()) &&
123 "Created a thunk with an unexpected prefix!");
124
125 Module &M = const_cast<Module &>(*MMI.getModule());
126 LLVMContext &Ctx = M.getContext();
127 auto *Type = FunctionType::get(Type::getVoidTy(Ctx), false);
131 Name, &M);
132 if (Comdat) {
133 F->setVisibility(GlobalValue::HiddenVisibility);
134 F->setComdat(M.getOrInsertComdat(Name));
135 }
136
137 // Add Attributes so that we don't create a frame, unwind information, or
138 // inline.
139 AttrBuilder B(Ctx);
140 B.addAttribute(llvm::Attribute::NoUnwind);
141 B.addAttribute(llvm::Attribute::Naked);
142 if (TargetAttrs != "")
143 B.addAttribute("target-features", TargetAttrs);
144 F->addFnAttrs(B);
145
146 // Populate our function a bit so that we can verify.
147 BasicBlock *Entry = BasicBlock::Create(Ctx, "entry", F);
148 IRBuilder<> Builder(Entry);
149
150 Builder.CreateRetVoid();
151
152 // MachineFunctions aren't created automatically for the IR-level constructs
153 // we already made. Create them and insert them into the module.
155 // A MachineBasicBlock must not be created for the Entry block; code
156 // generation from an empty naked function in C source code also does not
157 // generate one. At least GlobalISel asserts if this invariant isn't
158 // respected.
159
160 // Set MF properties. We never use vregs...
162}
163
164template <typename Derived, typename InsertedThunksTy>
166 MachineFunction &MF) {
167 // If MF is not a thunk, check to see if we need to insert a thunk.
168 if (!MF.getName().starts_with(getDerived().getThunkPrefix())) {
169 // Only add thunks if one of the functions may use them.
170 if (!getDerived().mayUseThunk(MF))
171 return false;
172
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);
178 return true;
179 }
180
181 // If this *is* a thunk function, we need to populate it with the correct MI.
182 getDerived().populateThunk(MF);
183 return true;
184}
185
186/// Basic implementation of MachineFunctionPass wrapping one or more
187/// `ThunkInserter`s passed as type parameters.
188template <typename... Inserters>
190protected:
191 std::tuple<Inserters...> TIs;
192
194
195public:
196 bool doInitialization(Module &M) override {
197 initTIs(M, TIs);
198 return false;
199 }
200
202 auto &MMI = getAnalysis<MachineModuleInfoWrapperPass>().getMMI();
203 return runTIs(MMI, MF, TIs);
204 }
205
206private:
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
220} // namespace llvm
221
222#endif
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
std::string Name
#define F(x, y, z)
Definition: MD5.cpp:55
Module.h This file contains the declarations for the Module class.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
LLVM Basic Block Representation.
Definition: BasicBlock.h:61
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
Definition: BasicBlock.h:212
static FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
Definition: Function.h:172
@ HiddenVisibility
The GV is hidden.
Definition: GlobalValue.h:68
@ InternalLinkage
Rename collisions when linking (static functions).
Definition: GlobalValue.h:59
@ LinkOnceODRLinkage
Same, but only replaced by something equivalent.
Definition: GlobalValue.h:55
ReturnInst * CreateRetVoid()
Create a 'ret void' instruction.
Definition: IRBuilder.h:1107
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition: IRBuilder.h:2686
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:67
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
MachineFunctionProperties & set(Property P)
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
const MachineFunctionProperties & getProperties() const
Get the function properties.
This class contains meta information specific to a module.
const Module * getModule() const
MachineFunction & getOrCreateMachineFunction(Function &F)
Returns the MachineFunction constructed for the IR function F.
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:65
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition: StringRef.h:250
Basic implementation of MachineFunctionPass wrapping one or more ThunkInserters passed as type parame...
bool doInitialization(Module &M) override
doInitialization - Virtual method overridden by subclasses to do any necessary initialization before ...
bool runOnMachineFunction(MachineFunction &MF) override
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
std::tuple< Inserters... > TIs
This class assists in inserting MI thunk functions into the module and rewriting the existing machine...
bool mayUseThunk(const MachineFunction &MF)
Checks if MF may use thunks (true - maybe, false - definitely not).
void createThunkFunction(MachineModuleInfo &MMI, StringRef Name, bool Comdat=true, StringRef TargetAttrs="")
Create an empty thunk function.
InsertedThunksTy insertThunks(MachineModuleInfo &MMI, MachineFunction &MF, InsertedThunksTy ExistingThunks)
Rewrites the function if necessary, returns the set of thunks added.
bool run(MachineModuleInfo &MMI, MachineFunction &MF)
void doInitialization(Module &M)
Initializes thunk inserter.
const char * getThunkPrefix()
Returns common prefix for thunk function's names.
void init(Module &M)
void populateThunk(MachineFunction &MF)
Populate the thunk function with instructions.
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
static Type * getVoidTy(LLVMContext &C)
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18