/src/llvm-project/llvm/lib/Transforms/Utils/ModuleUtils.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- ModuleUtils.cpp - Functions to manipulate Modules -----------------===// |
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 | | // This family of functions perform manipulations on Modules. |
10 | | // |
11 | | //===----------------------------------------------------------------------===// |
12 | | |
13 | | #include "llvm/Transforms/Utils/ModuleUtils.h" |
14 | | #include "llvm/Analysis/VectorUtils.h" |
15 | | #include "llvm/ADT/SmallString.h" |
16 | | #include "llvm/IR/DerivedTypes.h" |
17 | | #include "llvm/IR/Function.h" |
18 | | #include "llvm/IR/IRBuilder.h" |
19 | | #include "llvm/IR/MDBuilder.h" |
20 | | #include "llvm/IR/Module.h" |
21 | | #include "llvm/Support/raw_ostream.h" |
22 | | #include "llvm/Support/xxhash.h" |
23 | | |
24 | | using namespace llvm; |
25 | | |
26 | | #define DEBUG_TYPE "moduleutils" |
27 | | |
28 | | static void appendToGlobalArray(StringRef ArrayName, Module &M, Function *F, |
29 | 0 | int Priority, Constant *Data) { |
30 | 0 | IRBuilder<> IRB(M.getContext()); |
31 | 0 | FunctionType *FnTy = FunctionType::get(IRB.getVoidTy(), false); |
32 | | |
33 | | // Get the current set of static global constructors and add the new ctor |
34 | | // to the list. |
35 | 0 | SmallVector<Constant *, 16> CurrentCtors; |
36 | 0 | StructType *EltTy; |
37 | 0 | if (GlobalVariable *GVCtor = M.getNamedGlobal(ArrayName)) { |
38 | 0 | EltTy = cast<StructType>(GVCtor->getValueType()->getArrayElementType()); |
39 | 0 | if (Constant *Init = GVCtor->getInitializer()) { |
40 | 0 | unsigned n = Init->getNumOperands(); |
41 | 0 | CurrentCtors.reserve(n + 1); |
42 | 0 | for (unsigned i = 0; i != n; ++i) |
43 | 0 | CurrentCtors.push_back(cast<Constant>(Init->getOperand(i))); |
44 | 0 | } |
45 | 0 | GVCtor->eraseFromParent(); |
46 | 0 | } else { |
47 | 0 | EltTy = StructType::get(IRB.getInt32Ty(), |
48 | 0 | PointerType::get(FnTy, F->getAddressSpace()), |
49 | 0 | IRB.getPtrTy()); |
50 | 0 | } |
51 | | |
52 | | // Build a 3 field global_ctor entry. We don't take a comdat key. |
53 | 0 | Constant *CSVals[3]; |
54 | 0 | CSVals[0] = IRB.getInt32(Priority); |
55 | 0 | CSVals[1] = F; |
56 | 0 | CSVals[2] = Data ? ConstantExpr::getPointerCast(Data, IRB.getPtrTy()) |
57 | 0 | : Constant::getNullValue(IRB.getPtrTy()); |
58 | 0 | Constant *RuntimeCtorInit = |
59 | 0 | ConstantStruct::get(EltTy, ArrayRef(CSVals, EltTy->getNumElements())); |
60 | |
|
61 | 0 | CurrentCtors.push_back(RuntimeCtorInit); |
62 | | |
63 | | // Create a new initializer. |
64 | 0 | ArrayType *AT = ArrayType::get(EltTy, CurrentCtors.size()); |
65 | 0 | Constant *NewInit = ConstantArray::get(AT, CurrentCtors); |
66 | | |
67 | | // Create the new global variable and replace all uses of |
68 | | // the old global variable with the new one. |
69 | 0 | (void)new GlobalVariable(M, NewInit->getType(), false, |
70 | 0 | GlobalValue::AppendingLinkage, NewInit, ArrayName); |
71 | 0 | } |
72 | | |
73 | 0 | void llvm::appendToGlobalCtors(Module &M, Function *F, int Priority, Constant *Data) { |
74 | 0 | appendToGlobalArray("llvm.global_ctors", M, F, Priority, Data); |
75 | 0 | } |
76 | | |
77 | 0 | void llvm::appendToGlobalDtors(Module &M, Function *F, int Priority, Constant *Data) { |
78 | 0 | appendToGlobalArray("llvm.global_dtors", M, F, Priority, Data); |
79 | 0 | } |
80 | | |
81 | | static void collectUsedGlobals(GlobalVariable *GV, |
82 | 0 | SmallSetVector<Constant *, 16> &Init) { |
83 | 0 | if (!GV || !GV->hasInitializer()) |
84 | 0 | return; |
85 | | |
86 | 0 | auto *CA = cast<ConstantArray>(GV->getInitializer()); |
87 | 0 | for (Use &Op : CA->operands()) |
88 | 0 | Init.insert(cast<Constant>(Op)); |
89 | 0 | } |
90 | | |
91 | 0 | static void appendToUsedList(Module &M, StringRef Name, ArrayRef<GlobalValue *> Values) { |
92 | 0 | GlobalVariable *GV = M.getGlobalVariable(Name); |
93 | |
|
94 | 0 | SmallSetVector<Constant *, 16> Init; |
95 | 0 | collectUsedGlobals(GV, Init); |
96 | 0 | if (GV) |
97 | 0 | GV->eraseFromParent(); |
98 | |
|
99 | 0 | Type *ArrayEltTy = llvm::PointerType::getUnqual(M.getContext()); |
100 | 0 | for (auto *V : Values) |
101 | 0 | Init.insert(ConstantExpr::getPointerBitCastOrAddrSpaceCast(V, ArrayEltTy)); |
102 | |
|
103 | 0 | if (Init.empty()) |
104 | 0 | return; |
105 | | |
106 | 0 | ArrayType *ATy = ArrayType::get(ArrayEltTy, Init.size()); |
107 | 0 | GV = new llvm::GlobalVariable(M, ATy, false, GlobalValue::AppendingLinkage, |
108 | 0 | ConstantArray::get(ATy, Init.getArrayRef()), |
109 | 0 | Name); |
110 | 0 | GV->setSection("llvm.metadata"); |
111 | 0 | } |
112 | | |
113 | 0 | void llvm::appendToUsed(Module &M, ArrayRef<GlobalValue *> Values) { |
114 | 0 | appendToUsedList(M, "llvm.used", Values); |
115 | 0 | } |
116 | | |
117 | 0 | void llvm::appendToCompilerUsed(Module &M, ArrayRef<GlobalValue *> Values) { |
118 | 0 | appendToUsedList(M, "llvm.compiler.used", Values); |
119 | 0 | } |
120 | | |
121 | | static void removeFromUsedList(Module &M, StringRef Name, |
122 | 0 | function_ref<bool(Constant *)> ShouldRemove) { |
123 | 0 | GlobalVariable *GV = M.getNamedGlobal(Name); |
124 | 0 | if (!GV) |
125 | 0 | return; |
126 | | |
127 | 0 | SmallSetVector<Constant *, 16> Init; |
128 | 0 | collectUsedGlobals(GV, Init); |
129 | |
|
130 | 0 | Type *ArrayEltTy = cast<ArrayType>(GV->getValueType())->getElementType(); |
131 | |
|
132 | 0 | SmallVector<Constant *, 16> NewInit; |
133 | 0 | for (Constant *MaybeRemoved : Init) { |
134 | 0 | if (!ShouldRemove(MaybeRemoved->stripPointerCasts())) |
135 | 0 | NewInit.push_back(MaybeRemoved); |
136 | 0 | } |
137 | |
|
138 | 0 | if (!NewInit.empty()) { |
139 | 0 | ArrayType *ATy = ArrayType::get(ArrayEltTy, NewInit.size()); |
140 | 0 | GlobalVariable *NewGV = |
141 | 0 | new GlobalVariable(M, ATy, false, GlobalValue::AppendingLinkage, |
142 | 0 | ConstantArray::get(ATy, NewInit), "", GV, |
143 | 0 | GV->getThreadLocalMode(), GV->getAddressSpace()); |
144 | 0 | NewGV->setSection(GV->getSection()); |
145 | 0 | NewGV->takeName(GV); |
146 | 0 | } |
147 | |
|
148 | 0 | GV->eraseFromParent(); |
149 | 0 | } |
150 | | |
151 | | void llvm::removeFromUsedLists(Module &M, |
152 | 0 | function_ref<bool(Constant *)> ShouldRemove) { |
153 | 0 | removeFromUsedList(M, "llvm.used", ShouldRemove); |
154 | 0 | removeFromUsedList(M, "llvm.compiler.used", ShouldRemove); |
155 | 0 | } |
156 | | |
157 | 0 | void llvm::setKCFIType(Module &M, Function &F, StringRef MangledType) { |
158 | 0 | if (!M.getModuleFlag("kcfi")) |
159 | 0 | return; |
160 | | // Matches CodeGenModule::CreateKCFITypeId in Clang. |
161 | 0 | LLVMContext &Ctx = M.getContext(); |
162 | 0 | MDBuilder MDB(Ctx); |
163 | 0 | F.setMetadata( |
164 | 0 | LLVMContext::MD_kcfi_type, |
165 | 0 | MDNode::get(Ctx, MDB.createConstant(ConstantInt::get( |
166 | 0 | Type::getInt32Ty(Ctx), |
167 | 0 | static_cast<uint32_t>(xxHash64(MangledType)))))); |
168 | | // If the module was compiled with -fpatchable-function-entry, ensure |
169 | | // we use the same patchable-function-prefix. |
170 | 0 | if (auto *MD = mdconst::extract_or_null<ConstantInt>( |
171 | 0 | M.getModuleFlag("kcfi-offset"))) { |
172 | 0 | if (unsigned Offset = MD->getZExtValue()) |
173 | 0 | F.addFnAttr("patchable-function-prefix", std::to_string(Offset)); |
174 | 0 | } |
175 | 0 | } |
176 | | |
177 | | FunctionCallee llvm::declareSanitizerInitFunction(Module &M, StringRef InitName, |
178 | | ArrayRef<Type *> InitArgTypes, |
179 | 0 | bool Weak) { |
180 | 0 | assert(!InitName.empty() && "Expected init function name"); |
181 | 0 | auto *VoidTy = Type::getVoidTy(M.getContext()); |
182 | 0 | auto *FnTy = FunctionType::get(VoidTy, InitArgTypes, false); |
183 | 0 | auto FnCallee = M.getOrInsertFunction(InitName, FnTy); |
184 | 0 | auto *Fn = cast<Function>(FnCallee.getCallee()); |
185 | 0 | if (Weak && Fn->isDeclaration()) |
186 | 0 | Fn->setLinkage(Function::ExternalWeakLinkage); |
187 | 0 | return FnCallee; |
188 | 0 | } |
189 | | |
190 | 0 | Function *llvm::createSanitizerCtor(Module &M, StringRef CtorName) { |
191 | 0 | Function *Ctor = Function::createWithDefaultAttr( |
192 | 0 | FunctionType::get(Type::getVoidTy(M.getContext()), false), |
193 | 0 | GlobalValue::InternalLinkage, M.getDataLayout().getProgramAddressSpace(), |
194 | 0 | CtorName, &M); |
195 | 0 | Ctor->addFnAttr(Attribute::NoUnwind); |
196 | 0 | setKCFIType(M, *Ctor, "_ZTSFvvE"); // void (*)(void) |
197 | 0 | BasicBlock *CtorBB = BasicBlock::Create(M.getContext(), "", Ctor); |
198 | 0 | ReturnInst::Create(M.getContext(), CtorBB); |
199 | | // Ensure Ctor cannot be discarded, even if in a comdat. |
200 | 0 | appendToUsed(M, {Ctor}); |
201 | 0 | return Ctor; |
202 | 0 | } |
203 | | |
204 | | std::pair<Function *, FunctionCallee> llvm::createSanitizerCtorAndInitFunctions( |
205 | | Module &M, StringRef CtorName, StringRef InitName, |
206 | | ArrayRef<Type *> InitArgTypes, ArrayRef<Value *> InitArgs, |
207 | 0 | StringRef VersionCheckName, bool Weak) { |
208 | 0 | assert(!InitName.empty() && "Expected init function name"); |
209 | 0 | assert(InitArgs.size() == InitArgTypes.size() && |
210 | 0 | "Sanitizer's init function expects different number of arguments"); |
211 | 0 | FunctionCallee InitFunction = |
212 | 0 | declareSanitizerInitFunction(M, InitName, InitArgTypes, Weak); |
213 | 0 | Function *Ctor = createSanitizerCtor(M, CtorName); |
214 | 0 | IRBuilder<> IRB(M.getContext()); |
215 | |
|
216 | 0 | BasicBlock *RetBB = &Ctor->getEntryBlock(); |
217 | 0 | if (Weak) { |
218 | 0 | RetBB->setName("ret"); |
219 | 0 | auto *EntryBB = BasicBlock::Create(M.getContext(), "entry", Ctor, RetBB); |
220 | 0 | auto *CallInitBB = |
221 | 0 | BasicBlock::Create(M.getContext(), "callfunc", Ctor, RetBB); |
222 | 0 | auto *InitFn = cast<Function>(InitFunction.getCallee()); |
223 | 0 | auto *InitFnPtr = |
224 | 0 | PointerType::get(InitFn->getType(), InitFn->getAddressSpace()); |
225 | 0 | IRB.SetInsertPoint(EntryBB); |
226 | 0 | Value *InitNotNull = |
227 | 0 | IRB.CreateICmpNE(InitFn, ConstantPointerNull::get(InitFnPtr)); |
228 | 0 | IRB.CreateCondBr(InitNotNull, CallInitBB, RetBB); |
229 | 0 | IRB.SetInsertPoint(CallInitBB); |
230 | 0 | } else { |
231 | 0 | IRB.SetInsertPoint(RetBB->getTerminator()); |
232 | 0 | } |
233 | |
|
234 | 0 | IRB.CreateCall(InitFunction, InitArgs); |
235 | 0 | if (!VersionCheckName.empty()) { |
236 | 0 | FunctionCallee VersionCheckFunction = M.getOrInsertFunction( |
237 | 0 | VersionCheckName, FunctionType::get(IRB.getVoidTy(), {}, false), |
238 | 0 | AttributeList()); |
239 | 0 | IRB.CreateCall(VersionCheckFunction, {}); |
240 | 0 | } |
241 | |
|
242 | 0 | if (Weak) |
243 | 0 | IRB.CreateBr(RetBB); |
244 | |
|
245 | 0 | return std::make_pair(Ctor, InitFunction); |
246 | 0 | } |
247 | | |
248 | | std::pair<Function *, FunctionCallee> |
249 | | llvm::getOrCreateSanitizerCtorAndInitFunctions( |
250 | | Module &M, StringRef CtorName, StringRef InitName, |
251 | | ArrayRef<Type *> InitArgTypes, ArrayRef<Value *> InitArgs, |
252 | | function_ref<void(Function *, FunctionCallee)> FunctionsCreatedCallback, |
253 | 0 | StringRef VersionCheckName, bool Weak) { |
254 | 0 | assert(!CtorName.empty() && "Expected ctor function name"); |
255 | | |
256 | 0 | if (Function *Ctor = M.getFunction(CtorName)) |
257 | | // FIXME: Sink this logic into the module, similar to the handling of |
258 | | // globals. This will make moving to a concurrent model much easier. |
259 | 0 | if (Ctor->arg_empty() || |
260 | 0 | Ctor->getReturnType() == Type::getVoidTy(M.getContext())) |
261 | 0 | return {Ctor, |
262 | 0 | declareSanitizerInitFunction(M, InitName, InitArgTypes, Weak)}; |
263 | | |
264 | 0 | Function *Ctor; |
265 | 0 | FunctionCallee InitFunction; |
266 | 0 | std::tie(Ctor, InitFunction) = llvm::createSanitizerCtorAndInitFunctions( |
267 | 0 | M, CtorName, InitName, InitArgTypes, InitArgs, VersionCheckName, Weak); |
268 | 0 | FunctionsCreatedCallback(Ctor, InitFunction); |
269 | 0 | return std::make_pair(Ctor, InitFunction); |
270 | 0 | } |
271 | | |
272 | | void llvm::filterDeadComdatFunctions( |
273 | 0 | SmallVectorImpl<Function *> &DeadComdatFunctions) { |
274 | 0 | SmallPtrSet<Function *, 32> MaybeDeadFunctions; |
275 | 0 | SmallPtrSet<Comdat *, 32> MaybeDeadComdats; |
276 | 0 | for (Function *F : DeadComdatFunctions) { |
277 | 0 | MaybeDeadFunctions.insert(F); |
278 | 0 | if (Comdat *C = F->getComdat()) |
279 | 0 | MaybeDeadComdats.insert(C); |
280 | 0 | } |
281 | | |
282 | | // Find comdats for which all users are dead now. |
283 | 0 | SmallPtrSet<Comdat *, 32> DeadComdats; |
284 | 0 | for (Comdat *C : MaybeDeadComdats) { |
285 | 0 | auto IsUserDead = [&](GlobalObject *GO) { |
286 | 0 | auto *F = dyn_cast<Function>(GO); |
287 | 0 | return F && MaybeDeadFunctions.contains(F); |
288 | 0 | }; |
289 | 0 | if (all_of(C->getUsers(), IsUserDead)) |
290 | 0 | DeadComdats.insert(C); |
291 | 0 | } |
292 | | |
293 | | // Only keep functions which have no comdat or a dead comdat. |
294 | 0 | erase_if(DeadComdatFunctions, [&](Function *F) { |
295 | 0 | Comdat *C = F->getComdat(); |
296 | 0 | return C && !DeadComdats.contains(C); |
297 | 0 | }); |
298 | 0 | } |
299 | | |
300 | 0 | std::string llvm::getUniqueModuleId(Module *M) { |
301 | 0 | MD5 Md5; |
302 | 0 | bool ExportsSymbols = false; |
303 | 0 | auto AddGlobal = [&](GlobalValue &GV) { |
304 | 0 | if (GV.isDeclaration() || GV.getName().starts_with("llvm.") || |
305 | 0 | !GV.hasExternalLinkage() || GV.hasComdat()) |
306 | 0 | return; |
307 | 0 | ExportsSymbols = true; |
308 | 0 | Md5.update(GV.getName()); |
309 | 0 | Md5.update(ArrayRef<uint8_t>{0}); |
310 | 0 | }; |
311 | |
|
312 | 0 | for (auto &F : *M) |
313 | 0 | AddGlobal(F); |
314 | 0 | for (auto &GV : M->globals()) |
315 | 0 | AddGlobal(GV); |
316 | 0 | for (auto &GA : M->aliases()) |
317 | 0 | AddGlobal(GA); |
318 | 0 | for (auto &IF : M->ifuncs()) |
319 | 0 | AddGlobal(IF); |
320 | |
|
321 | 0 | if (!ExportsSymbols) |
322 | 0 | return ""; |
323 | | |
324 | 0 | MD5::MD5Result R; |
325 | 0 | Md5.final(R); |
326 | |
|
327 | 0 | SmallString<32> Str; |
328 | 0 | MD5::stringifyResult(R, Str); |
329 | 0 | return ("." + Str).str(); |
330 | 0 | } |
331 | | |
332 | | void VFABI::setVectorVariantNames(CallInst *CI, |
333 | 0 | ArrayRef<std::string> VariantMappings) { |
334 | 0 | if (VariantMappings.empty()) |
335 | 0 | return; |
336 | | |
337 | 0 | SmallString<256> Buffer; |
338 | 0 | llvm::raw_svector_ostream Out(Buffer); |
339 | 0 | for (const std::string &VariantMapping : VariantMappings) |
340 | 0 | Out << VariantMapping << ","; |
341 | | // Get rid of the trailing ','. |
342 | 0 | assert(!Buffer.str().empty() && "Must have at least one char."); |
343 | 0 | Buffer.pop_back(); |
344 | |
|
345 | 0 | Module *M = CI->getModule(); |
346 | 0 | #ifndef NDEBUG |
347 | 0 | for (const std::string &VariantMapping : VariantMappings) { |
348 | 0 | LLVM_DEBUG(dbgs() << "VFABI: adding mapping '" << VariantMapping << "'\n"); |
349 | 0 | std::optional<VFInfo> VI = |
350 | 0 | VFABI::tryDemangleForVFABI(VariantMapping, CI->getFunctionType()); |
351 | 0 | assert(VI && "Cannot add an invalid VFABI name."); |
352 | 0 | assert(M->getNamedValue(VI->VectorName) && |
353 | 0 | "Cannot add variant to attribute: " |
354 | 0 | "vector function declaration is missing."); |
355 | 0 | } |
356 | 0 | #endif |
357 | 0 | CI->addFnAttr( |
358 | 0 | Attribute::get(M->getContext(), MappingsAttrName, Buffer.str())); |
359 | 0 | } |
360 | | |
361 | | void llvm::embedBufferInModule(Module &M, MemoryBufferRef Buf, |
362 | 0 | StringRef SectionName, Align Alignment) { |
363 | | // Embed the memory buffer into the module. |
364 | 0 | Constant *ModuleConstant = ConstantDataArray::get( |
365 | 0 | M.getContext(), ArrayRef(Buf.getBufferStart(), Buf.getBufferSize())); |
366 | 0 | GlobalVariable *GV = new GlobalVariable( |
367 | 0 | M, ModuleConstant->getType(), true, GlobalValue::PrivateLinkage, |
368 | 0 | ModuleConstant, "llvm.embedded.object"); |
369 | 0 | GV->setSection(SectionName); |
370 | 0 | GV->setAlignment(Alignment); |
371 | |
|
372 | 0 | LLVMContext &Ctx = M.getContext(); |
373 | 0 | NamedMDNode *MD = M.getOrInsertNamedMetadata("llvm.embedded.objects"); |
374 | 0 | Metadata *MDVals[] = {ConstantAsMetadata::get(GV), |
375 | 0 | MDString::get(Ctx, SectionName)}; |
376 | |
|
377 | 0 | MD->addOperand(llvm::MDNode::get(Ctx, MDVals)); |
378 | 0 | GV->setMetadata(LLVMContext::MD_exclude, llvm::MDNode::get(Ctx, {})); |
379 | |
|
380 | 0 | appendToCompilerUsed(M, GV); |
381 | 0 | } |
382 | | |
383 | | bool llvm::lowerGlobalIFuncUsersAsGlobalCtor( |
384 | 0 | Module &M, ArrayRef<GlobalIFunc *> FilteredIFuncsToLower) { |
385 | 0 | SmallVector<GlobalIFunc *, 32> AllIFuncs; |
386 | 0 | ArrayRef<GlobalIFunc *> IFuncsToLower = FilteredIFuncsToLower; |
387 | 0 | if (FilteredIFuncsToLower.empty()) { // Default to lowering all ifuncs |
388 | 0 | for (GlobalIFunc &GI : M.ifuncs()) |
389 | 0 | AllIFuncs.push_back(&GI); |
390 | 0 | IFuncsToLower = AllIFuncs; |
391 | 0 | } |
392 | |
|
393 | 0 | bool UnhandledUsers = false; |
394 | 0 | LLVMContext &Ctx = M.getContext(); |
395 | 0 | const DataLayout &DL = M.getDataLayout(); |
396 | |
|
397 | 0 | PointerType *TableEntryTy = |
398 | 0 | PointerType::get(Ctx, DL.getProgramAddressSpace()); |
399 | |
|
400 | 0 | ArrayType *FuncPtrTableTy = |
401 | 0 | ArrayType::get(TableEntryTy, IFuncsToLower.size()); |
402 | |
|
403 | 0 | Align PtrAlign = DL.getABITypeAlign(TableEntryTy); |
404 | | |
405 | | // Create a global table of function pointers we'll initialize in a global |
406 | | // constructor. |
407 | 0 | auto *FuncPtrTable = new GlobalVariable( |
408 | 0 | M, FuncPtrTableTy, false, GlobalValue::InternalLinkage, |
409 | 0 | PoisonValue::get(FuncPtrTableTy), "", nullptr, |
410 | 0 | GlobalVariable::NotThreadLocal, DL.getDefaultGlobalsAddressSpace()); |
411 | 0 | FuncPtrTable->setAlignment(PtrAlign); |
412 | | |
413 | | // Create a function to initialize the function pointer table. |
414 | 0 | Function *NewCtor = Function::Create( |
415 | 0 | FunctionType::get(Type::getVoidTy(Ctx), false), Function::InternalLinkage, |
416 | 0 | DL.getProgramAddressSpace(), "", &M); |
417 | |
|
418 | 0 | BasicBlock *BB = BasicBlock::Create(Ctx, "", NewCtor); |
419 | 0 | IRBuilder<> InitBuilder(BB); |
420 | |
|
421 | 0 | size_t TableIndex = 0; |
422 | 0 | for (GlobalIFunc *GI : IFuncsToLower) { |
423 | 0 | Function *ResolvedFunction = GI->getResolverFunction(); |
424 | | |
425 | | // We don't know what to pass to a resolver function taking arguments |
426 | | // |
427 | | // FIXME: Is this even valid? clang and gcc don't complain but this |
428 | | // probably should be invalid IR. We could just pass through undef. |
429 | 0 | if (!std::empty(ResolvedFunction->getFunctionType()->params())) { |
430 | 0 | LLVM_DEBUG(dbgs() << "Not lowering ifunc resolver function " |
431 | 0 | << ResolvedFunction->getName() << " with parameters\n"); |
432 | 0 | UnhandledUsers = true; |
433 | 0 | continue; |
434 | 0 | } |
435 | | |
436 | | // Initialize the function pointer table. |
437 | 0 | CallInst *ResolvedFunc = InitBuilder.CreateCall(ResolvedFunction); |
438 | 0 | Value *Casted = InitBuilder.CreatePointerCast(ResolvedFunc, TableEntryTy); |
439 | 0 | Constant *GEP = cast<Constant>(InitBuilder.CreateConstInBoundsGEP2_32( |
440 | 0 | FuncPtrTableTy, FuncPtrTable, 0, TableIndex++)); |
441 | 0 | InitBuilder.CreateAlignedStore(Casted, GEP, PtrAlign); |
442 | | |
443 | | // Update all users to load a pointer from the global table. |
444 | 0 | for (User *User : make_early_inc_range(GI->users())) { |
445 | 0 | Instruction *UserInst = dyn_cast<Instruction>(User); |
446 | 0 | if (!UserInst) { |
447 | | // TODO: Should handle constantexpr casts in user instructions. Probably |
448 | | // can't do much about constant initializers. |
449 | 0 | UnhandledUsers = true; |
450 | 0 | continue; |
451 | 0 | } |
452 | | |
453 | 0 | IRBuilder<> UseBuilder(UserInst); |
454 | 0 | LoadInst *ResolvedTarget = |
455 | 0 | UseBuilder.CreateAlignedLoad(TableEntryTy, GEP, PtrAlign); |
456 | 0 | Value *ResolvedCast = |
457 | 0 | UseBuilder.CreatePointerCast(ResolvedTarget, GI->getType()); |
458 | 0 | UserInst->replaceUsesOfWith(GI, ResolvedCast); |
459 | 0 | } |
460 | | |
461 | | // If we handled all users, erase the ifunc. |
462 | 0 | if (GI->use_empty()) |
463 | 0 | GI->eraseFromParent(); |
464 | 0 | } |
465 | |
|
466 | 0 | InitBuilder.CreateRetVoid(); |
467 | |
|
468 | 0 | PointerType *ConstantDataTy = PointerType::get(Ctx, 0); |
469 | | |
470 | | // TODO: Is this the right priority? Probably should be before any other |
471 | | // constructors? |
472 | 0 | const int Priority = 10; |
473 | 0 | appendToGlobalCtors(M, NewCtor, Priority, |
474 | 0 | ConstantPointerNull::get(ConstantDataTy)); |
475 | 0 | return UnhandledUsers; |
476 | 0 | } |