Skip to content

Commit 7767967

Browse files
committed
[Lang] SNode-arm bound-expr capture: distinct-axis identity, accept ndrange uniformly across LLVM and SPIR-V
1 parent a470eb9 commit 7767967

1 file changed

Lines changed: 10 additions & 30 deletions

File tree

quadrants/transforms/static_adstack_analysis.cpp

Lines changed: 10 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -354,43 +354,23 @@ StaticAdStackAnalysisResult analyze_adstack_static_bounds(OffloadedStmt *task_ir
354354
}
355355
return false;
356356
};
357-
// For each iterating axis, walk back to its root source: the underlying `LoopIndexStmt` (StructFor case)
358-
// or the `AdStackAllocaStmt` whose `AdStackLoadTopStmt` replays it (autodiff reverse task). Multi-axis
359-
// gates whose iterating axes all derive from the SAME source (`field[i % 2, i % 2]`) are non-injective
360-
// even though they have multiple iterating axes; requiring `distinct_iterating_sources == n_iterating`
361-
// rejects those while admitting the canonical sparse-grid shape where each ndrange axis is replayed via
362-
// a distinct per-axis adstack. `BinaryOpStmt` / `UnaryOpStmt` operands are walked recursively to find the
363-
// leaf source.
364-
std::function<Stmt *(Stmt *, int)> root_source = [&](Stmt *s, int depth) -> Stmt * {
365-
if (s == nullptr || depth > 8)
366-
return nullptr;
367-
if (s->is<LoopIndexStmt>())
368-
return s;
369-
if (auto *load_top = s->cast<AdStackLoadTopStmt>()) {
370-
return load_top->stack;
371-
}
372-
if (auto *bin = s->cast<BinaryOpStmt>()) {
373-
if (Stmt *r = root_source(bin->lhs, depth + 1))
374-
return r;
375-
return root_source(bin->rhs, depth + 1);
376-
}
377-
if (auto *un = s->cast<UnaryOpStmt>()) {
378-
return root_source(un->operand, depth + 1);
379-
}
380-
return nullptr;
381-
};
357+
// Reject fold-attack shapes like `field[i % 2, i % 2]` where two iterating axes are the same IR
358+
// statement (CSE collapses both occurrences to a single `BinaryOpStmt`), causing multiple pushes per
359+
// outer-loop iteration to alias onto the same SNode cell and undersize the heap. The canonical
360+
// `qd.ndrange(*shape)` decomposition produces structurally distinct `floordiv` / `mod` / `sub`
361+
// statements per axis even though every axis is rooted at the same `LoopIndexStmt`, so identity
362+
// distinctness is the right gate: it rejects the fold attack while admitting the joint-bijective
363+
// ndrange shape uniformly across LLVM and SPIR-V backends.
382364
int n_iterating = 0;
383365
int n_bare_iterating = 0;
384-
std::unordered_set<Stmt *> distinct_iterating_sources;
366+
std::unordered_set<Stmt *> distinct_iterating_axes;
385367
for (Stmt *axis : axes) {
386368
if (contains_loop_index(axis, 0)) {
387369
n_iterating++;
388370
if (axis->is<LoopIndexStmt>()) {
389371
n_bare_iterating++;
390372
}
391-
if (Stmt *src = root_source(axis, 0)) {
392-
distinct_iterating_sources.insert(src);
393-
}
373+
distinct_iterating_axes.insert(axis);
394374
}
395375
}
396376
if (n_iterating == 0) {
@@ -399,7 +379,7 @@ StaticAdStackAnalysisResult analyze_adstack_static_bounds(OffloadedStmt *task_ir
399379
if (n_iterating == 1 && n_bare_iterating == 0) {
400380
return false;
401381
}
402-
if (static_cast<int>(distinct_iterating_sources.size()) < n_iterating) {
382+
if (static_cast<int>(distinct_iterating_axes.size()) < n_iterating) {
403383
return false;
404384
}
405385
out.field_source_kind = StaticAdStackBoundExpr::FieldSourceKind::SNode;

0 commit comments

Comments
 (0)