From e7e943a1d3ffd4a8e44fc40ffcd19b217ba8ad4c Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 02:00:06 -0500 Subject: [PATCH] Accept only nested scans that highestCount walks pass by pass The first pass of guardedLoopCounterFacts accepted a nested while loop anywhere outside an opaque region, and highestCount then left counters unbounded where it does not walk such a loop. The first pass now accepts the same loops highestCount walks: statements of the body, its blocks and its branches. A loop in a labeled block or among an expression's statements is an ordinary loop region, whose counter writes are refused. --- packages/compiler/src/ir/integer-loop-facts.ts | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/compiler/src/ir/integer-loop-facts.ts b/packages/compiler/src/ir/integer-loop-facts.ts index 31edc2f48..8807212dc 100644 --- a/packages/compiler/src/ir/integer-loop-facts.ts +++ b/packages/compiler/src/ir/integer-loop-facts.ts @@ -276,16 +276,26 @@ export function guardedLoopCounterFacts( else budget.set(id, (budget.get(id) ?? 0) + delta); }; // Nested while loops outside opaque regions, checked against their own - // conditions once the stable bounds are known. + // conditions once the stable bounds are known. Only loops that highestCount + // walks pass by pass qualify: statements of the body, its blocks and its + // branches. One in a labeled block or among an expression's statements + // (`indirect`) is an ordinary loop region. const nested: (IrStmt & { kind: "while" })[] = []; + let indirect = 0; const expr = (e: IrExpr): boolean => { if (e.kind === "assignExpr") write(e.localId, increment(e.localId, e.value)); if (e.kind === "incDec") write(e.localId, e.op === "+" ? 1 : null); - return everyExprChild(e, expr, stmt); + return everyExprChild(e, expr, (x) => { + indirect++; + const completed = stmt(x); + indirect--; + return completed; + }); }; const condition = new Set(); const stmt = (s: IrStmt): boolean => { - const bounded = s.kind === "while" && opaque === 0 && !s.labels?.length; + const bounded = s.kind === "while" && opaque === 0 && indirect === 0 && !s.labels?.length; + const labeled = s.kind === "block" && !!s.labels?.length; const region = !bounded && (s.kind === "for" || @@ -299,10 +309,12 @@ export function guardedLoopCounterFacts( conditionWrites(s.cond); } if (region) opaque++; + if (labeled) indirect++; if (s.kind === "assign") write(s.localId, increment(s.localId, s.value)); if (s.kind === "varDecl" || s.kind === "forOf") write(s.localId, null); if (s.kind === "tryCatch" && s.catchLocalId) write(s.catchLocalId, null); const completed = everyStmtChild(s, expr, stmt); + if (labeled) indirect--; if (region) opaque--; return completed; };