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