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
5
6# REQUIRES: asserts
7
8--- |
9  target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
10  target triple = "aarch64--"
11
12  define void @multiple_copies(ptr %addr) {
13  entry:
14    br i1 0, label %if, label %else
15  if:
16    br label %exit
17  else:
18    br label %exit
19  exit:
20    ret void
21  }
22
23  define void @sink_to_phi_trivially_dominating(ptr %addr) {
24  entry:
25    br i1 0, label %if, label %exit
26  if:
27    br label %exit
28  exit:
29    ret void
30  }
31
32  define void @sink_to_phi_nondominating(ptr %addr) {
33  entry:
34    br i1 0, label %if, label %else
35  if:
36    br label %exit
37  else:
38    br label %exit
39  exit:
40    ret void
41  }
42
43  define void @sink_to_phi_emptyblock(ptr %addr) {
44  entry:
45    br i1 0, label %if, label %else
46  if:
47    br label %exit
48  else:
49    br label %else2
50  else2:
51    br label %exit
52  exit:
53    ret void
54  }
55
56  define void @use_doesnt_def_anything(ptr %addr) {
57  entry:
58    ret void
59  }
60
61  define void @op0_isnt_a_reg(ptr %addr) {
62  entry:
63    ret void
64  }
65...
66
67---
68name:            multiple_copies
69# CHECK-LABEL: name: multiple_copies
70tracksRegLiveness: true
71body: |
72  bb.0.entry:
73    liveins: $x0, $w1
74    successors: %bb.1(0x40000000), %bb.2(0x40000000); %bb.1(50.00%), %bb.2(50.00%)
75    ; CHECK: [[T0:%[0-9]+]]:_(s32) = G_SEXTLOAD
76    %0:_(p0) = COPY $x0
77    %1:_(s32) = COPY $w1
78    %2:_(s8) = G_LOAD %0 :: (load (s8) from %ir.addr)
79    %3:_(s32) = G_SEXT %2
80    %4:_(s32) = G_CONSTANT i32 1
81    %5:_(s1) = G_ICMP intpred(ne), %1:_(s32), %4:_
82    G_BRCOND %5:_(s1), %bb.1
83    G_BR %bb.2.else
84  bb.1.if:
85  ; CHECK: bb.1.if:
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]], {{.*}}
91    G_BR %bb.3.exit
92  bb.2.else:
93  ; CHECK: bb.2.else:
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_ADD [[T3]], {{.*}}
99    G_BR %bb.3.exit
100  bb.3.exit:
101  ; CHECK: bb.3.exit:
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)
108    $w0 = COPY %3
109    $w1 = COPY %9
110
111# Check that we report the correct modifications to the observer. This acts as
112# a test of the debug output and a test.
113#
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
127...
128
129---
130name:            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
134# of a BB
135tracksRegLiveness: true
136body: |
137  bb.0.entry:
138    liveins: $x0, $w1
139    successors: %bb.1(0x40000000), %bb.2(0x40000000); %bb.1(50.00%), %bb.2(50.00%)
140    ; CHECK: [[T0:%[0-9]+]]:_(s32) = G_SEXTLOAD
141    %0:_(p0) = COPY $x0
142    %1:_(s32) = COPY $w1
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
149    G_BR %bb.2.exit
150  bb.1.if:
151  ; CHECK: bb.1.if:
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]], {{.*}}
157    G_BR %bb.2.exit
158  bb.2.exit:
159  ; CHECK: bb.2.exit:
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)
166    $w0 = COPY %3
167    $w1 = COPY %9
168...
169
170---
171name:            sink_to_phi_nondominating
172# CHECK-LABEL: name: sink_to_phi_nondominating
173tracksRegLiveness: true
174body: |
175  bb.0.entry:
176    liveins: $x0, $w1
177    successors: %bb.1(0x40000000), %bb.2(0x40000000); %bb.1(50.00%), %bb.2(50.00%)
178    ; CHECK: [[T0:%[0-9]+]]:_(s32) = G_SEXTLOAD
179    %0:_(p0) = COPY $x0
180    %1:_(s32) = COPY $w1
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
185    G_BR %bb.2.else
186  bb.1.if:
187  ; CHECK: bb.1.if:
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]], {{.*}}
193    G_BR %bb.3.exit
194  bb.2.else:
195  ; CHECK: bb.2.else:
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_ADD [[T3]], {{.*}}
201    G_BR %bb.3.exit
202  bb.3.exit:
203  ; CHECK: bb.3.exit:
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)
211    $w0 = COPY %10
212    $w1 = COPY %11
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
228...
229
230---
231name:            sink_to_phi_emptyblock
232# CHECK-LABEL: name: sink_to_phi_emptyblock
233tracksRegLiveness: true
234body: |
235  bb.0.entry:
236    liveins: $x0, $w1
237    successors: %bb.1(0x40000000), %bb.2(0x40000000); %bb.1(50.00%), %bb.2(50.00%)
238    ; CHECK: [[T0:%[0-9]+]]:_(s32) = G_SEXTLOAD
239    %0:_(p0) = COPY $x0
240    %1:_(s32) = COPY $w1
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
246    G_BR %bb.2.else
247  bb.1.if:
248  ; CHECK: bb.1.if:
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]], {{.*}}
254    G_BR %bb.4.exit
255  bb.2.else:
256  ; CHECK: bb.2.else:
257    successors: %bb.3(0x80000000)
258    G_BR %bb.3.else2
259  bb.3.else2:
260  ; CHECK: bb.3.else2:
261    successors: %bb.4(0x80000000)
262    ; CHECK: [[T4:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32)
263    ; Fallthrough
264  bb.4.exit:
265  ; CHECK: bb.4.exit:
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)
272    $w0 = COPY %3
273    $w1 = COPY %9
274...
275
276---
277name:            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.
285tracksRegLiveness: true
286body: |
287  bb.0.entry:
288    liveins: $x0, $w1
289    %0:_(p0) = COPY $x0
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)
294...
295
296---
297name:            op0_isnt_a_reg
298# CHECK-LABEL: name: op0_isnt_a_reg
299# This test covers the variant of use_doesnt_def_anything that would crash.
300tracksRegLiveness: true
301body: |
302  bb.0.entry:
303    liveins: $x0, $w1
304    %0:_(p0) = COPY $x0
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)
309...
310