LLVM 24.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
85 /// Returns common prefix for thunk function's names.
86 const char *getThunkPrefix(); // undefined
87
88 /// Checks if MF may use thunks (true - maybe, false - definitely not).
89 bool mayUseThunk(const MachineFunction &MF); // undefined
90
91 /// Rewrites the function if necessary, returns the set of thunks added.
93 InsertedThunksTy ExistingThunks); // undefined
94
95 /// Populate the thunk function with instructions.
96 ///
97 /// If multiple thunks are created, the content that must be inserted in the
98 /// thunk function body should be derived from the MF's name.
99 ///
100 /// Depending on the preceding passes in the pass manager, by the time
101 /// populateThunk is called, MF may have a few target-specific instructions
102 /// (such as a single MBB containing the return instruction).
103 void populateThunk(MachineFunction &MF); // undefined
104
105public:
106 // return `true` if `MMI` or `MF` was modified
108};
109
110template <typename Derived, typename InsertedThunksTy>
112 MachineModuleInfo &MMI, StringRef Name, bool Comdat,
113 StringRef TargetAttrs) {
114 assert(Name.starts_with(getDerived().getThunkPrefix()) &&
115 "Created a thunk with an unexpected prefix!");
116
117 Module &M = const_cast<Module &>(*MMI.getModule());
118 LLVMContext &Ctx = M.getContext();
119 auto *Type = FunctionType::get(Type::getVoidTy(Ctx), false);
123 Name, &M);
124 if (Comdat) {
125 F->setVisibility(GlobalValue::HiddenVisibility);
126 F->setComdat(M.getOrInsertComdat(Name));
127 }
128
129 // Add Attributes so that we don't create a frame, unwind information, or
130 // inline.
131 AttrBuilder B(Ctx);
132 B.addAttribute(llvm::Attribute::NoUnwind);
133 B.addAttribute(llvm::Attribute::Naked);
134 if (TargetAttrs != "")
135 B.addAttribute("target-features", TargetAttrs);
136 F->addFnAttrs(B);
137
138 // Populate our function a bit so that we can verify.
139 BasicBlock *Entry = BasicBlock::Create(Ctx, "entry", F);
140 IRBuilder<> Builder(Entry);
141
142 Builder.CreateRetVoid();
143
144 // MachineFunctions aren't created automatically for the IR-level constructs
145 // we already made. Create them and insert them into the module.
147 // A MachineBasicBlock must not be created for the Entry block; code
148 // generation from an empty naked function in C source code also does not
149 // generate one. At least GlobalISel asserts if this invariant isn't
150 // respected.
151
152 // Set MF properties. We never use vregs.
153 MF.getProperties().setNoVRegs();
154}
155
156template <typename Derived, typename InsertedThunksTy>
158 MachineFunction &MF) {
159 // If MF is not a thunk, check to see if we need to insert a thunk.
160 if (!MF.getName().starts_with(getDerived().getThunkPrefix())) {
161 // Only add thunks if one of the functions may use them.
162 if (!getDerived().mayUseThunk(MF))
163 return false;
164
165 // The target can use InsertedThunks to detect whether relevant thunks
166 // have already been inserted.
167 // FIXME: Provide the way for insertThunks to notify us whether it changed
168 // the MF, instead of conservatively assuming it did.
169 InsertedThunks |= getDerived().insertThunks(MMI, MF, InsertedThunks);
170 return true;
171 }
172
173 // If this *is* a thunk function, we need to populate it with the correct MI.
174 getDerived().populateThunk(MF);
175 return true;
176}
177
178/// Basic implementation of MachineFunctionPass wrapping one or more
179/// `ThunkInserter`s passed as type parameters.
180template <typename... Inserters>
182protected:
183 std::tuple<Inserters...> TIs;
184
186
187public:
188 bool doInitialization(Module &M) override {
189 TIs = {};
190 return false;
191 }
192
194 auto &MMI = getAnalysis<MachineModuleInfoWrapperPass>().getMMI();
195 return runTIs(MMI, MF, TIs);
196 }
197
198private:
199 template <typename... ThunkInserterT>
200 static bool runTIs(MachineModuleInfo &MMI, MachineFunction &MF,
201 std::tuple<ThunkInserterT...> &ThunkInserters) {
202 return (0 | ... | std::get<ThunkInserterT>(ThunkInserters).run(MMI, MF));
203 }
204};
205
206} // namespace llvm
207
208#endif
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
Module.h This file contains the declarations for the Module class.
#define F(x, y, z)
Definition MD5.cpp:54
LLVM Basic Block Representation.
Definition BasicBlock.h:62
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
Definition BasicBlock.h:206
static LLVM_ABI 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:169
@ HiddenVisibility
The GV is hidden.
Definition GlobalValue.h:69
@ InternalLinkage
Rename collisions when linking (static functions).
Definition GlobalValue.h:60
@ LinkOnceODRLinkage
Same, but only replaced by something equivalent.
Definition GlobalValue.h:56
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2949
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:76
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
LLVM_ABI 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:68
AnalysisType & getAnalysis() const
getAnalysis<AnalysisType>() - This function is used by subclasses to get to the analysis information ...
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition StringRef.h:258
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)
const char * getThunkPrefix()
Returns common prefix for thunk function's names.
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:46
static LLVM_ABI Type * getVoidTy(LLVMContext &C)
Definition Type.cpp:272
This is an optimization pass for GlobalISel generic memory operations.