Skip to content

Commit 980c4df

Browse files
committedJul 23, 2018
Re-land r335297 "[X86] Implement more of x86-64 large and medium PIC code models"
Don't try to generate large PIC code for non-ELF targets. Neither COFF nor MachO have relocations for large position independent code, and users have been using "large PIC" code models to JIT 64-bit code for a while now. With this change, if they are generating ELF code, their JITed code will truly be PIC, but if they target MachO or COFF, it will contain 64-bit immediates that directly reference external symbols. For a JIT, that's perfectly fine. llvm-svn: 337740
1 parent 07dee81 commit 980c4df

15 files changed

+545
-36
lines changed
 

‎llvm/lib/Target/X86/X86ISelDAGToDAG.cpp

+6-4
Original file line numberDiff line numberDiff line change
@@ -991,11 +991,13 @@ bool X86DAGToDAGISel::matchWrapper(SDValue N, X86ISelAddressMode &AM) {
991991

992992
bool IsRIPRel = N.getOpcode() == X86ISD::WrapperRIP;
993993

994-
// Only do this address mode folding for 64-bit if we're in the small code
995-
// model.
996-
// FIXME: But we can do GOTPCREL addressing in the medium code model.
994+
// We can't use an addressing mode in the 64-bit large code model. In the
995+
// medium code model, we use can use an mode when RIP wrappers are present.
996+
// That signifies access to globals that are known to be "near", such as the
997+
// GOT itself.
997998
CodeModel::Model M = TM.getCodeModel();
998-
if (Subtarget->is64Bit() && M != CodeModel::Small && M != CodeModel::Kernel)
999+
if (Subtarget->is64Bit() &&
1000+
(M == CodeModel::Large || (M == CodeModel::Medium && !IsRIPRel)))
9991001
return true;
10001002

10011003
// Base and index reg must be 0 in order to use %rip as base.

‎llvm/lib/Target/X86/X86InstrCompiler.td

+4
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ let hasSideEffects = 0, isNotDuplicable = 1, Uses = [ESP, SSP],
3737
def MOVPC32r : Ii32<0xE8, Pseudo, (outs GR32:$reg), (ins i32imm:$label),
3838
"", []>;
3939

40+
// 64-bit large code model PIC base construction.
41+
let hasSideEffects = 0, mayLoad = 1, isNotDuplicable = 1, SchedRW = [WriteJump] in
42+
def MOVGOT64r : PseudoI<(outs GR64:$reg),
43+
(ins GR64:$scratch, i64i32imm_pcrel:$got), []>;
4044

4145
// ADJCALLSTACKDOWN/UP implicitly use/def ESP because they may be expanded into
4246
// a stack adjustment and the codegen must know that they may modify the stack

‎llvm/lib/Target/X86/X86InstrInfo.cpp

+44-16
Original file line numberDiff line numberDiff line change
@@ -5851,7 +5851,9 @@ isSafeToMoveRegClassDefs(const TargetRegisterClass *RC) const {
58515851
/// TODO: Eliminate this and move the code to X86MachineFunctionInfo.
58525852
///
58535853
unsigned X86InstrInfo::getGlobalBaseReg(MachineFunction *MF) const {
5854-
assert(!Subtarget.is64Bit() &&
5854+
assert((!Subtarget.is64Bit() ||
5855+
MF->getTarget().getCodeModel() == CodeModel::Medium ||
5856+
MF->getTarget().getCodeModel() == CodeModel::Large) &&
58555857
"X86-64 PIC uses RIP relative addressing");
58565858

58575859
X86MachineFunctionInfo *X86FI = MF->getInfo<X86MachineFunctionInfo>();
@@ -5862,7 +5864,8 @@ unsigned X86InstrInfo::getGlobalBaseReg(MachineFunction *MF) const {
58625864
// Create the register. The code to initialize it is inserted
58635865
// later, by the CGBR pass (below).
58645866
MachineRegisterInfo &RegInfo = MF->getRegInfo();
5865-
GlobalBaseReg = RegInfo.createVirtualRegister(&X86::GR32_NOSPRegClass);
5867+
GlobalBaseReg = RegInfo.createVirtualRegister(
5868+
Subtarget.is64Bit() ? &X86::GR64_NOSPRegClass : &X86::GR32_NOSPRegClass);
58665869
X86FI->setGlobalBaseReg(GlobalBaseReg);
58675870
return GlobalBaseReg;
58685871
}
@@ -7321,9 +7324,10 @@ namespace {
73217324
static_cast<const X86TargetMachine *>(&MF.getTarget());
73227325
const X86Subtarget &STI = MF.getSubtarget<X86Subtarget>();
73237326

7324-
// Don't do anything if this is 64-bit as 64-bit PIC
7325-
// uses RIP relative addressing.
7326-
if (STI.is64Bit())
7327+
// Don't do anything in the 64-bit small and kernel code models. They use
7328+
// RIP-relative addressing for everything.
7329+
if (STI.is64Bit() && (TM->getCodeModel() == CodeModel::Small ||
7330+
TM->getCodeModel() == CodeModel::Kernel))
73277331
return false;
73287332

73297333
// Only emit a global base reg in PIC mode.
@@ -7350,17 +7354,41 @@ namespace {
73507354
else
73517355
PC = GlobalBaseReg;
73527356

7353-
// Operand of MovePCtoStack is completely ignored by asm printer. It's
7354-
// only used in JIT code emission as displacement to pc.
7355-
BuildMI(FirstMBB, MBBI, DL, TII->get(X86::MOVPC32r), PC).addImm(0);
7356-
7357-
// If we're using vanilla 'GOT' PIC style, we should use relative addressing
7358-
// not to pc, but to _GLOBAL_OFFSET_TABLE_ external.
7359-
if (STI.isPICStyleGOT()) {
7360-
// Generate addl $__GLOBAL_OFFSET_TABLE_ + [.-piclabel], %some_register
7361-
BuildMI(FirstMBB, MBBI, DL, TII->get(X86::ADD32ri), GlobalBaseReg)
7362-
.addReg(PC).addExternalSymbol("_GLOBAL_OFFSET_TABLE_",
7363-
X86II::MO_GOT_ABSOLUTE_ADDRESS);
7357+
if (STI.is64Bit()) {
7358+
if (TM->getCodeModel() == CodeModel::Medium) {
7359+
// In the medium code model, use a RIP-relative LEA to materialize the
7360+
// GOT.
7361+
BuildMI(FirstMBB, MBBI, DL, TII->get(X86::LEA64r), PC)
7362+
.addReg(X86::RIP)
7363+
.addImm(0)
7364+
.addReg(0)
7365+
.addExternalSymbol("_GLOBAL_OFFSET_TABLE_")
7366+
.addReg(0);
7367+
} else if (TM->getCodeModel() == CodeModel::Large) {
7368+
// Loading the GOT in the large code model requires math with labels,
7369+
// so we use a pseudo instruction and expand it during MC emission.
7370+
unsigned Scratch = RegInfo.createVirtualRegister(&X86::GR64RegClass);
7371+
BuildMI(FirstMBB, MBBI, DL, TII->get(X86::MOVGOT64r), PC)
7372+
.addReg(Scratch, RegState::Undef | RegState::Define)
7373+
.addExternalSymbol("_GLOBAL_OFFSET_TABLE_");
7374+
} else {
7375+
llvm_unreachable("unexpected code model");
7376+
}
7377+
} else {
7378+
// Operand of MovePCtoStack is completely ignored by asm printer. It's
7379+
// only used in JIT code emission as displacement to pc.
7380+
BuildMI(FirstMBB, MBBI, DL, TII->get(X86::MOVPC32r), PC).addImm(0);
7381+
7382+
// If we're using vanilla 'GOT' PIC style, we should use relative
7383+
// addressing not to pc, but to _GLOBAL_OFFSET_TABLE_ external.
7384+
if (STI.isPICStyleGOT()) {
7385+
// Generate addl $__GLOBAL_OFFSET_TABLE_ + [.-piclabel],
7386+
// %some_register
7387+
BuildMI(FirstMBB, MBBI, DL, TII->get(X86::ADD32ri), GlobalBaseReg)
7388+
.addReg(PC)
7389+
.addExternalSymbol("_GLOBAL_OFFSET_TABLE_",
7390+
X86II::MO_GOT_ABSOLUTE_ADDRESS);
7391+
}
73647392
}
73657393

73667394
return true;

‎llvm/lib/Target/X86/X86MCInstLower.cpp

+35
Original file line numberDiff line numberDiff line change
@@ -1720,6 +1720,41 @@ void X86AsmPrinter::EmitInstruction(const MachineInstr *MI) {
17201720
return;
17211721
}
17221722

1723+
case X86::MOVGOT64r: {
1724+
// Materializes the GOT for the 64-bit large code model.
1725+
MCSymbol *DotSym = OutContext.createTempSymbol();
1726+
OutStreamer->EmitLabel(DotSym);
1727+
1728+
unsigned DstReg = MI->getOperand(0).getReg();
1729+
unsigned ScratchReg = MI->getOperand(1).getReg();
1730+
MCSymbol *GOTSym = MCInstLowering.GetSymbolFromOperand(MI->getOperand(2));
1731+
1732+
// .LtmpN: leaq .LtmpN(%rip), %dst
1733+
const MCExpr *DotExpr = MCSymbolRefExpr::create(DotSym, OutContext);
1734+
EmitAndCountInstruction(MCInstBuilder(X86::LEA64r)
1735+
.addReg(DstReg) // dest
1736+
.addReg(X86::RIP) // base
1737+
.addImm(1) // scale
1738+
.addReg(0) // index
1739+
.addExpr(DotExpr) // disp
1740+
.addReg(0)); // seg
1741+
1742+
// movq $_GLOBAL_OFFSET_TABLE_ - .LtmpN, %scratch
1743+
const MCExpr *GOTSymExpr = MCSymbolRefExpr::create(GOTSym, OutContext);
1744+
const MCExpr *GOTDiffExpr =
1745+
MCBinaryExpr::createSub(GOTSymExpr, DotExpr, OutContext);
1746+
EmitAndCountInstruction(MCInstBuilder(X86::MOV64ri)
1747+
.addReg(ScratchReg) // dest
1748+
.addExpr(GOTDiffExpr)); // disp
1749+
1750+
// addq %scratch, %dst
1751+
EmitAndCountInstruction(MCInstBuilder(X86::ADD64rr)
1752+
.addReg(DstReg) // dest
1753+
.addReg(DstReg) // dest
1754+
.addReg(ScratchReg)); // src
1755+
return;
1756+
}
1757+
17231758
case X86::ADD32ri: {
17241759
// Lower the MO_GOT_ABSOLUTE_ADDRESS form of ADD32ri.
17251760
if (MI->getOperand(2).getTargetFlags() != X86II::MO_GOT_ABSOLUTE_ADDRESS)

‎llvm/lib/Target/X86/X86Subtarget.cpp

+36-8
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,36 @@ X86Subtarget::classifyGlobalReference(const GlobalValue *GV) const {
6868

6969
unsigned char
7070
X86Subtarget::classifyLocalReference(const GlobalValue *GV) const {
71-
// 64 bits can use %rip addressing for anything local.
72-
if (is64Bit())
71+
// If we're not PIC, it's not very interesting.
72+
if (!isPositionIndependent())
7373
return X86II::MO_NO_FLAG;
7474

75-
// If this is for a position dependent executable, the static linker can
76-
// figure it out.
77-
if (!isPositionIndependent())
75+
if (is64Bit()) {
76+
// 64-bit ELF PIC local references may use GOTOFF relocations.
77+
if (isTargetELF()) {
78+
switch (TM.getCodeModel()) {
79+
// 64-bit small code model is simple: All rip-relative.
80+
case CodeModel::Small:
81+
case CodeModel::Kernel:
82+
return X86II::MO_NO_FLAG;
83+
84+
// The large PIC code model uses GOTOFF.
85+
case CodeModel::Large:
86+
return X86II::MO_GOTOFF;
87+
88+
// Medium is a hybrid: RIP-rel for code, GOTOFF for DSO local data.
89+
case CodeModel::Medium:
90+
if (isa<Function>(GV))
91+
return X86II::MO_NO_FLAG; // All code is RIP-relative
92+
return X86II::MO_GOTOFF; // Local symbols use GOTOFF.
93+
}
94+
llvm_unreachable("invalid code model");
95+
}
96+
97+
// Otherwise, this is either a RIP-relative reference or a 64-bit movabsq,
98+
// both of which use MO_NO_FLAG.
7899
return X86II::MO_NO_FLAG;
100+
}
79101

80102
// The COFF dynamic linker just patches the executable sections.
81103
if (isTargetCOFF())
@@ -97,8 +119,8 @@ X86Subtarget::classifyLocalReference(const GlobalValue *GV) const {
97119

98120
unsigned char X86Subtarget::classifyGlobalReference(const GlobalValue *GV,
99121
const Module &M) const {
100-
// Large model never uses stubs.
101-
if (TM.getCodeModel() == CodeModel::Large)
122+
// The static large model never uses stubs.
123+
if (TM.getCodeModel() == CodeModel::Large && !isPositionIndependent())
102124
return X86II::MO_NO_FLAG;
103125

104126
// Absolute symbols can be referenced directly.
@@ -120,8 +142,14 @@ unsigned char X86Subtarget::classifyGlobalReference(const GlobalValue *GV,
120142
if (isTargetCOFF())
121143
return X86II::MO_DLLIMPORT;
122144

123-
if (is64Bit())
145+
if (is64Bit()) {
146+
// ELF supports a large, truly PIC code model with non-PC relative GOT
147+
// references. Other object file formats do not. Use the no-flag, 64-bit
148+
// reference for them.
149+
if (TM.getCodeModel() == CodeModel::Large)
150+
return isTargetELF() ? X86II::MO_GOT : X86II::MO_NO_FLAG;
124151
return X86II::MO_GOTPCREL;
152+
}
125153

126154
if (isTargetDarwin()) {
127155
if (!isPositionIndependent())

‎llvm/lib/Target/X86/X86TargetMachine.cpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -160,9 +160,15 @@ static std::string computeDataLayout(const Triple &TT) {
160160
}
161161

162162
static Reloc::Model getEffectiveRelocModel(const Triple &TT,
163+
bool JIT,
163164
Optional<Reloc::Model> RM) {
164165
bool is64Bit = TT.getArch() == Triple::x86_64;
165166
if (!RM.hasValue()) {
167+
// JIT codegen should use static relocations by default, since it's
168+
// typically executed in process and not relocatable.
169+
if (JIT)
170+
return Reloc::Static;
171+
166172
// Darwin defaults to PIC in 64 bit mode and dynamic-no-pic in 32 bit mode.
167173
// Win64 requires rip-rel addressing, thus we force it to PIC. Otherwise we
168174
// use static relocation model by default.
@@ -214,7 +220,7 @@ X86TargetMachine::X86TargetMachine(const Target &T, const Triple &TT,
214220
CodeGenOpt::Level OL, bool JIT)
215221
: LLVMTargetMachine(
216222
T, computeDataLayout(TT), TT, CPU, FS, Options,
217-
getEffectiveRelocModel(TT, RM),
223+
getEffectiveRelocModel(TT, JIT, RM),
218224
getEffectiveCodeModel(CM, JIT, TT.getArch() == Triple::x86_64), OL),
219225
TLOF(createTLOF(getTargetTriple())) {
220226
// Windows stack unwinder gets confused when execution flow "falls through"

‎llvm/test/CodeGen/X86/cleanuppad-large-codemodel.ll

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
; RUN: llc -mtriple=x86_64-pc-windows-msvc -code-model=large -o - < %s | FileCheck %s
1+
; RUN: llc -mtriple=x86_64-pc-windows-msvc -code-model=large -relocation-model=static -o - < %s | FileCheck %s
22

33
declare i32 @__CxxFrameHandler3(...)
44

0 commit comments

Comments
 (0)
Please sign in to comment.