Skip to content

Commit 32c119e

Browse files
committed
[ssbuffer](fix) adjust iter_args insertion position in whileOp
Signed-off-by: m-everglow <2276518549@qq.com>
1 parent 4253a77 commit 32c119e

3 files changed

Lines changed: 151 additions & 34 deletions

File tree

third_party/ascend/lib/DynamicCVPipeline/AllocMultiCache/AddMultiBufferInnerScope.cpp

Lines changed: 79 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1849,7 +1849,9 @@ static void buildBeforeRegion(scf::WhileOp oldWhile, OpBuilder &bb, Location bl,
18491849
bb.create<scf::ConditionOp>(bl, condValue, carriedValues);
18501850
}
18511851

1852-
// Build the after-region of the new whileOp
1852+
// Build the after-region of the new whileOp. The counter add-1 is not
1853+
// created here; it is inserted later by insertWhileCounterOps at the right
1854+
// position. counterIterArgOut is yielded as a placeholder and gets replaced.
18531855
static void buildAfterRegion(scf::WhileOp oldWhile, OpBuilder &ab, Location al,
18541856
ValueRange iterArgs, Value &counterIterArgOut) {
18551857
Block *oldAfter = oldWhile.getAfterBody();
@@ -1871,35 +1873,12 @@ static void buildAfterRegion(scf::WhileOp oldWhile, OpBuilder &ab, Location al,
18711873
if (!oldYield)
18721874
return;
18731875

1874-
std::optional<int> counterBlockId;
1875-
if (Block *doBlock = ab.getInsertionBlock()) {
1876-
for (Operation &op : llvm::reverse(*doBlock)) {
1877-
if (auto id = getOpBlockId(&op); id.has_value()) {
1878-
counterBlockId = id;
1879-
break;
1880-
}
1881-
}
1882-
}
1883-
if (!counterBlockId)
1884-
counterBlockId = getOpBlockId(oldWhile);
1885-
1886-
Value one = ab.create<arith::ConstantIntOp>(al, 1, 32);
1887-
Value nextCounter = ab.create<arith::AddIOp>(al, counterIterArgOut, one);
1888-
nextCounter.getDefiningOp()->setAttr(kIterCounter, ab.getUnitAttr());
1889-
1890-
if (counterBlockId) {
1891-
one.getDefiningOp()->setAttr(kBlockId,
1892-
ab.getI32IntegerAttr(*counterBlockId));
1893-
nextCounter.getDefiningOp()->setAttr(kBlockId,
1894-
ab.getI32IntegerAttr(*counterBlockId));
1895-
}
1896-
18971876
SmallVector<Value> newYieldOps;
18981877
for (Value operand : oldYield->getOperands()) {
18991878
Value mapped = mapper.lookupOrNull(operand);
19001879
newYieldOps.push_back(mapped ? mapped : operand);
19011880
}
1902-
newYieldOps.push_back(nextCounter);
1881+
newYieldOps.push_back(counterIterArgOut);
19031882
ab.create<scf::YieldOp>(al, newYieldOps);
19041883
}
19051884

@@ -1952,6 +1931,77 @@ setupWhileIterArgCounter(const MainLoop &loop, OpBuilder &builder) {
19521931
return {counterIterArg, newWhile};
19531932
}
19541933

1934+
// Insert the iterCounter add-1 (and its constant 1) right after the last op
1935+
// sharing the block_id of the first op that consumes mainLoop.iterCounter.
1936+
// Must run after processTensorDependencies (dispatch ops land there later).
1937+
// Fallback when no counter user exists: last op's block_id, mirroring the
1938+
// legacy buildAfterRegion placement.
1939+
static void insertWhileCounterOps(const MainLoop &mainLoop) {
1940+
if (!mainLoop.isWhile() || !mainLoop.iterCounter)
1941+
return;
1942+
1943+
auto whileOp = cast<scf::WhileOp>(mainLoop.getOperation());
1944+
Block *doBlock = whileOp.getAfterBody();
1945+
if (!doBlock)
1946+
return;
1947+
1948+
std::optional<int> counterBlockId;
1949+
for (Operation &op : *doBlock) {
1950+
if (llvm::is_contained(op.getOperands(), mainLoop.iterCounter)) {
1951+
counterBlockId = getOpBlockId(&op);
1952+
break;
1953+
}
1954+
}
1955+
if (!counterBlockId) {
1956+
for (Operation &op : llvm::reverse(*doBlock)) {
1957+
if (auto id = getOpBlockId(&op); id.has_value()) {
1958+
counterBlockId = id;
1959+
break;
1960+
}
1961+
}
1962+
if (!counterBlockId)
1963+
return;
1964+
}
1965+
1966+
Operation *lastWithBlockId = nullptr;
1967+
for (Operation &op : *doBlock) {
1968+
auto id = getOpBlockId(&op);
1969+
if (id.has_value() && *id == *counterBlockId)
1970+
lastWithBlockId = &op;
1971+
}
1972+
1973+
Location loc = lastWithBlockId->getLoc();
1974+
OpBuilder builder(mainLoop.getContext());
1975+
builder.setInsertionPointAfter(lastWithBlockId);
1976+
IntegerAttr blockIdAttr = builder.getI32IntegerAttr(*counterBlockId);
1977+
1978+
Value one = builder.create<arith::ConstantIntOp>(
1979+
loc, 1, mainLoop.iterCounter.getType().getIntOrFloatBitWidth());
1980+
one.getDefiningOp()->setAttr(kBlockId, blockIdAttr);
1981+
1982+
Value nextCounter =
1983+
builder.create<arith::AddIOp>(loc, mainLoop.iterCounter, one);
1984+
Operation *iterAddOp = nextCounter.getDefiningOp();
1985+
iterAddOp->setAttr(kBlockId, blockIdAttr);
1986+
iterAddOp->setAttr(kIterCounter, builder.getUnitAttr());
1987+
1988+
// Replace the placeholder counterIterArgOut operand in the yield with
1989+
// nextCounter so the iter_arg increments each iteration.
1990+
Operation *yieldOp = doBlock->getTerminator();
1991+
SmallVector<Value> newOperands(yieldOp->getOperands().begin(),
1992+
yieldOp->getOperands().end());
1993+
bool replaced = false;
1994+
for (Value &operand : newOperands) {
1995+
if (operand == mainLoop.iterCounter) {
1996+
operand = nextCounter;
1997+
replaced = true;
1998+
break;
1999+
}
2000+
}
2001+
if (replaced)
2002+
yieldOp->setOperands(newOperands);
2003+
}
2004+
19552005
static int addInnerMultiBuffer(MainLoop mainLoop, OpBuilder &builder,
19562006
scope::ScopeOp vectorScope, int &groupId,
19572007
bool &i1Found) {
@@ -2087,6 +2137,10 @@ static int addInnerMultiBuffer(MainLoop mainLoop, OpBuilder &builder,
20872137
return -1;
20882138
}
20892139

2140+
// WhileOp only: insert the counter add-1 now that the dispatch ops that
2141+
// use mainLoop.iterCounter have been emitted.
2142+
insertWhileCounterOps(mainLoop);
2143+
20902144
LLVM_DEBUG(llvm::dbgs() << "[addInnerMultiBuffer] DONE\n");
20912145
return 0;
20922146
}

third_party/ascend/lib/DynamicCVPipeline/AnalyzeDataFlow/AnalyzeName.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@ namespace {
4242

4343
static constexpr llvm::StringLiteral interceptrFunc[]{
4444
"chunk_abc_bwd_kernel_dh", "flash_varlen_fwd_kernel",
45-
"chunk_gsa_bwd_k_kernel_dqkvg", "_jagged_flash_attention_bwd_basic_kernel",
46-
"_sparse_decode_kernel", "chunk_gsa_fwd_k_kernel_intra",
45+
"chunk_gsa_bwd_k_kernel_dqkvg", "_sparse_decode_kernel",
4746
"_sparse_decode_model1_kernel", "sparse_flash_attention_grad_kernel"};
4847

4948
static LogicalResult verifyFuncNames(ModuleOp module) {

third_party/ascend/unittest/Conversion/General/DynamicCVPipeline/AllocMultiCache/Inner-scope-whileop.mlir

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,24 @@
3535
// (3 block-args instead of 2; the new arg is i32).
3636
// - arith.addi counter, 1 is present in the do-region for the yield.
3737
// - 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.
3841

3942
// CHECK-LABEL: func.func @test_while_mainloop_bufnum_two
4043
// Two UB allocs (ping/pong).
4144
// CHECK-DAG: memref.alloc() : memref<128xf32, #hivm.address_space<ub>>
4245
// CHECK-DAG: memref.alloc() : memref<128xf32, #hivm.address_space<ub>>
4346
// WhileOp's do-region bb0 has 3 block-args now (the new i32 counter is the last one).
4447
// CHECK: ^bb0(%{{.*}}: tensor<128xf32>, %{{.*}}: i32, %{{.*}}: i32):
45-
// Producer scf.if dispatch (the original counter increment lives inside this region).
48+
// Producer scf.if dispatch.
4649
// CHECK: scf.if
4750
// 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
4853
// Consumer scf.if dispatch returning tensor.
4954
// CHECK: scf.if {{.*}} -> (tensor<128xf32>)
5055
// 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
5356
// Counter-aware whileOp carries ssbuffer.iterCounter alongside main_loop.
5457
// CHECK: } {{.*}}ssbuffer.iterCounter, {{.*}}ssbuffer.main_loop = 1 : i64
5558

@@ -63,11 +66,11 @@
6366
// Producer alloc + copy before the whileOp.
6467
// CHECK-DAG: memref.alloc() : memref<64xf16, #hivm.address_space<ub>>
6568
// 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
6671
// Consumer scf.if + to_tensor inside the do-region.
6772
// CHECK: scf.if {{.*}} -> (tensor<64xf16>)
6873
// 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
7174
// Counter-aware whileOp carries ssbuffer.iterCounter alongside main_loop.
7275
// CHECK: } {{.*}}ssbuffer.iterCounter, {{.*}}ssbuffer.main_loop = 1 : i64
7376

@@ -90,8 +93,8 @@
9093
// Producer-side dispatch.
9194
// CHECK: scf.if
9295
// 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
9598
// Counter-aware whileOp carries ssbuffer.iterCounter alongside main_loop.
9699
// CHECK: } {{.*}}ssbuffer.iterCounter, {{.*}}ssbuffer.main_loop = 1 : i64
97100

@@ -121,6 +124,34 @@
121124
// Not implemented in this initial drop — to be added when the negative case
122125
// is needed for a regression guard.
123126

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+
124155
// ---- Inputs ----
125156

126157
module attributes {hacc.target = #hacc.target<"Ascend950PR_9579">,
@@ -277,4 +308,37 @@ module attributes {hacc.target = #hacc.target<"Ascend950PR_9579">,
277308
} {hivm.tcore_type = #hivm.tcore_type<VECTOR>}
278309
return
279310
}
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+
}
280344
}

0 commit comments

Comments
 (0)