1 // 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
3 include "llvm/Target/Target.td"
4 include "GlobalISelEmitterCommon.td"
6 // Test the generation of patterns with multiple output operands and makes sure that
7 // we are able to create a new instruction if necessary, or just simply change the
8 // opcode if the input and output operands of the generic instruction are the same
9 // as the target-specific instruction
11 // Verify that patterns with multiple outputs are translated
13 //-----------------------------------------------------------------------------
14 // Test where only the opcode is mutated during ISel
16 let Constraints = "$ptr_out = $addr" in
17 def LDPost : I<(outs GPR32:$val, GPR32:$ptr_out), (ins GPR32:$addr, GPR32:$off), []>;
18 def SDTLoadPost : SDTypeProfile<2, 2, [
19 SDTCisInt<0>, SDTCisSameAs<1,2>, SDTCisPtrTy<2>, SDTCisInt<3>,
21 def loadpost : SDNode<"MyTgt::LOADPOST", SDTLoadPost, [
22 SDNPHasChain, SDNPMayLoad, SDNPMemOperand
24 def G_POST_LOAD : MyTargetGenericInstruction{
25 let OutOperandList = (outs type0:$val, type1:$ptr_out);
26 let InOperandList = (ins type1:$ptr, type2:$off);
28 def : GINodeEquiv<G_POST_LOAD, loadpost>;
29 def : Pat<(loadpost (p0 GPR32:$addr), (i32 GPR32:$off)),
30 (LDPost GPR32:$addr, GPR32:$off)
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] addr
41 // 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] off
44 // 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,
50 //-----------------------------------------------------------------------------
51 // Test where a whole new MIR instruction is created during ISel
53 def TWO_INS : I<(outs GPR32:$out1, GPR32:$out2), (ins GPR32:$in1, GPR32:$in2), []>;
55 def SDTTwoIn : SDTypeProfile<2, 2, [
56 SDTCisInt<0>, SDTCisInt<1>, SDTCisInt<2>, SDTCisInt<3>
58 def two_in : SDNode<"MyTgt::TWO_IN", SDTTwoIn, []>;
59 def G_TWO_IN : MyTargetGenericInstruction{
60 let OutOperandList = (outs type0:$out1, type0:$out2);
61 let InOperandList = (ins type0:$in1, type0:$in2);
63 def : GINodeEquiv<G_TWO_IN, two_in>;
65 // Swap the input operands for an easy way to force the creation of a new instruction
66 def : Pat<(two_in GPR32:$i1, GPR32:$i2), (TWO_INS GPR32:$i2, GPR32:$i1)>;
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] i1
76 // 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] i2
79 // 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, // i2
86 // CHECK-NEXT: GIR_RootToRootCopy, /*OpIdx*/2, // i1
87 // CHECK-NEXT: GIR_RootConstrainSelectedInstOperands,
88 // CHECK-NEXT: // GIR_Coverage
89 // CHECK-NEXT: GIR_EraseRootFromParent_Done,
91 //-----------------------------------------------------------------------------
92 // Test where implicit defs are added using Defs.
95 def ImplicitDefInstr : I<(outs GPR32:$dst), (ins GPR32:$src), []>;
96 def OtherInstr : I<(outs GPR32:$dst), (ins GPR32:$src), []>;
98 def : Pat<(i32 (add i32:$src, i32:$src)),
99 (OtherInstr (ImplicitDefInstr GPR32:$src))>;
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] src
106 // CHECK-NEXT: GIM_RootCheckType, /*Op*/1, /*Type*/GILLT_s32,
107 // CHECK-NEXT: // MIs[0] src
108 // 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, // src
114 // 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_Coverage
121 // CHECK-NEXT: GIR_EraseRootFromParent_Done,
123 //-----------------------------------------------------------------------------
124 // Test when the inner instruction in the output pattern has two outs
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] src
131 // CHECK-NEXT: GIM_RootCheckType, /*Op*/1, /*Type*/GILLT_s32,
132 // CHECK-NEXT: // MIs[0] src
133 // 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, // src
141 // 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_Coverage
147 // CHECK-NEXT: GIR_EraseRootFromParent_Done,
149 def TwoOutsInstr : I<(outs GPR32:$out1, GPR32:$out2), (ins GPR32:$src), []>;
151 def : Pat<(i32 (add i32:$src, i32:$src)),
152 (OtherInstr (TwoOutsInstr GPR32:$src))>;