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 .setOperandDead(3); // implicit-def $eflags
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 .setOperandDead(3); // implicit-def $eflags
130 }
131 }
132
133 return true;
134}
135
136bool X86GlobalBaseRegLegacy::runOnMachineFunction(MachineFunction &MF) {
137 return initGlobalBaseReg(MF);
138}
139
140PreservedAnalyses
141X86GlobalBaseRegPass::run(MachineFunction &MF,
142 MachineFunctionAnalysisManager &MFAM) {
143 return initGlobalBaseReg(MF) ? getMachineFunctionPassPreservedAnalyses()
144 .preserveSet<CFGAnalyses>()
145 : PreservedAnalyses::all();
146}
147