-
Notifications
You must be signed in to change notification settings - Fork 15.9k
[TableGen] Introduce RegisterByHwMode #175227
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
[TableGen] Introduce RegisterByHwMode #175227
Conversation
Created using spr 1.3.8-beta.1
|
@llvm/pr-subscribers-tablegen @llvm/pr-subscribers-llvm-selectiondag Author: Alexander Richardson (arichardson) ChangesThis is useful for Patch is 57.26 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/175227.diff 19 Files Affected:
diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td
index 315de55b75510..61388c4902eb4 100644
--- a/llvm/include/llvm/Target/Target.td
+++ b/llvm/include/llvm/Target/Target.td
@@ -1078,6 +1078,16 @@ class RegisterOperand<RegisterClassLike regclass, string pm = "printOperand">
Register GIZeroRegister = ?;
}
+/// RegisterByHwMode - Useful for InstAliases with a hardcoded register operand
+/// where the operand type is a RegClassByHwMode.
+class RegisterByHwMode<RegisterClassLike RegClass, list<HwMode> Modes,
+ list<Register> Registers>
+ : HwModeSelect<Modes, !size(Registers)>, RegisterOperand<RegClass> {
+ list<Register> Objects = Registers;
+ // Note: No assertions to validate the registers against the
+ // register class here, this is done inside llvm-tblgen.
+}
+
let OperandType = "OPERAND_IMMEDIATE" in {
def i1imm : Operand<i1>;
def i8imm : Operand<i8>;
diff --git a/llvm/test/TableGen/Common/RegisterByHwModeCommon.td b/llvm/test/TableGen/Common/RegisterByHwModeCommon.td
new file mode 100644
index 0000000000000..57ec5b2d616c8
--- /dev/null
+++ b/llvm/test/TableGen/Common/RegisterByHwModeCommon.td
@@ -0,0 +1,92 @@
+include "llvm/Target/Target.td"
+
+/// A minimal reduced version of the RISC-V RVY register variants where pointers
+/// use either Xn or Xn_Y registers depending on CapMode and 64-bit predicates.
+/// Define HWModes for the full cross-product here since we can only match one
+/// HWMode at any given time.
+def Is32Bit : Predicate<"!Subtarget->is64Bit()">;
+def Is64Bit : Predicate<"Subtarget->is64Bit()">;
+def UseYRegForPtr : Predicate<"Subtarget->useYRegForPtr()">;
+def UseXRegForPtr : Predicate<"!Subtarget->useYRegForPtr()">;
+defvar XPtr32 = DefaultMode;
+def XPtr64 : HwMode<[Is64Bit, UseXRegForPtr]>;
+def YPtr32 : HwMode<[Is32Bit, UseYRegForPtr]>;
+def YPtr64 : HwMode<[Is64Bit, UseYRegForPtr]>;
+
+class MyReg<string n> : Register<n> {
+ let Namespace = "MyTarget";
+}
+
+def X0 : MyReg<"x0">;
+def X1 : MyReg<"x1">;
+def X2 : MyReg<"x2">;
+def X3 : MyReg<"x3">;
+
+def Y0 : MyReg<"y0">;
+def Y1 : MyReg<"y1">;
+def Y2 : MyReg<"y2">;
+def Y3 : MyReg<"y3">;
+
+def XLenVT : ValueTypeByHwMode<[XPtr32, XPtr64, YPtr32, YPtr64],
+ [i32, i64, i32, i64]>;
+def YLenVT : ValueTypeByHwMode<[XPtr32, XPtr64, YPtr32, YPtr64],
+ [c64, c128, c64, c128]>;
+def PtrVT : ValueTypeByHwMode<[XPtr32, XPtr64, YPtr32, YPtr64],
+ [XLenVT, XLenVT, YLenVT, YLenVT]>;
+defvar RegInfo32 = RegInfo<32,32,32>;
+defvar RegInfo64 = RegInfo<64,64,64>;
+def XLenRI : RegInfoByHwMode<[XPtr32, XPtr64, YPtr32, YPtr64],
+ [RegInfo32, RegInfo32, RegInfo64, RegInfo64]>;
+def XRegs : RegisterClass<"MyTarget", [XLenVT], 32, (add X0, X1, X2, X3)> {
+ let RegInfos = XLenRI; // Needed to determine size of registers
+}
+defvar RegInfo128 = RegInfo<128,128,128>;
+def YLenRI : RegInfoByHwMode<[XPtr32, XPtr64, YPtr32, YPtr64],
+ [RegInfo64, RegInfo64, RegInfo128, RegInfo128]>;
+
+def YRegs : RegisterClass<"MyTarget", [YLenVT], 64, (add Y0, Y1, Y2, Y3)> {
+ let RegInfos = YLenRI; // Needed to determine size of registers
+}
+def PtrRC : RegClassByHwMode<[XPtr32, XPtr64, YPtr32, YPtr64],
+ [XRegs, XRegs, YRegs, YRegs]>;
+
+def PtrRegOperand : RegisterOperand<PtrRC>;
+
+def NullReg : RegisterByHwMode<PtrRC, [XPtr32, XPtr64, YPtr32, YPtr64],
+ [X0, X0, Y0, Y0]>;
+
+class TestInstruction : Instruction {
+ let Size = 2;
+ let Namespace = "MyTarget";
+ let hasSideEffects = false;
+ let hasExtraSrcRegAllocReq = false;
+ let hasExtraDefRegAllocReq = false;
+
+ field bits<16> Inst;
+ bits<3> dst;
+ bits<3> src;
+ bits<3> opcode;
+
+ let Inst{2-0} = dst;
+ let Inst{5-3} = src;
+ let Inst{7-5} = opcode;
+}
+
+def TEST_XREG : TestInstruction {
+ let OutOperandList = (outs XRegs:$dst);
+ let InOperandList = (ins XRegs:$src);
+ let AsmString = "test_x $dst, $src";
+ let opcode = 0;
+}
+def TEST_YREG : TestInstruction {
+ let OutOperandList = (outs YRegs:$dst);
+ let InOperandList = (ins YRegs:$src);
+ let AsmString = "test_y $dst, $src";
+ let opcode = 1;
+}
+def TEST_PTRREG : TestInstruction {
+ let OutOperandList = (outs PtrRegOperand:$dst);
+ let InOperandList = (ins PtrRegOperand:$src);
+ let AsmString = "test_ptr $dst, $src";
+ let opcode = 2;
+}
\ No newline at end of file
diff --git a/llvm/test/TableGen/RegClassByHwModeAlias.td b/llvm/test/TableGen/RegClassByHwModeAlias.td
index 726bd3a0a5a49..09d57974a70b3 100644
--- a/llvm/test/TableGen/RegClassByHwModeAlias.td
+++ b/llvm/test/TableGen/RegClassByHwModeAlias.td
@@ -11,6 +11,7 @@ def EvenXRegs : RegisterClass<"MyTarget", [i64], 64, (add X0, X2, X4, X6)>;
def EvenYRegs : RegisterClass<"MyTarget", [i64], 64, (add Y0, Y2, Y4, Y6)>;
def PtrRC : RegClassByHwMode<[PtrX, PtrY], [XRegs, YRegs]>;
def EvenPtrRC : RegClassByHwMode<[PtrX, PtrY], [EvenXRegs, EvenYRegs]>;
+def NullReg : RegisterByHwMode<PtrRC, [PtrX, PtrY], [X0, Y0]>;
def TEST_XREG : TestInstruction {
let OutOperandList = (outs XRegs:$dst);
@@ -28,21 +29,49 @@ def TEST_PTR : TestInstruction {
def MY_T_X : InstAlias<"t_x $src", (TEST_XREG X0, XRegs:$src)>;
def MY_T_X_EVEN : InstAlias<"t_x.even $src", (TEST_XREG EvenXRegs:$dst, EvenXRegs:$src)>;
-// TODO: Can't use a fixed register for this instruction, would need RegisterByHwMode.
-// def MY_T_PTR : InstAlias<"t_ptr $src", (TEST_PTR X0, XRegs:$src)>;
+def MY_T_PTR : InstAlias<"t_ptr $src", (TEST_PTR NullReg, PtrRC:$src)>;
def MY_T_PTR_EVEN : InstAlias<"t_ptr.even $src", (TEST_PTR EvenPtrRC:$dst, EvenPtrRC:$src)>;
// CHECK-LABEL: static const AliasPatternCond Conds[] = {
-// CHECK-NEXT: // (TEST_PTR EvenPtrRC:$dst, EvenPtrRC:$src) - 0
+// CHECK-NEXT: // (TEST_PTR NullReg, PtrRC:$src) - 0
+// CHECK-NEXT: {AliasPatternCond::K_Custom, 1/*NullReg*/},
+// CHECK-NEXT: {AliasPatternCond::K_RegClassByHwMode, MyTarget::PtrRC},
+// CHECK-NEXT: // (TEST_PTR EvenPtrRC:$dst, EvenPtrRC:$src) - 2
// CHECK-NEXT: {AliasPatternCond::K_RegClassByHwMode, MyTarget::EvenPtrRC},
// CHECK-NEXT: {AliasPatternCond::K_RegClassByHwMode, MyTarget::EvenPtrRC},
-// CHECK-NEXT: // (TEST_XREG X0, XRegs:$src) - 2
+// CHECK-NEXT: // (TEST_XREG X0, XRegs:$src) - 4
// CHECK-NEXT: {AliasPatternCond::K_Reg, MyTarget::X0},
// CHECK-NEXT: {AliasPatternCond::K_RegClass, MyTarget::XRegsRegClassID},
-// CHECK-NEXT: // (TEST_XREG EvenXRegs:$dst, EvenXRegs:$src) - 4
+// CHECK-NEXT: // (TEST_XREG EvenXRegs:$dst, EvenXRegs:$src) - 6
// CHECK-NEXT: {AliasPatternCond::K_RegClass, MyTarget::EvenXRegsRegClassID},
// CHECK-NEXT: {AliasPatternCond::K_RegClass, MyTarget::EvenXRegsRegClassID},
// CHECK-NEXT: };
+// CHECK-LABEL: static bool MyTargetInstPrinterValidateMCOperand(const MCOperand &MCOp,
+// CHECK-NEXT: const MCSubtargetInfo &STI,
+// CHECK-NEXT: unsigned PredicateIndex) {
+// CHECK-NEXT: switch (PredicateIndex) {
+// CHECK-NEXT: default:
+// CHECK-NEXT: llvm_unreachable("Unknown MCOperandPredicate kind");
+// CHECK-NEXT: break;
+// CHECK-NEXT: case 1: {
+// CHECK-NEXT: auto getNullReg = [](unsigned HwMode) {
+// CHECK-NEXT: switch (HwMode) {
+// CHECK-NEXT: case 0: return MyTarget::X0; // DefaultMode
+// CHECK-NEXT: case 1: return MyTarget::Y0; // PtrY
+// CHECK-NEXT: default: llvm_unreachable("Unhandled HwMode for Register NullReg");
+// CHECK-NEXT: }
+// CHECK-NEXT: };
+// CHECK-NEXT: return MCOp.isReg() && MCOp.getReg() == getNullReg(STI.getHwMode(MCSubtargetInfo::HwMode_RegInfo));
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+
def MyTargetISA : InstrInfo;
-def MyTarget : Target { let InstructionSet = MyTargetISA; }
+def MyTargetAsmWriter : AsmWriter {
+ int PassSubtarget = 1;
+}
+def MyTarget : Target {
+ let InstructionSet = MyTargetISA;
+ let AssemblyWriters = [MyTargetAsmWriter];
+}
diff --git a/llvm/test/TableGen/RegClassByHwModeCompressPat.td b/llvm/test/TableGen/RegClassByHwModeCompressPat.td
index d642584e52b37..f2b12aac9e008 100644
--- a/llvm/test/TableGen/RegClassByHwModeCompressPat.td
+++ b/llvm/test/TableGen/RegClassByHwModeCompressPat.td
@@ -6,7 +6,7 @@ def IsPtr64 : Predicate<"Subtarget->isPtr64()">;
defvar Ptr32 = DefaultMode;
def Ptr64 : HwMode<[IsPtr64]>;
def PtrRC : RegClassByHwMode<[Ptr32, Ptr64], [XRegs, YRegs]>;
-
+def NullReg : RegisterByHwMode<PtrRC, [Ptr32, Ptr64], [X0, Y0]>;
def X_MOV : TestInstruction {
let OutOperandList = (outs XRegs:$dst);
@@ -74,9 +74,8 @@ def : CompressPat<(X_MOV XRegs:$dst, XRegs:$dst),
(X_MOV_TIED XRegs:$dst)>;
def : CompressPat<(X_MOV XRegs:$dst, XRegs:$src),
(X_MOV_SMALL XRegs:$dst, XRegs:$src)>;
-// TODO: Should also be able to use a fixed register with RegClassByHwMode
-// def : CompressPat<(PTR_MOV PtrRC:$dst, X0),
-// (PTR_MOV_ZERO PtrRC:$dst)>;
+def : CompressPat<(PTR_MOV PtrRC:$dst, NullReg),
+ (PTR_MOV_ZERO PtrRC:$dst)>;
def : CompressPat<(PTR_MOV PtrRC:$dst, PtrRC:$dst),
(PTR_MOV_TIED PtrRC:$dst)>;
def : CompressPat<(PTR_MOV PtrRC:$dst, PtrRC:$src),
@@ -89,6 +88,23 @@ def : CompressPat<(PTR_MOV PtrRC:$dst, PtrRC:$src),
// CHECK-NEXT: switch (MI.getOpcode()) {
// CHECK-NEXT: default: return false;
// CHECK-NEXT: case MyTarget::PTR_MOV: {
+// CHECK-NEXT: if (MI.getOperand(1).isReg() &&
+// CHECK-NEXT: (MI.getOperand(1).getReg() == [](unsigned HwMode) {
+// CHECK-NEXT: switch (HwMode)
+// CHECK-NEXT: case 0: return MyTarget::X0; // DefaultMode
+// CHECK-NEXT: case 1: return MyTarget::Y0; // Ptr64
+// CHECK-NEXT: default: llvm_unreachable("Unhandled HwMode for Register NullReg");
+// CHECK-NEXT: }
+// CHECK-NEXT: }(HwModeId)) &&
+// CHECK-NEXT: MI.getOperand(0).isReg() &&
+// CHECK-NEXT: MyTargetMCRegisterClasses[MyTargetRegClassByHwModeTables[HwModeId][MyTarget::PtrRC]].contains(MI.getOperand(0).getReg())) {
+// CHECK-NEXT: // ptr_mov.zero $dst
+// CHECK-NEXT: OutInst.setOpcode(MyTarget::PTR_MOV_ZERO);
+// CHECK-NEXT: // Operand: dst
+// CHECK-NEXT: OutInst.addOperand(MI.getOperand(0));
+// CHECK-NEXT: OutInst.setLoc(MI.getLoc());
+// CHECK-NEXT: return true;
+// CHECK-NEXT: } // if
// CHECK-NEXT: if (MI.getOperand(1).isReg() && MI.getOperand(0).isReg() &&
// CHECK-NEXT: (MI.getOperand(1).getReg() == MI.getOperand(0).getReg()) &&
// CHECK-NEXT: MI.getOperand(1).isReg() &&
@@ -199,6 +215,26 @@ def : CompressPat<(PTR_MOV PtrRC:$dst, PtrRC:$src),
// CHECK-NEXT: } // if
// CHECK-NEXT: break;
// CHECK-NEXT: } // case PTR_MOV_TIED
+// CHECK-NEXT: case MyTarget::PTR_MOV_ZERO: {
+// CHECK-NEXT: if (MI.getOperand(0).isReg() &&
+// CHECK-NEXT: MyTargetMCRegisterClasses[MyTargetRegClassByHwModeTables[HwModeId][MyTarget::PtrRC]].contains(MI.getOperand(0).getReg())) {
+// CHECK-NEXT: // ptr_mov $dst, $src
+// CHECK-NEXT: OutInst.setOpcode(MyTarget::PTR_MOV);
+// CHECK-NEXT: // Operand: dst
+// CHECK-NEXT: OutInst.addOperand(MI.getOperand(0));
+// CHECK-NEXT: // Operand: src
+// CHECK-NEXT: OutInst.addOperand(MCOperand::createReg([](unsigned HwMode) {
+// CHECK-NEXT: switch (HwMode) {
+// CHECK-NEXT: case 0: return MyTarget::X0; // DefaultMode
+// CHECK-NEXT: case 1: return MyTarget::Y0; // Ptr64
+// CHECK-NEXT: default: llvm_unreachable("Unhandled HwMode for Register NullReg");
+// CHECK-NEXT: }
+// CHECK-NEXT: }(HwModeId)));
+// CHECK-NEXT: OutInst.setLoc(MI.getLoc());
+// CHECK-NEXT: return true;
+// CHECK-NEXT: } // if
+// CHECK-NEXT: break;
+// CHECK-NEXT: } // case PTR_MOV_ZERO
// CHECK-NEXT: case MyTarget::X_MOV_SMALL: {
// CHECK-NEXT: if (MI.getOperand(0).isReg() &&
// CHECK-NEXT: MyTargetMCRegisterClasses[MyTarget::XRegsRegClassID].contains(MI.getOperand(0).getReg()) &&
@@ -273,6 +309,20 @@ def : CompressPat<(PTR_MOV PtrRC:$dst, PtrRC:$src),
// CHECK-NEXT: // Operand: src
// CHECK-NEXT: return true;
// CHECK-NEXT: } // if
+// CHECK-NEXT: if (MI.getOperand(1).isReg() &&
+// CHECK-NEXT: (MI.getOperand(1).getReg() == [](unsigned HwMode) {
+// CHECK-NEXT: switch (HwMode)
+// CHECK-NEXT: case 0: return MyTarget::X0; // DefaultMode
+// CHECK-NEXT: case 1: return MyTarget::Y0; // Ptr64
+// CHECK-NEXT: default: llvm_unreachable("Unhandled HwMode for Register NullReg");
+// CHECK-NEXT: }
+// CHECK-NEXT: }(HwModeId)) &&
+// CHECK-NEXT: MI.getOperand(0).isReg() && MI.getOperand(0).getReg().isPhysical() &&
+// CHECK-NEXT: MyTargetMCRegisterClasses[MyTargetRegClassByHwModeTables[HwModeId][MyTarget::PtrRC]].contains(MI.getOperand(0).getReg())) {
+// CHECK-NEXT: // ptr_mov.zero $dst
+// CHECK-NEXT: // Operand: dst
+// CHECK-NEXT: return true;
+// CHECK-NEXT: } // if
// CHECK-NEXT: break;
// CHECK-NEXT: } // case PTR_MOV
// CHECK-NEXT: case MyTarget::X_MOV: {
diff --git a/llvm/test/TableGen/RegClassByHwModeErrors.td b/llvm/test/TableGen/RegClassByHwModeErrors.td
index c7731312e28a6..833224074ac34 100644
--- a/llvm/test/TableGen/RegClassByHwModeErrors.td
+++ b/llvm/test/TableGen/RegClassByHwModeErrors.td
@@ -66,8 +66,7 @@ def PTR_ZERO_SMALL : TestInstruction {
/// This should fail since X0 is not necessarily part of PtrRC.
def : CompressPat<(PTR_MOV PtrRC:$dst, X0),
(PTR_ZERO_SMALL PtrRC:$dst)>;
-// CHECK: [[#@LINE-2]]:1: error: cannot resolve HwMode for PtrRC
-// CHECK: Common.td:7:5: note: PtrRC defined here
+// CHECK: [[#@LINE-2]]:1: error: Error in Dag '(PTR_MOV PtrRC:$dst, X0)': Register 'X0' is not in register class 'PtrRC'
def MyTargetISA : InstrInfo;
def MyTarget : Target { let InstructionSet = MyTargetISA; }
diff --git a/llvm/test/TableGen/RegisterByHwMode.td b/llvm/test/TableGen/RegisterByHwMode.td
new file mode 100644
index 0000000000000..5a128a3b6d849
--- /dev/null
+++ b/llvm/test/TableGen/RegisterByHwMode.td
@@ -0,0 +1,316 @@
+// RUN: llvm-tblgen --gen-asm-matcher -I %p/../../include -I %S %s -o - | FileCheck --check-prefix=ASMMATCHER %s
+// RUN: llvm-tblgen --gen-pseudo-lowering -I %p/../../include -I %S %s -o - | FileCheck --check-prefix=PSEUDO %s
+// RUN: llvm-tblgen --gen-subtarget -I %p/../../include -I %S %s -o - | FileCheck --check-prefix=SUBTARGET %s
+// RUN: llvm-tblgen --gen-instr-info -I %p/../../include -I %S %s -o - | FileCheck --check-prefix=INSTRINFO %s
+// RUN: llvm-tblgen --gen-asm-writer -I %p/../../include -I %S %s -o - | FileCheck --check-prefix=ASMWRITER %s
+/// Note: No impact on disassembler (handled by the alias expansion), so not tested here
+/// Note: DAGIsel is not supported yet
+// RUNTODO: llvm-tblgen --gen-dag-isel -I %p/../../include -I %S %s -o -
+// RUNTODO: llvm-tblgen --gen-global-isel -I %p/../../include -I %S %s -o -
+
+
+// SUBTARGET-LABEL: enum class MyTargetHwModeBits : unsigned {
+// SUBTARGET-NEXT: DefaultMode = 0,
+// SUBTARGET-NEXT: XPtr64 = (1 << 0),
+// SUBTARGET-NEXT: YPtr32 = (1 << 1),
+// SUBTARGET-NEXT: YPtr64 = (1 << 2),
+// SUBTARGET-EMPTY:
+// SUBTARGET-NEXT: LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/YPtr64),
+// SUBTARGET-NEXT: };
+// SUBTARGET-NEXT: unsigned getHwModeSet() const override;
+// SUBTARGET-NEXT: unsigned getHwMode(enum HwModeType type = HwMode_Default) const override;
+
+// SUBTARGET-LABEL: unsigned MyTargetGenSubtargetInfo::getHwModeSet() const {
+// SUBTARGET{LITERAL}:[[maybe_unused]] const auto *Subtarget =
+// SUBTARGET-NEXT: static_cast<const MyTargetSubtarget *>(this);
+// SUBTARGET-NEXT: // Collect HwModes and store them as a bit set.
+// SUBTARGET-NEXT: unsigned Modes = 0;
+// SUBTARGET-NEXT: if ((Subtarget->is64Bit()) && (!Subtarget->useYRegForPtr())) Modes |= (1 << 0);
+// SUBTARGET-NEXT: if ((!Subtarget->is64Bit()) && (Subtarget->useYRegForPtr())) Modes |= (1 << 1);
+// SUBTARGET-NEXT: if ((Subtarget->is64Bit()) && (Subtarget->useYRegForPtr())) Modes |= (1 << 2);
+// SUBTARGET-NEXT: return Modes;
+// SUBTARGET-NEXT:}
+
+// INSTRINFO-LABEL: extern const MyTargetInstrTable MyTargetDescs
+// INSTRINFO: { MyTarget::EvenPtrRC, 0|(1<<MCOI::LookupRegClassByHwMode), MCOI::OPERAND_REGISTER, 0 },
+// INSTRINFO-NEXT: { MyTarget::EvenXRegsRegClassID, 0, MCOI::OPERAND_REGISTER, 0 },
+// INSTRINFO-NEXT: { MyTarget::PtrRC, 0|(1<<MCOI::LookupRegClassByHwMode), MCOI::OPERAND_REGISTER, 0 }, { MyTarget::PtrRC, 0|(1<<MCOI::LookupRegClassByHwMode), MCOI::OPERAND_REGISTER, 0 },
+// INSTRINFO-NEXT: { MyTarget::XRegsRegClassID, 0, MCOI::OPERAND_REGISTER, 0 }, { MyTarget::XRegsRegClassID, 0, MCOI::OPERAND_REGISTER, 0 },
+// INSTRINFO-NEXT: { MyTarget::YRegsRegClassID, 0, MCOI::OPERAND_REGISTER, 0 }, { MyTarget::YRegsRegClassID, 0, MCOI::OPERAND_REGISTER, 0 },
+
+// INSTRINFO-LABEL: extern const int16_t MyTargetRegClassByHwModeTables[4][2] = {
+// INSTRINFO-NEXT: { // DefaultMode
+// INSTRINFO-NEXT: MyTarget::EvenXRegsRegClassID,
+// INSTRINFO-NEXT: MyTarget::XRegsRegClassID,
+// INSTRINFO-NEXT: },
+// INSTRINFO-NEXT: { // XPtr64
+// INSTRINFO-NEXT: MyTarget::EvenXRegsRegClassID,
+// INSTRINFO-NEXT: MyTarget::XRegsRegClassID,
+// INSTRINFO-NEXT: },
+// INSTRINFO-NEXT: { // YPtr32
+// INSTRINFO-NEXT: MyTarget::EvenYRegsRegClassID,
+// INSTRINFO-NEXT: MyTarget::YRegsRegClassID,
+// INSTRINFO-NEXT: },
+// INSTRINFO-NEXT: { // YPtr64
+// INSTRINFO-NEXT: MyTarget::EvenYRegsRegClassID,
+// INSTRINFO-NEXT: MyTarget::YRegsRegClassID,
+// INSTRINFO-NEXT: },
+// INSTRINFO-NEXT: };
+
+// ASMWRITER-LABEL: static const AliasPatternCond Conds[] = {
+// ASMWRITER-NEXT: // (TEST_PTRREG PtrRC:$dst, PtrRC:$src) - 0
+// ASMWRITER-NEXT: {AliasPatternCond::K_RegClassByHwMode, MyTarget::PtrRC},
+// ASMWRITER-NEXT: {AliasPatternCond::K_RegClassByHwMode, MyTarget::PtrRC},
+// ASMWRITER-NEXT: // (TEST_PTRREG EvenPtrRC:$dst, EvenPtrRC:$src) - 2
+// ASMWRITER-NEXT: {AliasPatternCond::K_RegClassByHwMode, MyTarget::EvenPtrRC},
+// ASMWRITER-NEXT: {AliasPatternCond::K_RegClassByHwMode, MyTarget::EvenPtrRC},
+// ASMWRITER-NEXT: // (TEST_PTRREG NullReg, PtrRC:$src) - 4
+// ASMWRITER-NEXT: {AliasPatternCond::K_Custom, 1/*NullReg*/},
+// ASMWRITER-NEXT: {AliasPatternCond::K_RegClassByHwMode, MyTarget::PtrRC},
+// ASMWRITER-NEXT: // (TEST_PTRREG NullReg, EvenPtrRC:$src) - 6
+// ASMWRITER-NEXT: {AliasPatternCond::K_Custom, 1/*NullReg*/},
+// ASMWRITER-NEXT: {AliasPatternCond::K_RegClassByHwMode, MyTarget::EvenPtrRC},
+// ASMWRITER-NEXT: // (TEST_XREG X0, XRegs:$src) - 8
+// ASMWRITER-NEXT: {AliasPatternCond::K_Reg, MyTarget::X0},
+// ASMWRITER-NEXT: {AliasPatternCond::K_RegClass, MyTarget::XRegsRegClassID},
+// ASMWRITER-NEXT: // (TEST_XREG X0, EvenXRegs:$src) - 10
+// ASMWRITER-NEXT: {AliasPatternCond::K_Reg, MyTarget::X0},
+// ASMWRITER-NEXT: {AliasPatternCond::K_RegClass, MyTarget::EvenXRegsRegClassID},
+// ASMWRITER-NEXT: // (TEST_XREG ModeCountReg, XRegs:$src) - 12
+// ASMWRITER-NEXT: {AliasPatternCond::K_Custom, 2/*ModeCountReg*/},
+// ASMWRITER-NEXT: {AliasPatternCond::K_RegClass, MyTarget::XRegsRegClassID},
+// ASMWRITER-NEXT: // (TEST_YREG Y0, YRegs:$src) - 14
+// ASMWRITER-NEXT: {AliasPatternCond::K_Reg, MyTarget::Y0},
+// ASMWRITER-NEXT: {AliasPatternCond::K_RegClass, MyTarget::YRegsRegClassID},
+// ASMWRITER-NEXT: // (TEST_YREG Y0, EvenYRegs:$src) - 16
+// ASMWRITER-NEXT: {AliasPatternCond::K_Reg, MyTarget::Y0},
+// ASMWRITER-NEXT: {AliasPatternCond::K_RegClass, MyTarget::EvenYRegsRegClassID},
+// ASMWRITER-NEXT: };
+
+// ASMWRITER-LABEL: static bool MyTargetInstPrinterValidateMCOperand(const MCOperand &MCOp,
+// ASMWRITER-NEXT: const MCSubtargetInfo &STI,
+// ASMWRITER-NEXT: unsigned PredicateIndex) {
+// ASMWRITER-NEXT: switch (PredicateIndex) {
+// ASMWRITER-NEXT: default:
+// ASMWRITER-NEXT: llvm_unreachable("Unknown MCOperandPredicate kind");
+// ASMWRITER-NEXT: break;
+// ASMWRITER-NEXT: case 1: {
...
[truncated]
|
| // CHECK-NEXT: default: return false; | ||
| // CHECK-NEXT: case MyTarget::PTR_MOV: { | ||
| // CHECK-NEXT: if (MI.getOperand(1).isReg() && | ||
| // CHECK-NEXT: (MI.getOperand(1).getReg() == [](unsigned HwMode) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this usually get inlined? Just curious if we end up with a bunch of these lambdas in the final binary if there are multiple instructions using the same RegClassByHwMode.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes we do end up with quite a few, In my current RVY branch there are 25 definitions. I was hoping to put it somewhere central, but not sure where the best place is to be sure that it's accessible from all callsites.
$ grep -rn "\[\](unsigned HwMode)" *
RISCVGenAsmMatcher.inc:2570: Inst.addOperand(MCOperand::createReg([](unsigned HwMode) {
RISCVGenAsmMatcher.inc:2581: Inst.addOperand(MCOperand::createReg([](unsigned HwMode) {
RISCVGenAsmWriter.inc:37169: auto getNullReg = [](unsigned HwMode) {
RISCVGenAsmWriter.inc:37221: auto getReturnReg = [](unsigned HwMode) {
RISCVGenCompressInstEmitter.inc:853: (MI.getOperand(0).getReg() == [](unsigned HwMode) {
RISCVGenCompressInstEmitter.inc:872: (MI.getOperand(0).getReg() == [](unsigned HwMode) {
RISCVGenCompressInstEmitter.inc:894: (MI.getOperand(0).getReg() == [](unsigned HwMode) {
RISCVGenCompressInstEmitter.inc:916: (MI.getOperand(0).getReg() == [](unsigned HwMode) {
RISCVGenCompressInstEmitter.inc:1730: OutInst.addOperand(MCOperand::createReg([](unsigned HwMode) {
RISCVGenCompressInstEmitter.inc:1764: OutInst.addOperand(MCOperand::createReg([](unsigned HwMode) {
RISCVGenCompressInstEmitter.inc:3640: OutInst.addOperand(MCOperand::createReg([](unsigned HwMode) {
RISCVGenCompressInstEmitter.inc:3664: OutInst.addOperand(MCOperand::createReg([](unsigned HwMode) {
RISCVGenCompressInstEmitter.inc:3688: OutInst.addOperand(MCOperand::createReg([](unsigned HwMode) {
RISCVGenCompressInstEmitter.inc:3714: OutInst.addOperand(MCOperand::createReg([](unsigned HwMode) {
RISCVGenCompressInstEmitter.inc:5490: (MI.getOperand(0).getReg() == [](unsigned HwMode) {
RISCVGenCompressInstEmitter.inc:5508: (MI.getOperand(0).getReg() == [](unsigned HwMode) {
RISCVGenCompressInstEmitter.inc:5528: (MI.getOperand(0).getReg() == [](unsigned HwMode) {
RISCVGenCompressInstEmitter.inc:5547: (MI.getOperand(0).getReg() == [](unsigned HwMode) {
RISCVGenMCPseudoLowering.inc:52: Inst.addOperand(MCOperand::createReg([](unsigned HwMode) {
RISCVGenMCPseudoLowering.inc:86: Inst.addOperand(MCOperand::createReg([](unsigned HwMode) {
RISCVGenMCPseudoLowering.inc:170: Inst.addOperand(MCOperand::createReg([](unsigned HwMode) {
RISCVGenMCPseudoLowering.inc:180: Inst.addOperand(MCOperand::createReg([](unsigned HwMode) {
RISCVGenMCPseudoLowering.inc:285: Inst.addOperand(MCOperand::createReg([](unsigned HwMode) {
RISCVGenMCPseudoLowering.inc:305: Inst.addOperand(MCOperand::createReg([](unsigned HwMode) {
RISCVGenMCPseudoLowering.inc:325: Inst.addOperand(MCOperand::createReg([](unsigned HwMode) {
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Emitting one function now, so now we get something like llvm::TARGET::RegisterByHwMode::getFooReg.
| // CHECK-NEXT: case MyTarget::PTR_MOV: { | ||
| // CHECK-NEXT: if (MI.getOperand(1).isReg() && | ||
| // CHECK-NEXT: (MI.getOperand(1).getReg() == [](unsigned HwMode) { | ||
| // CHECK-NEXT: switch (HwMode) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if the class isn't specified for one of the modes? Should case 0: be default:?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good point, let me add another test cases where we have a RegisterByHwMode that is not specified for all HwModes. Since we only have two here it's fully covered.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a test case where not all hwmodes are covered.
arsenm
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm interested in this for AMDGPU to fix problems with wavesize management
| /// where the operand type is a RegClassByHwMode. | ||
| class RegisterByHwMode<RegisterClassLike RegClass, list<HwMode> Modes, | ||
| list<Register> Registers> | ||
| : HwModeSelect<Modes, !size(Registers)>, RegisterOperand<RegClass> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does it need RegisterClassLike?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So that the type of the register can be a RegClassByHwMode instead of just a fixed RegisterClass. I need this in the RVY changes since I need to use a PtrRC that is either the normal GPR register class (RVI mode) or the extended YGPR class (RVY mode).
| // CHECK-NEXT: default: llvm_unreachable("Unhandled HwMode for Register NullReg"); | ||
| // CHECK-NEXT: } | ||
| // CHECK-NEXT: }; | ||
| // CHECK-NEXT: return MCOp.isReg() && MCOp.getReg() == getNullReg(STI.getHwMode(MCSubtargetInfo::HwMode_RegInfo)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that getHwMode is a virtual function. It may make sense to cache its result somewhere in the base class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Absolutely agreed, although so far these calls are probably not in a particularly hot path. We can always do something like #174471 once needed.
Can you describe what the issue is? |
We have VCC = [VCC_LO, VCC_HI] and the instructions unconditionally use VCC. Depending on the HwMode, VCC should be swapped to the subregister VCC_LO in the instruction definitions |
This is useful for `InstAlias` where a fixed register may depend on the
HwMode. The motivating use case for this is the RISC-V RVY ISA where
certain instructions mnemonics are remapped to take a different
register class depending on the HwMode and can be used as follows:
```
def NullReg : RegisterByHwMode<PtrRC, [RV32I, RV64I, RV64Y, RV64Y],
[X0, X0, X0_Y, X0_Y]>;
```
Pull Request: llvm#175227
Created using spr 1.3.8-beta.1
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
Created using spr 1.3.8-beta.1
🐧 Linux x64 Test Results
✅ The build succeeded and all tests passed. |
🪟 Windows x64 Test Results
✅ The build succeeded and all tests passed. |
|
lgtm but the tests are still failing |
Created using spr 1.3.8-beta.1
Sorry pushed too early. Fixed now. |
This is useful for
InstAliaswhere a fixed register may depend on theHwMode. The motivating use case for this is the RISC-V RVY ISA where
certain instructions mnemonics are remapped to take a different
register class depending on the HwMode and can be used as follows: