153 lines · plain
1// RUN: llvm-tblgen -gen-global-isel -optimize-match-table=false -warn-on-skipped-patterns -I %p/../../../include -I %p/../Common %s | FileCheck %s2 3include "llvm/Target/Target.td"4include "GlobalISelEmitterCommon.td"5 6// Test the generation of patterns with multiple output operands and makes sure that7// we are able to create a new instruction if necessary, or just simply change the8// opcode if the input and output operands of the generic instruction are the same9// as the target-specific instruction10 11// Verify that patterns with multiple outputs are translated12 13//-----------------------------------------------------------------------------14// Test where only the opcode is mutated during ISel15 16let Constraints = "$ptr_out = $addr" in17def LDPost : I<(outs GPR32:$val, GPR32:$ptr_out), (ins GPR32:$addr, GPR32:$off), []>;18def SDTLoadPost : SDTypeProfile<2, 2, [19 SDTCisInt<0>, SDTCisSameAs<1,2>, SDTCisPtrTy<2>, SDTCisInt<3>,20]>;21def loadpost : SDNode<"MyTgt::LOADPOST", SDTLoadPost, [22 SDNPHasChain, SDNPMayLoad, SDNPMemOperand23]>;24def G_POST_LOAD : MyTargetGenericInstruction{25 let OutOperandList = (outs type0:$val, type1:$ptr_out);26 let InOperandList = (ins type1:$ptr, type2:$off);27}28def : GINodeEquiv<G_POST_LOAD, loadpost>;29def : Pat<(loadpost (p0 GPR32:$addr), (i32 GPR32:$off)),30 (LDPost GPR32:$addr, GPR32:$off)31>;32 33// CHECK: GIM_CheckOpcode, /*MI*/0, GIMT_Encode2(MyTarget::G_POST_LOAD),34// CHECK-NEXT: // MIs[0] DstI[val]35// CHECK-NEXT: GIM_RootCheckType, /*Op*/0, /*Type*/GILLT_s32,36// CHECK-NEXT: GIM_RootCheckRegBankForClass, /*Op*/0, /*RC*/GIMT_Encode2(MyTarget::GPR32RegClassID),37// CHECK-NEXT: // MIs[0] DstI[ptr_out]38// CHECK-NEXT: GIM_RootCheckType, /*Op*/1, /*Type*/GILLT_p0s32,39// CHECK-NEXT: GIM_RootCheckRegBankForClass, /*Op*/1, /*RC*/GIMT_Encode2(MyTarget::GPR32RegClassID),40// CHECK-NEXT: // MIs[0] addr41// CHECK-NEXT: GIM_RootCheckType, /*Op*/2, /*Type*/GILLT_p0s32,42// CHECK-NEXT: GIM_RootCheckRegBankForClass, /*Op*/2, /*RC*/GIMT_Encode2(MyTarget::GPR32RegClassID),43// CHECK-NEXT: // MIs[0] off44// CHECK-NEXT: GIM_RootCheckType, /*Op*/3, /*Type*/GILLT_s32,45// CHECK-NEXT: GIM_RootCheckRegBankForClass, /*Op*/3, /*RC*/GIMT_Encode2(MyTarget::GPR32RegClassID),46// CHECK-NEXT: // (loadpost:{ *:[i32] }:{ *:[i32] } GPR32:{ *:[i32] }:$addr, GPR32:{ *:[i32] }:$off) => (LDPost:{ *:[i32] }:{ *:[i32] } GPR32:{ *:[i32] }:$addr, GPR32:{ *:[i32] }:$off)47// CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/GIMT_Encode2(MyTarget::LDPost),48// CHECK-NEXT: GIR_RootConstrainSelectedInstOperands,49 50//-----------------------------------------------------------------------------51// Test where a whole new MIR instruction is created during ISel52 53def TWO_INS : I<(outs GPR32:$out1, GPR32:$out2), (ins GPR32:$in1, GPR32:$in2), []>;54 55def SDTTwoIn : SDTypeProfile<2, 2, [56 SDTCisInt<0>, SDTCisInt<1>, SDTCisInt<2>, SDTCisInt<3>57]>;58def two_in : SDNode<"MyTgt::TWO_IN", SDTTwoIn, []>;59def G_TWO_IN : MyTargetGenericInstruction{60 let OutOperandList = (outs type0:$out1, type0:$out2);61 let InOperandList = (ins type0:$in1, type0:$in2);62}63def : GINodeEquiv<G_TWO_IN, two_in>;64 65// Swap the input operands for an easy way to force the creation of a new instruction66def : Pat<(two_in GPR32:$i1, GPR32:$i2), (TWO_INS GPR32:$i2, GPR32:$i1)>;67 68// CHECK: GIM_CheckOpcode, /*MI*/0, GIMT_Encode2(MyTarget::G_TWO_IN),69// CHECK-NEXT: // MIs[0] DstI[out1]70// CHECK-NEXT: GIM_RootCheckType, /*Op*/0, /*Type*/GILLT_s32,71// CHECK-NEXT: GIM_RootCheckRegBankForClass, /*Op*/0, /*RC*/GIMT_Encode2(MyTarget::GPR32RegClassID),72// CHECK-NEXT: // MIs[0] DstI[out2]73// CHECK-NEXT: GIM_RootCheckType, /*Op*/1, /*Type*/GILLT_s32,74// CHECK-NEXT: GIM_RootCheckRegBankForClass, /*Op*/1, /*RC*/GIMT_Encode2(MyTarget::GPR32RegClassID),75// CHECK-NEXT: // MIs[0] i176// CHECK-NEXT: GIM_RootCheckType, /*Op*/2, /*Type*/GILLT_s32,77// CHECK-NEXT: GIM_RootCheckRegBankForClass, /*Op*/2, /*RC*/GIMT_Encode2(MyTarget::GPR32RegClassID),78// CHECK-NEXT: // MIs[0] i279// CHECK-NEXT: GIM_RootCheckType, /*Op*/3, /*Type*/GILLT_s32,80// CHECK-NEXT: GIM_RootCheckRegBankForClass, /*Op*/3, /*RC*/GIMT_Encode2(MyTarget::GPR32RegClassID),81// CHECK-NEXT: // (two_in:{ *:[i32] }:{ *:[i32] } GPR32:{ *:[i32] }:$i1, GPR32:{ *:[i32] }:$i2) => (TWO_INS:{ *:[i32] }:{ *:[i32] } GPR32:{ *:[i32] }:$i2, GPR32:{ *:[i32] }:$i1)82// CHECK-NEXT: GIR_BuildRootMI, /*Opcode*/GIMT_Encode2(MyTarget::TWO_INS),83// CHECK-NEXT: GIR_RootToRootCopy, /*OpIdx*/0, // DstI[out1]84// CHECK-NEXT: GIR_RootToRootCopy, /*OpIdx*/1, // DstI[out2]85// CHECK-NEXT: GIR_RootToRootCopy, /*OpIdx*/3, // i286// CHECK-NEXT: GIR_RootToRootCopy, /*OpIdx*/2, // i187// CHECK-NEXT: GIR_RootConstrainSelectedInstOperands,88// CHECK-NEXT: // GIR_Coverage89// CHECK-NEXT: GIR_EraseRootFromParent_Done,90 91//-----------------------------------------------------------------------------92// Test where implicit defs are added using Defs.93 94let Defs = [R0] in95def ImplicitDefInstr : I<(outs GPR32:$dst), (ins GPR32:$src), []>;96def OtherInstr : I<(outs GPR32:$dst), (ins GPR32:$src), []>;97 98def : Pat<(i32 (add i32:$src, i32:$src)),99 (OtherInstr (ImplicitDefInstr GPR32:$src))>;100 101// CHECK: GIM_CheckOpcode, /*MI*/0, GIMT_Encode2(TargetOpcode::G_ADD),102// CHECK-NEXT: // MIs[0] DstI[dst]103// CHECK-NEXT: GIM_RootCheckType, /*Op*/0, /*Type*/GILLT_s32,104// CHECK-NEXT: GIM_RootCheckRegBankForClass, /*Op*/0, /*RC*/GIMT_Encode2(MyTarget::GPR32RegClassID),105// CHECK-NEXT: // MIs[0] src106// CHECK-NEXT: GIM_RootCheckType, /*Op*/1, /*Type*/GILLT_s32,107// CHECK-NEXT: // MIs[0] src108// CHECK-NEXT: GIM_CheckIsSameOperand, /*MI*/0, /*OpIdx*/2, /*OtherMI*/0, /*OtherOpIdx*/1,109// CHECK-NEXT: // (add:{ *:[i32] } i32:{ *:[i32] }:$src, i32:{ *:[i32] }:$src) => (OtherInstr:{ *:[i32] } (ImplicitDefInstr:{ *:[i32] }:{ *:[i32] } GPR32:{ *:[i32] }:$src))110// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s32,111// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/GIMT_Encode2(MyTarget::ImplicitDefInstr),112// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/GIMT_Encode2(RegState::Define),113// CHECK-NEXT: GIR_Copy, /*NewInsnID*/1, /*OldInsnID*/0, /*OpIdx*/1, // src114// CHECK-NEXT: GIR_SetImplicitDefDead, /*InsnID*/1, /*OpIdx for MyTarget::R0*/0,115// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/1,116// CHECK-NEXT: GIR_BuildRootMI, /*Opcode*/GIMT_Encode2(MyTarget::OtherInstr),117// CHECK-NEXT: GIR_RootToRootCopy, /*OpIdx*/0, // DstI[dst]118// CHECK-NEXT: GIR_AddSimpleTempRegister, /*InsnID*/0, /*TempRegID*/0,119// CHECK-NEXT: GIR_RootConstrainSelectedInstOperands,120// CHECK-NEXT: // GIR_Coverage121// CHECK-NEXT: GIR_EraseRootFromParent_Done,122 123//-----------------------------------------------------------------------------124// Test when the inner instruction in the output pattern has two outs125 126// CHECK: GIM_CheckOpcode, /*MI*/0, GIMT_Encode2(TargetOpcode::G_ADD),127// CHECK-NEXT: // MIs[0] DstI[dst]128// CHECK-NEXT: GIM_RootCheckType, /*Op*/0, /*Type*/GILLT_s32,129// CHECK-NEXT: GIM_RootCheckRegBankForClass, /*Op*/0, /*RC*/GIMT_Encode2(MyTarget::GPR32RegClassID),130// CHECK-NEXT: // MIs[0] src131// CHECK-NEXT: GIM_RootCheckType, /*Op*/1, /*Type*/GILLT_s32,132// CHECK-NEXT: // MIs[0] src133// CHECK-NEXT: GIM_CheckIsSameOperand, /*MI*/0, /*OpIdx*/2, /*OtherMI*/0, /*OtherOpIdx*/1,134// CHECK-NEXT: // (add:{ *:[i32] } i32:{ *:[i32] }:$src, i32:{ *:[i32] }:$src) => (OtherInstr:{ *:[i32] } (TwoOutsInstr:{ *:[i32] }:{ *:[i32] } GPR32:{ *:[i32] }:$src))135// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/1, /*TypeID*/GILLT_s32,136// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s32,137// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/GIMT_Encode2(MyTarget::TwoOutsInstr),138// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/GIMT_Encode2(RegState::Define),139// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/1, /*TempRegFlags*/GIMT_Encode2(RegState::Define|RegState::Dead),140// CHECK-NEXT: GIR_Copy, /*NewInsnID*/1, /*OldInsnID*/0, /*OpIdx*/1, // src141// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/1,142// CHECK-NEXT: GIR_BuildRootMI, /*Opcode*/GIMT_Encode2(MyTarget::OtherInstr),143// CHECK-NEXT: GIR_RootToRootCopy, /*OpIdx*/0, // DstI[dst]144// CHECK-NEXT: GIR_AddSimpleTempRegister, /*InsnID*/0, /*TempRegID*/0,145// CHECK-NEXT: GIR_RootConstrainSelectedInstOperands,146// CHECK-NEXT: // GIR_Coverage147// CHECK-NEXT: GIR_EraseRootFromParent_Done,148 149def TwoOutsInstr : I<(outs GPR32:$out1, GPR32:$out2), (ins GPR32:$src), []>;150 151def : Pat<(i32 (add i32:$src, i32:$src)),152 (OtherInstr (TwoOutsInstr GPR32:$src))>;153