llvm-project/llvm/test/TableGen/RegClassByHwModeCompressPat.td
Alexander Richardson 3459bb4f27
[TableGen] Introduce RegisterByHwMode
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: https://github.com/llvm/llvm-project/pull/175227
2026-02-18 17:23:10 -08:00

351 lines
17 KiB
TableGen

// RUN: llvm-tblgen --gen-compress-inst-emitter -I %p/../../include -I %S %s -o - | FileCheck %s
include "Common/RegClassByHwModeCommon.td"
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);
let InOperandList = (ins XRegs:$src);
let AsmString = "x_mov $dst, $src";
let opcode = 0;
}
def X_MOV_SMALL : TestInstruction {
let OutOperandList = (outs XRegs:$dst);
let InOperandList = (ins XRegs:$src);
let AsmString = "x_mov.small $dst, $src";
let opcode = 1;
let Size = 1;
}
def X_MOV_ZERO : TestInstruction {
let OutOperandList = (outs XRegs:$dst);
let InOperandList = (ins);
let AsmString = "x_mov.zero $dst";
let opcode = 2;
let Size = 1;
}
def X_MOV_TIED : TestInstruction {
let OutOperandList = (outs XRegs:$dst);
let InOperandList = (ins XRegs:$src);
let Constraints = "$src = $dst";
let AsmString = "x_mov.tied $dst, $src";
let opcode = 3;
let Size = 1;
}
def PTR_MOV : TestInstruction {
let OutOperandList = (outs PtrRC:$dst);
let InOperandList = (ins PtrRC:$src);
let AsmString = "ptr_mov $dst, $src";
let opcode = 3;
}
def PTR_MOV_SMALL : TestInstruction {
let OutOperandList = (outs PtrRC:$dst);
let InOperandList = (ins PtrRC:$src);
let AsmString = "ptr_mov.small $dst, $src";
let opcode = 4;
let Size = 1;
}
def PTR_MOV_ZERO : TestInstruction {
let OutOperandList = (outs PtrRC:$dst);
let InOperandList = (ins);
let AsmString = "ptr_mov.zero $dst";
let opcode = 3;
let Size = 1;
}
def PTR_MOV_TIED : TestInstruction {
let OutOperandList = (outs PtrRC:$dst);
let InOperandList = (ins PtrRC:$src);
let Constraints = "$src = $dst";
let AsmString = "ptr_mov.tied $dst, $src";
let opcode = 3;
let Size = 1;
}
def : CompressPat<(X_MOV XRegs:$dst, X0),
(X_MOV_ZERO XRegs:$dst)>;
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)>;
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),
(PTR_MOV_SMALL PtrRC:$dst, PtrRC:$src)>;
// CHECK: static bool compressInst(MCInst &OutInst,
// CHECK-NEXT: const MCInst &MI,
// CHECK-NEXT: const MCSubtargetInfo &STI) {
// CHECK-NEXT: {{\[\[}}maybe_unused]] unsigned HwModeId = STI.getHwMode(MCSubtargetInfo::HwMode_RegInfo);
// 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() == MyTarget::RegisterByHwMode::getNullReg(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() &&
// CHECK-NEXT: MyTargetMCRegisterClasses[MyTargetRegClassByHwModeTables[HwModeId][MyTarget::PtrRC]].contains(MI.getOperand(1).getReg())) {
// CHECK-NEXT: // ptr_mov.tied $dst, $src
// CHECK-NEXT: OutInst.setOpcode(MyTarget::PTR_MOV_TIED);
// CHECK-NEXT: // Operand: dst
// CHECK-NEXT: OutInst.addOperand(MI.getOperand(1));
// CHECK-NEXT: // Operand: src
// CHECK-NEXT: OutInst.addOperand(MI.getOperand(1));
// CHECK-NEXT: OutInst.setLoc(MI.getLoc());
// CHECK-NEXT: return true;
// CHECK-NEXT: } // if
// CHECK-NEXT: if (MI.getOperand(0).isReg() &&
// CHECK-NEXT: MyTargetMCRegisterClasses[MyTargetRegClassByHwModeTables[HwModeId][MyTarget::PtrRC]].contains(MI.getOperand(0).getReg()) &&
// CHECK-NEXT: MI.getOperand(1).isReg() &&
// CHECK-NEXT: MyTargetMCRegisterClasses[MyTargetRegClassByHwModeTables[HwModeId][MyTarget::PtrRC]].contains(MI.getOperand(1).getReg())) {
// CHECK-NEXT: // ptr_mov.small $dst, $src
// CHECK-NEXT: OutInst.setOpcode(MyTarget::PTR_MOV_SMALL);
// CHECK-NEXT: // Operand: dst
// CHECK-NEXT: OutInst.addOperand(MI.getOperand(0));
// CHECK-NEXT: // Operand: src
// CHECK-NEXT: OutInst.addOperand(MI.getOperand(1));
// CHECK-NEXT: OutInst.setLoc(MI.getLoc());
// CHECK-NEXT: return true;
// CHECK-NEXT: } // if
// CHECK-NEXT: break;
// CHECK-NEXT: } // case PTR_MOV
// CHECK-NEXT: case MyTarget::X_MOV: {
// CHECK-NEXT: if (MI.getOperand(1).isReg() &&
// CHECK-NEXT: (MI.getOperand(1).getReg() == MyTarget::X0) &&
// CHECK-NEXT: MI.getOperand(0).isReg() &&
// CHECK-NEXT: MyTargetMCRegisterClasses[MyTarget::XRegsRegClassID].contains(MI.getOperand(0).getReg())) {
// CHECK-NEXT: // x_mov.zero $dst
// CHECK-NEXT: OutInst.setOpcode(MyTarget::X_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() &&
// CHECK-NEXT: MyTargetMCRegisterClasses[MyTarget::XRegsRegClassID].contains(MI.getOperand(1).getReg())) {
// CHECK-NEXT: // x_mov.tied $dst, $src
// CHECK-NEXT: OutInst.setOpcode(MyTarget::X_MOV_TIED);
// CHECK-NEXT: // Operand: dst
// CHECK-NEXT: OutInst.addOperand(MI.getOperand(1));
// CHECK-NEXT: // Operand: src
// CHECK-NEXT: OutInst.addOperand(MI.getOperand(1));
// CHECK-NEXT: OutInst.setLoc(MI.getLoc());
// CHECK-NEXT: return true;
// CHECK-NEXT: } // if
// CHECK-NEXT: if (MI.getOperand(0).isReg() &&
// CHECK-NEXT: MyTargetMCRegisterClasses[MyTarget::XRegsRegClassID].contains(MI.getOperand(0).getReg()) &&
// CHECK-NEXT: MI.getOperand(1).isReg() &&
// CHECK-NEXT: MyTargetMCRegisterClasses[MyTarget::XRegsRegClassID].contains(MI.getOperand(1).getReg())) {
// CHECK-NEXT: // x_mov.small $dst, $src
// CHECK-NEXT: OutInst.setOpcode(MyTarget::X_MOV_SMALL);
// CHECK-NEXT: // Operand: dst
// CHECK-NEXT: OutInst.addOperand(MI.getOperand(0));
// CHECK-NEXT: // Operand: src
// CHECK-NEXT: OutInst.addOperand(MI.getOperand(1));
// CHECK-NEXT: OutInst.setLoc(MI.getLoc());
// CHECK-NEXT: return true;
// CHECK-NEXT: } // if
// CHECK-NEXT: break;
// CHECK-NEXT: } // case X_MOV
// CHECK-NEXT: } // switch
// CHECK-NEXT: return false;
// CHECK-NEXT: }
// CHECK: static bool uncompressInst(MCInst &OutInst,
// CHECK-NEXT: const MCInst &MI,
// CHECK-NEXT: const MCSubtargetInfo &STI) {
// CHECK-NEXT: {{\[\[}}maybe_unused]] unsigned HwModeId = STI.getHwMode(MCSubtargetInfo::HwMode_RegInfo);
// CHECK-NEXT: switch (MI.getOpcode()) {
// CHECK-NEXT: default: return false;
// CHECK-NEXT: case MyTarget::PTR_MOV_SMALL: {
// CHECK-NEXT: if (MI.getOperand(0).isReg() &&
// CHECK-NEXT: MyTargetMCRegisterClasses[MyTargetRegClassByHwModeTables[HwModeId][MyTarget::PtrRC]].contains(MI.getOperand(0).getReg()) &&
// CHECK-NEXT: MI.getOperand(1).isReg() &&
// CHECK-NEXT: MyTargetMCRegisterClasses[MyTargetRegClassByHwModeTables[HwModeId][MyTarget::PtrRC]].contains(MI.getOperand(1).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(MI.getOperand(1));
// CHECK-NEXT: OutInst.setLoc(MI.getLoc());
// CHECK-NEXT: return true;
// CHECK-NEXT: } // if
// CHECK-NEXT: break;
// CHECK-NEXT: } // case PTR_MOV_SMALL
// CHECK-NEXT: case MyTarget::PTR_MOV_TIED: {
// CHECK-NEXT: if (MI.getOperand(0).isReg() &&
// CHECK-NEXT: MyTargetMCRegisterClasses[MyTargetRegClassByHwModeTables[HwModeId][MyTarget::PtrRC]].contains(MI.getOperand(0).getReg()) &&
// CHECK-NEXT: 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(MI.getOperand(0));
// CHECK-NEXT: OutInst.setLoc(MI.getLoc());
// CHECK-NEXT: return true;
// 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(MyTarget::RegisterByHwMode::getNullReg(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()) &&
// CHECK-NEXT: MI.getOperand(1).isReg() &&
// CHECK-NEXT: MyTargetMCRegisterClasses[MyTarget::XRegsRegClassID].contains(MI.getOperand(1).getReg())) {
// CHECK-NEXT: // x_mov $dst, $src
// CHECK-NEXT: OutInst.setOpcode(MyTarget::X_MOV);
// CHECK-NEXT: // Operand: dst
// CHECK-NEXT: OutInst.addOperand(MI.getOperand(0));
// CHECK-NEXT: // Operand: src
// CHECK-NEXT: OutInst.addOperand(MI.getOperand(1));
// CHECK-NEXT: OutInst.setLoc(MI.getLoc());
// CHECK-NEXT: return true;
// CHECK-NEXT: } // if
// CHECK-NEXT: break;
// CHECK-NEXT: } // case X_MOV_SMALL
// CHECK-NEXT: case MyTarget::X_MOV_TIED: {
// CHECK-NEXT: if (MI.getOperand(0).isReg() &&
// CHECK-NEXT: MyTargetMCRegisterClasses[MyTarget::XRegsRegClassID].contains(MI.getOperand(0).getReg()) &&
// CHECK-NEXT: MI.getOperand(0).isReg() &&
// CHECK-NEXT: MyTargetMCRegisterClasses[MyTarget::XRegsRegClassID].contains(MI.getOperand(0).getReg())) {
// CHECK-NEXT: // x_mov $dst, $src
// CHECK-NEXT: OutInst.setOpcode(MyTarget::X_MOV);
// CHECK-NEXT: // Operand: dst
// CHECK-NEXT: OutInst.addOperand(MI.getOperand(0));
// CHECK-NEXT: // Operand: src
// CHECK-NEXT: OutInst.addOperand(MI.getOperand(0));
// CHECK-NEXT: OutInst.setLoc(MI.getLoc());
// CHECK-NEXT: return true;
// CHECK-NEXT: } // if
// CHECK-NEXT: break;
// CHECK-NEXT: } // case X_MOV_TIED
// CHECK-NEXT: case MyTarget::X_MOV_ZERO: {
// CHECK-NEXT: if (MI.getOperand(0).isReg() &&
// CHECK-NEXT: MyTargetMCRegisterClasses[MyTarget::XRegsRegClassID].contains(MI.getOperand(0).getReg())) {
// CHECK-NEXT: // x_mov $dst, $src
// CHECK-NEXT: OutInst.setOpcode(MyTarget::X_MOV);
// CHECK-NEXT: // Operand: dst
// CHECK-NEXT: OutInst.addOperand(MI.getOperand(0));
// CHECK-NEXT: // Operand: src
// CHECK-NEXT: OutInst.addOperand(MCOperand::createReg(MyTarget::X0));
// CHECK-NEXT: OutInst.setLoc(MI.getLoc());
// CHECK-NEXT: return true;
// CHECK-NEXT: } // if
// CHECK-NEXT: break;
// CHECK-NEXT: } // case X_MOV_ZERO
// CHECK-NEXT: } // switch
// CHECK-NEXT: return false;
// CHECK-NEXT: }
// CHECK: static bool isCompressibleInst(const MachineInstr &MI,
// CHECK-NEXT: const MyTargetSubtarget &STI) {
// CHECK-NEXT: {{\[\[}}maybe_unused]] unsigned HwModeId = STI.getHwMode(MCSubtargetInfo::HwMode_RegInfo);
// CHECK-NEXT: switch (MI.getOpcode()) {
// CHECK-NEXT: default: return false;
// CHECK-NEXT: case MyTarget::PTR_MOV: {
// CHECK-NEXT: if (MI.getOperand(0).isReg() && MI.getOperand(0).getReg().isPhysical() &&
// CHECK-NEXT: MyTargetMCRegisterClasses[MyTargetRegClassByHwModeTables[HwModeId][MyTarget::PtrRC]].contains(MI.getOperand(0).getReg()) &&
// CHECK-NEXT: MI.getOperand(1).isReg() && MI.getOperand(1).getReg().isPhysical() &&
// CHECK-NEXT: MyTargetMCRegisterClasses[MyTargetRegClassByHwModeTables[HwModeId][MyTarget::PtrRC]].contains(MI.getOperand(1).getReg())) {
// CHECK-NEXT: // ptr_mov.small $dst, $src
// CHECK-NEXT: // Operand: dst
// CHECK-NEXT: // Operand: src
// 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() && MI.getOperand(1).getReg().isPhysical() &&
// CHECK-NEXT: MyTargetMCRegisterClasses[MyTargetRegClassByHwModeTables[HwModeId][MyTarget::PtrRC]].contains(MI.getOperand(1).getReg())) {
// CHECK-NEXT: // ptr_mov.tied $dst, $src
// CHECK-NEXT: // Operand: dst
// CHECK-NEXT: // Operand: src
// CHECK-NEXT: return true;
// CHECK-NEXT: } // if
// CHECK-NEXT: if (MI.getOperand(1).isReg() &&
// CHECK-NEXT: (MI.getOperand(1).getReg() == MyTarget::RegisterByHwMode::getNullReg(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: {
// CHECK-NEXT: if (MI.getOperand(0).isReg() && MI.getOperand(0).getReg().isPhysical() &&
// CHECK-NEXT: MyTargetMCRegisterClasses[MyTarget::XRegsRegClassID].contains(MI.getOperand(0).getReg()) &&
// CHECK-NEXT: MI.getOperand(1).isReg() && MI.getOperand(1).getReg().isPhysical() &&
// CHECK-NEXT: MyTargetMCRegisterClasses[MyTarget::XRegsRegClassID].contains(MI.getOperand(1).getReg())) {
// CHECK-NEXT: // x_mov.small $dst, $src
// CHECK-NEXT: // Operand: dst
// CHECK-NEXT: // Operand: src
// 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() && MI.getOperand(1).getReg().isPhysical() &&
// CHECK-NEXT: MyTargetMCRegisterClasses[MyTarget::XRegsRegClassID].contains(MI.getOperand(1).getReg())) {
// CHECK-NEXT: // x_mov.tied $dst, $src
// CHECK-NEXT: // Operand: dst
// CHECK-NEXT: // Operand: src
// CHECK-NEXT: return true;
// CHECK-NEXT: } // if
// CHECK-NEXT: if (MI.getOperand(1).isReg() &&
// CHECK-NEXT: (MI.getOperand(1).getReg() == MyTarget::X0) &&
// CHECK-NEXT: MI.getOperand(0).isReg() && MI.getOperand(0).getReg().isPhysical() &&
// CHECK-NEXT: MyTargetMCRegisterClasses[MyTarget::XRegsRegClassID].contains(MI.getOperand(0).getReg())) {
// CHECK-NEXT: // x_mov.zero $dst
// CHECK-NEXT: // Operand: dst
// CHECK-NEXT: return true;
// CHECK-NEXT: } // if
// CHECK-NEXT: break;
// CHECK-NEXT: } // case X_MOV
// CHECK-NEXT: } // switch
// CHECK-NEXT: return false;
// CHECK-NEXT: }
def MyTargetISA : InstrInfo;
def MyTargetAsmWriter : AsmWriter {
int PassSubtarget = 1;
}
def MyTarget : Target {
let InstructionSet = MyTargetISA;
let AssemblyWriters = [MyTargetAsmWriter];
}