diff --git a/llvm/test/TableGen/GlobalISelEmitterMatchTableOptimizer.td b/llvm/test/TableGen/GlobalISelEmitterMatchTableOptimizer.td new file mode 100644 --- /dev/null +++ b/llvm/test/TableGen/GlobalISelEmitterMatchTableOptimizer.td @@ -0,0 +1,85 @@ +// RUN: llvm-tblgen %s -gen-global-isel -optimize-match-table=true -I %p/../../include -I %p/Common -o - | FileCheck %s + +include "llvm/Target/Target.td" +include "GlobalISelEmitterCommon.td" + +// Two LOADs with same output size but different input size, hence their +// GIM_CheckPointerToAny should *not* be merged +def LOAD8 : I<(outs GPR8:$dst), (ins GPR8:$src), []>; +def LOAD32 : I<(outs GPR8:$dst), (ins GPR32:$src), []>; +// CHECK: Label 1: @{{[0-9]+}} +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[L1_ID:[0-9]+]]*/ [[L1_AT:[0-9]+]], +// CHECK-NEXT: GIM_CheckMemorySizeEqualToLLT, /*MI*/0, /*MMO*/0, /*OpIdx*/0, +// CHECK-NEXT: GIM_CheckAtomicOrdering, /*MI*/0, /*Order*/(int64_t)AtomicOrdering::NotAtomic, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR8RegClassID, +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[L2_ID:[0-9]+]]*/ [[L2_AT:[0-9]+]], +// CHECK-NEXT: // MIs[0] src +// CHECK-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/8, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR8RegClassID, +// CHECK-NEXT: // (ld:{ *:[i8] } GPR8:{ *:[i8] }:$src)<><> => (LOAD8:{ *:[i8] } GPR8:{ *:[i8] }:$src) +// CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::LOAD8, +// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, +// CHECK-NEXT: // GIR_Coverage, 0, +// CHECK-NEXT: GIR_Done, +// CHECK-NEXT: // Label [[L2_ID]]: @[[L2_AT]] +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[L3_ID:[0-9]+]]*/ [[L3_AT:[0-9]+]], +// CHECK-NEXT: // MIs[0] src +// CHECK-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // (ld:{ *:[i8] } GPR32:{ *:[i32] }:$src)<><> => (LOAD32:{ *:[i8] } GPR32:{ *:[i32] }:$src) +// CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::LOAD32, +// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, +// CHECK-NEXT: // GIR_Coverage, 1, +// CHECK-NEXT: GIR_Done, +// CHECK-NEXT: // Label [[L3_ID]]: @[[L3_AT]] +// CHECK-NEXT: GIM_Reject, +// CHECK-NEXT: // Label [[L1_ID]]: @[[L1_AT]] +def : Pat<(i8 (load GPR8:$src)), + (LOAD8 GPR8:$src)>; +def : Pat<(i8 (load GPR32:$src)), + (LOAD32 GPR32:$src)>; + +// Two LOADs with same output size and input size, hence their +// GIM_CheckPointerToAny *should* be merged +def S0 : Register<"s0"> { let Namespace = "MyTarget"; } +def GPR16 : RegisterClass<"MyTarget", [i16], 16, (add S0)>; +def LOAD16 : I<(outs GPR16:$dst), (ins GPR16:$src), []>; +def LOAD16Imm : I<(outs GPR16:$dst), (ins GPR16:$src), []>; +// CHECK: // Label 2: @{{[0-9]+}} +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[L1_ID:[0-9]+]]*/ [[L1_AT:[0-9]+]], +// CHECK-NEXT: GIM_CheckMemorySizeEqualToLLT, /*MI*/0, /*MMO*/0, /*OpIdx*/0, +// CHECK-NEXT: GIM_CheckAtomicOrdering, /*MI*/0, /*Order*/(int64_t)AtomicOrdering::NotAtomic, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR16RegClassID, +// CHECK-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/16, +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[L2_ID:[0-9]+]]*/ [[L2_AT:[0-9]+]], +// CHECK-NEXT: GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/1, // MIs[1] +// CHECK-NEXT: GIM_CheckOpcode, /*MI*/1, TargetOpcode::G_ADD, +// CHECK-NEXT: GIM_CheckType, /*MI*/1, /*Op*/1, /*Type*/GILLT_s16, +// CHECK-NEXT: GIM_CheckType, /*MI*/1, /*Op*/2, /*Type*/GILLT_s16, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/1, /*RC*/MyTarget::GPR16RegClassID, +// CHECK-NEXT: GIM_CheckConstantInt, /*MI*/1, /*Op*/2, 10, +// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/1, +// CHECK-NEXT: // (ld:{ *:[i16] } (add:{ *:[i16] } GPR16:{ *:[i16] }:$src, 10:{ *:[i16] }))<><> => (LOAD16Imm:{ *:[i16] } GPR16:{ *:[i16] }:$src) +// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::LOAD16Imm, +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/1, // src +// CHECK-NEXT: GIR_MergeMemOperands, /*InsnID*/0, /*MergeInsnID's*/0, 1, GIU_MergeMemOperands_EndOfList, +// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, +// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, +// CHECK-NEXT: // GIR_Coverage, 3, +// CHECK-NEXT: GIR_Done, +// CHECK-NEXT: // Label [[L2_ID]]: @[[L2_AT]] +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[L3_ID:[0-9]+]]*/ [[L3_AT:[0-9]+]], +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR16RegClassID, +// CHECK-NEXT: // (ld:{ *:[i16] } GPR16:{ *:[i16] }:$src)<><> => (LOAD16:{ *:[i16] } GPR16:{ *:[i16] }:$src) +// CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::LOAD16, +// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, +// CHECK-NEXT: // GIR_Coverage, 2, +// CHECK-NEXT: GIR_Done, +// CHECK-NEXT: // Label [[L3_ID]]: @[[L3_AT]] +// CHECK-NEXT: GIM_Reject, +// CHECK-NEXT: // Label [[L1_ID]]: @[[L1_AT]] +def : Pat<(i16 (load GPR16:$src)), + (LOAD16 GPR16:$src)>; +def : Pat<(i16 (load (add GPR16:$src, 10))), + (LOAD16Imm GPR16:$src)>; diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp --- a/llvm/utils/TableGen/GlobalISelEmitter.cpp +++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp @@ -1271,10 +1271,15 @@ : OperandPredicateMatcher(OPM_PointerToAny, InsnVarID, OpIdx), SizeInBits(SizeInBits) {} - static bool classof(const OperandPredicateMatcher *P) { + static bool classof(const PredicateMatcher *P) { return P->getKind() == OPM_PointerToAny; } + bool isIdentical(const PredicateMatcher &B) const override { + return OperandPredicateMatcher::isIdentical(B) && + SizeInBits == cast(&B)->SizeInBits; + } + void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule) const override { Table << MatchTable::Opcode("GIM_CheckPointerToAny")