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
142 lines
6.3 KiB
TableGen
142 lines
6.3 KiB
TableGen
// RUN: rm -rf %t && split-file %s %t
|
|
// RUN: not llvm-tblgen --gen-asm-matcher -I %p/../../include -I %t -I %S \
|
|
// RUN: %t/inst-alias-bad-reg.td -o /dev/null 2>&1 | FileCheck %t/inst-alias-bad-reg.td --implicit-check-not="error:"
|
|
// RUN: not llvm-tblgen --gen-asm-matcher -I %p/../../include -I %t -I %S \
|
|
// RUN: %t/inst-alias-static-predicates.td -o /dev/null 2>&1 | FileCheck %t/inst-alias-static-predicates.td --implicit-check-not="error:"
|
|
// RUN: not llvm-tblgen --gen-compress-inst-emitter -I %p/../../include -I %t -I %S \
|
|
// RUN: %t/compress-regclass-by-hwmode.td -o /dev/null 2>&1 | FileCheck %t/compress-regclass-by-hwmode.td --implicit-check-not="error:"
|
|
// RUN: not llvm-tblgen --gen-compress-inst-emitter -I %p/../../include -I %t -I %S \
|
|
// RUN: %t/compress-regclass-by-hwmode-2.td -o /dev/null 2>&1 | FileCheck %t/compress-regclass-by-hwmode-2.td --implicit-check-not="error:"
|
|
// RUN: not llvm-tblgen --gen-dag-isel -I %p/../../include -I %t -I %S \
|
|
// RUN: %t/vt-by-hwmode-missing.td -o /dev/null 2>&1 | FileCheck %t/vt-by-hwmode-missing.td --implicit-check-not="error:"
|
|
// RUN: not llvm-tblgen --gen-dag-isel -I %p/../../include -I %t -I %S \
|
|
// RUN: %t/multiple-entries-for-same-mode.td -o /dev/null 2>&1 | FileCheck %t/multiple-entries-for-same-mode.td --implicit-check-not="error:"
|
|
|
|
//--- Common.td
|
|
include "Common/RegClassByHwModeCommon.td"
|
|
|
|
def IsPtr64 : Predicate<"Subtarget->isPtr64()">;
|
|
def IsPtr32 : Predicate<"!Subtarget->isPtr64()">;
|
|
defvar Ptr32 = DefaultMode;
|
|
def Ptr64 : HwMode<[IsPtr64]>;
|
|
def PtrRC : RegClassByHwMode<[Ptr32, Ptr64], [XRegs, YRegs]>;
|
|
|
|
def PTR_MOV : TestInstruction {
|
|
let OutOperandList = (outs PtrRC:$dst);
|
|
let InOperandList = (ins PtrRC:$src);
|
|
let AsmString = "ptr_mov $dst, $src";
|
|
let opcode = 0;
|
|
}
|
|
|
|
|
|
//--- inst-alias-bad-reg.td
|
|
include "Common.td"
|
|
/// This should fail since X0 is not necessarily part of PtrRC.
|
|
def BAD_REG : InstAlias<"ptr_zero $rd", (PTR_MOV PtrRC:$dst, X0)>;
|
|
// CHECK: [[#@LINE-1]]:5: error: cannot resolve HwMode for PtrRC
|
|
// CHECK: Common.td:7:5: note: PtrRC defined here
|
|
def MyTargetISA : InstrInfo;
|
|
def MyTarget : Target { let InstructionSet = MyTargetISA; }
|
|
|
|
|
|
//--- inst-alias-static-predicates.td
|
|
include "Common.td"
|
|
/// In theory we could allow the following code since the predicates statically
|
|
/// resolve to the correct register class, but since this is non-trivial, check
|
|
// that we get a sensible-ish error instead.
|
|
let Predicates = [IsPtr32] in
|
|
def MOV_X0 : InstAlias<"mov_x0 $dst", (PTR_MOV PtrRC:$dst, X0)>;
|
|
// CHECK: [[#@LINE-1]]:5: error: cannot resolve HwMode for PtrRC
|
|
// CHECK: Common.td:7:5: note: PtrRC defined here
|
|
let Predicates = [IsPtr64] in
|
|
def MOV_Y0 : InstAlias<"mov_y0 $dst", (PTR_MOV PtrRC:$dst, Y0)>;
|
|
|
|
def MyTargetISA : InstrInfo;
|
|
def MyTarget : Target { let InstructionSet = MyTargetISA; }
|
|
|
|
//--- compress-regclass-by-hwmode.td
|
|
include "Common.td"
|
|
def PTR_ZERO_SMALL : TestInstruction {
|
|
let OutOperandList = (outs PtrRC:$dst);
|
|
let InOperandList = (ins);
|
|
let AsmString = "ptr_zero $dst";
|
|
let opcode = 1;
|
|
let Size = 1;
|
|
}
|
|
/// 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: 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; }
|
|
|
|
|
|
//--- compress-regclass-by-hwmode-2.td
|
|
include "Common.td"
|
|
def X_MOV_BIG : TestInstruction {
|
|
let OutOperandList = (outs XRegs:$dst);
|
|
let InOperandList = (ins XRegs:$src);
|
|
let AsmString = "x_mov $dst, $src";
|
|
let opcode = 1;
|
|
let Size = 4;
|
|
}
|
|
/// This should fail since PtrRC is not necessarily part of XRegs.
|
|
/// In theory, this could be resolved depending on the Predicates but
|
|
/// for not we should just always emit an error.
|
|
let Predicates = [IsPtr32] in
|
|
def : CompressPat<(X_MOV_BIG XRegs:$dst, XRegs:$src),
|
|
(PTR_MOV PtrRC:$dst, PtrRC:$src)>;
|
|
// CHECK: [[#@LINE-2]]:1: error: Type mismatch between Input and Output Dag operand 'dst'
|
|
def MyTargetISA : InstrInfo;
|
|
def MyTarget : Target { let InstructionSet = MyTargetISA; }
|
|
|
|
|
|
//--- vt-by-hwmode-missing.td
|
|
include "Common.td"
|
|
/// This should fail since we are missing a DefaultMode entry for the
|
|
/// ValueTypeByHwMode and can't resolve it for the Ptr32 (default) case.
|
|
def BadVT : ValueTypeByHwMode<[Ptr64], [i64]>;
|
|
def BadVTRegClass : RegisterClass<"MyTarget", [i64, BadVT], 64, (add Y0, Y1)>;
|
|
/// NOTE: this error only occurs for RegClassByHwMode, normal RegisterClass
|
|
/// logic for VT resolution takes a different code path and does not error.
|
|
def TEST_OK : TestInstruction {
|
|
let OutOperandList = (outs BadVTRegClass:$dst);
|
|
let InOperandList = (ins BadVTRegClass:$src1, BadVTRegClass:$src2);
|
|
let AsmString = "test $dst, $src1, $src2";
|
|
let Pattern = [(set BadVTRegClass:$dst, (add BadVTRegClass:$src1, BadVTRegClass:$src2))];
|
|
}
|
|
/// Once we use RegClassByHwMode, we get an error about missing modes:
|
|
def BadPtrRC : RegClassByHwMode<[Ptr32, Ptr64], [BadVTRegClass, YRegs]>;
|
|
// CHECK: vt-by-hwmode-missing.td:[[#@LINE-1]]:5: error: Could not resolve VT for Mode DefaultMode
|
|
// CHECK: vt-by-hwmode-missing.td:4:5: note: ValueTypeByHwMode BadVT defined here
|
|
// CHECK: vt-by-hwmode-missing.td:[[#@LINE+1]]:5: note: pattern instantiated here
|
|
def TEST : TestInstruction {
|
|
let OutOperandList = (outs BadPtrRC:$dst);
|
|
let InOperandList = (ins BadPtrRC:$src1, BadPtrRC:$src2);
|
|
let AsmString = "test $dst, $src1, $src2";
|
|
let opcode = 0;
|
|
let Pattern = [(set BadPtrRC:$dst, (add BadPtrRC:$src1, BadPtrRC:$src2))];
|
|
}
|
|
|
|
def MyTargetISA : InstrInfo;
|
|
def MyTarget : Target { let InstructionSet = MyTargetISA; }
|
|
|
|
|
|
//--- multiple-entries-for-same-mode.td
|
|
include "Common.td"
|
|
/// We should get an error if the same mode is listed more than once
|
|
defvar Ptr64Alias = Ptr64;
|
|
def BadRegClass : RegClassByHwMode<[Ptr32, Ptr64, Ptr64Alias], [XRegs, YRegs, YRegs]>;
|
|
// CHECK: [[#@LINE-1]]:5: error: duplicate RegisterClass entry for HwMode Ptr64: YRegs
|
|
// Need at least one CompressPat use of the bad reg class to trigger the error:
|
|
def USE_BAD_REG_CLASS : TestInstruction {
|
|
let OutOperandList = (outs BadRegClass:$dst);
|
|
let InOperandList = (ins BadRegClass:$src1, BadRegClass:$src2);
|
|
let AsmString = "bad $dst";
|
|
let Pattern = [(set BadRegClass:$dst, (add BadRegClass:$src1, BadRegClass:$src2))];
|
|
}
|
|
def MyTargetISA : InstrInfo;
|
|
def MyTarget : Target {
|
|
let InstructionSet = MyTargetISA;
|
|
}
|