1
- // RUN: mlir-opt %s -allocate-arm-sme-tiles -split-input-file -verify-diagnostics | FileCheck %s
1
+ // RUN: mlir-opt %s -allocate-arm-sme-tiles -split-input-file -verify-diagnostics | FileCheck %s --check-prefix=CHECK-BAD
2
2
3
- // This file tests some simple aspects of using liveness in the SME tile allocator.
4
-
5
- // Note: This is an XFAIL the new allocator is not yet upstream, and the current
6
- // allocator gives incorrect results for these tests.
7
- // XFAIL: *
3
+ // This file tests some aspects of liveness issues in the SME tile allocator.
4
+ // These tests were designed with a new liveness-based tile allocator in mind,
5
+ // with the current tile allocator these tests all give incorrect results (which
6
+ // is documented by `CHECK-BAD`).
7
+ //
8
+ // Currently only the `CHECK-BAD` tests are run (as the new liveness based
9
+ // allocator is not yet available -- so all other tests fail).
8
10
9
11
// CHECK-LIVE-RANGE: ========== Coalesced Live Ranges:
10
12
// CHECK-LIVE-RANGE-NEXT: @constant_with_multiple_users
15
17
// CHECK-LIVE-RANGE-NEXT: |E test.some_use
16
18
// CHECK-LIVE-RANGE-NEXT: E test.some_use
17
19
20
+ // Incorrect result! The second `move_vector_to_tile_slice` overwrites the first (which is still live).
21
+ //
22
+ // CHECK-BAD-LABEL: @constant_with_multiple_users(
23
+ // CHECK-BAD-SAME: %[[VECTOR_A:.*]]: vector<[4]xf32>, %[[VECTOR_B:.*]]: vector<[4]xf32>
24
+ // CHECK-BAD: %[[ZERO_TILE:.*]] = arm_sme.zero {tile_id = 0 : i32} : vector<[4]x[4]xf32>
25
+ // CHECK-BAD: %[[INSERT_TILE_1:.*]] = arm_sme.move_vector_to_tile_slice %[[VECTOR_A]], %[[ZERO_TILE]], %{{.*}} {tile_id = 0 : i32} : vector<[4]xf32> into vector<[4]x[4]xf32>
26
+ // CHECK-BAD: %[[INSERT_TILE_0:.*]] = arm_sme.move_vector_to_tile_slice %[[VECTOR_B]], %[[ZERO_TILE]], %{{.*}} {tile_id = 0 : i32} : vector<[4]xf32> into vector<[4]x[4]xf32>
27
+
18
28
// CHECK-LABEL: @constant_with_multiple_users(
19
29
// CHECK-SAME: %[[VECTOR_A:.*]]: vector<[4]xf32>, %[[VECTOR_B:.*]]: vector<[4]xf32>
20
30
func.func @constant_with_multiple_users (%a: vector <[4 ]xf32 >, %b: vector <[4 ]xf32 >, %index: index ) {
@@ -40,8 +50,10 @@ func.func @constant_with_multiple_users(%a: vector<[4]xf32>, %b: vector<[4]xf32>
40
50
// CHECK-LIVE-RANGE-NEXT: |E test.some_use
41
51
// CHECK-LIVE-RANGE-NEXT: E test.some_use
42
52
53
+ // (No CHECK-BAD -- the current tile allocator ignores this case)
54
+
43
55
func.func @value_with_multiple_users (%tile: vector <[4 ]x[4 ]xf32 >, %a: vector <[4 ]xf32 >, %b: vector <[4 ]xf32 >, %index: index ) {
44
- // expected-error@below {{op failed to rectify tile operand with tile result (move required)}}
56
+ // A future allocator should error here (as `%` tile would need to be copied).
45
57
%tile_a = arm_sme.move_vector_to_tile_slice %a , %tile , %index : vector <[4 ]xf32 > into vector <[4 ]x[4 ]xf32 >
46
58
%tile_b = arm_sme.move_vector_to_tile_slice %b , %tile , %index : vector <[4 ]xf32 > into vector <[4 ]x[4 ]xf32 >
47
59
" test.some_use" (%tile_a ) : (vector <[4 ]x[4 ]xf32 >) -> ()
@@ -77,6 +89,19 @@ func.func @value_with_multiple_users(%tile: vector<[4]x[4]xf32>, %a: vector<[4]x
77
89
// CHECK-LIVE-RANGE-NEXT: E| test.some_use
78
90
// CHECK-LIVE-RANGE-NEXT: E test.some_use
79
91
92
+ // CHECK-BAD-LABEL: @reuse_tiles_after_initial_use
93
+ // CHECK-BAD: arm_sme.get_tile {tile_id = 0 : i32}
94
+ // CHECK-BAD: arm_sme.get_tile {tile_id = 1 : i32}
95
+ // CHECK-BAD: arm_sme.get_tile {tile_id = 2 : i32}
96
+ // CHECK-BAD: arm_sme.get_tile {tile_id = 3 : i32}
97
+ //
98
+ // -> Spills after the fourth tile (unnecessary):
99
+ //
100
+ // CHECK-BAD: arm_sme.zero {tile_id = 16 : i32}
101
+ // CHECK-BAD: arm_sme.zero {tile_id = 17 : i32}
102
+ // CHECK-BAD: arm_sme.zero {tile_id = 18 : i32}
103
+ // CHECK-BAD: arm_sme.zero {tile_id = 19 : i32}
104
+
80
105
// CHECK-LABEL: @reuse_tiles_after_initial_use
81
106
func.func @reuse_tiles_after_initial_use () {
82
107
// CHECK: arm_sme.get_tile {tile_id = 0 : i32}
@@ -98,9 +123,14 @@ func.func @reuse_tiles_after_initial_use() {
98
123
// CHECK: arm_sme.zero {tile_id = 1 : i32}
99
124
// CHECK: arm_sme.zero {tile_id = 2 : i32}
100
125
// CHECK: arm_sme.zero {tile_id = 3 : i32}
126
+ // Unnecessary spills:
127
+ // expected-warning @below {{failed to allocate SME virtual tile to operation, all tile operations will go through memory, expect degraded performance}}
101
128
%tile_1 = arm_sme.zero : vector <[4 ]x[4 ]xf32 >
129
+ // expected-warning @below {{failed to allocate SME virtual tile to operation, all tile operations will go through memory, expect degraded performance}}
102
130
%tile_2 = arm_sme.zero : vector <[4 ]x[4 ]xf32 >
131
+ // expected-warning @below {{failed to allocate SME virtual tile to operation, all tile operations will go through memory, expect degraded performance}}
103
132
%tile_3 = arm_sme.zero : vector <[4 ]x[4 ]xf32 >
133
+ // expected-warning @below {{failed to allocate SME virtual tile to operation, all tile operations will go through memory, expect degraded performance}}
104
134
%tile_4 = arm_sme.zero : vector <[4 ]x[4 ]xf32 >
105
135
" test.dummy" (): () -> ()
106
136
" test.dummy" (): () -> ()
@@ -125,6 +155,12 @@ func.func @reuse_tiles_after_initial_use() {
125
155
// CHECK-LIVE-RANGE-NEXT: | arm_sme.copy_tile
126
156
// CHECK-LIVE-RANGE-NEXT: E cf.br
127
157
158
+ // Incorrect result! Both branches should yield the result via the same tile.
159
+ //
160
+ // CHECK-BAD-LABEL: @non_overlapping_branches
161
+ // CHECK-BAD: arm_sme.zero {tile_id = 0 : i32} : vector<[4]x[4]xf32>
162
+ // CHECK-BAD: arm_sme.get_tile {tile_id = 1 : i32} : vector<[4]x[4]xf32>
163
+
128
164
// CHECK-LABEL: @non_overlapping_branches
129
165
func.func @non_overlapping_branches (%cond: i1 ) {
130
166
// CHECK: arm_sme.zero {tile_id = 0 : i32} : vector<[4]x[4]xf32>
@@ -147,6 +183,13 @@ func.func @non_overlapping_branches(%cond: i1) {
147
183
// CHECK-LIVE-RANGE: ========== Coalesced Live Ranges:
148
184
// <deliberately omitted>
149
185
186
+ // Incorrect result! Everything assigned to tile 0 (which means values that are still live are overwritten).
187
+ //
188
+ // CHECK-BAD-LABEL: @constant_loop_init_with_multiple_users
189
+ // CHECK-BAD: arm_sme.zero {tile_id = 0 : i32} : vector<[4]x[4]xf32>
190
+ // CHECK-BAD: arm_sme.move_vector_to_tile_slice {{.*}} {tile_id = 0 : i32} : vector<[4]xf32> into vector<[4]x[4]xf32>
191
+ // CHECK-BAD: arm_sme.move_vector_to_tile_slice {{.*}} {tile_id = 0 : i32} : vector<[4]xf32> into vector<[4]x[4]xf32>
192
+
150
193
// CHECK-LABEL: @constant_loop_init_with_multiple_users
151
194
func.func @constant_loop_init_with_multiple_users (%a: vector <[4 ]xf32 >, %b: vector <[4 ]xf32 >) {
152
195
// CHECK: arm_sme.zero {tile_id = 0 : i32} : vector<[4]x[4]xf32>
@@ -183,6 +226,12 @@ func.func @constant_loop_init_with_multiple_users(%a: vector<[4]xf32>, %b: vecto
183
226
184
227
// Note in the live ranges (above) there is five tile values, but we only have four tiles.
185
228
229
+ // Incorrect result! Everything assigned to tile 0 (which means values that are still live are overwritten).
230
+ //
231
+ // CHECK-BAD-LABEL: @run_out_of_tiles_but_avoid_spill
232
+ // CHECK-BAD: arm_sme.zero {tile_id = 0 : i32}
233
+ // CHECK-BAD-COUNT-4: arm_sme.move_vector_to_tile_slice {{.*}} {tile_id = 0 : i32} : vector<[4]xf32> into vector<[4]x[4]xf32>
234
+
186
235
// CHECK-LABEL: @run_out_of_tiles_but_avoid_spill
187
236
func.func @run_out_of_tiles_but_avoid_spill (%a: vector <[4 ]xf32 >, %b: vector <[4 ]xf32 >, %c: vector <[4 ]xf32 >, %d: vector <[4 ]xf32 >) {
188
237
%init = arm_sme.zero : vector <[4 ]x[4 ]xf32 >
@@ -239,13 +288,20 @@ func.func @run_out_of_tiles_but_avoid_spill(%a: vector<[4]xf32>, %b: vector<[4]x
239
288
// CHECK-LIVE-RANGE-NEXT: || E test.some_use
240
289
// CHECK-LIVE-RANGE-NEXT: || arith.addi
241
290
// CHECK-LIVE-RANGE-NEXT: EE cf.br
242
-
291
+ //
243
292
// Note in the live ranges (above) there is two constant live-ins (first two ranges),
244
293
// which gives six overlapping live ranges. The allocator currently will spill the
245
294
// first constant (which results in a real spill at it's use), however, this could
246
295
// be avoided by using the knowledge that at the first "test.some_use" there's
247
296
// actually only two live ranges (so we can fix this be duplicating the constant).
248
297
298
+ // Incorrect result! Everything other than zero assigned to tile 1 (which means values that are still live are overwritten).
299
+ //
300
+ // CHECK-BAD-LABEL: @avoidable_spill
301
+ // CHECK-BAD: arm_sme.zero {tile_id = 0 : i32}
302
+ // CHECK-BAD: arm_sme.get_tile {tile_id = 1 : i32}
303
+ // CHECK-BAD-COUNT-4: arm_sme.move_vector_to_tile_slice {{.*}} {tile_id = 1 : i32}
304
+
249
305
// CHECK-LABEL: @avoidable_spill
250
306
func.func @avoidable_spill (%a: vector <[4 ]xf32 >, %b: vector <[4 ]xf32 >, %c: vector <[4 ]xf32 >, %d: vector <[4 ]xf32 >) {
251
307
// CHECK: arm_sme.zero {tile_id = 16 : i32} : vector<[4]x[4]xf32>
0 commit comments