aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Target/PowerPC/PPCPrepareIFuncsOnAIX.cpp
blob: 5b6a6d6b95c52718973a7acf98484be16f23ba64 (plain)
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;
}