|
35 | 35 | // (3 block-args instead of 2; the new arg is i32). |
36 | 36 | // - arith.addi counter, 1 is present in the do-region for the yield. |
37 | 37 | // - Multi-buffer producer/consumer with scf.if dispatch works as forOp. |
| 38 | +// - The counter add-1 op (and its constant-1) is relocated to the |
| 39 | +// block_id of the first op that consumes the counter arg (here: the |
| 40 | +// producer scf.if at block_id = 7), not its old fallback position. |
38 | 41 |
|
39 | 42 | // CHECK-LABEL: func.func @test_while_mainloop_bufnum_two |
40 | 43 | // Two UB allocs (ping/pong). |
41 | 44 | // CHECK-DAG: memref.alloc() : memref<128xf32, #hivm.address_space<ub>> |
42 | 45 | // CHECK-DAG: memref.alloc() : memref<128xf32, #hivm.address_space<ub>> |
43 | 46 | // WhileOp's do-region bb0 has 3 block-args now (the new i32 counter is the last one). |
44 | 47 | // CHECK: ^bb0(%{{.*}}: tensor<128xf32>, %{{.*}}: i32, %{{.*}}: i32): |
45 | | -// Producer scf.if dispatch (the original counter increment lives inside this region). |
| 48 | +// Producer scf.if dispatch. |
46 | 49 | // CHECK: scf.if |
47 | 50 | // CHECK: hivm.hir.copy |
| 51 | +// arith.addi increment for the multi-buffer counter (block_id=7, the first user's block). |
| 52 | +// CHECK: %{{.+}} = arith.addi %{{.+}}, %{{.+}} {ssbuffer.block_id = 7 : i32, ssbuffer.iterCounter} : i32 |
48 | 53 | // Consumer scf.if dispatch returning tensor. |
49 | 54 | // CHECK: scf.if {{.*}} -> (tensor<128xf32>) |
50 | 55 | // CHECK: bufferization.to_tensor |
51 | | -// arith.addi increment for the multi-buffer counter is present (block_id=10), tagged iterCounter. |
52 | | -// CHECK: %{{.+}} = arith.addi %{{.+}}, %{{.+}} {ssbuffer.block_id = 10 : i32, ssbuffer.iterCounter} : i32 |
53 | 56 | // Counter-aware whileOp carries ssbuffer.iterCounter alongside main_loop. |
54 | 57 | // CHECK: } {{.*}}ssbuffer.iterCounter, {{.*}}ssbuffer.main_loop = 1 : i64 |
55 | 58 |
|
|
63 | 66 | // Producer alloc + copy before the whileOp. |
64 | 67 | // CHECK-DAG: memref.alloc() : memref<64xf16, #hivm.address_space<ub>> |
65 | 68 | // CHECK-DAG: memref.alloc() : memref<64xf16, #hivm.address_space<ub>> |
| 69 | +// arith.addi increment for the multi-buffer counter (block_id=7, the first user's block). |
| 70 | +// CHECK: %{{.+}} = arith.addi %{{.+}}, %{{.+}} {ssbuffer.block_id = 7 : i32, ssbuffer.iterCounter} : i32 |
66 | 71 | // Consumer scf.if + to_tensor inside the do-region. |
67 | 72 | // CHECK: scf.if {{.*}} -> (tensor<64xf16>) |
68 | 73 | // CHECK: bufferization.to_tensor |
69 | | -// arith.addi increment for the multi-buffer counter is present (block_id=12), tagged iterCounter. |
70 | | -// CHECK: %{{.+}} = arith.addi %{{.+}}, %{{.+}} {ssbuffer.block_id = 12 : i32, ssbuffer.iterCounter} : i32 |
71 | 74 | // Counter-aware whileOp carries ssbuffer.iterCounter alongside main_loop. |
72 | 75 | // CHECK: } {{.*}}ssbuffer.iterCounter, {{.*}}ssbuffer.main_loop = 1 : i64 |
73 | 76 |
|
|
90 | 93 | // Producer-side dispatch. |
91 | 94 | // CHECK: scf.if |
92 | 95 | // CHECK: hivm.hir.copy |
93 | | -// arith.addi increment for the multi-buffer counter is present (block_id=12), tagged iterCounter. |
94 | | -// CHECK: %{{.+}} = arith.addi %{{.+}}, %{{.+}} {ssbuffer.block_id = 12 : i32, ssbuffer.iterCounter} : i32 |
| 96 | +// arith.addi increment for the multi-buffer counter (block_id=8, the first user's block). |
| 97 | +// CHECK: %{{.+}} = arith.addi %{{.+}}, %{{.+}} {ssbuffer.block_id = 8 : i32, ssbuffer.iterCounter} : i32 |
95 | 98 | // Counter-aware whileOp carries ssbuffer.iterCounter alongside main_loop. |
96 | 99 | // CHECK: } {{.*}}ssbuffer.iterCounter, {{.*}}ssbuffer.main_loop = 1 : i64 |
97 | 100 |
|
|
121 | 124 | // Not implemented in this initial drop — to be added when the negative case |
122 | 125 | // is needed for a regression guard. |
123 | 126 |
|
| 127 | +// T-while-G: Regression guard for relocateWhileCounterOps. |
| 128 | +// The counter add-1 (and its constant 1) used to be appended at the end of |
| 129 | +// the do-region, carrying the whileOp's own block_id (= 99 here, distinct |
| 130 | +// from both producer and consumer). The pass now relocates them to the |
| 131 | +// block_id of the first op that consumes the counter iter_arg — the |
| 132 | +// producer scf.if at block_id = 5. |
| 133 | +// We assert: |
| 134 | +// - The counter add-1 carries block_id = 5 (NOT 99, NOT 50). |
| 135 | +// - The constant 1 used by the addi also carries block_id = 5. |
| 136 | +// - The scf.yield that consumes the add-1's SSA value still references |
| 137 | +// // the same %result (SSA is preserved across the move). |
| 138 | + |
| 139 | +// CHECK-LABEL: func.func @test_while_counter_relocation |
| 140 | +// Multi-buffer producer (two allocs at block 5) emits the dispatch. |
| 141 | +// CHECK-DAG: memref.alloc() : memref<16xf32, #hivm.address_space<ub>> |
| 142 | +// CHECK-DAG: memref.alloc() : memref<16xf32, #hivm.address_space<ub>> |
| 143 | +// CHECK: scf.if |
| 144 | +// CHECK: hivm.hir.copy |
| 145 | +// Constant 1 carrying block_id = 5 (relocated with the addi). |
| 146 | +// CHECK: %{{.+}} = arith.constant {ssbuffer.block_id = 5 : i32} 1 : i32 |
| 147 | +// Counter add-1 carries block_id = 5 and is tagged iterCounter. |
| 148 | +// CHECK: %{{.+}} = arith.addi %{{.+}}, %{{.+}} {ssbuffer.block_id = 5 : i32, ssbuffer.iterCounter} : i32 |
| 149 | +// scf.yield forwards the counter (referenced by the addi's %addi-res), proving |
| 150 | +// SSA is preserved. |
| 151 | +// CHECK: scf.yield %{{.*}}, %{{.*}}, %{{.+}} |
| 152 | +// Counter-aware whileOp carries ssbuffer.iterCounter alongside main_loop. |
| 153 | +// CHECK: } {{.*}}ssbuffer.iterCounter, {{.*}}ssbuffer.main_loop = 1 : i64 |
| 154 | + |
124 | 155 | // ---- Inputs ---- |
125 | 156 |
|
126 | 157 | module attributes {hacc.target = #hacc.target<"Ascend950PR_9579">, |
@@ -277,4 +308,37 @@ module attributes {hacc.target = #hacc.target<"Ascend950PR_9579">, |
277 | 308 | } {hivm.tcore_type = #hivm.tcore_type<VECTOR>} |
278 | 309 | return |
279 | 310 | } |
| 311 | + |
| 312 | + // T-while-G: dedicated regression test for relocateWhileCounterOps. |
| 313 | + // Producer at block_id = 5, consumer at block_id = 50, whileOp at block_id = 99. |
| 314 | + // Before the fix: counter add-1 would land at block_id = 99 (whileOp's own id). |
| 315 | + // After the fix: counter add-1 (and its constant 1) land at block_id = 5 |
| 316 | + // (the block_id of the first op that consumes the counter iter_arg). |
| 317 | + func.func @test_while_counter_relocation() { |
| 318 | + %c0_i32 = arith.constant 0 : i32 |
| 319 | + %c10_i32 = arith.constant 10 : i32 |
| 320 | + %c1_i32 = arith.constant 1 : i32 |
| 321 | + %cst_zero = arith.constant 0.0 : f32 |
| 322 | + %init = tensor.empty() : tensor<16xf32> |
| 323 | + %carry = linalg.fill ins(%cst_zero : f32) outs(%init : tensor<16xf32>) -> tensor<16xf32> |
| 324 | + scope.scope : () -> () { |
| 325 | + %result:2 = scf.while (%arg0 = %carry, %arg1 = %c0_i32) |
| 326 | + : (tensor<16xf32>, i32) -> (tensor<16xf32>, i32) { |
| 327 | + %cmp = arith.cmpi slt, %arg1, %c10_i32 {ssbuffer.block_id = 16 : i32} : i32 |
| 328 | + scf.condition(%cmp) %arg0, %arg1 : tensor<16xf32>, i32 |
| 329 | + } do { |
| 330 | + ^bb0(%arg0: tensor<16xf32>, %arg1: i32): |
| 331 | + // Producer block_id = 5. |
| 332 | + %alloc = memref.alloc() {ssbuffer.block_id = 5 : i32} : memref<16xf32> |
| 333 | + %prod = bufferization.to_tensor %alloc {ssbuffer.block_id = 5 : i32} : memref<16xf32> to tensor<16xf32> |
| 334 | + // Consumer block_id = 50 (very different from 5, to make the relocation |
| 335 | + // verdict unambiguous). |
| 336 | + %consumed = arith.addf %prod, %prod {ssbuffer.block_id = 50 : i32} : tensor<16xf32> |
| 337 | + %next = arith.addi %arg1, %c1_i32 : i32 |
| 338 | + scf.yield %consumed, %next : tensor<16xf32>, i32 |
| 339 | + } attributes {ssbuffer.main_loop = 1 : i64, ssbuffer.block_id = 99 : i32} |
| 340 | + scope.return |
| 341 | + } {hivm.tcore_type = #hivm.tcore_type<VECTOR>} |
| 342 | + return |
| 343 | + } |
280 | 344 | } |
0 commit comments