diff --git a/llvm/include/llvm/Target/GenericOpcodes.td b/llvm/include/llvm/Target/GenericOpcodes.td --- a/llvm/include/llvm/Target/GenericOpcodes.td +++ b/llvm/include/llvm/Target/GenericOpcodes.td @@ -1045,7 +1045,7 @@ // then the value is loaded from $newaddr. def G_INDEXED_LOAD : GenericInstruction { let OutOperandList = (outs type0:$dst, ptype1:$newaddr); - let InOperandList = (ins ptype1:$base, type2:$offset, unknown:$am); + let InOperandList = (ins ptype1:$base, type2:$offset, untyped_imm_0:$am); let hasSideEffects = false; let mayLoad = true; } @@ -1053,7 +1053,7 @@ // Same as G_INDEXED_LOAD except that the load performed is sign-extending, as with G_SEXTLOAD. def G_INDEXED_SEXTLOAD : GenericInstruction { let OutOperandList = (outs type0:$dst, ptype1:$newaddr); - let InOperandList = (ins ptype1:$base, type2:$offset, unknown:$am); + let InOperandList = (ins ptype1:$base, type2:$offset, untyped_imm_0:$am); let hasSideEffects = false; let mayLoad = true; } @@ -1061,7 +1061,7 @@ // Same as G_INDEXED_LOAD except that the load performed is zero-extending, as with G_ZEXTLOAD. def G_INDEXED_ZEXTLOAD : GenericInstruction { let OutOperandList = (outs type0:$dst, ptype1:$newaddr); - let InOperandList = (ins ptype1:$base, type2:$offset, unknown:$am); + let InOperandList = (ins ptype1:$base, type2:$offset, untyped_imm_0:$am); let hasSideEffects = false; let mayLoad = true; } @@ -1077,8 +1077,8 @@ // Combines a store with a GEP. See description of G_INDEXED_LOAD for indexing behaviour. def G_INDEXED_STORE : GenericInstruction { let OutOperandList = (outs ptype0:$newaddr); - let InOperandList = (ins type1:$src, ptype0:$base, ptype2:$offset, - unknown:$am); + let InOperandList = (ins type1:$src, ptype0:$base, type2:$offset, + untyped_imm_0:$am); let hasSideEffects = false; let mayStore = true; } diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir --- a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir @@ -164,19 +164,19 @@ # DEBUG-NEXT: G_ZEXTLOAD (opcode {{[0-9]+}}): 2 type indices, 0 imm indices # DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected # DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected -# DEBUG-NEXT: G_INDEXED_LOAD (opcode {{[0-9]+}}): 3 type indices, 0 imm indices +# DEBUG-NEXT: G_INDEXED_LOAD (opcode {{[0-9]+}}): 3 type indices, 1 imm index # DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined # DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined -# DEBUG-NEXT: G_INDEXED_SEXTLOAD (opcode {{[0-9]+}}): 3 type indices, 0 imm indices +# DEBUG-NEXT: G_INDEXED_SEXTLOAD (opcode {{[0-9]+}}): 3 type indices, 1 imm index # DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined # DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined -# DEBUG-NEXT: G_INDEXED_ZEXTLOAD (opcode {{[0-9]+}}): 3 type indices, 0 imm indices +# DEBUG-NEXT: G_INDEXED_ZEXTLOAD (opcode {{[0-9]+}}): 3 type indices, 1 imm index # DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined # DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined # DEBUG-NEXT: G_STORE (opcode {{[0-9]+}}): 2 type indices, 0 imm indices # DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected # DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected -# DEBUG-NEXT: G_INDEXED_STORE (opcode {{[0-9]+}}): 3 type indices, 0 imm indices +# DEBUG-NEXT: G_INDEXED_STORE (opcode {{[0-9]+}}): 3 type indices, 1 imm index # DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined # DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined # DEBUG-NEXT: G_ATOMIC_CMPXCHG_WITH_SUCCESS (opcode {{[0-9]+}}): 3 type indices, 0 imm indices diff --git a/llvm/test/TableGen/GlobalISelEmitterIndexed.td b/llvm/test/TableGen/GlobalISelEmitterIndexed.td new file mode 100644 --- /dev/null +++ b/llvm/test/TableGen/GlobalISelEmitterIndexed.td @@ -0,0 +1,145 @@ +// RUN: llvm-tblgen -gen-global-isel -optimize-match-table=false -warn-on-skipped-patterns -I %p/../../include -I %p/Common %s -o - < %s | FileCheck %s + +include "llvm/Target/Target.td" +include "GlobalISelEmitterCommon.td" + +// Test the generation of patterns for G_INDEXED_* instructions, and making sure a +// GIM_CheckLiteralInt is generated for the 5th operand + + +def SDTIndexedLoad : SDTypeProfile<2, 3, [ + SDTCisInt<0>, SDTCisPtrTy<1>, SDTCisPtrTy<2>, SDTCisInt<3>, +]>; +def indexedload : SDNode<"MyTgt::INDEXEDLOAD", SDTIndexedLoad, [ + SDNPHasChain, SDNPMayLoad, SDNPMemOperand +]>; +def : GINodeEquiv; + +def LDPostInc : I<(outs GPR32:$ptr_out, GPR32:$val), (ins GPR32:$addr, GPR32:$off), []>; +def : Pat<(indexedload (p0 GPR32:$addr), (i32 GPR32:$off), (i32 1)), + (LDPostInc GPR32:$addr, GPR32:$off) +>; + +// CHECK: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_INDEXED_LOAD, +// CHECK-NEXT: // MIs[0] ptr_out +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] val +// CHECK-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] addr +// CHECK-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/2, /*SizeInBits*/32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] off +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/3, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/3, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] Operand 4 +// CHECK-NEXT: GIM_CheckLiteralInt, /*MI*/0, /*Op*/4, 1, +// CHECK-NEXT: // (indexedload:{ *:[i32] }:{ *:[i32] } GPR32:{ *:[i32] }:$addr, GPR32:{ *:[i32] }:$off, 1:{ *:[i32] }) => (LDPostInc:{ *:[i32] }:{ *:[i32] } GPR32:{ *:[i32] }:$addr, GPR32:{ *:[i32] }:$off) +// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::LDPostInc, +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // ptr_out +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // val +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/2, // addr +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/3, // off +// CHECK-NEXT: GIR_MergeMemOperands, /*InsnID*/0, /*MergeInsnID's*/0, GIU_MergeMemOperands_EndOfList, +// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, +// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, + +def LDPreInc : I<(outs GPR32:$val, GPR32:$ptr_out), (ins GPR32:$addr, GPR32:$off), []>; +def : Pat<(indexedload (p0 GPR32:$addr), (i32 GPR32:$off), (i32 0)), + (LDPreInc GPR32:$addr, GPR32:$off) +>; + +// CHECK: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_INDEXED_LOAD, +// CHECK-NEXT: // MIs[0] val +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] ptr_out +// CHECK-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] addr +// CHECK-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/2, /*SizeInBits*/32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] off +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/3, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/3, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] Operand 4 +// CHECK-NEXT: GIM_CheckLiteralInt, /*MI*/0, /*Op*/4, 0, +// CHECK-NEXT: // (indexedload:{ *:[i32] }:{ *:[i32] } GPR32:{ *:[i32] }:$addr, GPR32:{ *:[i32] }:$off, 0:{ *:[i32] }) => (LDPreInc:{ *:[i32] }:{ *:[i32] } GPR32:{ *:[i32] }:$addr, GPR32:{ *:[i32] }:$off) +// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::LDPreInc, +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // val +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // ptr_out +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/2, // addr +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/3, // off +// CHECK-NEXT: GIR_MergeMemOperands, /*InsnID*/0, /*MergeInsnID's*/0, GIU_MergeMemOperands_EndOfList, +// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, +// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, + +def SDTIndexedStore : SDTypeProfile<1, 4, [ + SDTCisInt<1>, SDTCisSameAs<0,2>, SDTCisPtrTy<2>, SDTCisInt<3>, +]>; +def indexedstore : SDNode<"MyTgt::INDEXEDSTORE", SDTIndexedStore, [ + SDNPHasChain, SDNPMayStore, SDNPMemOperand +]>; +def : GINodeEquiv; + +def STPostInc : I<(outs GPR32:$ptr_out), (ins GPR32:$val, GPR32:$addr, GPR32:$off), []>; +def : Pat<(indexedstore (i32 GPR32:$val), (p0 GPR32:$addr), (i32 GPR32:$off), (i32 1)), + (STPostInc GPR32:$val, GPR32:$addr, GPR32:$off) +>; + +// CHECK: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_INDEXED_STORE, +// CHECK-NEXT: // MIs[0] ptr_out +// CHECK-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/0, /*SizeInBits*/32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] val +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] addr +// CHECK-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/2, /*SizeInBits*/32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] off +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/3, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/3, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] Operand 4 +// CHECK-NEXT: GIM_CheckLiteralInt, /*MI*/0, /*Op*/4, 1, +// CHECK-NEXT: // (indexedstore:{ *:[i32] } GPR32:{ *:[i32] }:$val, GPR32:{ *:[i32] }:$addr, GPR32:{ *:[i32] }:$off, 1:{ *:[i32] }) => (STPostInc:{ *:[i32] } GPR32:{ *:[i32] }:$val, GPR32:{ *:[i32] }:$addr, GPR32:{ *:[i32] }:$off) +// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::STPostInc, +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // ptr_out +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // val +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/2, // addr +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/3, // off +// CHECK-NEXT: GIR_MergeMemOperands, /*InsnID*/0, /*MergeInsnID's*/0, GIU_MergeMemOperands_EndOfList, +// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, +// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, + +def STPreInc : I<(outs GPR32:$ptr_out), (ins GPR32:$val, GPR32:$addr, GPR32:$off), []>; +def : Pat<(indexedstore (i32 GPR32:$val), (p0 GPR32:$addr), (i32 GPR32:$off), (i32 0)), + (STPreInc GPR32:$val, GPR32:$addr, GPR32:$off) +>; + +// CHECK: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_INDEXED_STORE, +// CHECK-NEXT: // MIs[0] ptr_out +// CHECK-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/0, /*SizeInBits*/32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] val +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] addr +// CHECK-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/2, /*SizeInBits*/32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] off +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/3, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/3, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] Operand 4 +// CHECK-NEXT: GIM_CheckLiteralInt, /*MI*/0, /*Op*/4, 0, +// CHECK-NEXT: // (indexedstore:{ *:[i32] } GPR32:{ *:[i32] }:$val, GPR32:{ *:[i32] }:$addr, GPR32:{ *:[i32] }:$off, 0:{ *:[i32] }) => (STPreInc:{ *:[i32] } GPR32:{ *:[i32] }:$val, GPR32:{ *:[i32] }:$addr, GPR32:{ *:[i32] }:$off) +// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::STPreInc, +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // ptr_out +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // val +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/2, // addr +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/3, // off +// CHECK-NEXT: GIR_MergeMemOperands, /*InsnID*/0, /*MergeInsnID's*/0, GIU_MergeMemOperands_EndOfList, +// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, +// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, +