Skip to content

Commit c9017bc

Browse files
authored
[X86] Support EGPR (R16-R31) for APX (#70958)
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. This PR is to reland #67702 after #70222 in order to reduce some compile-time regression when EGPR is not used.
1 parent ed86e74 commit c9017bc

17 files changed

+1580
-50
lines changed

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

+37
Original file line numberDiff line numberDiff line change
@@ -1237,6 +1237,43 @@ namespace X86II {
12371237
return false;
12381238
}
12391239

1240+
inline bool canUseApxExtendedReg(const MCInstrDesc &Desc) {
1241+
uint64_t TSFlags = Desc.TSFlags;
1242+
uint64_t Encoding = TSFlags & EncodingMask;
1243+
// EVEX can always use egpr.
1244+
if (Encoding == X86II::EVEX)
1245+
return true;
1246+
1247+
// To be conservative, egpr is not used for all pseudo instructions
1248+
// because we are not sure what instruction it will become.
1249+
// FIXME: Could we improve it in X86ExpandPseudo?
1250+
if (isPseudo(TSFlags))
1251+
return false;
1252+
1253+
// MAP OB/TB in legacy encoding space can always use egpr except
1254+
// XSAVE*/XRSTOR*.
1255+
unsigned Opcode = Desc.Opcode;
1256+
switch (Opcode) {
1257+
default:
1258+
break;
1259+
case X86::XSAVE:
1260+
case X86::XSAVE64:
1261+
case X86::XSAVEOPT:
1262+
case X86::XSAVEOPT64:
1263+
case X86::XSAVEC:
1264+
case X86::XSAVEC64:
1265+
case X86::XSAVES:
1266+
case X86::XSAVES64:
1267+
case X86::XRSTOR:
1268+
case X86::XRSTOR64:
1269+
case X86::XRSTORS:
1270+
case X86::XRSTORS64:
1271+
return false;
1272+
}
1273+
uint64_t OpMap = TSFlags & X86II::OpMapMask;
1274+
return !Encoding && (OpMap == X86II::OB || OpMap == X86II::TB);
1275+
}
1276+
12401277
/// \returns true if the MemoryOperand is a 32 extended (zmm16 or higher)
12411278
/// registers, e.g. zmm21, etc.
12421279
static inline bool is32ExtendedReg(unsigned RegNo) {

llvm/lib/Target/X86/X86.td

+2
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,8 @@ def FeatureAVX10_1 : SubtargetFeature<"avx10.1-256", "HasAVX10_1", "true",
341341
def FeatureAVX10_1_512 : SubtargetFeature<"avx10.1-512", "HasAVX10_1_512", "true",
342342
"Support AVX10.1 up to 512-bit instruction",
343343
[FeatureAVX10_1, FeatureEVEX512]>;
344+
def FeatureEGPR : SubtargetFeature<"egpr", "HasEGPR", "true",
345+
"Support extended general purpose register">;
344346

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

llvm/lib/Target/X86/X86InstrInfo.cpp

+31
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

+11
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

+12-3
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:
@@ -611,6 +615,10 @@ BitVector X86RegisterInfo::getReservedRegs(const MachineFunction &MF) const {
611615
}
612616
}
613617

618+
// Reserve the extended general purpose registers.
619+
if (!Is64Bit || !MF.getSubtarget<X86Subtarget>().hasEGPR())
620+
Reserved.set(X86::R16, X86::R31WH + 1);
621+
614622
assert(checkAllSuperRegsMarked(Reserved,
615623
{X86::SIL, X86::DIL, X86::BPL, X86::SPL,
616624
X86::SIH, X86::DIH, X86::BPH, X86::SPH}));
@@ -629,13 +637,14 @@ unsigned X86RegisterInfo::getNumSupportedRegs(const MachineFunction &MF) const {
629637
// APX registers (R16-R31)
630638
//
631639
// and try to return the minimum number of registers supported by the target.
632-
633640
assert((X86::R15WH + 1 == X86 ::YMM0) && (X86::YMM15 + 1 == X86::K0) &&
634-
(X86::K6_K7 + 1 == X86::TMMCFG) &&
635-
(X86::TMM7 + 1 == X86::NUM_TARGET_REGS) &&
641+
(X86::K6_K7 + 1 == X86::TMMCFG) && (X86::TMM7 + 1 == X86::R16) &&
642+
(X86::R31WH + 1 == X86::NUM_TARGET_REGS) &&
636643
"Register number may be incorrect");
637644

638645
const X86Subtarget &ST = MF.getSubtarget<X86Subtarget>();
646+
if (ST.hasEGPR())
647+
return X86::NUM_TARGET_REGS;
639648
if (ST.hasAMXTILE())
640649
return X86::TMM7 + 1;
641650
if (ST.hasAVX512())

0 commit comments

Comments
 (0)