Skip to content

Commit feea5db

Browse files
authored
[X86] Support EGPR (R16-R31) for APX (#67702)
1. Map R16-R31 to DWARF registers 130-145. 2. Make R16-R31 caller-saved registers. 3. Make R16-31 allocatable only when feature EGPR is supported 4. Make R16-31 availabe for instructions in legacy maps 0/1 and EVEX space, except XSAVE*/XRSTOR RFC: https://discourse.llvm.org/t/rfc-design-for-apx-feature-egpr-and-ndd-support/73031/4 Explanations for some seemingly unrelated changes: inline-asm-registers.mir, statepoint-invoke-ra-enter-at-end.mir: The immediate (TargetInstrInfo.cpp:1612) used for the regdef/reguse is the encoding for the register class in the enum generated by tablegen. This encoding will change any time a new register class is added. Since the number is part of the input, this means it can become stale. seh-directive-errors.s: R16-R31 makes ".seh_pushreg 17" legal musttail-varargs.ll: It seems some LLVM passes use the number of registers rather the number of allocatable registers as heuristic.
1 parent b5dffd4 commit feea5db

17 files changed

+1568
-47
lines changed

llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1208,6 +1208,43 @@ namespace X86II {
12081208
return false;
12091209
}
12101210

1211+
inline bool canUseApxExtendedReg(const MCInstrDesc &Desc) {
1212+
uint64_t TSFlags = Desc.TSFlags;
1213+
uint64_t Encoding = TSFlags & EncodingMask;
1214+
// EVEX can always use egpr.
1215+
if (Encoding == X86II::EVEX)
1216+
return true;
1217+
1218+
// To be conservative, egpr is not used for all pseudo instructions
1219+
// because we are not sure what instruction it will become.
1220+
// FIXME: Could we improve it in X86ExpandPseudo?
1221+
if (isPseudo(TSFlags))
1222+
return false;
1223+
1224+
// MAP OB/TB in legacy encoding space can always use egpr except
1225+
// XSAVE*/XRSTOR*.
1226+
unsigned Opcode = Desc.Opcode;
1227+
switch (Opcode) {
1228+
default:
1229+
break;
1230+
case X86::XSAVE:
1231+
case X86::XSAVE64:
1232+
case X86::XSAVEOPT:
1233+
case X86::XSAVEOPT64:
1234+
case X86::XSAVEC:
1235+
case X86::XSAVEC64:
1236+
case X86::XSAVES:
1237+
case X86::XSAVES64:
1238+
case X86::XRSTOR:
1239+
case X86::XRSTOR64:
1240+
case X86::XRSTORS:
1241+
case X86::XRSTORS64:
1242+
return false;
1243+
}
1244+
uint64_t OpMap = TSFlags & X86II::OpMapMask;
1245+
return !Encoding && (OpMap == X86II::OB || OpMap == X86II::TB);
1246+
}
1247+
12111248
/// \returns true if the MemoryOperand is a 32 extended (zmm16 or higher)
12121249
/// registers, e.g. zmm21, etc.
12131250
static inline bool is32ExtendedReg(unsigned RegNo) {

llvm/lib/Target/X86/X86.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,8 @@ def FeatureMOVDIRI : SubtargetFeature<"movdiri", "HasMOVDIRI", "true",
331331
"Support movdiri instruction (direct store integer)">;
332332
def FeatureMOVDIR64B : SubtargetFeature<"movdir64b", "HasMOVDIR64B", "true",
333333
"Support movdir64b instruction (direct store 64 bytes)">;
334+
def FeatureEGPR : SubtargetFeature<"egpr", "HasEGPR", "true",
335+
"Support extended general purpose register">;
334336

335337
// Ivy Bridge and newer processors have enhanced REP MOVSB and STOSB (aka
336338
// "string operations"). See "REP String Enhancement" in the Intel Software

llvm/lib/Target/X86/X86InstrInfo.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,37 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
9292
Subtarget(STI), RI(STI.getTargetTriple()) {
9393
}
9494

95+
const TargetRegisterClass *
96+
X86InstrInfo::getRegClass(const MCInstrDesc &MCID, unsigned OpNum,
97+
const TargetRegisterInfo *TRI,
98+
const MachineFunction &MF) const {
99+
auto *RC = TargetInstrInfo::getRegClass(MCID, OpNum, TRI, MF);
100+
// If the target does not have egpr, then r16-r31 will be resereved for all
101+
// instructions.
102+
if (!RC || !Subtarget.hasEGPR())
103+
return RC;
104+
105+
if (X86II::canUseApxExtendedReg(MCID))
106+
return RC;
107+
108+
switch (RC->getID()) {
109+
default:
110+
return RC;
111+
case X86::GR8RegClassID:
112+
return &X86::GR8_NOREX2RegClass;
113+
case X86::GR16RegClassID:
114+
return &X86::GR16_NOREX2RegClass;
115+
case X86::GR32RegClassID:
116+
return &X86::GR32_NOREX2RegClass;
117+
case X86::GR64RegClassID:
118+
return &X86::GR64_NOREX2RegClass;
119+
case X86::GR32_NOSPRegClassID:
120+
return &X86::GR32_NOREX2_NOSPRegClass;
121+
case X86::GR64_NOSPRegClassID:
122+
return &X86::GR64_NOREX2_NOSPRegClass;
123+
}
124+
}
125+
95126
bool
96127
X86InstrInfo::isCoalescableExtInstr(const MachineInstr &MI,
97128
Register &SrcReg, Register &DstReg,

llvm/lib/Target/X86/X86InstrInfo.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,17 @@ class X86InstrInfo final : public X86GenInstrInfo {
150150
public:
151151
explicit X86InstrInfo(X86Subtarget &STI);
152152

153+
/// Given a machine instruction descriptor, returns the register
154+
/// class constraint for OpNum, or NULL. Returned register class
155+
/// may be different from the definition in the TD file, e.g.
156+
/// GR*RegClass (definition in TD file)
157+
/// ->
158+
/// GR*_NOREX2RegClass (Returned register class)
159+
const TargetRegisterClass *
160+
getRegClass(const MCInstrDesc &MCID, unsigned OpNum,
161+
const TargetRegisterInfo *TRI,
162+
const MachineFunction &MF) const override;
163+
153164
/// getRegisterInfo - TargetInstrInfo is a superset of MRegister info. As
154165
/// such, whenever a client has an instance of instruction info, it should
155166
/// always be able to get register info as well (through this method).

llvm/lib/Target/X86/X86RegisterInfo.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,10 @@ X86RegisterInfo::getLargestLegalSuperClass(const TargetRegisterClass *RC,
158158
case X86::GR16RegClassID:
159159
case X86::GR32RegClassID:
160160
case X86::GR64RegClassID:
161+
case X86::GR8_NOREX2RegClassID:
162+
case X86::GR16_NOREX2RegClassID:
163+
case X86::GR32_NOREX2RegClassID:
164+
case X86::GR64_NOREX2RegClassID:
161165
case X86::RFP32RegClassID:
162166
case X86::RFP64RegClassID:
163167
case X86::RFP80RegClassID:
@@ -610,6 +614,14 @@ BitVector X86RegisterInfo::getReservedRegs(const MachineFunction &MF) const {
610614
}
611615
}
612616

617+
// Reserve the extended general purpose registers.
618+
if (!Is64Bit || !MF.getSubtarget<X86Subtarget>().hasEGPR()) {
619+
for (unsigned n = 0; n != 16; ++n) {
620+
for (MCRegAliasIterator AI(X86::R16 + n, this, true); AI.isValid(); ++AI)
621+
Reserved.set(*AI);
622+
}
623+
}
624+
613625
assert(checkAllSuperRegsMarked(Reserved,
614626
{X86::SIL, X86::DIL, X86::BPL, X86::SPL,
615627
X86::SIH, X86::DIH, X86::BPH, X86::SPH}));

0 commit comments

Comments
 (0)