Index: llvm/trunk/test/TableGen/GlobalISelEmitter.td =================================================================== --- llvm/trunk/test/TableGen/GlobalISelEmitter.td +++ llvm/trunk/test/TableGen/GlobalISelEmitter.td @@ -1,4 +1,11 @@ -// RUN: llvm-tblgen -gen-global-isel -I %p/../../include %s | FileCheck %s +// RUN: llvm-tblgen -optimize-match-table=false -gen-global-isel -I %p/../../include %s | FileCheck %s --check-prefix=CHECK --check-prefix=NOOPT +// +// The optimized table can reorder predicates between rules, but the rules +// order must remain the same. +// RUN: llvm-tblgen -optimize-match-table=true -gen-global-isel -I %p/../../include %s | FileCheck %s --check-prefix=CHECK --check-prefix=OPT +// +// Make sure the default is to optimize the table. +// RUN: llvm-tblgen -gen-global-isel -I %p/../../include %s | FileCheck %s --check-prefix=CHECK --check-prefix=OPT include "llvm/Target/Target.td" @@ -166,9 +173,12 @@ // // CHECK-LABEL: MatchTable0[] = { -// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 0*/ [[LABEL:[0-9]+]], +// OPT-NEXT: GIM_Try, /*On fail goto*//*Label [[GRP_LABEL_NUM:[0-9]+]]*/ [[GRP_LABEL:[0-9]+]], +// OPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SELECT, +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/4, -// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SELECT, +// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SELECT, +// OPT-NEXT: // No instruction predicates // CHECK-NEXT: // MIs[0] dst // CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, // CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, @@ -191,7 +201,7 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, -// CHECK-NEXT: // Label 0: @[[LABEL]] +// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]] def INSN3 : I<(outs GPR32:$dst), (ins GPR32Op:$src1, GPR32:$src2a, GPR32:$src2b, GPR32:$scr), []>; @@ -208,11 +218,12 @@ //===- Test a pattern with multiple ComplexPattern operands. --------------===// // -// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 1*/ [[LABEL:[0-9]+]], +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/4, // CHECK-NEXT: GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/3, // MIs[1] // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/1, /*Expected*/4, -// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SELECT, +// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SELECT, +// OPT-NEXT: // No instruction predicates // CHECK-NEXT: // MIs[0] dst // CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, // CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, @@ -254,7 +265,11 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, -// CHECK-NEXT: // Label 1: @[[LABEL]] +// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]] +// Closing the G_SELECT group. +// OPT-NEXT: GIM_Reject, +// OPT-NEXT: GIR_Done, +// OPT-NEXT: // Label [[GRP_LABEL_NUM]]: @[[GRP_LABEL]] def : GINodeEquiv; let mayLoad = 1 in { @@ -265,9 +280,12 @@ //===- Test a simple pattern with regclass operands. ----------------------===// -// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 2*/ [[LABEL:[0-9]+]], +// OPT-NEXT: GIM_Try, /*On fail goto*//*Label [[GRP_LABEL_NUM:[0-9]+]]*/ [[GRP_LABEL:[0-9]+]], +// OPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_ADD, +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, -// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_ADD, +// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_ADD, +// OPT-NEXT: // No instruction predicates // CHECK-NEXT: // MIs[0] dst // CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, // CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, @@ -281,16 +299,17 @@ // CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::ADD, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, -// CHECK-NEXT: // Label 2: @[[LABEL]] +// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]] def ADD : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2), [(set GPR32:$dst, (add GPR32:$src1, GPR32:$src2))]>; //===- Test a pattern with a tied operand in the matcher ------------------===// -// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 3*/ [[LABEL:[0-9]+]], +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, -// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_ADD, +// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_ADD, +// OPT-NEXT: // No instruction predicates // CHECK-NEXT: // MIs[0] dst // CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, // CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, @@ -306,15 +325,16 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, -// CHECK-NEXT: // Label 3: @[[LABEL]] +// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]] def DOUBLE : I<(outs GPR32:$dst), (ins GPR32:$src), [(set GPR32:$dst, (add GPR32:$src, GPR32:$src))]>; //===- Test a simple pattern with ValueType operands. ----------------------===// -// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 4*/ [[LABEL:[0-9]+]], +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, -// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_ADD, +// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_ADD, +// OPT-NEXT: // No instruction predicates // CHECK-NEXT: // MIs[0] dst // CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, // CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, @@ -326,7 +346,11 @@ // CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::ADD, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, -// CHECK-NEXT: // Label 4: @[[LABEL]] +// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]] +// Closing the G_ADD group. +// OPT-NEXT: GIM_Reject, +// OPT-NEXT: GIR_Done, +// OPT-NEXT: // Label [[GRP_LABEL_NUM]]: @[[GRP_LABEL]] def : Pat<(add i32:$src1, i32:$src2), (ADD i32:$src1, i32:$src2)>; @@ -334,9 +358,12 @@ //===- Test a simple pattern with an intrinsic. ---------------------------===// // -// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 5*/ [[LABEL:[0-9]+]], +// OPT-NEXT: GIM_Try, /*On fail goto*//*Label [[GRP_LABEL_NUM:[0-9]+]]*/ [[GRP_LABEL:[0-9]+]], +// OPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_INTRINSIC, +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, -// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_INTRINSIC, +// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_INTRINSIC, +// OPT-NEXT: // No instruction predicates // CHECK-NEXT: // MIs[0] dst // CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, // CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, @@ -353,19 +380,26 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, -// CHECK-NEXT: // Label 5: @[[LABEL]] +// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]] +// Closing the G_INTRINSIC group. +// OPT-NEXT: GIM_Reject, +// OPT-NEXT: GIR_Done, +// OPT-NEXT: // Label [[GRP_LABEL_NUM]]: @[[GRP_LABEL]] def MOV : I<(outs GPR32:$dst), (ins GPR32:$src1), [(set GPR32:$dst, (int_mytarget_nop GPR32:$src1))]>; //===- Test a nested instruction match. -----------------------------------===// -// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 6*/ [[LABEL:[0-9]+]], +// OPT-NEXT: GIM_Try, /*On fail goto*//*Label [[GRP_LABEL_NUM:[0-9]+]]*/ [[GRP_LABEL:[0-9]+]], +// OPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_MUL, +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckFeatures, GIFBS_HasA, // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, // CHECK-NEXT: GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/1, // MIs[1] // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/1, /*Expected*/3, -// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_MUL, +// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_MUL, +// OPT-NEXT: // No instruction predicates // CHECK-NEXT: // MIs[0] dst // CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, // CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, @@ -393,15 +427,16 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, -// CHECK-NEXT: // Label 6: @[[LABEL]] +// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]] // We also get a second rule by commutativity. -// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 7*/ [[LABEL:[0-9]+]], +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckFeatures, GIFBS_HasA, // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, // CHECK-NEXT: GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/2, // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/1, /*Expected*/3, -// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_MUL, +// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_MUL, +// OPT-NEXT: // No instruction predicates // CHECK-NEXT: // MIs[0] dst // CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, // CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, @@ -429,7 +464,7 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, -// CHECK-NEXT: // Label 7: @[[LABEL]] +// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]] def MULADD : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2, GPR32:$src3), [(set GPR32:$dst, @@ -438,10 +473,11 @@ //===- Test another simple pattern with regclass operands. ----------------===// -// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 8*/ [[LABEL:[0-9]+]], +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckFeatures, GIFBS_HasA_HasB_HasC, // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, -// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_MUL, +// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_MUL, +// OPT-NEXT: // No instruction predicates // CHECK-NEXT: // MIs[0] dst // CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, // CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, @@ -459,7 +495,11 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, -// CHECK-NEXT: // Label 8: @[[LABEL]] +// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]] +// Closing the G_MUL group. +// OPT-NEXT: GIM_Reject, +// OPT-NEXT: GIR_Done, +// OPT-NEXT: // Label [[GRP_LABEL_NUM]]: @[[GRP_LABEL]] def MUL : I<(outs GPR32:$dst), (ins GPR32:$src2, GPR32:$src1), [(set GPR32:$dst, (mul GPR32:$src1, GPR32:$src2))]>, @@ -467,14 +507,17 @@ //===- Test a more complex multi-instruction match. -----------------------===// -// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 9*/ [[LABEL:[0-9]+]], +// OPT-NEXT: GIM_Try, /*On fail goto*//*Label [[GRP_LABEL_NUM:[0-9]+]]*/ [[GRP_LABEL:[0-9]+]], +// OPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SUB, +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckFeatures, GIFBS_HasA, // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, // CHECK-NEXT: GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/1, // MIs[1] // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/1, /*Expected*/3, // CHECK-NEXT: GIM_RecordInsn, /*DefineMI*/2, /*MI*/0, /*OpIdx*/2, // MIs[2] // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/2, /*Expected*/3, -// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SUB, +// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SUB, +// OPT-NEXT: // No instruction predicates // CHECK-NEXT: // MIs[0] dst // CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, // CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, @@ -512,7 +555,7 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, -// CHECK-NEXT: // Label 9: @[[LABEL]] +// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]] def INSNBOB : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2, GPR32:$src3, GPR32:$src4), [(set GPR32:$dst, @@ -522,9 +565,10 @@ //===- Test a pattern with ComplexPattern operands. -----------------------===// // -// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 10*/ [[LABEL:[0-9]+]], +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, -// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SUB, +// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SUB, +// OPT-NEXT: // No instruction predicates // CHECK-NEXT: // MIs[0] dst // CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, // CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, @@ -542,7 +586,11 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, -// CHECK-NEXT: // Label 10: @[[LABEL]] +// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]] +// Closing the G_SUB group. +// OPT-NEXT: GIM_Reject, +// OPT-NEXT: GIR_Done, +// OPT-NEXT: // Label [[GRP_LABEL_NUM]]: @[[GRP_LABEL]] def INSN1 : I<(outs GPR32:$dst), (ins GPR32:$src1, complex:$src2), []>; def : Pat<(sub GPR32:$src1, complex:$src2), (INSN1 GPR32:$src1, complex:$src2)>; @@ -550,9 +598,12 @@ //===- Test a simple pattern with a default operand. ----------------------===// // -// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 11*/ [[LABEL:[0-9]+]], +// OPT-NEXT: GIM_Try, /*On fail goto*//*Label [[GRP_LABEL_NUM:[0-9]+]]*/ [[GRP_LABEL:[0-9]+]], +// OPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR, +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, -// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR, +// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR, +// OPT-NEXT: // No instruction predicates // CHECK-NEXT: // MIs[0] dst // CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, // CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, @@ -570,7 +621,7 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, -// CHECK-NEXT: // Label 11: @[[LABEL]] +// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]] // The -2 is just to distinguish it from the 'not' case below. def XORI : I<(outs GPR32:$dst), (ins m1:$src2, GPR32:$src1), @@ -579,9 +630,10 @@ //===- Test a simple pattern with a default register operand. -------------===// // -// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 12*/ [[LABEL:[0-9]+]], +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, -// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR, +// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR, +// OPT-NEXT: // No instruction predicates // CHECK-NEXT: // MIs[0] dst // CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, // CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, @@ -599,7 +651,7 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, -// CHECK-NEXT: // Label 12: @[[LABEL]] +// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]] // The -3 is just to distinguish it from the 'not' case below and the other default op case above. def XOR : I<(outs GPR32:$dst), (ins Z:$src2, GPR32:$src1), @@ -608,9 +660,10 @@ //===- Test a simple pattern with a multiple default operands. ------------===// // -// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 13*/ [[LABEL:[0-9]+]], +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, -// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR, +// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR, +// OPT-NEXT: // No instruction predicates // CHECK-NEXT: // MIs[0] dst // CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, // CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, @@ -629,7 +682,7 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, -// CHECK-NEXT: // Label 13: @[[LABEL]] +// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]] // The -4 is just to distinguish it from the other 'not' cases. def XORlike : I<(outs GPR32:$dst), (ins m1Z:$src2, GPR32:$src1), @@ -638,9 +691,10 @@ //===- Test a simple pattern with multiple operands with defaults. --------===// // -// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 14*/ [[LABEL:[0-9]+]], +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, -// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR, +// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR, +// OPT-NEXT: // No instruction predicates // CHECK-NEXT: // MIs[0] dst // CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, // CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, @@ -660,7 +714,7 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, -// CHECK-NEXT: // Label 14: @[[LABEL]] +// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]] // The -5 is just to distinguish it from the other cases. def XORManyDefaults : I<(outs GPR32:$dst), (ins m1Z:$src3, Z:$src2, GPR32:$src1), @@ -671,9 +725,10 @@ // This must precede the 3-register variants because constant immediates have // priority over register banks. -// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 15*/ [[LABEL:[0-9]+]], +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, -// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR, +// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR, +// OPT-NEXT: // No instruction predicates // CHECK-NEXT: // MIs[0] dst // CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, // CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, @@ -691,7 +746,11 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, -// CHECK-NEXT: // Label 15: @[[LABEL]] +// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]] +// Closing the G_XOR group. +// OPT-NEXT: GIM_Reject, +// OPT-NEXT: GIR_Done, +// OPT-NEXT: // Label [[GRP_LABEL_NUM]]: @[[GRP_LABEL]] def ORN : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2), []>; def : Pat<(not GPR32:$Wm), (ORN R0, GPR32:$Wm)>; @@ -699,9 +758,12 @@ //===- Test a COPY_TO_REGCLASS --------------------------------------------===// // -// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 16*/ [[LABEL:[0-9]+]], +// OPT-NEXT: GIM_Try, /*On fail goto*//*Label [[GRP_LABEL_NUM:[0-9]+]]*/ [[GRP_LABEL:[0-9]+]], +// OPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_BITCAST, +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2, -// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_BITCAST, +// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_BITCAST, +// OPT-NEXT: // No instruction predicates // CHECK-NEXT: // MIs[0] dst // CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, // CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, @@ -712,16 +774,23 @@ // CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/TargetOpcode::COPY, // CHECK-NEXT: GIR_ConstrainOperandRC, /*InsnID*/0, /*Op*/0, /*RC GPR32*/1, // CHECK-NEXT: GIR_Done, -// CHECK-NEXT: // Label 16: @[[LABEL]] +// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]] +// Closing the G_BITCAST group. +// OPT-NEXT: GIM_Reject, +// OPT-NEXT: GIR_Done, +// OPT-NEXT: // Label [[GRP_LABEL_NUM]]: @[[GRP_LABEL]] def : Pat<(i32 (bitconvert FPR32:$src1)), (COPY_TO_REGCLASS FPR32:$src1, GPR32)>; //===- Test a simple pattern with just a specific leaf immediate. ---------===// -// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 17*/ [[LABEL:[0-9]+]], +// OPT-NEXT: GIM_Try, /*On fail goto*//*Label [[GRP_LABEL_NUM:[0-9]+]]*/ [[GRP_LABEL:[0-9]+]], +// OPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_CONSTANT, +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2, -// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_CONSTANT, +// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_CONSTANT, +// OPT-NEXT: // No instruction predicates // CHECK-NEXT: // MIs[0] dst // CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, // CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, @@ -733,15 +802,15 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, -// CHECK-NEXT: // Label 17: @[[LABEL]] +// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]] def MOV1 : I<(outs GPR32:$dst), (ins), [(set GPR32:$dst, 1)]>; //===- Test a simple pattern with a leaf immediate and a predicate. -------===// -// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 18*/ [[LABEL:[0-9]+]], +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2, -// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_CONSTANT, +// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_CONSTANT, // CHECK-NEXT: GIM_CheckI64ImmPredicate, /*MI*/0, /*Predicate*/GIPFP_I64_Predicate_simm8, // CHECK-NEXT: // MIs[0] dst // CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, @@ -755,16 +824,16 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, -// CHECK-NEXT: // Label 18: @[[LABEL]] +// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]] def simm8 : ImmLeaf(Imm); }]>; def MOVimm8 : I<(outs GPR32:$dst), (ins i32imm:$imm), [(set GPR32:$dst, simm8:$imm)]>; //===- Same again but use an IntImmLeaf. ----------------------------------===// -// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 19*/ [[LABEL:[0-9]+]], +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2, -// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_CONSTANT, +// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_CONSTANT, // CHECK-NEXT: GIM_CheckAPIntImmPredicate, /*MI*/0, /*Predicate*/GIPFP_APInt_Predicate_simm9, // CHECK-NEXT: // MIs[0] dst // CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, @@ -778,16 +847,17 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, -// CHECK-NEXT: // Label 19: @[[LABEL]] +// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]] def simm9 : IntImmLeaf(Imm->getSExtValue()); }]>; def MOVimm9 : I<(outs GPR32:$dst), (ins i32imm:$imm), [(set GPR32:$dst, simm9:$imm)]>; //===- Test a simple pattern with just a leaf immediate. ------------------===// -// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 20*/ [[LABEL:[0-9]+]], +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2, -// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_CONSTANT, +// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_CONSTANT, +// OPT-NEXT: // No instruction predicates // CHECK-NEXT: // MIs[0] dst // CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, // CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, @@ -800,15 +870,21 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, -// CHECK-NEXT: // Label 20: @[[LABEL]] +// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]] +// Closing the G_CONSTANT group. +// OPT-NEXT: GIM_Reject, +// OPT-NEXT: GIR_Done, +// OPT-NEXT: // Label [[GRP_LABEL_NUM]]: @[[GRP_LABEL]] def MOVimm : I<(outs GPR32:$dst), (ins i32imm:$imm), [(set GPR32:$dst, imm:$imm)]>; //===- Test a simple pattern with a FP immediate and a predicate. ---------===// -// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 21*/ [[LABEL:[0-9]+]], +// OPT-NEXT: GIM_Try, /*On fail goto*//*Label [[GRP_LABEL_NUM:[0-9]+]]*/ [[GRP_LABEL:[0-9]+]], +// OPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_FCONSTANT, +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2, -// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_FCONSTANT, +// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_FCONSTANT, // CHECK-NEXT: GIM_CheckAPFloatImmPredicate, /*MI*/0, /*Predicate*/GIPFP_APFloat_Predicate_fpimmz, // CHECK-NEXT: // MIs[0] dst // CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, @@ -822,16 +898,22 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, -// CHECK-NEXT: // Label 21: @[[LABEL]] +// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]] +// Closing the G_FCONSTANT group. +// OPT-NEXT: GIM_Reject, +// OPT-NEXT: GIR_Done, +// OPT-NEXT: // Label [[GRP_LABEL_NUM]]: @[[GRP_LABEL]] def fpimmz : FPImmLeafisExactlyValue(0.0); }]>; def MOVfpimmz : I<(outs FPR32:$dst), (ins f32imm:$imm), [(set FPR32:$dst, fpimmz:$imm)]>; //===- Test a simple pattern with inferred pointer operands. ---------------===// -// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 22*/ [[LABEL:[0-9]+]], +// OPT-NEXT: GIM_Try, /*On fail goto*//*Label [[GRP_LABEL_NUM:[0-9]+]]*/ [[GRP_LABEL:[0-9]+]], +// OPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_LOAD, +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2, -// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_LOAD, +// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_LOAD, // CHECK-NEXT: GIM_CheckAtomicOrdering, /*MI*/0, /*Order*/(int64_t)AtomicOrdering::NotAtomic, // CHECK-NEXT: // MIs[0] dst // CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, @@ -843,18 +925,25 @@ // CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::LOAD, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, -// CHECK-NEXT: // Label 22: @[[LABEL]] +// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]] +// Closing the G_LOAD group. +// OPT-NEXT: GIM_Reject, +// OPT-NEXT: GIR_Done, +// OPT-NEXT: // Label [[GRP_LABEL_NUM]]: @[[GRP_LABEL]] def LOAD : I<(outs GPR32:$dst), (ins GPR32:$src1), [(set GPR32:$dst, (load GPR32:$src1))]>; //===- Test a simple pattern with a sextload -------------------------------===// -// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 23*/ [[LABEL:[0-9]+]], +// OPT-NEXT: GIM_Try, /*On fail goto*//*Label [[GRP_LABEL_NUM:[0-9]+]]*/ [[GRP_LABEL:[0-9]+]], +// OPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SEXT, +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2, // CHECK-NEXT: GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/1, // MIs[1] // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/1, /*Expected*/2, -// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SEXT, +// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SEXT, +// OPT-NEXT: // No instruction predicates // CHECK-NEXT: // MIs[0] dst // CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, // CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, @@ -876,23 +965,34 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, -// CHECK-NEXT: // Label 23: @[[LABEL]] +// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]] +// Closing the G_SEXT group. +// OPT-NEXT: GIM_Reject, +// OPT-NEXT: GIR_Done, +// OPT-NEXT: // Label [[GRP_LABEL_NUM]]: @[[GRP_LABEL]] def SEXTLOAD : I<(outs GPR32:$dst), (ins GPR32:$src1), [(set GPR32:$dst, (sextloadi16 GPR32:$src1))]>; //===- Test a pattern with an MBB operand. --------------------------------===// -// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 24*/ [[LABEL:[0-9]+]], +// OPT-NEXT: GIM_Try, /*On fail goto*//*Label [[GRP_LABEL_NUM:[0-9]+]]*/ [[GRP_LABEL:[0-9]+]], +// OPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_BR, +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/1, -// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_BR, +// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_BR, +// OPT-NEXT: // No instruction predicates // CHECK-NEXT: // MIs[0] target // CHECK-NEXT: GIM_CheckIsMBB, /*MI*/0, /*Op*/0, // CHECK-NEXT: // (br (bb:{ *:[Other] }):$target) => (BR (bb:{ *:[Other] }):$target) // CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::BR, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, -// CHECK-NEXT: // Label 24: @[[LABEL]] +// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]] +// Closing the G_BR group. +// OPT-NEXT: GIM_Reject, +// OPT-NEXT: GIR_Done, +// OPT-NEXT: // Label [[GRP_LABEL_NUM]]: @[[GRP_LABEL]] def BR : I<(outs), (ins unknown:$target), [(br bb:$target)]>; Index: llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp =================================================================== --- llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp +++ llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp @@ -74,10 +74,14 @@ cl::desc("Specify file to retrieve coverage information from"), cl::cat(GlobalISelEmitterCat)); +static cl::opt OptimizeMatchTable( + "optimize-match-table", + cl::desc("Generate an optimized version of the match table"), + cl::init(true), cl::cat(GlobalISelEmitterCat)); + namespace { //===- Helper functions ---------------------------------------------------===// - /// Get the name of the enum value used to number the predicate function. std::string getEnumNameForPredicate(const TreePredicateFn &Predicate) { return "GIPFP_" + Predicate.getImmTypeIdentifier().str() + "_" + @@ -563,9 +567,38 @@ class OperandMatcher; class MatchAction; +class PredicateMatcher; +class RuleMatcher; + +class Matcher { +public: + virtual ~Matcher() = default; + virtual void emit(MatchTable &Table) = 0; +}; + +class GroupMatcher : public Matcher { + SmallVector, 8> Conditions; + SmallVector Rules; + +public: + void addCondition(std::unique_ptr &&Predicate) { + Conditions.emplace_back(std::move(Predicate)); + } + void addRule(Matcher &Rule) { Rules.push_back(&Rule); } + const std::unique_ptr &conditions_back() const { + return Conditions.back(); + } + bool lastConditionMatches(const PredicateMatcher &Predicate) const; + bool conditions_empty() const { return Conditions.empty(); } + void clear() { + Conditions.clear(); + Rules.clear(); + } + void emit(MatchTable &Table) override; +}; /// Generates code to check that a match rule matches. -class RuleMatcher { +class RuleMatcher : public Matcher { public: using ActionVec = std::vector>; using action_iterator = ActionVec::iterator; @@ -705,7 +738,7 @@ void emitCaptureOpcodes(MatchTable &Table); - void emit(MatchTable &Table); + void emit(MatchTable &Table) override; /// Compare the priority of this object and B. /// @@ -716,11 +749,16 @@ /// matcher. unsigned countRendererFns() const; + std::unique_ptr forgetFirstCondition(); + // FIXME: Remove this as soon as possible - InstructionMatcher &insnmatcher_front() const { return *Matchers.front(); } + InstructionMatcher &insnmatchers_front() const { return *Matchers.front(); } unsigned allocateOutputInsnID() { return NextOutputInsnID++; } unsigned allocateTempRegID() { return NextTempRegID++; } + + bool insnmatchers_empty() const { return Matchers.empty(); } + void insnmatchers_pop_front() { Matchers.erase(Matchers.begin()); } }; uint64_t RuleMatcher::NextRuleID = 0; @@ -757,6 +795,13 @@ typename PredicateVec::size_type predicates_size() const { return Predicates.size(); } + bool predicates_empty() const { return Predicates.empty(); } + + std::unique_ptr predicates_pop_front() { + std::unique_ptr Front = std::move(Predicates.front()); + Predicates.erase(Predicates.begin()); + return Front; + } /// Emit MatchTable opcodes that tests whether all the predicates are met. template @@ -1513,6 +1558,9 @@ iterator_range operands() const { return make_range(operands_begin(), operands_end()); } + bool operands_empty() const { return Operands.empty(); } + + void pop_front() { Operands.erase(Operands.begin()); } /// Emit MatchTable opcodes to check the shape of the match and capture /// instructions into the MIs table. @@ -2535,6 +2583,40 @@ TreePatternNode *fixupPatternNode(TreePatternNode *N); void fixupPatternTrees(TreePattern *P); + + /// Takes a sequence of \p Rules and group them based on the predicates + /// they share. \p StorageGroupMatcher is used as a memory container + /// for the the group that are created as part of this process. + /// The optimization process does not change the relative order of + /// the rules. In particular, we don't try to share predicates if + /// that means reordering the rules (e.g., we won't group R1 and R3 + /// in the following example as it would imply reordering R2 and R3 + /// => R1 p1, R2 p2, R3 p1). + /// + /// What this optimization does looks like: + /// Output without optimization: + /// \verbatim + /// # R1 + /// # predicate A + /// # predicate B + /// ... + /// # R2 + /// # predicate A // <-- effectively this is going to be checked twice. + /// // Once in R1 and once in R2. + /// # predicate C + /// \endverbatim + /// Output with optimization: + /// \verbatim + /// # Group1_2 + /// # predicate A // <-- Check is now shared. + /// # R1 + /// # predicate B + /// # R2 + /// # predicate C + /// \endverbatim + std::vector optimizeRules( + std::vector &Rules, + std::vector> &StorageGroupMatcher); }; void GlobalISelEmitter::gatherNodeEquivs() { @@ -3469,6 +3551,38 @@ OS << "};\n"; } +std::vector GlobalISelEmitter::optimizeRules( + std::vector &Rules, + std::vector> &StorageGroupMatcher) { + std::vector OptRules; + // Start with a stupid grouping for now. + std::unique_ptr CurrentGroup = make_unique(); + assert(CurrentGroup->conditions_empty()); + unsigned NbGroup = 0; + for (RuleMatcher &Rule : Rules) { + std::unique_ptr Predicate = Rule.forgetFirstCondition(); + if (!CurrentGroup->conditions_empty() && + !CurrentGroup->lastConditionMatches(*Predicate)) { + // Start a new group. + ++NbGroup; + OptRules.push_back(CurrentGroup.get()); + StorageGroupMatcher.emplace_back(std::move(CurrentGroup)); + CurrentGroup = make_unique(); + assert(CurrentGroup->conditions_empty()); + } + if (CurrentGroup->conditions_empty()) + CurrentGroup->addCondition(std::move(Predicate)); + CurrentGroup->addRule(Rule); + } + if (!CurrentGroup->conditions_empty()) { + ++NbGroup; + OptRules.push_back(CurrentGroup.get()); + StorageGroupMatcher.emplace_back(std::move(CurrentGroup)); + } + DEBUG(dbgs() << "NbGroup: " << NbGroup << "\n"); + return OptRules; +} + void GlobalISelEmitter::run(raw_ostream &OS) { if (!UseCoverageFile.empty()) { RuleCoverage = CodeGenCoverage(); @@ -3519,17 +3633,6 @@ Rules.push_back(std::move(MatcherOrErr.get())); } - std::stable_sort(Rules.begin(), Rules.end(), - [&](const RuleMatcher &A, const RuleMatcher &B) { - if (A.isHigherPriorityThan(B)) { - assert(!B.isHigherPriorityThan(A) && "Cannot be more important " - "and less important at " - "the same time"); - return true; - } - return false; - }); - std::vector ComplexPredicates = RK.getAllDerivedDefinitions("GIComplexOperandMatcher"); std::sort(ComplexPredicates.begin(), ComplexPredicates.end(), @@ -3708,9 +3811,28 @@ << " State.MIs.clear();\n" << " State.MIs.push_back(&I);\n\n"; + std::stable_sort(Rules.begin(), Rules.end(), [&](const RuleMatcher &A, + const RuleMatcher &B) { + if (A.isHigherPriorityThan(B)) { + assert(!B.isHigherPriorityThan(A) && "Cannot be more important " + "and less important at " + "the same time"); + return true; + } + return false; + }); + std::vector> StorageGroupMatcher; + + std::vector OptRules; + if (OptimizeMatchTable) + OptRules = optimizeRules(Rules, StorageGroupMatcher); + else + for (Matcher &Rule : Rules) + OptRules.push_back(&Rule); + MatchTable Table(0); - for (auto &Rule : Rules) { - Rule.emit(Table); + for (Matcher *Rule : OptRules) { + Rule->emit(Table); ++NumPatternEmitted; } Table << MatchTable::Opcode("GIM_Reject") << MatchTable::LineBreak; @@ -3827,6 +3949,61 @@ } } +std::unique_ptr RuleMatcher::forgetFirstCondition() { + assert(!insnmatchers_empty() && + "Trying to forget something that does not exist"); + + InstructionMatcher &Matcher = insnmatchers_front(); + std::unique_ptr Condition; + if (!Matcher.predicates_empty()) + Condition = Matcher.predicates_pop_front(); + if (!Condition) { + // If there is no more predicate on the instruction itself, look at its + // operands. + assert(!Matcher.operands_empty() && + "Empty instruction should have been discarded"); + OperandMatcher &OpMatcher = **Matcher.operands_begin(); + assert(!OpMatcher.predicates_empty() && "no operand constraint"); + Condition = OpMatcher.predicates_pop_front(); + // If this operand is free of constraints, rip it off. + if (OpMatcher.predicates_empty()) + Matcher.pop_front(); + } + // Rip the instruction off when it is empty. + if (Matcher.operands_empty() && Matcher.predicates_empty()) + insnmatchers_pop_front(); + return Condition; +} + +bool GroupMatcher::lastConditionMatches( + const PredicateMatcher &Predicate) const { + const auto &LastCondition = conditions_back(); + return Predicate.isIdentical(*LastCondition); +} + +void GroupMatcher::emit(MatchTable &Table) { + unsigned LabelID = Table.allocateLabelID(); + if (!conditions_empty()) { + Table << MatchTable::Opcode("GIM_Try", +1) + << MatchTable::Comment("On fail goto") + << MatchTable::JumpTarget(LabelID) << MatchTable::LineBreak; + for (auto &Condition : Conditions) + Condition->emitPredicateOpcodes( + Table, *static_cast(*Rules.begin())); + } + // Emit the conditions. + // Then checks apply the rules. + for (const auto &Rule : Rules) + Rule->emit(Table); + // If we don't succeeded for that block, that means we are not going to select + // this instruction. + if (!conditions_empty()) { + Table << MatchTable::Opcode("GIM_Reject") << MatchTable::LineBreak; + Table << MatchTable::Opcode("GIR_Done", -1) << MatchTable::LineBreak + << MatchTable::Label(LabelID); + } +} + unsigned OperandMatcher::getInsnVarID() const { return Insn.getVarID(); } } // end anonymous namespace