1//===-- PPCPrepareIFuncsOnAIX.cpp - Prepare for ifunc lowering in codegen ===//
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 pass generates...
10//
11//===----------------------------------------------------------------------===//
12
13#include "PPC.h"
14#include "PPCSubtarget.h"
15#include "PPCTargetMachine.h"
16#include "llvm/ADT/STLExtras.h"
17#include "llvm/ADT/Statistic.h"
18#include "llvm/Analysis/TargetTransformInfo.h"
19#include "llvm/CodeGen/TargetPassConfig.h"
20#include "llvm/IR/Instructions.h"
21#include "llvm/IR/Module.h"
22#include <cassert>
23
24using namespace llvm;
25
26#define DEBUG_TYPE "ppc-prep-ifunc-aix"
27
28STATISTIC(NumIFuncs, "Number of IFuncs prepared");
29
30namespace {
31class PPCPrepareIFuncsOnAIX : public ModulePass {
32public:
33 static char ID;
34
35 PPCPrepareIFuncsOnAIX() : ModulePass(ID) {}
36
37 bool runOnModule(Module &M) override;
38
39 StringRef getPassName() const override {
40 return "PPC Prepare for AIX IFunc lowering";
41 }
42};
43} // namespace
44
45char PPCPrepareIFuncsOnAIX::ID = 0;
46
47INITIALIZE_PASS(PPCPrepareIFuncsOnAIX, DEBUG_TYPE,
48 "PPC Prepare for AIX IFunc lowering", false, false)
49
50ModulePass *llvm::createPPCPrepareIFuncsOnAIXPass() {
51 return new PPCPrepareIFuncsOnAIX();
52}
53
54// For each ifunc `foo` with a resolver `foo_resolver`, create a global variable
55// `__update_foo` in the `ifunc_sec` section, representing the pair:
56// { ptr @foo, ptr @foo_resolver }
57// The compiler arranges for the constructor function `__init_ifuncs` to be
58// included on the link step. The constructor walks the `ifunc_sec` section,
59// calling the resolver function and storing the result in foo's descriptor.
60// On AIX, the address of a function is the address of its descriptor, so the
61// constructor accesses foo's descriptor from the first field of the pair.
62//
63// Since the global `__update_foo` is unreferenced, it's liveness needs to be
64// associated to the liveness of ifunc `foo`
65//
66bool PPCPrepareIFuncsOnAIX::runOnModule(Module &M) {
67 if (M.ifuncs().empty())
68 return false;
69
70 const DataLayout &DL = M.getDataLayout();
71 LLVMContext &Ctx = M.getContext();
72 auto *PtrTy = PointerType::getUnqual(C&: Ctx);
73 StringRef IFuncUpdatePrefix = "__update_";
74 StringRef IFuncUpdateSectionName = "__ifunc_sec";
75 StructType *IFuncPairType = StructType::get(elt1: PtrTy, elts: PtrTy);
76
77 StringRef IFuncConstructorName = "__init_ifuncs";
78 auto *IFuncConstructorFnType =
79 FunctionType::get(Result: Type::getVoidTy(C&: Ctx), Params: {}, /*isVarArg=*/false);
80 auto *IFuncConstructorDecl = cast<Function>(
81 Val: M.getOrInsertFunction(Name: IFuncConstructorName, T: IFuncConstructorFnType)
82 .getCallee());
83
84 for (GlobalIFunc &IFunc : M.ifuncs()) {
85 NumIFuncs++;
86 LLVM_DEBUG(dbgs() << "expanding ifunc " << IFunc.getName() << "\n");
87 // @__update_foo = private global { ptr @foo, ptr @foo_resolver },
88 // section "ifunc_sec"
89 std::string Name = (Twine(IFuncUpdatePrefix) + IFunc.getName()).str();
90 auto *GV = new GlobalVariable(M, IFuncPairType, /*isConstant*/ false,
91 GlobalValue::PrivateLinkage, nullptr, Name);
92 GV->setAlignment(DL.getPointerPrefAlignment());
93 GV->setSection(IFuncUpdateSectionName);
94
95 // Note that on AIX, the address of a function is the address of it's
96 // function descriptor, which is what these two values end up being
97 // in assembly.
98 Constant *InitVals[] = {&IFunc, IFunc.getResolver()};
99 GV->setInitializer(ConstantStruct::get(T: IFuncPairType, V: InitVals));
100
101 // Liveness of __update_foo is dependent on liveness of ifunc foo.
102 IFunc.setMetadata(KindID: LLVMContext::MD_implicit_ref,
103 Node: MDNode::get(Context&: Ctx, MDs: ValueAsMetadata::get(V: GV)));
104
105 // An implicit.ref creates linkage dependency, so make function foo require
106 // the constructor that calls each ifunc's resolver and saves the result in
107 // the ifunc's function descriptor.
108 IFunc.addMetadata(
109 KindID: LLVMContext::MD_implicit_ref,
110 MD&: *MDNode::get(Context&: Ctx, MDs: ValueAsMetadata::get(V: IFuncConstructorDecl)));
111 }
112
113 return true;
114}
115