llvm.org GIT mirror llvm / 2de9fad
[ARM GlobalISel] Support G_CTLZ and G_CTLZ_ZERO_UNDEF We can now select CLZ via the TableGen'erated code, so support G_CTLZ and G_CTLZ_ZERO_UNDEF throughout the pipeline for types <= s32. Legalizer: If the CLZ instruction is available, use it for both G_CTLZ and G_CTLZ_ZERO_UNDEF. Otherwise, use a libcall for G_CTLZ_ZERO_UNDEF and lower G_CTLZ in terms of it. In order to achieve this we need to add support to the LegalizerHelper for the legalization of G_CTLZ_ZERO_UNDEF for s32 as a libcall (__clzsi2). We also need to allow lowering of G_CTLZ in terms of G_CTLZ_ZERO_UNDEF if that is supported as a libcall, as opposed to just if it is Legal or Custom. Due to a minor refactoring of the helper function in charge of this, we will also allow the same behaviour for G_CTTZ and G_CTPOP. This is not going to be a problem in practice since we don't yet have support for treating G_CTTZ and G_CTPOP as libcalls (not even in DAGISel). Reg bank select: Map G_CTLZ to GPR. G_CTLZ_ZERO_UNDEF should not make it to this point. Instruction select: Nothing to do. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@347545 91177308-0d34-0410-b5e6-96231b3b80d8 Diana Picus 11 months ago
6 changed file(s) with 255 addition(s) and 9 deletion(s). Raw diff Collapse all Expand all
9292 case TargetOpcode::G_UREM:
9393 assert(Size == 32 && "Unsupported size");
9494 return RTLIB::UREM_I32;
95 case TargetOpcode::G_CTLZ_ZERO_UNDEF:
96 assert(Size == 32 && "Unsupported size");
97 return RTLIB::CTLZ_I32;
9598 case TargetOpcode::G_FADD:
9699 assert((Size == 32 || Size == 64) && "Unsupported size");
97100 return Size == 64 ? RTLIB::ADD_F64 : RTLIB::ADD_F32;
188191 case TargetOpcode::G_SDIV:
189192 case TargetOpcode::G_UDIV:
190193 case TargetOpcode::G_SREM:
191 case TargetOpcode::G_UREM: {
194 case TargetOpcode::G_UREM:
195 case TargetOpcode::G_CTLZ_ZERO_UNDEF: {
192196 Type *HLTy = Type::getInt32Ty(Ctx);
193197 auto Status = simpleLibcall(MI, MIRBuilder, Size, HLTy);
194198 if (Status != Legalized)
11071111 LegalizerHelper::lowerBitCount(MachineInstr &MI, unsigned TypeIdx, LLT Ty) {
11081112 unsigned Opc = MI.getOpcode();
11091113 auto &TII = *MI.getMF()->getSubtarget().getInstrInfo();
1110 auto isLegalOrCustom = [this](const LegalityQuery &Q) {
1114 auto isSupported = [this](const LegalityQuery &Q) {
11111115 auto QAction = LI.getAction(Q).Action;
1112 return QAction == Legal || QAction == Custom;
1116 return QAction == Legal || QAction == Libcall || QAction == Custom;
11131117 };
11141118 switch (Opc) {
11151119 default:
11231127 case TargetOpcode::G_CTLZ: {
11241128 unsigned SrcReg = MI.getOperand(1).getReg();
11251129 unsigned Len = Ty.getSizeInBits();
1126 if (isLegalOrCustom({TargetOpcode::G_CTLZ_ZERO_UNDEF, {Ty}})) {
1127 // If CTLZ_ZERO_UNDEF is legal or custom, emit that and a select with
1128 // zero.
1130 if (isSupported({TargetOpcode::G_CTLZ_ZERO_UNDEF, {Ty}})) {
1131 // If CTLZ_ZERO_UNDEF is supported, emit that and a select for zero.
11291132 auto MIBCtlzZU =
11301133 MIRBuilder.buildInstr(TargetOpcode::G_CTLZ_ZERO_UNDEF, Ty, SrcReg);
11311134 auto MIBZero = MIRBuilder.buildConstant(Ty, 0);
11721175 case TargetOpcode::G_CTTZ: {
11731176 unsigned SrcReg = MI.getOperand(1).getReg();
11741177 unsigned Len = Ty.getSizeInBits();
1175 if (isLegalOrCustom({TargetOpcode::G_CTTZ_ZERO_UNDEF, {Ty}})) {
1178 if (isSupported({TargetOpcode::G_CTTZ_ZERO_UNDEF, {Ty}})) {
11761179 // If CTTZ_ZERO_UNDEF is legal or custom, emit that and a select with
11771180 // zero.
11781181 auto MIBCttzZU =
11961199 auto MIBTmp = MIRBuilder.buildInstr(
11971200 TargetOpcode::G_AND, Ty, MIBNot,
11981201 MIRBuilder.buildInstr(TargetOpcode::G_ADD, Ty, SrcReg, MIBCstNeg1));
1199 if (!isLegalOrCustom({TargetOpcode::G_CTPOP, {Ty}}) &&
1200 isLegalOrCustom({TargetOpcode::G_CTLZ, {Ty}})) {
1202 if (!isSupported({TargetOpcode::G_CTPOP, {Ty}}) &&
1203 isSupported({TargetOpcode::G_CTLZ, {Ty}})) {
12011204 auto MIBCstLen = MIRBuilder.buildConstant(Ty, Len);
12021205 MIRBuilder.buildInstr(
12031206 TargetOpcode::G_SUB, MI.getOperand(0).getReg(),
107107 getActionDefinitionsBuilder(G_PTRTOINT).legalFor({{s32, p0}});
108108
109109 getActionDefinitionsBuilder({G_ASHR, G_LSHR, G_SHL}).legalFor({s32});
110
111 if (ST.hasV5TOps()) {
112 getActionDefinitionsBuilder(G_CTLZ)
113 .legalFor({s32})
114 .clampScalar(0, s32, s32);
115 getActionDefinitionsBuilder(G_CTLZ_ZERO_UNDEF)
116 .lowerFor({s32})
117 .clampScalar(0, s32, s32);
118 } else {
119 getActionDefinitionsBuilder(G_CTLZ_ZERO_UNDEF)
120 .libcallFor({s32})
121 .clampScalar(0, s32, s32);
122 getActionDefinitionsBuilder(G_CTLZ)
123 .lowerFor({s32})
124 .clampScalar(0, s32, s32);
125 }
110126
111127 getActionDefinitionsBuilder(G_GEP).legalFor({{p0, s32}});
112128
233233 case G_GEP:
234234 case G_INTTOPTR:
235235 case G_PTRTOINT:
236 case G_CTLZ:
236237 // FIXME: We're abusing the fact that everything lives in a GPR for now; in
237238 // the real world we would use different mappings.
238239 OperandsMapping = &ARM::ValueMappings[ARM::GPR3OpsIdx];
0 # RUN: llc -mtriple arm-linux-gnueabi -mattr=+v5t -run-pass=legalizer %s -o - | FileCheck %s -check-prefixes=CHECK,CLZ
1 # RUN: llc -mtriple arm-linux-gnueabi -mattr=-v5t -run-pass=legalizer %s -o - | FileCheck %s -check-prefixes=CHECK,LIBCALLS
2 --- |
3 define void @test_ctlz_s32() { ret void }
4 define void @test_ctlz_zero_undef_s32() { ret void }
5
6 ; same as above but with extensions
7 define void @test_ctlz_s16() { ret void }
8 define void @test_ctlz_zero_undef_s8() { ret void }
9 ...
10 ---
11 name: test_ctlz_s32
12 # CHECK-LABEL: name: test_ctlz_s32
13 legalized: false
14 # CHECK: legalized: true
15 regBankSelected: false
16 selected: false
17 tracksRegLiveness: true
18 registers:
19 - { id: 0, class: _ }
20 - { id: 1, class: _ }
21 body: |
22 bb.0:
23 liveins: $r0
24
25 ; CHECK: [[X:%[0-9]+]]:_(s32) = COPY $r0
26 %0(s32) = COPY $r0
27
28 ; CLZ: [[R:%[0-9]+]]:_(s32) = G_CTLZ [[X]]
29 ; LIBCALLS-NOT: G_CTLZ
30 ; LIBCALLS: ADJCALLSTACKDOWN
31 ; LIBCALLS: $r0 = COPY [[X]]
32 ; LIBCALLS: BL &__clzsi2, {{.*}}, implicit $r0, implicit-def $r0
33 ; LIBCALLS: [[COUNT:%[0-9]+]]:_(s32) = COPY $r0
34 ; LIBCALLS: ADJCALLSTACKUP
35 ; LIBCALLS-NOT: G_CTLZ
36 ; LIBCALLS: [[ZERO:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
37 ; LIBCALLS: [[BITS:%[0-9]+]]:_(s32) = G_CONSTANT i32 32
38 ; LIBCALLS: [[CMP:%[0-9]+]]:_(s1) = G_ICMP intpred(eq), [[X]](s32), [[ZERO]]
39 ; LIBCALLS: [[R:%[0-9]+]]:_(s32) = G_SELECT [[CMP]](s1), [[BITS]], [[COUNT]]
40 ; LIBCALLS-NOT: G_CTLZ
41 %1(s32) = G_CTLZ %0
42
43 ; CHECK: $r0 = COPY [[R]]
44 $r0 = COPY %1(s32)
45 BX_RET 14, $noreg, implicit $r0
46 ...
47 ---
48 name: test_ctlz_zero_undef_s32
49 # CHECK-LABEL: name: test_ctlz_zero_undef_s32
50 legalized: false
51 # CHECK: legalized: true
52 regBankSelected: false
53 selected: false
54 tracksRegLiveness: true
55 registers:
56 - { id: 0, class: _ }
57 - { id: 1, class: _ }
58 body: |
59 bb.0:
60 liveins: $r0
61
62 ; CHECK: [[X:%[0-9]+]]:_(s32) = COPY $r0
63 %0(s32) = COPY $r0
64
65 ; CLZ: [[R:%[0-9]+]]:_(s32) = G_CTLZ [[X]]
66 ; LIBCALLS-NOT: G_CTLZ
67 ; LIBCALLS: ADJCALLSTACKDOWN
68 ; LIBCALLS: $r0 = COPY [[X]]
69 ; LIBCALLS: BL &__clzsi2, {{.*}}, implicit $r0, implicit-def $r0
70 ; LIBCALLS: [[R:%[0-9]+]]:_(s32) = COPY $r0
71 ; LIBCALLS: ADJCALLSTACKUP
72 ; LIBCALLS-NOT: G_CTLZ
73 %1(s32) = G_CTLZ_ZERO_UNDEF %0
74
75 ; CHECK: $r0 = COPY [[R]]
76 $r0 = COPY %1(s32)
77 BX_RET 14, $noreg, implicit $r0
78 ...
79 ---
80 name: test_ctlz_s16
81 # CHECK-LABEL: name: test_ctlz_s16
82 legalized: false
83 # CHECK: legalized: true
84 regBankSelected: false
85 selected: false
86 tracksRegLiveness: true
87 registers:
88 - { id: 0, class: _ }
89 - { id: 1, class: _ }
90 - { id: 2, class: _ }
91 - { id: 3, class: _ }
92 body: |
93 bb.0:
94 liveins: $r0
95
96 ; CHECK: [[X:%[0-9]+]]:_(s32) = COPY $r0
97 ; CHECK: [[BITMASK:%[0-9]+]]:_(s32) = G_CONSTANT i32 65535
98 ; CHECK: [[XAGAIN:%[0-9]+]]:_(s32) = COPY [[X]]
99 ; CHECK: [[X32:%[0-9]+]]:_(s32) = G_AND [[XAGAIN]], [[BITMASK]]
100 %0(s32) = COPY $r0
101 %1(s16) = G_TRUNC %0(s32)
102
103 ; Check that the operation is performed for 32 bits
104 ; CLZ: [[COUNT:%[0-9]+]]:_(s32) = G_CTLZ [[X32]]
105 ; LIBCALLS-NOT: G_CTLZ
106 ; LIBCALLS: ADJCALLSTACKDOWN
107 ; LIBCALLS: $r0 = COPY [[X32]]
108 ; LIBCALLS: BL &__clzsi2, {{.*}}, implicit $r0, implicit-def $r0
109 ; LIBCALLS: [[UNDEFCOUNT:%[0-9]+]]:_(s32) = COPY $r0
110 ; LIBCALLS: ADJCALLSTACKUP
111 ; LIBCALLS-NOT: G_CTLZ
112 ; LIBCALLS: [[ZERO:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
113 ; LIBCALLS: [[BITS:%[0-9]+]]:_(s32) = G_CONSTANT i32 32
114 ; LIBCALLS: [[CMP:%[0-9]+]]:_(s1) = G_ICMP intpred(eq), {{%[0-9]+}}(s32), [[ZERO]]
115 ; LIBCALLS: [[COUNT:%[0-9]+]]:_(s32) = G_SELECT [[CMP]](s1), [[BITS]], [[UNDEFCOUNT]]
116 ; LIBCALLS-NOT: G_CTLZ
117 ; CHECK: [[BITDIFF:%[0-9]+]]:_(s32) = G_CONSTANT i32 16
118 ; CHECK: [[R32:%[0-9]+]]:_(s32) = G_SUB [[COUNT]], [[BITDIFF]]
119 %2(s16) = G_CTLZ %1
120
121 ; CHECK: [[BITDIFF:%[0-9]+]]:_(s32) = G_CONSTANT i32 16
122 ; CHECK: [[RAGAIN:%[0-9]+]]:_(s32) = COPY [[R32]]
123 ; CHECK: [[SHIFTEDR:%[0-9]+]]:_(s32) = G_SHL [[RAGAIN]], [[BITDIFF]]
124 ; CHECK: [[R:%[0-9]+]]:_(s32) = G_ASHR [[SHIFTEDR]], [[BITDIFF]]
125 ; CHECK: $r0 = COPY [[R]]
126 %3(s32) = G_SEXT %2(s16)
127 $r0 = COPY %3(s32)
128 BX_RET 14, $noreg, implicit $r0
129 ...
130 ---
131 name: test_ctlz_zero_undef_s8
132 # CHECK-LABEL: name: test_ctlz_zero_undef_s8
133 legalized: false
134 # CHECK: legalized: true
135 regBankSelected: false
136 selected: false
137 tracksRegLiveness: true
138 registers:
139 - { id: 0, class: _ }
140 - { id: 1, class: _ }
141 - { id: 2, class: _ }
142 - { id: 3, class: _ }
143 body: |
144 bb.0:
145 liveins: $r0
146
147 ; CHECK: [[X:%[0-9]+]]:_(s32) = COPY $r0
148 ; CHECK: [[BITMASK:%[0-9]+]]:_(s32) = G_CONSTANT i32 255
149 ; CHECK: [[XAGAIN:%[0-9]+]]:_(s32) = COPY [[X]]
150 ; CHECK: [[X32:%[0-9]+]]:_(s32) = G_AND [[XAGAIN]], [[BITMASK]]
151 %0(s32) = COPY $r0
152 %1(s8) = G_TRUNC %0(s32)
153
154 ; Check that the operation is performed for 32 bits
155 ; CLZ: [[COUNT:%[0-9]+]]:_(s32) = G_CTLZ
156 ; CLZ-NOT: G_CTLZ_ZERO_UNDEF
157 ; LIBCALLS-NOT: G_CTLZ
158 ; LIBCALLS: ADJCALLSTACKDOWN
159 ; LIBCALLS: $r0 = COPY [[X32]]
160 ; LIBCALLS: BL &__clzsi2, {{.*}}, implicit $r0, implicit-def $r0
161 ; LIBCALLS: [[COUNT:%[0-9]+]]:_(s32) = COPY $r0
162 ; LIBCALLS: ADJCALLSTACKUP
163 ; LIBCALLS-NOT: G_CTLZ
164 ; CHECK: [[BITDIFF:%[0-9]+]]:_(s32) = G_CONSTANT i32 24
165 ; CHECK: [[R32:%[0-9]+]]:_(s32) = G_SUB [[COUNT]], [[BITDIFF]]
166 %2(s8) = G_CTLZ_ZERO_UNDEF %1
167
168 ; CHECK: [[BITDIFF:%[0-9]+]]:_(s32) = G_CONSTANT i32 24
169 ; CHECK: [[RAGAIN:%[0-9]+]]:_(s32) = COPY [[R32]]
170 ; CHECK: [[SHIFTEDR:%[0-9]+]]:_(s32) = G_SHL [[RAGAIN]], [[BITDIFF]]
171 ; CHECK: [[R:%[0-9]+]]:_(s32) = G_ASHR [[SHIFTEDR]], [[BITDIFF]]
172 ; CHECK: $r0 = COPY [[R]]
173 %3(s32) = G_SEXT %2(s8)
174 $r0 = COPY %3(s32)
175 BX_RET 14, $noreg, implicit $r0
176 ...
2626 define void @test_inttoptr_s32() { ret void }
2727 define void @test_ptrtoint_s32() { ret void }
2828
29 define void @test_ctlz_s32() #3 { ret void }
30
2931 @a_global = global float 1.0
3032 define void @test_globals() { ret void }
3133
8284 attributes #0 = { "target-features"="+vfp2"}
8385 attributes #1 = { "target-features"="+hwdiv-arm" }
8486 attributes #2 = { "target-features"="+vfp4"}
87 attributes #3 = { "target-features"="+v5t"}
8588 ...
8689 ---
8790 name: test_add_s32
560563 BX_RET 14, $noreg, implicit $r0
561564 ...
562565 ---
566 name: test_ctlz_s32
567 # CHECK-LABEL: name: test_ctlz_s32
568 legalized: true
569 regBankSelected: false
570 selected: false
571 # CHECK: registers:
572 # CHECK: - { id: 0, class: gprb, preferred-register: '' }
573 # CHECK: - { id: 1, class: gprb, preferred-register: '' }
574 registers:
575 - { id: 0, class: _ }
576 - { id: 1, class: _ }
577 body: |
578 bb.0:
579 %0(s32) = COPY $r0
580 %1(s32) = G_CTLZ %0(s32)
581 $r0 = COPY %1(s32)
582 BX_RET 14, $noreg, implicit $r0
583 ...
584 ---
563585 name: test_globals
564586 # CHECK-LABEL: name: test_globals
565587 legalized: true
141141 CHECK: [[SIXTY4:%[0-9]+]]:_(s64) = G_CONSTANT i64 64
142142 CHECK: [[CMP:%[0-9]+]]:_(s1) = G_ICMP intpred(eq), %0:_(s64), [[ZERO]]
143143 CHECK: [[SEL:%[0-9]+]]:_(s64) = G_SELECT [[CMP]]:_(s1), [[SIXTY4]]:_, [[CZU]]
144 )";
145
146 // Check
147 ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr));
148 }
149
150 // CTLZ expansion in terms of CTLZ_ZERO_UNDEF if the latter is a libcall
151 TEST_F(LegalizerHelperTest, LowerBitCountingCTLZLibcall) {
152 if (!TM)
153 return;
154
155 // Declare your legalization info
156 DefineLegalizerInfo(
157 A, { getActionDefinitionsBuilder(G_CTLZ_ZERO_UNDEF).libcallFor({s64}); });
158 // Build
159 auto MIBCTLZ = B.buildInstr(TargetOpcode::G_CTLZ, LLT::scalar(64), Copies[0]);
160 AInfo Info(MF->getSubtarget());
161 LegalizerHelper Helper(*MF, Info);
162 ASSERT_TRUE(Helper.lower(*MIBCTLZ, 0, LLT::scalar(64)) ==
163 LegalizerHelper::LegalizeResult::Legalized);
164
165 auto CheckStr = R"(
166 CHECK: [[CZU:%[0-9]+]]:_(s64) = G_CTLZ_ZERO_UNDEF %0
167 CHECK: [[ZERO:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
168 CHECK: [[THIRTY2:%[0-9]+]]:_(s64) = G_CONSTANT i64 64
169 CHECK: [[CMP:%[0-9]+]]:_(s1) = G_ICMP intpred(eq), %0:_(s64), [[ZERO]]
170 CHECK: [[SEL:%[0-9]+]]:_(s64) = G_SELECT [[CMP]]:_(s1), [[THIRTY2]]:_, [[CZU]]
144171 )";
145172
146173 // Check