1 # RUN: llc -O0 -run-pass=aarch64-prelegalizer-combiner -global-isel %s -o - | FileCheck %s
2 # RUN: llc -O0 -run-pass=aarch64-prelegalizer-combiner -global-isel %s -o - \
3 # RUN: -debug-only=aarch64-prelegalizer-combiner,gi-combiner 2>&1 >/dev/null \
4 # RUN: | FileCheck %s --check-prefix=CHECK-WORKLIST
9 target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
10 target triple = "aarch64--"
12 define void @multiple_copies(i8* %addr) {
14 br i1 0, label %if, label %else
23 define void @sink_to_phi_trivially_dominating(i8* %addr) {
25 br i1 0, label %if, label %exit
32 define void @sink_to_phi_nondominating(i8* %addr) {
34 br i1 0, label %if, label %else
43 define void @sink_to_phi_emptyblock(i8* %addr) {
45 br i1 0, label %if, label %else
56 define void @use_doesnt_def_anything(i8* %addr) {
61 define void @op0_isnt_a_reg(i8* %addr) {
69 # CHECK-LABEL: name: multiple_copies
70 tracksRegLiveness: true
74 successors: %bb.1(0x40000000), %bb.2(0x40000000); %bb.1(50.00%), %bb.2(50.00%)
75 ; CHECK: [[T0:%[0-9]+]]:_(s32) = G_SEXTLOAD
78 %2:_(s8) = G_LOAD %0 :: (load (s8) from %ir.addr)
80 %4:_(s32) = G_CONSTANT i32 1
81 %5:_(s1) = G_ICMP intpred(ne), %1:_(s32), %4:_
82 G_BRCOND %5:_(s1), %bb.1
86 successors: %bb.3(0x80000000)
87 %10:_(s8) = G_CONSTANT i8 1
88 ; CHECK: [[T1:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32)
89 %6:_(s8) = G_ADD %2, %10
90 ; CHECK: [[T2:%[0-9]+]]:_(s8) = G_ADD [[T1]], {{.*}}
94 successors: %bb.3(0x80000000)
95 %11:_(s8) = G_CONSTANT i8 1
96 ; CHECK: [[T3:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32)
97 %7:_(s8) = G_SUB %2, %11
98 ; CHECK: [[T4:%[0-9]+]]:_(s8) = G_SUB [[T3]], {{.*}}
102 %8:_(s8) = G_PHI %6:_(s8), %bb.1, %7:_(s8), %bb.2
103 ; CHECK: [[T5:%[0-9]+]]:_(s8) = G_PHI [[T2]](s8), %bb.1, [[T4]](s8)
104 %9:_(s32) = G_ZEXT %8
105 ; CHECK: [[T6:%[0-9]+]]:_(s32) = G_ZEXT [[T5]](s8)
106 ; CHECK: $w0 = COPY [[T0]](s32)
107 ; CHECK: $w1 = COPY [[T6]](s32)
111 # Check that we report the correct modifications to the observer. This acts as
112 # a test of the debug output and a test.
114 # CHECK-WORKLIST-LABEL: Generic MI Combiner for: multiple_copies
115 # CHECK-WORKLIST: Try combining [[IN0:%[0-9]+]]:_(s8) = G_LOAD [[IN1:%[0-9]+]]:_(p0){{.*}} :: (load (s8) from %ir.addr)
116 # CHECK-WORKLIST: Preferred use is: [[IN2:%[0-9]+]]:_(s32) = G_SEXT [[IN0]]:_(s8)
117 # CHECK-WORKLIST-DAG: Changing: [[IN0]]:_(s8) = G_LOAD [[IN1]]:_(p0){{.*}} :: (load (s8) from %ir.addr)
118 # CHECK-WORKLIST-DAG: Changing: [[IN3:%[0-9]+]]:_(s8) = G_ADD [[IN0]]:_, [[IN4:%[0-9]+]]:_
119 # CHECK-WORKLIST-DAG: Changed: [[IN3]]:_(s8) = G_ADD [[NEW1:%[0-9]+]]:_, [[IN4]]:_
120 # CHECK-WORKLIST-DAG: Changing: [[IN5:%[0-9]+]]:_(s8) = G_SUB [[IN0]]:_, [[IN6:%[0-9]+]]:_
121 # CHECK-WORKLIST-DAG: Changed: [[IN5]]:_(s8) = G_SUB [[NEW2:%[0-9]+]]:_, [[IN6]]:_
122 # CHECK-WORKLIST-DAG: Erasing: [[IN2]]:_(s32) = G_SEXT [[IN0]]:_(s8)
123 # CHECK-WORKLIST-DAG: Changed: [[IN2]]:_(s32) = G_SEXTLOAD [[IN1]]:_(p0){{.*}} :: (load (s8) from %ir.addr)
124 # CHECK-WORKLIST-DAG: Created: [[NEW1]]:_(s8) = G_TRUNC [[IN2]]:_(s32)
125 # CHECK-WORKLIST-DAG: Created: [[NEW2]]:_(s8) = G_TRUNC [[IN2]]:_(s32)
126 # CHECK-WORKLIST: Try combining
130 name: sink_to_phi_trivially_dominating
131 # CHECK-LABEL: name: sink_to_phi_trivially_dominating
132 # This test currently tests that we don't sink if we would sink to a phi. This
133 # is needed to avoid inserting into the middle of the leading G_PHI instructions
135 tracksRegLiveness: true
139 successors: %bb.1(0x40000000), %bb.2(0x40000000); %bb.1(50.00%), %bb.2(50.00%)
140 ; CHECK: [[T0:%[0-9]+]]:_(s32) = G_SEXTLOAD
143 %2:_(s8) = G_LOAD %0 :: (load (s8) from %ir.addr)
144 ; CHECK: [[T4:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32)
145 %3:_(s32) = G_SEXT %2
146 %4:_(s32) = G_CONSTANT i32 1
147 %5:_(s1) = G_ICMP intpred(ne), %1:_(s32), %4:_
148 G_BRCOND %5:_(s1), %bb.1
152 successors: %bb.2(0x80000000)
153 %10:_(s8) = G_CONSTANT i8 1
154 ; CHECK: [[T1:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32)
155 %6:_(s8) = G_ADD %2, %10
156 ; CHECK: [[T2:%[0-9]+]]:_(s8) = G_ADD [[T1]], {{.*}}
160 %8:_(s8) = G_PHI %6:_(s8), %bb.1, %2:_(s8), %bb.0
161 ; CHECK: [[T5:%[0-9]+]]:_(s8) = G_PHI [[T2]](s8), %bb.1, [[T4]](s8)
162 %9:_(s32) = G_ZEXT %8
163 ; CHECK: [[T6:%[0-9]+]]:_(s32) = G_ZEXT [[T5]](s8)
164 ; CHECK: $w0 = COPY [[T0]](s32)
165 ; CHECK: $w1 = COPY [[T6]](s32)
171 name: sink_to_phi_nondominating
172 # CHECK-LABEL: name: sink_to_phi_nondominating
173 tracksRegLiveness: true
177 successors: %bb.1(0x40000000), %bb.2(0x40000000); %bb.1(50.00%), %bb.2(50.00%)
178 ; CHECK: [[T0:%[0-9]+]]:_(s32) = G_SEXTLOAD
181 %2:_(s8) = G_LOAD %0 :: (load (s8) from %ir.addr)
182 %3:_(s32) = G_CONSTANT i32 1
183 %4:_(s1) = G_ICMP intpred(ne), %1:_(s32), %3:_
184 G_BRCOND %4:_(s1), %bb.1
188 successors: %bb.3(0x80000000)
189 %5:_(s8) = G_CONSTANT i8 1
190 ; CHECK: [[T1:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32)
191 %6:_(s8) = G_ADD %2, %5
192 ; CHECK: [[T2:%[0-9]+]]:_(s8) = G_ADD [[T1]], {{.*}}
196 successors: %bb.3(0x80000000)
197 %7:_(s8) = G_CONSTANT i8 1
198 ; CHECK: [[T3:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32)
199 %8:_(s8) = G_SUB %2, %7
200 ; CHECK: [[T4:%[0-9]+]]:_(s8) = G_SUB [[T3]], {{.*}}
204 %9:_(s8) = G_PHI %6:_(s8), %bb.1, %8:_(s8), %bb.2
205 ; CHECK: [[T5:%[0-9]+]]:_(s8) = G_PHI [[T2]](s8), %bb.1, [[T4]](s8)
206 %10:_(s32) = G_SEXT %2
207 %11:_(s32) = G_ZEXT %9
208 ; CHECK: [[T6:%[0-9]+]]:_(s32) = G_ZEXT [[T5]](s8)
209 ; CHECK: $w0 = COPY [[T0]](s32)
210 ; CHECK: $w1 = COPY [[T6]](s32)
213 # CHECK-WORKLIST-LABEL: Generic MI Combiner for: sink_to_phi_nondominating
214 # CHECK-WORKLIST: Try combining [[IN0:%[0-9]+]]:_(s8) = G_LOAD [[IN1:%[0-9]+]]:_(p0){{.*}} :: (load (s8) from %ir.addr)
215 # CHECK-WORKLIST: Preferred use is: [[IN2:%[0-9]+]]:_(s32) = G_SEXT [[IN0]]:_(s8)
216 # CHECK-WORKLIST-DAG: Changing: [[IN0]]:_(s8) = G_LOAD [[IN1]]:_(p0){{.*}} :: (load (s8) from %ir.addr)
217 # CHECK-WORKLIST-DAG: Creating: G_TRUNC
218 # CHECK-WORKLIST-DAG: Changing: [[IN3:%[0-9]+]]:_(s8) = G_ADD [[IN0]]:_, [[IN4:%[0-9]+]]:_
219 # CHECK-WORKLIST-DAG: Changed: [[IN3]]:_(s8) = G_ADD [[OUT1:%[0-9]+]]:_, [[IN4]]:_
220 # CHECK-WORKLIST-DAG: Creating: G_TRUNC
221 # CHECK-WORKLIST-DAG: Changing: [[IN5:%[0-9]+]]:_(s8) = G_SUB [[IN0]]:_, [[IN6:%[0-9]+]]:_
222 # CHECK-WORKLIST-DAG: Changed: [[IN5]]:_(s8) = G_SUB [[OUT2:%[0-9]+]]:_, [[IN6]]:_
223 # CHECK-WORKLIST-DAG: Erasing: [[IN2]]:_(s32) = G_SEXT [[IN0]]:_(s8)
224 # CHECK-WORKLIST-DAG: Changed: [[IN2]]:_(s32) = G_SEXTLOAD [[IN1]]:_(p0){{.*}} :: (load (s8) from %ir.addr)
225 # CHECK-WORKLIST-DAG: Created: [[OUT1]]:_(s8) = G_TRUNC [[IN2]]:_(s32)
226 # CHECK-WORKLIST-DAG: Created: [[OUT2]]:_(s8) = G_TRUNC [[IN2]]:_(s32)
227 # CHECK-WORKLIST: Try combining
231 name: sink_to_phi_emptyblock
232 # CHECK-LABEL: name: sink_to_phi_emptyblock
233 tracksRegLiveness: true
237 successors: %bb.1(0x40000000), %bb.2(0x40000000); %bb.1(50.00%), %bb.2(50.00%)
238 ; CHECK: [[T0:%[0-9]+]]:_(s32) = G_SEXTLOAD
241 %2:_(s8) = G_LOAD %0 :: (load (s8) from %ir.addr)
242 %3:_(s32) = G_SEXT %2
243 %4:_(s32) = G_CONSTANT i32 1
244 %5:_(s1) = G_ICMP intpred(ne), %1:_(s32), %4:_
245 G_BRCOND %5:_(s1), %bb.1
249 successors: %bb.4(0x80000000)
250 %10:_(s8) = G_CONSTANT i8 1
251 ; CHECK: [[T1:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32)
252 %6:_(s8) = G_ADD %2, %10
253 ; CHECK: [[T2:%[0-9]+]]:_(s8) = G_ADD [[T1]], {{.*}}
257 successors: %bb.3(0x80000000)
261 successors: %bb.4(0x80000000)
262 ; CHECK: [[T4:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32)
266 %8:_(s8) = G_PHI %6:_(s8), %bb.1, %2:_(s8), %bb.3
267 ; CHECK: [[T5:%[0-9]+]]:_(s8) = G_PHI [[T2]](s8), %bb.1, [[T4]](s8)
268 %9:_(s32) = G_ZEXT %8
269 ; CHECK: [[T6:%[0-9]+]]:_(s32) = G_ZEXT [[T5]](s8)
270 ; CHECK: $w0 = COPY [[T0]](s32)
271 ; CHECK: $w1 = COPY [[T6]](s32)
277 name: use_doesnt_def_anything
278 # CHECK-LABEL: name: use_doesnt_def_anything
279 # Check that we don't crash when inspecting a use that doesn't define anything.
280 # The real issue which was that the combine rule was looking through
281 # non-truncates as if they were truncates and attempting to obtain the result
282 # register. It would usually go on to make the right overall decision anyway but
283 # would sometimes crash on things like (SOME_INTRINSIC imm). This test covers
284 # the case that it would recover from.
285 tracksRegLiveness: true
290 %1:_(s8) = G_LOAD %0 :: (load (s8) from %ir.addr)
291 ; CHECK: %1:_(s8) = G_LOAD %0(p0) :: (load (s8) from %ir.addr)
292 G_STORE %1(s8), %0(p0) :: (store (s8) into %ir.addr)
293 ; CHECK: G_STORE %1(s8), %0(p0) :: (store (s8) into %ir.addr)
298 # CHECK-LABEL: name: op0_isnt_a_reg
299 # This test covers the variant of use_doesnt_def_anything that would crash.
300 tracksRegLiveness: true
305 %1:_(s8) = G_LOAD %0 :: (load (s8) from %ir.addr)
306 ; CHECK: %1:_(s8) = G_LOAD %0(p0) :: (load (s8) from %ir.addr)
307 G_INTRINSIC_W_SIDE_EFFECTS intrinsic(@llvm.aarch64.hint), %1(s8)
308 ; CHECK: G_INTRINSIC_W_SIDE_EFFECTS intrinsic(@llvm.aarch64.hint), %1(s8)