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