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.startswith(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(Type::getVoidTy(Ctx), false); 57 Function *F = Function::Create(Type, 58 Comdat ? GlobalValue::LinkOnceODRLinkage 59 : GlobalValue::InternalLinkage, 60 Name, &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::Naked); 71 if (TargetAttrs != "") 72 B.addAttribute("target-features", TargetAttrs); 73 F->addFnAttrs(B); 74 75 // Populate our function a bit so that we can verify. 76 BasicBlock *Entry = BasicBlock::Create(Ctx, "entry", 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); 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().startswith(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