| 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 | |
| 24 | using namespace llvm; |
| 25 | |
| 26 | #define DEBUG_TYPE "x86-global-base-reg" |
| 27 | |
| 28 | namespace { |
| 29 | class X86GlobalBaseRegLegacy : public MachineFunctionPass { |
| 30 | public: |
| 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 | |
| 47 | char X86GlobalBaseRegLegacy::ID = 0; |
| 48 | |
| 49 | FunctionPass *llvm::createX86GlobalBaseRegLegacyPass() { |
| 50 | return new X86GlobalBaseRegLegacy(); |
| 51 | } |
| 52 | |
| 53 | static 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 | |
| 135 | bool X86GlobalBaseRegLegacy::runOnMachineFunction(MachineFunction &MF) { |
| 136 | return initGlobalBaseReg(MF); |
| 137 | } |
| 138 | |
| 139 | PreservedAnalyses |
| 140 | X86GlobalBaseRegPass::run(MachineFunction &MF, |
| 141 | MachineFunctionAnalysisManager &MFAM) { |
| 142 | return initGlobalBaseReg(MF) ? getMachineFunctionPassPreservedAnalyses() |
| 143 | .preserveSet<CFGAnalyses>() |
| 144 | : PreservedAnalyses::all(); |
| 145 | } |
| 146 | |