1 | //===---- IndirectThunks.h - Indirect Thunk Base Class ----------*- 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 class for Passes that inject an MI thunk. |
11 | /// |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef LLVM_CODEGEN_INDIRECTTHUNKS_H |
15 | #define LLVM_CODEGEN_INDIRECTTHUNKS_H |
16 | |
17 | #include "llvm/CodeGen/MachineFunction.h" |
18 | #include "llvm/CodeGen/MachineModuleInfo.h" |
19 | #include "llvm/IR/IRBuilder.h" |
20 | #include "llvm/IR/Module.h" |
21 | |
22 | namespace llvm { |
23 | |
24 | template <typename Derived, typename InsertedThunksTy = bool> |
25 | class ThunkInserter { |
26 | Derived &getDerived() { return *static_cast<Derived *>(this); } |
27 | |
28 | protected: |
29 | // A variable used to track whether (and possible which) thunks have been |
30 | // inserted so far. InsertedThunksTy is usually a bool, but can be other types |
31 | // to represent more than one type of thunk. Requires an |= operator to |
32 | // accumulate results. |
33 | InsertedThunksTy InsertedThunks; |
34 | void doInitialization(Module &M) {} |
35 | void createThunkFunction(MachineModuleInfo &MMI, StringRef Name, |
36 | bool Comdat = true, StringRef TargetAttrs = "" ); |
37 | |
38 | public: |
39 | void init(Module &M) { |
40 | InsertedThunks = InsertedThunksTy{}; |
41 | getDerived().doInitialization(M); |
42 | } |
43 | // return `true` if `MMI` or `MF` was modified |
44 | bool run(MachineModuleInfo &MMI, MachineFunction &MF); |
45 | }; |
46 | |
47 | template <typename Derived, typename InsertedThunksTy> |
48 | void ThunkInserter<Derived, InsertedThunksTy>::createThunkFunction( |
49 | MachineModuleInfo &MMI, StringRef Name, bool Comdat, |
50 | StringRef TargetAttrs) { |
51 | assert(Name.starts_with(getDerived().getThunkPrefix()) && |
52 | "Created a thunk with an unexpected prefix!" ); |
53 | |
54 | Module &M = const_cast<Module &>(*MMI.getModule()); |
55 | LLVMContext &Ctx = M.getContext(); |
56 | auto Type = FunctionType::get(Result: Type::getVoidTy(C&: Ctx), isVarArg: false); |
57 | Function *F = Function::Create(Ty: Type, |
58 | Linkage: Comdat ? GlobalValue::LinkOnceODRLinkage |
59 | : GlobalValue::InternalLinkage, |
60 | N: Name, M: &M); |
61 | if (Comdat) { |
62 | F->setVisibility(GlobalValue::HiddenVisibility); |
63 | F->setComdat(M.getOrInsertComdat(Name)); |
64 | } |
65 | |
66 | // Add Attributes so that we don't create a frame, unwind information, or |
67 | // inline. |
68 | AttrBuilder B(Ctx); |
69 | B.addAttribute(llvm::Attribute::NoUnwind); |
70 | B.addAttribute(llvm::Attribute::A: Naked); |
71 | if (TargetAttrs != "" ) |
72 | B.addAttribute(A: "target-features" , V: TargetAttrs); |
73 | F->addFnAttrs(Attrs: B); |
74 | |
75 | // Populate our function a bit so that we can verify. |
76 | BasicBlock *Entry = BasicBlock::Create(Context&: Ctx, Name: "entry" , Parent: F); |
77 | IRBuilder<> Builder(Entry); |
78 | |
79 | Builder.CreateRetVoid(); |
80 | |
81 | // MachineFunctions aren't created automatically for the IR-level constructs |
82 | // we already made. Create them and insert them into the module. |
83 | MachineFunction &MF = MMI.getOrCreateMachineFunction(F&: *F); |
84 | // A MachineBasicBlock must not be created for the Entry block; code |
85 | // generation from an empty naked function in C source code also does not |
86 | // generate one. At least GlobalISel asserts if this invariant isn't |
87 | // respected. |
88 | |
89 | // Set MF properties. We never use vregs... |
90 | MF.getProperties().set(MachineFunctionProperties::Property::NoVRegs); |
91 | } |
92 | |
93 | template <typename Derived, typename InsertedThunksTy> |
94 | bool ThunkInserter<Derived, InsertedThunksTy>::run(MachineModuleInfo &MMI, |
95 | MachineFunction &MF) { |
96 | // If MF is not a thunk, check to see if we need to insert a thunk. |
97 | if (!MF.getName().starts_with(Prefix: 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)) |
108 | return false; |
109 | |
110 | InsertedThunks |= getDerived().insertThunks(MMI, MF); |
111 | return true; |
112 | } |
113 | |
114 | // If this *is* a thunk function, we need to populate it with the correct MI. |
115 | getDerived().populateThunk(MF); |
116 | return true; |
117 | } |
118 | |
119 | } // namespace llvm |
120 | |
121 | #endif |
122 | |