1//===- X86GlobalBaseReg.cpp - PIC Global Base Register Initialization -----===//
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 file contains the pass that initializes the PIC global base register
10// for x86-32.
11//
12//===----------------------------------------------------------------------===//
13
14#include "X86.h"
15#include "X86InstrInfo.h"
16#include "X86MachineFunctionInfo.h"
17#include "X86Subtarget.h"
18#include "X86TargetMachine.h"
19#include "llvm/CodeGen/MachineFunctionPass.h"
20#include "llvm/CodeGen/MachineInstrBuilder.h"
21#include "llvm/CodeGen/MachineRegisterInfo.h"
22#include "llvm/InitializePasses.h"
23
24using namespace llvm;
25
26#define DEBUG_TYPE "x86-global-base-reg"
27
28namespace {
29class X86GlobalBaseRegLegacy : public MachineFunctionPass {
30public:
31 static char ID;
32 X86GlobalBaseRegLegacy() : MachineFunctionPass(ID) {}
33
34 bool runOnMachineFunction(MachineFunction &MF) override;
35
36 StringRef getPassName() const override {
37 return "X86 PIC Global Base Reg Initialization";
38 }
39
40 void getAnalysisUsage(AnalysisUsage &AU) const override {
41 AU.setPreservesCFG();
42 MachineFunctionPass::getAnalysisUsage(AU);
43 }
44};
45} // end anonymous namespace
46
47char X86GlobalBaseRegLegacy::ID = 0;
48
49FunctionPass *llvm::createX86GlobalBaseRegLegacyPass() {
50 return new X86GlobalBaseRegLegacy();
51}
52
53static bool initGlobalBaseReg(MachineFunction &MF) {
54 const X86TargetMachine *TM =
55 static_cast<const X86TargetMachine *>(&MF.getTarget());
56 const X86Subtarget &STI = MF.getSubtarget<X86Subtarget>();
57
58 // Only emit a global base reg in PIC mode.
59 if (!TM->isPositionIndependent())
60 return false;
61
62 X86MachineFunctionInfo *X86FI = MF.getInfo<X86MachineFunctionInfo>();
63 Register GlobalBaseReg = X86FI->getGlobalBaseReg();
64
65 // If we didn't need a GlobalBaseReg, don't insert code.
66 if (GlobalBaseReg == 0)
67 return false;
68
69 // Insert the set of GlobalBaseReg into the first MBB of the function
70 MachineBasicBlock &FirstMBB = MF.front();
71 MachineBasicBlock::iterator MBBI = FirstMBB.begin();
72 DebugLoc DL = FirstMBB.findDebugLoc(MBBI);
73 MachineRegisterInfo &RegInfo = MF.getRegInfo();
74 const X86InstrInfo *TII = STI.getInstrInfo();
75
76 Register PC;
77 if (STI.isPICStyleGOT())
78 PC = RegInfo.createVirtualRegister(RegClass: &X86::GR32RegClass);
79 else
80 PC = GlobalBaseReg;
81
82 if (STI.is64Bit()) {
83 if (TM->getCodeModel() == CodeModel::Large) {
84 // In the large code model, we are aiming for this code, though the
85 // register allocation may vary:
86 // leaq .LN$pb(%rip), %rax
87 // movq $_GLOBAL_OFFSET_TABLE_ - .LN$pb, %rcx
88 // addq %rcx, %rax
89 // RAX now holds address of _GLOBAL_OFFSET_TABLE_.
90 Register PBReg = RegInfo.createVirtualRegister(RegClass: &X86::GR64RegClass);
91 Register GOTReg = RegInfo.createVirtualRegister(RegClass: &X86::GR64RegClass);
92 BuildMI(BB&: FirstMBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: X86::LEA64r), DestReg: PBReg)
93 .addReg(RegNo: X86::RIP)
94 .addImm(Val: 0)
95 .addReg(RegNo: 0)
96 .addSym(Sym: MF.getPICBaseSymbol())
97 .addReg(RegNo: 0);
98 std::prev(x: MBBI)->setPreInstrSymbol(MF, Symbol: MF.getPICBaseSymbol());
99 BuildMI(BB&: FirstMBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: X86::MOV64ri), DestReg: GOTReg)
100 .addExternalSymbol(FnName: "_GLOBAL_OFFSET_TABLE_",
101 TargetFlags: X86II::MO_PIC_BASE_OFFSET);
102 BuildMI(BB&: FirstMBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: X86::ADD64rr), DestReg: PC)
103 .addReg(RegNo: PBReg, Flags: RegState::Kill)
104 .addReg(RegNo: GOTReg, Flags: RegState::Kill);
105 } else {
106 // In other code models, use a RIP-relative LEA to materialize the
107 // GOT.
108 BuildMI(BB&: FirstMBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: X86::LEA64r), DestReg: PC)
109 .addReg(RegNo: X86::RIP)
110 .addImm(Val: 0)
111 .addReg(RegNo: 0)
112 .addExternalSymbol(FnName: "_GLOBAL_OFFSET_TABLE_")
113 .addReg(RegNo: 0);
114 }
115 } else {
116 // Operand of MovePCtoStack is completely ignored by asm printer. It's
117 // only used in JIT code emission as displacement to pc.
118 BuildMI(BB&: FirstMBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: X86::MOVPC32r), DestReg: PC).addImm(Val: 0);
119
120 // If we're using vanilla 'GOT' PIC style, we should use relative
121 // addressing not to pc, but to _GLOBAL_OFFSET_TABLE_ external.
122 if (STI.isPICStyleGOT()) {
123 // Generate addl $__GLOBAL_OFFSET_TABLE_ + [.-piclabel],
124 // %some_register
125 BuildMI(BB&: FirstMBB, I: MBBI, MIMD: DL, MCID: TII->get(Opcode: X86::ADD32ri), DestReg: GlobalBaseReg)
126 .addReg(RegNo: PC)
127 .addExternalSymbol(FnName: "_GLOBAL_OFFSET_TABLE_",
128 TargetFlags: X86II::MO_GOT_ABSOLUTE_ADDRESS);
129 }
130 }
131
132 return true;
133}
134
135bool X86GlobalBaseRegLegacy::runOnMachineFunction(MachineFunction &MF) {
136 return initGlobalBaseReg(MF);
137}
138
139PreservedAnalyses
140X86GlobalBaseRegPass::run(MachineFunction &MF,
141 MachineFunctionAnalysisManager &MFAM) {
142 return initGlobalBaseReg(MF) ? getMachineFunctionPassPreservedAnalyses()
143 .preserveSet<CFGAnalyses>()
144 : PreservedAnalyses::all();
145}
146