Craig Topper b103311c1d
[TableGen] Check destination instruction predicates in CompressInstEmitter. (#151061)
In addition to checking the predicate from the CompressPat, also check
the destination instruction. This prevents creating bad instructions if
CompressPat isn't a proper subset of the destination instruction. This
prevents mistakes that we can't catch at compile time.

We are able to verify RegisterClass hierarchy at compile time so don't
have to check the destination register class.

I've added comments for the operand names to make auditing easier.
2025-07-28 21:36:19 -07:00

263 lines
10 KiB
TableGen

// RUN: llvm-tblgen -gen-compress-inst-emitter -I %p/../../../include %s 2>&1 | FileCheck %s
include "llvm/Target/Target.td"
def ArchInstrInfo : InstrInfo { }
def ArchAsmWriter : AsmWriter {
int PassSubtarget = 1;
}
def Arch : Target {
let InstructionSet = ArchInstrInfo;
let AssemblyWriters = [ArchAsmWriter];
}
def Reg0 : Register<"reg0"> {
let HWEncoding{4-0} = 0;
}
def Reg1 : Register<"reg1"> {
let HWEncoding{4-0} = 1;
}
def Regs : RegisterClass<"Arch", [i32], 32, (add Reg0, Reg1)>;
def RegsC : RegisterClass<"Arch", [i32], 32, (sub Regs, Reg0)>;
def simm6 : Operand<i32>, ImmLeaf<i32, [{return isInt<6>(Imm);}]> {
let MCOperandPredicate = [{
int64_t Imm;
if (!MCOp.evaluateAsConstantImm(Imm))
return false;
return isInt<6>(Imm);
}];
}
def simm12 : Operand<i32>, ImmLeaf<i32, [{return isInt<12>(Imm);}]> {
let MCOperandPredicate = [{
int64_t Imm;
if (!MCOp.evaluateAsConstantImm(Imm))
return false;
return isInt<12>(Imm);
}];
}
def MemOpnd : Operand<iPTR> {
let MIOperandInfo = (ops Regs, simm12);
}
def MemOpndC : Operand<iPTR> {
let MIOperandInfo = (ops RegsC, simm6);
}
def BigInst : Instruction {
let Namespace = "MyNS";
let OutOperandList = (outs Regs:$dst);
let InOperandList = (ins MemOpnd:$addr);
let Size = 4;
let AsmString = "big $dst, $addr";
}
def SmallInst : Instruction {
let Namespace = "MyNS";
let OutOperandList = (outs RegsC:$dst);
let InOperandList = (ins MemOpndC:$addr);
let Size = 2;
let AsmString = "small $dst, $addr";
}
def : CompressPat<(BigInst RegsC:$dst, RegsC:$src, simm6:$imm),
(SmallInst RegsC:$dst, RegsC:$src, simm6:$imm)>;
def BigInst2 : Instruction {
let Namespace = "MyNS";
let OutOperandList = (outs Regs:$dst);
let InOperandList = (ins MemOpnd:$addr);
let Size = 4;
let AsmString = "big $dst, $addr";
}
def SmallInst2 : Instruction {
let Namespace = "MyNS";
let OutOperandList = (outs RegsC:$dst);
let InOperandList = (ins RegsC:$src, simm6:$imm);
let Size = 2;
let AsmString = "small $dst, $src, $imm";
}
def : CompressPat<(BigInst2 RegsC:$dst, RegsC:$src, simm6:$imm),
(SmallInst2 RegsC:$dst, RegsC:$src, simm6:$imm)>;
def BigInst3 : Instruction {
let Namespace = "MyNS";
let OutOperandList = (outs Regs:$dst);
let InOperandList = (ins Regs:$src, simm12:$imm);
let Size = 4;
let AsmString = "big $dst, $src, $imm";
}
def SmallInst3 : Instruction {
let Namespace = "MyNS";
let OutOperandList = (outs RegsC:$dst);
let InOperandList = (ins MemOpndC:$addr);
let Size = 2;
let AsmString = "small $dst, $addr";
}
def : CompressPat<(BigInst3 RegsC:$dst, RegsC:$src, simm6:$imm),
(SmallInst3 RegsC:$dst, RegsC:$src, simm6:$imm)>;
// CHECK-LABEL: ArchValidateMCOperandForCompress
// CHECK: // simm6
// CHECK: return isInt<6>(Imm);
// CHECK-LABEL: compressInst
// CHECK: case Arch::BigInst
// CHECK-NEXT: if (MI.getOperand(0).isReg() &&
// CHECK-NEXT: ArchMCRegisterClasses[Arch::RegsCRegClassID].contains(MI.getOperand(0).getReg()) &&
// CHECK-NEXT: MI.getOperand(1).isReg() &&
// CHECK-NEXT: ArchMCRegisterClasses[Arch::RegsCRegClassID].contains(MI.getOperand(1).getReg()) &&
// CHECK-NEXT: ArchValidateMCOperandForCompress(MI.getOperand(2), STI, 1 /* simm6 */)) {
// CHECK-NEXT: // small $dst, $addr
// CHECK-NEXT: OutInst.setOpcode(Arch::SmallInst);
// CHECK-NEXT: // Operand: dst
// CHECK-NEXT: OutInst.addOperand(MI.getOperand(0));
// CHECK-NEXT: // Operand: addr
// CHECK-NEXT: OutInst.addOperand(MI.getOperand(1));
// CHECK-NEXT: OutInst.addOperand(MI.getOperand(2));
// CHECK-NEXT: OutInst.setLoc(MI.getLoc());
// CHECK-NEXT: return true;
// CHECK-NEXT: } // if
// CHECK: case Arch::BigInst2
// CHECK-NEXT: if (MI.getOperand(0).isReg() &&
// CHECK-NEXT: ArchMCRegisterClasses[Arch::RegsCRegClassID].contains(MI.getOperand(0).getReg()) &&
// CHECK-NEXT: MI.getOperand(1).isReg() &&
// CHECK-NEXT: ArchMCRegisterClasses[Arch::RegsCRegClassID].contains(MI.getOperand(1).getReg()) &&
// CHECK-NEXT: ArchValidateMCOperandForCompress(MI.getOperand(2), STI, 1 /* simm6 */)) {
// CHECK-NEXT: // small $dst, $src, $imm
// CHECK-NEXT: OutInst.setOpcode(Arch::SmallInst2);
// CHECK-NEXT: // Operand: dst
// CHECK-NEXT: OutInst.addOperand(MI.getOperand(0));
// CHECK-NEXT: // Operand: src
// CHECK-NEXT: OutInst.addOperand(MI.getOperand(1));
// CHECK-NEXT: // Operand: imm
// CHECK-NEXT: OutInst.addOperand(MI.getOperand(2));
// CHECK-NEXT: OutInst.setLoc(MI.getLoc());
// CHECK-NEXT: return true;
// CHECK-NEXT: } // if
// CHECK: case Arch::BigInst3
// CHECK-NEXT: if (MI.getOperand(0).isReg() &&
// CHECK-NEXT: ArchMCRegisterClasses[Arch::RegsCRegClassID].contains(MI.getOperand(0).getReg()) &&
// CHECK-NEXT: MI.getOperand(1).isReg() &&
// CHECK-NEXT: ArchMCRegisterClasses[Arch::RegsCRegClassID].contains(MI.getOperand(1).getReg()) &&
// CHECK-NEXT: ArchValidateMCOperandForCompress(MI.getOperand(2), STI, 1 /* simm6 */)) {
// CHECK-NEXT: // small $dst, $addr
// CHECK-NEXT: OutInst.setOpcode(Arch::SmallInst3);
// CHECK-NEXT: // Operand: dst
// CHECK-NEXT: OutInst.addOperand(MI.getOperand(0));
// CHECK-NEXT: // Operand: addr
// CHECK-NEXT: OutInst.addOperand(MI.getOperand(1));
// CHECK-NEXT: OutInst.addOperand(MI.getOperand(2));
// CHECK-NEXT: OutInst.setLoc(MI.getLoc());
// CHECK-NEXT: return true;
// CHECK-NEXT: } // if
// CHECK-LABEL: ArchValidateMCOperandForUncompress
// CHECK: // simm6
// CHECK: return isInt<6>(Imm);
// CHECK-LABEL: uncompressInst
// CHECK: case Arch::SmallInst:
// CHECK-NEXT: if (MI.getOperand(0).isReg() &&
// CHECK-NEXT: ArchMCRegisterClasses[Arch::RegsCRegClassID].contains(MI.getOperand(0).getReg()) &&
// CHECK-NEXT: MI.getOperand(1).isReg() &&
// CHECK-NEXT: ArchMCRegisterClasses[Arch::RegsCRegClassID].contains(MI.getOperand(1).getReg()) &&
// CHECK-NEXT: ArchValidateMCOperandForUncompress(MI.getOperand(2), STI, 1 /* simm6 */) &&
// CHECK-NEXT: ArchValidateMCOperandForUncompress(MI.getOperand(2), STI, 2 /* simm12 */))
// CHECK-NEXT: // big $dst, $addr
// CHECK-NEXT: OutInst.setOpcode(Arch::BigInst);
// CHECK-NEXT: // Operand: dst
// CHECK-NEXT: OutInst.addOperand(MI.getOperand(0));
// CHECK-NEXT: // Operand: addr
// CHECK-NEXT: OutInst.addOperand(MI.getOperand(1));
// CHECK-NEXT: OutInst.addOperand(MI.getOperand(2));
// CHECK-NEXT: OutInst.setLoc(MI.getLoc());
// CHECK-NEXT: return true;
// CHECK-NEXT: } // if
// CHECK: case Arch::SmallInst2:
// CHECK-NEXT: if (MI.getOperand(0).isReg() &&
// CHECK-NEXT: ArchMCRegisterClasses[Arch::RegsCRegClassID].contains(MI.getOperand(0).getReg()) &&
// CHECK-NEXT: MI.getOperand(1).isReg() &&
// CHECK-NEXT: ArchMCRegisterClasses[Arch::RegsCRegClassID].contains(MI.getOperand(1).getReg()) &&
// CHECK-NEXT: ArchValidateMCOperandForUncompress(MI.getOperand(2), STI, 1 /* simm6 */) &&
// CHECK-NEXT: ArchValidateMCOperandForUncompress(MI.getOperand(2), STI, 2 /* simm12 */)) {
// CHECK-NEXT: // big $dst, $addr
// CHECK-NEXT: OutInst.setOpcode(Arch::BigInst2);
// CHECK-NEXT: // Operand: dst
// CHECK-NEXT: OutInst.addOperand(MI.getOperand(0));
// CHECK-NEXT: // Operand: addr
// CHECK-NEXT: OutInst.addOperand(MI.getOperand(1));
// CHECK-NEXT: OutInst.addOperand(MI.getOperand(2));
// CHECK-NEXT: OutInst.setLoc(MI.getLoc());
// CHECK-NEXT: return true;
// CHECK-NEXT: } // if
// CHECK: case Arch::SmallInst3:
// CHECK-NEXT: if (MI.getOperand(0).isReg() &&
// CHECK-NEXT: ArchMCRegisterClasses[Arch::RegsCRegClassID].contains(MI.getOperand(0).getReg()) &&
// CHECK-NEXT: MI.getOperand(1).isReg() &&
// CHECK-NEXT: ArchMCRegisterClasses[Arch::RegsCRegClassID].contains(MI.getOperand(1).getReg()) &&
// CHECK-NEXT: ArchValidateMCOperandForUncompress(MI.getOperand(2), STI, 1 /* simm6 */) &&
// CHECK-NEXT: ArchValidateMCOperandForUncompress(MI.getOperand(2), STI, 2 /* simm12 */)) {
// CHECK-NEXT: // big $dst, $src, $imm
// CHECK-NEXT: OutInst.setOpcode(Arch::BigInst3);
// CHECK-NEXT: // Operand: dst
// CHECK-NEXT: OutInst.addOperand(MI.getOperand(0));
// CHECK-NEXT: // Operand: src
// CHECK-NEXT: OutInst.addOperand(MI.getOperand(1));
// CHECK-NEXT: // Operand: imm
// CHECK-NEXT: OutInst.addOperand(MI.getOperand(2));
// CHECK-NEXT: OutInst.setLoc(MI.getLoc());
// CHECK-NEXT: return true;
// CHECK-NEXT: } // if
// CHECK-LABEL: ArchValidateMachineOperand
// CHECK: // simm6
// CHECK: return isInt<6>(Imm);
// CHECK-LABEL: isCompressibleInst
// CHECK: case Arch::BigInst: {
// CHECK-NEXT: if (MI.getOperand(0).isReg() && MI.getOperand(0).getReg().isPhysical() &&
// CHECK-NEXT: ArchMCRegisterClasses[Arch::RegsCRegClassID].contains(MI.getOperand(0).getReg()) &&
// CHECK-NEXT: MI.getOperand(1).isReg() && MI.getOperand(1).getReg().isPhysical() &&
// CHECK-NEXT: ArchMCRegisterClasses[Arch::RegsCRegClassID].contains(MI.getOperand(1).getReg()) &&
// CHECK-NEXT: MI.getOperand(2).isImm() &&
// CHECK-NEXT: ArchValidateMachineOperand(MI.getOperand(2), &STI, 1 /* simm6 */)) {
// CHECK-NEXT: // small $dst, $addr
// CHECK-NEXT: // Operand: dst
// CHECK-NEXT: // Operand: addr
// CHECK-NEXT: return true;
// CHECK-NEXT: } // if
// CHECK: case Arch::BigInst2: {
// CHECK-NEXT: if (MI.getOperand(0).isReg() && MI.getOperand(0).getReg().isPhysical() &&
// CHECK-NEXT: ArchMCRegisterClasses[Arch::RegsCRegClassID].contains(MI.getOperand(0).getReg()) &&
// CHECK-NEXT: MI.getOperand(1).isReg() && MI.getOperand(1).getReg().isPhysical() &&
// CHECK-NEXT: ArchMCRegisterClasses[Arch::RegsCRegClassID].contains(MI.getOperand(1).getReg()) &&
// CHECK-NEXT: MI.getOperand(2).isImm() &&
// CHECK-NEXT: ArchValidateMachineOperand(MI.getOperand(2), &STI, 1 /* simm6 */)) {
// CHECK-NEXT: // small $dst, $src, $imm
// CHECK-NEXT: // Operand: dst
// CHECK-NEXT: // Operand: src
// CHECK-NEXT: // Operand: imm
// CHECK-NEXT: return true;
// CHECK-NEXT: } // if
// CHECK: case Arch::BigInst3: {
// CHECK-NEXT: if (MI.getOperand(0).isReg() && MI.getOperand(0).getReg().isPhysical() &&
// CHECK-NEXT: ArchMCRegisterClasses[Arch::RegsCRegClassID].contains(MI.getOperand(0).getReg()) &&
// CHECK-NEXT: MI.getOperand(1).isReg() && MI.getOperand(1).getReg().isPhysical() &&
// CHECK-NEXT: ArchMCRegisterClasses[Arch::RegsCRegClassID].contains(MI.getOperand(1).getReg()) &&
// CHECK-NEXT: MI.getOperand(2).isImm() &&
// CHECK-NEXT: ArchValidateMachineOperand(MI.getOperand(2), &STI, 1 /* simm6 */)) {
// CHECK-NEXT: // small $dst, $addr
// CHECK-NEXT: // Operand: dst
// CHECK-NEXT: // Operand: addr
// CHECK-NEXT: return true;
// CHECK-NEXT: } // if