1# RUN: llc -march=amdgcn -run-pass detect-dead-lanes -o - %s | FileCheck %s
2...
3---
4# Combined use/def transfer check, the basics.
5# CHECK-LABEL: name: test0
6# CHECK: S_NOP 0, implicit-def %0
7# CHECK: S_NOP 0, implicit-def %1
8# CHECK: S_NOP 0, implicit-def dead %2
9# CHECK: %3:sreg_128 = REG_SEQUENCE %0,  %subreg.sub0, %1,  %subreg.sub1, undef %2, %subreg.sub3
10# CHECK: S_NOP 0, implicit %3.sub0
11# CHECK: S_NOP 0, implicit %3.sub1
12# CHECK: S_NOP 0, implicit undef %3.sub2
13# CHECK: %4:sreg_64 = COPY %3.sub0_sub1
14# CHECK: %5:sreg_64 = COPY undef %3.sub2_sub3
15# CHECK: S_NOP 0, implicit %4.sub0
16# CHECK: S_NOP 0, implicit %4.sub1
17# CHECK: S_NOP 0, implicit undef %5.sub0
18name: test0
19registers:
20  - { id: 0, class: sreg_32_xm0 }
21  - { id: 1, class: sreg_32_xm0 }
22  - { id: 2, class: sreg_32_xm0 }
23  - { id: 3, class: sreg_128 }
24  - { id: 4, class: sreg_64 }
25  - { id: 5, class: sreg_64 }
26body: |
27  bb.0:
28    S_NOP 0, implicit-def %0
29    S_NOP 0, implicit-def %1
30    S_NOP 0, implicit-def %2
31    %3 = REG_SEQUENCE %0, %subreg.sub0, %1, %subreg.sub1, %2, %subreg.sub3
32    S_NOP 0, implicit %3.sub0
33    S_NOP 0, implicit %3.sub1
34    S_NOP 0, implicit %3.sub2
35    %4 = COPY %3.sub0_sub1
36    %5 = COPY %3.sub2_sub3
37    S_NOP 0, implicit %4.sub0
38    S_NOP 0, implicit %4.sub1
39    S_NOP 0, implicit %5.sub0
40...
41---
42# Check defined lanes transfer; Includes checking for some special cases like
43# undef operands or IMPLICIT_DEF definitions.
44# CHECK-LABEL: name: test1
45# CHECK: %0:sreg_128 = REG_SEQUENCE $sgpr0, %subreg.sub0, $sgpr0, %subreg.sub2
46# CHECK: %1:sreg_128 = INSERT_SUBREG %0, $sgpr1,  %subreg.sub3
47# CHECK: %2:sreg_64 = INSERT_SUBREG %0.sub2_sub3, $sgpr42,  %subreg.sub0
48# CHECK: S_NOP 0, implicit %1.sub0
49# CHECK: S_NOP 0, implicit undef %1.sub1
50# CHECK: S_NOP 0, implicit %1.sub2
51# CHECK: S_NOP 0, implicit %1.sub3
52# CHECK: S_NOP 0, implicit %2.sub0
53# CHECK: S_NOP 0, implicit undef %2.sub1
54
55# CHECK: %3:sreg_32_xm0 = IMPLICIT_DEF
56# CHECK: %4:sreg_128 = INSERT_SUBREG %0, undef %3, %subreg.sub0
57# CHECK: S_NOP 0, implicit undef %4.sub0
58# CHECK: S_NOP 0, implicit undef %4.sub1
59# CHECK: S_NOP 0, implicit %4.sub2
60# CHECK: S_NOP 0, implicit undef %4.sub3
61
62# CHECK: %5:sreg_64 = EXTRACT_SUBREG %0, %subreg.sub0_sub1
63# CHECK: %6:sreg_32_xm0 = EXTRACT_SUBREG %5, %subreg.sub0
64# CHECK: %7:sreg_32_xm0 = EXTRACT_SUBREG %5, %subreg.sub1
65# CHECK: S_NOP 0, implicit %5
66# CHECK: S_NOP 0, implicit %6
67# CHECK: S_NOP 0, implicit undef %7
68
69# CHECK: %8:sreg_64 = IMPLICIT_DEF
70# CHECK: %9:sreg_32_xm0 = EXTRACT_SUBREG undef %8, %subreg.sub1
71# CHECK: S_NOP 0, implicit undef %9
72
73# CHECK: %10:sreg_128 = EXTRACT_SUBREG undef %0, %subreg.sub2_sub3
74# CHECK: S_NOP 0, implicit undef %10
75name: test1
76registers:
77  - { id: 0, class: sreg_128 }
78  - { id: 1, class: sreg_128 }
79  - { id: 2, class: sreg_64 }
80  - { id: 3, class: sreg_32_xm0 }
81  - { id: 4, class: sreg_128 }
82  - { id: 5, class: sreg_64 }
83  - { id: 6, class: sreg_32_xm0 }
84  - { id: 7, class: sreg_32_xm0 }
85  - { id: 8, class: sreg_64 }
86  - { id: 9, class: sreg_32_xm0 }
87  - { id: 10, class: sreg_128 }
88body: |
89  bb.0:
90    %0 = REG_SEQUENCE $sgpr0, %subreg.sub0, $sgpr0, %subreg.sub2
91    %1 = INSERT_SUBREG %0, $sgpr1, %subreg.sub3
92    %2 = INSERT_SUBREG %0.sub2_sub3, $sgpr42, %subreg.sub0
93    S_NOP 0, implicit %1.sub0
94    S_NOP 0, implicit %1.sub1
95    S_NOP 0, implicit %1.sub2
96    S_NOP 0, implicit %1.sub3
97    S_NOP 0, implicit %2.sub0
98    S_NOP 0, implicit %2.sub1
99
100    %3 = IMPLICIT_DEF
101    %4 = INSERT_SUBREG %0, %3, %subreg.sub0
102    S_NOP 0, implicit %4.sub0
103    S_NOP 0, implicit %4.sub1
104    S_NOP 0, implicit %4.sub2
105    S_NOP 0, implicit %4.sub3
106
107    %5 = EXTRACT_SUBREG %0, %subreg.sub0_sub1
108    %6 = EXTRACT_SUBREG %5, %subreg.sub0
109    %7 = EXTRACT_SUBREG %5, %subreg.sub1
110    S_NOP 0, implicit %5
111    S_NOP 0, implicit %6
112    S_NOP 0, implicit %7
113
114    %8 = IMPLICIT_DEF
115    %9 = EXTRACT_SUBREG %8, %subreg.sub1
116    S_NOP 0, implicit %9
117
118    %10 = EXTRACT_SUBREG undef %0, %subreg.sub2_sub3
119    S_NOP 0, implicit %10
120...
121---
122# Check used lanes transfer; Includes checking for some special cases like
123# undef operands.
124# CHECK-LABEL: name: test2
125# CHECK: S_NOP 0, implicit-def dead %0
126# CHECK: S_NOP 0, implicit-def %1
127# CHECK: S_NOP 0, implicit-def %2
128# CHECK: %3:sreg_128 = REG_SEQUENCE undef %0, %subreg.sub0, %1, %subreg.sub1, %2, %subreg.sub2_sub3
129# CHECK: S_NOP 0, implicit %3.sub1
130# CHECK: S_NOP 0, implicit %3.sub3
131
132# CHECK: S_NOP 0, implicit-def %4
133# CHECK: S_NOP 0, implicit-def dead %5
134# CHECK: %6:sreg_64 = REG_SEQUENCE %4, %subreg.sub0, undef %5, %subreg.sub1
135# CHECK: S_NOP 0, implicit %6
136
137# CHECK: S_NOP 0, implicit-def dead %7
138# CHECK: S_NOP 0, implicit-def %8
139# CHECK: %9:sreg_128 = INSERT_SUBREG undef %7, %8, %subreg.sub2_sub3
140# CHECK: S_NOP 0, implicit %9.sub2
141
142# CHECK: S_NOP 0, implicit-def %10
143# CHECK: S_NOP 0, implicit-def dead %11
144# CHECK: %12:sreg_128 = INSERT_SUBREG %10, undef %11, %subreg.sub0_sub1
145# CHECK: S_NOP 0, implicit %12.sub3
146
147# CHECK: S_NOP 0, implicit-def %13
148# CHECK: S_NOP 0, implicit-def dead %14
149# CHECK: %15:sreg_128 = REG_SEQUENCE %13, %subreg.sub0_sub1, undef %14, %subreg.sub2_sub3
150# CHECK: %16:sreg_64 = EXTRACT_SUBREG %15, %subreg.sub0_sub1
151# CHECK: S_NOP 0, implicit %16.sub1
152
153name: test2
154registers:
155  - { id: 0, class: sreg_32_xm0 }
156  - { id: 1, class: sreg_32_xm0 }
157  - { id: 2, class: sreg_64 }
158  - { id: 3, class: sreg_128 }
159  - { id: 4, class: sreg_32_xm0 }
160  - { id: 5, class: sreg_32_xm0 }
161  - { id: 6, class: sreg_64 }
162  - { id: 7, class: sreg_128 }
163  - { id: 8, class: sreg_64 }
164  - { id: 9, class: sreg_128 }
165  - { id: 10, class: sreg_128 }
166  - { id: 11, class: sreg_64 }
167  - { id: 12, class: sreg_128 }
168  - { id: 13, class: sreg_64 }
169  - { id: 14, class: sreg_64 }
170  - { id: 15, class: sreg_128 }
171  - { id: 16, class: sreg_64 }
172body: |
173  bb.0:
174    S_NOP 0, implicit-def %0
175    S_NOP 0, implicit-def %1
176    S_NOP 0, implicit-def %2
177    %3 = REG_SEQUENCE %0, %subreg.sub0, %1, %subreg.sub1, %2, %subreg.sub2_sub3
178    S_NOP 0, implicit %3.sub1
179    S_NOP 0, implicit %3.sub3
180
181    S_NOP 0, implicit-def %4
182    S_NOP 0, implicit-def %5
183    %6 = REG_SEQUENCE %4, %subreg.sub0, undef %5, %subreg.sub1
184    S_NOP 0, implicit %6
185
186    S_NOP 0, implicit-def %7
187    S_NOP 0, implicit-def %8
188    %9 = INSERT_SUBREG %7, %8, %subreg.sub2_sub3
189    S_NOP 0, implicit %9.sub2
190
191    S_NOP 0, implicit-def %10
192    S_NOP 0, implicit-def %11
193    %12 = INSERT_SUBREG %10, %11, %subreg.sub0_sub1
194    S_NOP 0, implicit %12.sub3
195
196    S_NOP 0, implicit-def %13
197    S_NOP 0, implicit-def %14
198    %15 = REG_SEQUENCE %13, %subreg.sub0_sub1, %14, %subreg.sub2_sub3
199    %16 = EXTRACT_SUBREG %15, %subreg.sub0_sub1
200    S_NOP 0, implicit %16.sub1
201...
202---
203# Check that copies to physregs use all lanes, copies from physregs define all
204# lanes. So we should not get a dead/undef flag here.
205# CHECK-LABEL: name: test3
206# CHECK: S_NOP 0, implicit-def %0
207# CHECK: $vcc = COPY %0
208# CHECK: %1:sreg_64 = COPY $vcc
209# CHECK: S_NOP 0, implicit %1
210name: test3
211tracksRegLiveness: true
212registers:
213  - { id: 0, class: sreg_64 }
214  - { id: 1, class: sreg_64 }
215body: |
216  bb.0:
217    S_NOP 0, implicit-def %0
218    $vcc = COPY %0
219
220    %1 = COPY $vcc
221    S_NOP 0, implicit %1
222...
223---
224# Check that implicit-def/kill do not count as def/uses.
225# CHECK-LABEL: name: test4
226# CHECK: S_NOP 0, implicit-def dead %0
227# CHECK: KILL undef %0
228# CHECK: %1:sreg_64 = IMPLICIT_DEF
229# CHECK: S_NOP 0, implicit undef %1
230name: test4
231tracksRegLiveness: true
232registers:
233  - { id: 0, class: sreg_64 }
234  - { id: 1, class: sreg_64 }
235body: |
236  bb.0:
237    S_NOP 0, implicit-def %0
238    KILL %0
239
240    %1 = IMPLICIT_DEF
241    S_NOP 0, implicit %1
242...
243---
244# Check that unused inputs are marked as undef, even if the vreg itself is
245# used.
246# CHECK-LABEL: name: test5
247# CHECK: S_NOP 0, implicit-def %0
248# CHECK: %1:sreg_64 = REG_SEQUENCE undef %0, %subreg.sub0, %0, %subreg.sub1
249# CHECK: S_NOP 0, implicit %1.sub1
250name: test5
251tracksRegLiveness: true
252registers:
253  - { id: 0, class: sreg_32_xm0 }
254  - { id: 1, class: sreg_64 }
255body: |
256  bb.0:
257    S_NOP 0, implicit-def %0
258    %1 = REG_SEQUENCE %0, %subreg.sub0, %0, %subreg.sub1
259    S_NOP 0, implicit %1.sub1
260...
261---
262# Check "optimistic" dataflow fixpoint in phi-loops.
263# CHECK-LABEL: name: loop0
264# CHECK: bb.0:
265# CHECK: S_NOP 0, implicit-def %0
266# CHECK: S_NOP 0, implicit-def dead %1
267# CHECK: S_NOP 0, implicit-def dead %2
268# CHECK: %3:sreg_128 = REG_SEQUENCE %0,  %subreg.sub0, undef %1,  %subreg.sub1, undef %2,  %subreg.sub2
269
270# CHECK: bb.1:
271# CHECK: %4:sreg_128 = PHI %3, %bb.0, %5, %bb.1
272
273# CHECK: bb.2:
274# CHECK:   S_NOP 0, implicit %4.sub0
275# CHECK:   S_NOP 0, implicit undef %4.sub3
276name: loop0
277tracksRegLiveness: true
278registers:
279  - { id: 0, class: sreg_32_xm0 }
280  - { id: 1, class: sreg_32_xm0 }
281  - { id: 2, class: sreg_32_xm0 }
282  - { id: 3, class: sreg_128 }
283  - { id: 4, class: sreg_128 }
284  - { id: 5, class: sreg_128 }
285body: |
286  bb.0:
287    S_NOP 0, implicit-def %0
288    S_NOP 0, implicit-def %1
289    S_NOP 0, implicit-def %2
290    %3 = REG_SEQUENCE %0, %subreg.sub0, %1, %subreg.sub1, %2, %subreg.sub2
291    S_BRANCH %bb.1
292
293  bb.1:
294    %4 = PHI %3, %bb.0, %5, %bb.1
295
296    ; let's swiffle some lanes around for fun...
297    %5 = REG_SEQUENCE %4.sub0, %subreg.sub0, %4.sub2, %subreg.sub1, %4.sub1, %subreg.sub2, %4.sub3, %subreg.sub3
298
299    S_CBRANCH_VCCNZ %bb.1, implicit undef $vcc
300    S_BRANCH %bb.2
301
302  bb.2:
303    S_NOP 0, implicit %4.sub0
304    S_NOP 0, implicit %4.sub3
305...
306---
307# Check a loop that needs to be traversed multiple times to reach the fixpoint
308# for the used lanes. The example reads sub3 lane at the end, however with each
309# loop iteration we should get 1 more lane marked as we cycles the sublanes
310# along. Sublanes sub0, sub1 and sub3 are rotate in the loop so only sub2
311# should be dead.
312# CHECK-LABEL: name: loop1
313# CHECK: bb.0:
314# CHECK: S_NOP 0, implicit-def %0
315# CHECK: S_NOP 0, implicit-def %1
316# CHECK: S_NOP 0, implicit-def dead %2
317# CHECK: S_NOP 0, implicit-def %3
318# CHECK: %4:sreg_128 = REG_SEQUENCE %0, %subreg.sub0, %1, %subreg.sub1, undef %2, %subreg.sub2, %3, %subreg.sub3
319
320# CHECK: bb.1:
321# CHECK: %5:sreg_128 = PHI %4, %bb.0, %6, %bb.1
322
323# CHECK: %6:sreg_128 = REG_SEQUENCE %5.sub1, %subreg.sub0, %5.sub3, %subreg.sub1, undef %5.sub2, %subreg.sub2, %5.sub0, %subreg.sub3
324
325# CHECK: bb.2:
326# CHECK:   S_NOP 0, implicit %6.sub3
327name: loop1
328tracksRegLiveness: true
329registers:
330  - { id: 0, class: sreg_32_xm0 }
331  - { id: 1, class: sreg_32_xm0 }
332  - { id: 2, class: sreg_32_xm0 }
333  - { id: 3, class: sreg_32_xm0 }
334  - { id: 4, class: sreg_128 }
335  - { id: 5, class: sreg_128 }
336  - { id: 6, class: sreg_128 }
337body: |
338  bb.0:
339    S_NOP 0, implicit-def %0
340    S_NOP 0, implicit-def %1
341    S_NOP 0, implicit-def dead %2
342    S_NOP 0, implicit-def %3
343    %4 = REG_SEQUENCE %0, %subreg.sub0, %1, %subreg.sub1, %2, %subreg.sub2, %3, %subreg.sub3
344    S_BRANCH %bb.1
345
346  bb.1:
347    %5 = PHI %4, %bb.0, %6, %bb.1
348
349    ; rotate lanes, but skip sub2 lane...
350    %6 = REG_SEQUENCE %5.sub1, %subreg.sub0, %5.sub3, %subreg.sub1, %5.sub2, %subreg.sub2, %5.sub0, %subreg.sub3
351
352    S_CBRANCH_VCCNZ %bb.1, implicit undef $vcc
353    S_BRANCH %bb.2
354
355  bb.2:
356    S_NOP 0, implicit %6.sub3
357...
358---
359# Similar to loop1 test, but check for fixpoint of defined lanes.
360# Lanes are rotate between sub0, sub2, sub3 so only sub1 should be dead/undef.
361# CHECK-LABEL: name: loop2
362# CHECK: bb.0:
363# CHECK: S_NOP 0, implicit-def %0
364# CHECK: %1:sreg_128 = REG_SEQUENCE %0, %subreg.sub0
365
366# CHECK: bb.1:
367# CHECK: %2:sreg_128 = PHI %1, %bb.0, %3, %bb.1
368
369# CHECK: %3:sreg_128 = REG_SEQUENCE %2.sub3, %subreg.sub0, undef %2.sub1, %subreg.sub1, %2.sub0, %subreg.sub2, %2.sub2, %subreg.sub3
370
371# CHECK: bb.2:
372# CHECK:   S_NOP 0, implicit %2.sub0
373# CHECK:   S_NOP 0, implicit undef %2.sub1
374# CHECK:   S_NOP 0, implicit %2.sub2
375# CHECK:   S_NOP 0, implicit %2.sub3
376name: loop2
377tracksRegLiveness: true
378registers:
379  - { id: 0, class: sreg_32_xm0 }
380  - { id: 1, class: sreg_128 }
381  - { id: 2, class: sreg_128 }
382  - { id: 3, class: sreg_128 }
383body: |
384  bb.0:
385    S_NOP 0, implicit-def %0
386    %1 = REG_SEQUENCE %0, %subreg.sub0
387    S_BRANCH %bb.1
388
389  bb.1:
390    %2 = PHI %1, %bb.0, %3, %bb.1
391
392    ; rotate subreg lanes, skipping sub1
393    %3 = REG_SEQUENCE %2.sub3, %subreg.sub0, %2.sub1, %subreg.sub1, %2.sub0, %subreg.sub2, %2.sub2, %subreg.sub3
394
395    S_CBRANCH_VCCNZ %bb.1, implicit undef $vcc
396    S_BRANCH %bb.2
397
398  bb.2:
399    S_NOP 0, implicit %2.sub0
400    S_NOP 0, implicit undef %2.sub1
401    S_NOP 0, implicit %2.sub2
402    S_NOP 0, implicit %2.sub3
403...
404