Skip to content

Commit f0a08bb

Browse files
fzou1GeorgeARM
authored andcommitted
[X86][APX] Suppress EGPR/NDD instructions for relocations (llvm#136660)
Suppress EGPR/NDD instructions for relocations to avoid APX relocation types emitted. This is to keep backward compatibility with old version of linkers without APX support. The use case is to try APX features with LLVM + old built-in linker on RHEL9 OS which is expected to be EOL in 2032. If there are APX relocation types, the old version of linkers would raise "unsupported relocation type" error. Example: ``` $ llvm-mc -filetype=obj -o got.o -triple=x86_64-unknown-linux got.s $ ld got.o -o got.exe ld: got.o: unsupported relocation type 0x2b ... $ cat got.s ... movq foo@GOTPCREL(%rip), %r16 $ llvm-objdump -dr got.o ... 1: d5 48 8b 05 00 00 00 00 movq (%rip), %r16 0000000000000005: R_X86_64_CODE_4_GOTPCRELX foo-0x4 ```
1 parent f4dca48 commit f0a08bb

28 files changed

+696
-18
lines changed

llvm/lib/Target/X86/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ set(sources
7878
X86SpeculativeLoadHardening.cpp
7979
X86SpeculativeExecutionSideEffectSuppression.cpp
8080
X86Subtarget.cpp
81+
X86SuppressAPXForReloc.cpp
8182
X86TargetMachine.cpp
8283
X86TargetObjectFile.cpp
8384
X86TargetTransformInfo.cpp

llvm/lib/Target/X86/X86.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ FunctionPass *createX86LoadValueInjectionRetHardeningPass();
169169
FunctionPass *createX86SpeculativeLoadHardeningPass();
170170
FunctionPass *createX86SpeculativeExecutionSideEffectSuppression();
171171
FunctionPass *createX86ArgumentStackSlotPass();
172+
FunctionPass *createX86SuppressAPXForRelocationPass();
172173

173174
void initializeCompressEVEXPassPass(PassRegistry &);
174175
void initializeFPSPass(PassRegistry &);
@@ -204,6 +205,7 @@ void initializeX86ReturnThunksPass(PassRegistry &);
204205
void initializeX86SpeculativeExecutionSideEffectSuppressionPass(PassRegistry &);
205206
void initializeX86SpeculativeLoadHardeningPassPass(PassRegistry &);
206207
void initializeX86TileConfigPass(PassRegistry &);
208+
void initializeX86SuppressAPXForRelocationPassPass(PassRegistry &);
207209

208210
namespace X86AS {
209211
enum : unsigned {

llvm/lib/Target/X86/X86CompressEVEX.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ using namespace llvm;
5858

5959
#define DEBUG_TYPE COMP_EVEX_NAME
6060

61+
extern cl::opt<bool> X86EnableAPXForRelocation;
62+
6163
namespace {
6264
// Including the generated EVEX compression tables.
6365
#define GET_X86_COMPRESS_EVEX_TABLE
@@ -252,6 +254,13 @@ static bool CompressEVEXImpl(MachineInstr &MI, const X86Subtarget &ST) {
252254
if (MI.definesRegister(Super, /*TRI=*/nullptr))
253255
IsRedundantNDD = false;
254256
}
257+
258+
// ADDrm/mr instructions with NDD + relocation had been transformed to the
259+
// instructions without NDD in X86SuppressAPXForRelocation pass. That is to
260+
// keep backward compatibility with linkers without APX support.
261+
if (!X86EnableAPXForRelocation)
262+
assert(!isAddMemInstrWithRelocation(MI) &&
263+
"Unexpected NDD instruction with relocation!");
255264
}
256265

257266
// NonNF -> NF only if it's not a compressible NDD instruction and eflags is

llvm/lib/Target/X86/X86FlagsCopyLowering.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ STATISTIC(NumTestsInserted, "Number of test instructions inserted");
6666
STATISTIC(NumAddsInserted, "Number of adds instructions inserted");
6767
STATISTIC(NumNFsConvertedTo, "Number of NF instructions converted to");
6868

69+
extern cl::opt<bool> X86EnableAPXForRelocation;
70+
6971
namespace {
7072

7173
// Convenient array type for storing registers associated with each condition.
@@ -242,7 +244,15 @@ static EFLAGSClobber getClobberType(const MachineInstr &MI) {
242244
MI.findRegisterDefOperand(X86::EFLAGS, /*TRI=*/nullptr);
243245
if (!FlagDef)
244246
return NoClobber;
245-
if (FlagDef->isDead() && X86::getNFVariant(MI.getOpcode()))
247+
248+
// For the instructions are ADDrm/ADDmr with relocation, we'll skip the
249+
// optimization for replacing non-NF with NF. This is to keep backward
250+
// compatiblity with old version of linkers without APX relocation type
251+
// support on Linux OS.
252+
bool IsWithReloc =
253+
X86EnableAPXForRelocation ? false : isAddMemInstrWithRelocation(MI);
254+
255+
if (FlagDef->isDead() && X86::getNFVariant(MI.getOpcode()) && !IsWithReloc)
246256
return EvitableClobber;
247257

248258
return InevitableClobber;

llvm/lib/Target/X86/X86InstrInfo.cpp

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ using namespace llvm;
5353
#define GET_INSTRINFO_CTOR_DTOR
5454
#include "X86GenInstrInfo.inc"
5555

56+
extern cl::opt<bool> X86EnableAPXForRelocation;
57+
5658
static cl::opt<bool>
5759
NoFusing("disable-spill-fusing",
5860
cl::desc("Disable fusing of spill code into instructions"),
@@ -102,22 +104,8 @@ X86InstrInfo::getRegClass(const MCInstrDesc &MCID, unsigned OpNum,
102104
if (X86II::canUseApxExtendedReg(MCID))
103105
return RC;
104106

105-
switch (RC->getID()) {
106-
default:
107-
return RC;
108-
case X86::GR8RegClassID:
109-
return &X86::GR8_NOREX2RegClass;
110-
case X86::GR16RegClassID:
111-
return &X86::GR16_NOREX2RegClass;
112-
case X86::GR32RegClassID:
113-
return &X86::GR32_NOREX2RegClass;
114-
case X86::GR64RegClassID:
115-
return &X86::GR64_NOREX2RegClass;
116-
case X86::GR32_NOSPRegClassID:
117-
return &X86::GR32_NOREX2_NOSPRegClass;
118-
case X86::GR64_NOSPRegClassID:
119-
return &X86::GR64_NOREX2_NOSPRegClass;
120-
}
107+
const X86RegisterInfo *RI = Subtarget.getRegisterInfo();
108+
return RI->constrainRegClassToNonRex2(RC);
121109
}
122110

123111
bool X86InstrInfo::isCoalescableExtInstr(const MachineInstr &MI,
@@ -5464,8 +5452,16 @@ bool X86InstrInfo::optimizeCompareInstr(MachineInstr &CmpInstr, Register SrcReg,
54645452
continue;
54655453
}
54665454

5455+
// For the instructions are ADDrm/ADDmr with relocation, we'll skip the
5456+
// optimization for replacing non-NF with NF. This is to keep backward
5457+
// compatiblity with old version of linkers without APX relocation type
5458+
// support on Linux OS.
5459+
bool IsWithReloc = X86EnableAPXForRelocation
5460+
? false
5461+
: isAddMemInstrWithRelocation(Inst);
5462+
54675463
// Try to replace non-NF with NF instructions.
5468-
if (HasNF && Inst.registerDefIsDead(X86::EFLAGS, TRI)) {
5464+
if (HasNF && Inst.registerDefIsDead(X86::EFLAGS, TRI) && !IsWithReloc) {
54695465
unsigned NewOp = X86::getNFVariant(Inst.getOpcode());
54705466
if (!NewOp)
54715467
return false;

llvm/lib/Target/X86/X86InstrInfo.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,19 @@ inline static bool isMem(const MachineInstr &MI, unsigned Op) {
174174
MI.getOperand(Op + X86::AddrSegmentReg).isReg() && isLeaMem(MI, Op);
175175
}
176176

177+
inline static bool isAddMemInstrWithRelocation(const MachineInstr &MI) {
178+
unsigned Op = MI.getOpcode();
179+
if (Op == X86::ADD64rm || Op == X86::ADD64mr_ND || Op == X86::ADD64rm_ND) {
180+
int MemOpNo = X86II::getMemoryOperandNo(MI.getDesc().TSFlags) +
181+
X86II::getOperandBias(MI.getDesc());
182+
const MachineOperand &MO = MI.getOperand(X86::AddrDisp + MemOpNo);
183+
if (MO.getTargetFlags() == X86II::MO_GOTTPOFF)
184+
return true;
185+
}
186+
187+
return false;
188+
}
189+
177190
class X86InstrInfo final : public X86GenInstrInfo {
178191
X86Subtarget &Subtarget;
179192
const X86RegisterInfo RI;

llvm/lib/Target/X86/X86RegisterInfo.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1237,3 +1237,23 @@ bool X86RegisterInfo::getRegAllocationHints(Register VirtReg,
12371237

12381238
return true;
12391239
}
1240+
1241+
const TargetRegisterClass *X86RegisterInfo::constrainRegClassToNonRex2(
1242+
const TargetRegisterClass *RC) const {
1243+
switch (RC->getID()) {
1244+
default:
1245+
return RC;
1246+
case X86::GR8RegClassID:
1247+
return &X86::GR8_NOREX2RegClass;
1248+
case X86::GR16RegClassID:
1249+
return &X86::GR16_NOREX2RegClass;
1250+
case X86::GR32RegClassID:
1251+
return &X86::GR32_NOREX2RegClass;
1252+
case X86::GR64RegClassID:
1253+
return &X86::GR64_NOREX2RegClass;
1254+
case X86::GR32_NOSPRegClassID:
1255+
return &X86::GR32_NOREX2_NOSPRegClass;
1256+
case X86::GR64_NOSPRegClassID:
1257+
return &X86::GR64_NOREX2_NOSPRegClass;
1258+
}
1259+
}

llvm/lib/Target/X86/X86RegisterInfo.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,9 @@ class X86RegisterInfo final : public X86GenRegisterInfo {
171171
SmallVectorImpl<MCPhysReg> &Hints,
172172
const MachineFunction &MF, const VirtRegMap *VRM,
173173
const LiveRegMatrix *Matrix) const override;
174+
175+
const TargetRegisterClass *
176+
constrainRegClassToNonRex2(const TargetRegisterClass *RC) const;
174177
};
175178

176179
} // End llvm namespace

0 commit comments

Comments
 (0)