1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 2
# RUN: llc -o - %s -mtriple=amdgcn-- -mcpu=fiji -verify-machineinstrs -run-pass=greedy,virtregrewriter | FileCheck %s
--- |
define amdgpu_kernel void @func0() #0 { ret void }
define amdgpu_kernel void @func1() #0 { ret void }
define amdgpu_kernel void @splitHoist() #0 { ret void }
attributes #0 = { "amdgpu-num-sgpr"="12" }
...
---
# Make sure we only get a single spill+reload even if liverange splitting
# created a sequence of multiple copy instructions.
name: func0
body: |
bb.0:
; CHECK-LABEL: name: func0
; CHECK: S_NOP 0, implicit-def renamable $sgpr0
; CHECK-NEXT: S_NOP 0, implicit-def renamable $sgpr3
; CHECK-NEXT: SI_SPILL_S128_SAVE renamable $sgpr0_sgpr1_sgpr2_sgpr3, %stack.0, implicit $exec, implicit $sp_reg :: (store (s128) into %stack.0, align 4, addrspace 5)
; CHECK-NEXT: S_NOP 0, implicit-def dead $sgpr0, implicit-def dead $sgpr1, implicit-def dead $sgpr2, implicit-def dead $sgpr3, implicit-def dead $sgpr4, implicit-def dead $sgpr5, implicit-def dead $sgpr6, implicit-def dead $sgpr7, implicit-def dead $sgpr8, implicit-def dead $sgpr9, implicit-def dead $sgpr10, implicit-def dead $sgpr11
; CHECK-NEXT: renamable $sgpr0_sgpr1_sgpr2_sgpr3 = SI_SPILL_S128_RESTORE %stack.0, implicit $exec, implicit $sp_reg :: (load (s128) from %stack.0, align 4, addrspace 5)
; CHECK-NEXT: S_NOP 0, implicit renamable $sgpr0
; CHECK-NEXT: S_NOP 0, implicit renamable $sgpr3
; CHECK-NEXT: S_NOP 0, implicit renamable $sgpr0
; CHECK-NEXT: S_NOP 0, implicit killed renamable $sgpr3
S_NOP 0, implicit-def undef %0.sub0 : sgpr_128
S_NOP 0, implicit-def %0.sub3 : sgpr_128
; Clobber registers
S_NOP 0, implicit-def dead $sgpr0, implicit-def dead $sgpr1, implicit-def dead $sgpr2, implicit-def dead $sgpr3, implicit-def dead $sgpr4, implicit-def dead $sgpr5, implicit-def dead $sgpr6, implicit-def dead $sgpr7, implicit-def dead $sgpr8, implicit-def dead $sgpr9, implicit-def dead $sgpr10, implicit-def dead $sgpr11
S_NOP 0, implicit %0.sub0
S_NOP 0, implicit %0.sub3
S_NOP 0, implicit %0.sub0
S_NOP 0, implicit %0.sub3
...
---
# LiveRange splitting should split this into 2 intervals with the second getting
# allocated to sgpr0_sgpr1 and the first to something else so we see two copies
# in between for the two subregisters that are alive.
name: func1
tracksRegLiveness: true
body: |
bb.0:
liveins: $sgpr0, $sgpr1, $sgpr2
; CHECK-LABEL: name: func1
; CHECK: liveins: $sgpr0, $sgpr1, $sgpr2
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: renamable $sgpr4 = COPY $sgpr0
; CHECK-NEXT: renamable $sgpr6 = COPY $sgpr2
; CHECK-NEXT: S_NOP 0, implicit-def dead $sgpr0, implicit-def dead $sgpr1
; CHECK-NEXT: S_NOP 0, implicit renamable $sgpr4
; CHECK-NEXT: S_NOP 0, implicit renamable $sgpr6
; CHECK-NEXT: renamable $sgpr0 = COPY killed renamable $sgpr4
; CHECK-NEXT: renamable $sgpr2 = COPY renamable $sgpr6
; CHECK-NEXT: S_NOP 0, implicit-def dead $sgpr4, implicit-def dead $sgpr5, implicit-def dead $sgpr6, implicit-def dead $sgpr7, implicit-def dead $sgpr8, implicit-def dead $sgpr9, implicit-def dead $sgpr10, implicit-def dead $sgpr11, implicit-def dead $sgpr12, implicit-def dead $sgpr13, implicit-def dead $sgpr14, implicit-def dead $sgpr15, implicit-def dead $vcc_lo, implicit-def dead $vcc_hi
; CHECK-NEXT: S_NOP 0, implicit renamable $sgpr0
; CHECK-NEXT: S_NOP 0, implicit killed renamable $sgpr2
undef %0.sub0 : sgpr_128 = COPY $sgpr0
%0.sub2 = COPY $sgpr2
S_NOP 0, implicit-def dead $sgpr0, implicit-def dead $sgpr1
S_NOP 0, implicit %0.sub0
S_NOP 0, implicit %0.sub2
; Clobber everything but sgpr0-sgpr3
S_NOP 0, implicit-def dead $sgpr4, implicit-def dead $sgpr5, implicit-def dead $sgpr6, implicit-def dead $sgpr7, implicit-def dead $sgpr8, implicit-def dead $sgpr9, implicit-def dead $sgpr10, implicit-def dead $sgpr11, implicit-def dead $sgpr12, implicit-def dead $sgpr13, implicit-def dead $sgpr14, implicit-def dead $sgpr15, implicit-def dead $vcc_lo, implicit-def dead $vcc_hi
S_NOP 0, implicit %0.sub0
S_NOP 0, implicit %0.sub2
...
---
# Check that copy hoisting out of loops works. This mainly should not crash the
# compiler when it hoists a subreg copy sequence.
name: splitHoist
tracksRegLiveness: true
body: |
; CHECK-LABEL: name: splitHoist
; CHECK: bb.0:
; CHECK-NEXT: successors: %bb.1(0x40000000), %bb.2(0x40000000)
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: S_NOP 0, implicit-def renamable $sgpr0
; CHECK-NEXT: S_NOP 0, implicit-def renamable $sgpr3
; CHECK-NEXT: SI_SPILL_S128_SAVE renamable $sgpr0_sgpr1_sgpr2_sgpr3, %stack.0, implicit $exec, implicit $sp_reg :: (store (s128) into %stack.0, align 4, addrspace 5)
; CHECK-NEXT: S_CBRANCH_VCCNZ %bb.1, implicit undef $vcc
; CHECK-NEXT: S_BRANCH %bb.2
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.1:
; CHECK-NEXT: successors: %bb.1(0x40000000), %bb.3(0x40000000)
; CHECK-NEXT: liveins: $sgpr0_sgpr1_sgpr2_sgpr3:0x00000000000000C3
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: S_NOP 0, implicit renamable $sgpr0
; CHECK-NEXT: S_NOP 0, implicit-def dead $sgpr0, implicit-def dead $sgpr1, implicit-def dead $sgpr2, implicit-def dead $sgpr3, implicit-def dead $sgpr4, implicit-def dead $sgpr5, implicit-def dead $sgpr6, implicit-def dead $sgpr7, implicit-def dead $sgpr8, implicit-def dead $sgpr9, implicit-def dead $sgpr10, implicit-def dead $sgpr11
; CHECK-NEXT: renamable $sgpr0_sgpr1_sgpr2_sgpr3 = SI_SPILL_S128_RESTORE %stack.0, implicit $exec, implicit $sp_reg :: (load (s128) from %stack.0, align 4, addrspace 5)
; CHECK-NEXT: S_CBRANCH_VCCNZ %bb.1, implicit undef $vcc
; CHECK-NEXT: S_BRANCH %bb.3
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.2:
; CHECK-NEXT: successors: %bb.3(0x80000000)
; CHECK-NEXT: liveins: $sgpr0_sgpr1_sgpr2_sgpr3:0x00000000000000C3
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: S_NOP 0, implicit-def dead $sgpr0, implicit-def dead $sgpr1, implicit-def dead $sgpr2, implicit-def dead $sgpr3, implicit-def dead $sgpr4, implicit-def dead $sgpr5, implicit-def dead $sgpr6, implicit-def dead $sgpr7, implicit-def dead $sgpr8, implicit-def dead $sgpr9, implicit-def dead $sgpr10, implicit-def dead $sgpr11
; CHECK-NEXT: renamable $sgpr0_sgpr1_sgpr2_sgpr3 = SI_SPILL_S128_RESTORE %stack.0, implicit $exec, implicit $sp_reg :: (load (s128) from %stack.0, align 4, addrspace 5)
; CHECK-NEXT: S_BRANCH %bb.3
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.3:
; CHECK-NEXT: liveins: $sgpr0_sgpr1_sgpr2_sgpr3:0x00000000000000C3
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: S_NOP 0, implicit renamable $sgpr0
; CHECK-NEXT: S_NOP 0, implicit renamable $sgpr3
; CHECK-NEXT: S_NOP 0, implicit renamable $sgpr0
; CHECK-NEXT: S_NOP 0, implicit killed renamable $sgpr3
bb.0:
successors: %bb.1, %bb.2
S_NOP 0, implicit-def undef %0.sub0 : sgpr_128
S_NOP 0, implicit-def %0.sub3 : sgpr_128
S_CBRANCH_VCCNZ %bb.1, implicit undef $vcc
S_BRANCH %bb.2
bb.1:
successors: %bb.1, %bb.3
S_NOP 0, implicit %0.sub0
; Clobber registers
S_NOP 0, implicit-def dead $sgpr0, implicit-def dead $sgpr1, implicit-def dead $sgpr2, implicit-def dead $sgpr3, implicit-def dead $sgpr4, implicit-def dead $sgpr5, implicit-def dead $sgpr6, implicit-def dead $sgpr7, implicit-def dead $sgpr8, implicit-def dead $sgpr9, implicit-def dead $sgpr10, implicit-def dead $sgpr11
S_CBRANCH_VCCNZ %bb.1, implicit undef $vcc
S_BRANCH %bb.3
bb.2:
successors: %bb.3
; Clobber registers
S_NOP 0, implicit-def dead $sgpr0, implicit-def dead $sgpr1, implicit-def dead $sgpr2, implicit-def dead $sgpr3, implicit-def dead $sgpr4, implicit-def dead $sgpr5, implicit-def dead $sgpr6, implicit-def dead $sgpr7, implicit-def dead $sgpr8, implicit-def dead $sgpr9, implicit-def dead $sgpr10, implicit-def dead $sgpr11
S_BRANCH %bb.3
bb.3:
S_NOP 0, implicit %0.sub0
S_NOP 0, implicit %0.sub3
S_NOP 0, implicit %0.sub0
S_NOP 0, implicit %0.sub3
...
|