mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-25 06:24:27 +08:00
Ignore products that only bound a loop's condition
A setup loop such as `for (i = 0; i < Math.floor(300000 * scale); i++) text.push(word())` multiplies only in its condition; its body does no integer work, so it keeps one copy. Also records the ts7 baseline of the speculative integer reads fixture.
This commit is contained in:
@@ -182,6 +182,9 @@ test("invariants may come from bindings no shadow could be written to", () => {
|
||||
test("loops that only count and compare keep one copy", () => {
|
||||
const counter = loop([increment("i")]);
|
||||
expect(planSpeculativeLoop(counter as never, all)).toBeNull();
|
||||
// A product in the condition alone is not.
|
||||
const bounded = loop([increment("i")], bin("<", ref("i"), bin("*", ref("n"), ref("scale"))));
|
||||
expect(planSpeculativeLoop(bounded as never, all)).toBeNull();
|
||||
// A variable step (a sieve's `j += i`) is worth a copy.
|
||||
const sieve = loop([assign("i", bin("+", ref("i"), ref("step")))]);
|
||||
expect(planSpeculativeLoop(sieve as never, all)?.locals.has("i")).toBe(true);
|
||||
|
||||
@@ -259,6 +259,9 @@ export function planSpeculativeLoop(
|
||||
// double forms cost the most. A loop whose integers only count and compare
|
||||
// gains nothing measurable from a second copy, so it keeps one.
|
||||
const multiplied = new Set<string>();
|
||||
// A product in the condition alone (`i < Math.floor(n * scale)`) does not
|
||||
// make the body's work integer.
|
||||
let inCondition = false;
|
||||
|
||||
const expr = (e: IrExpr): boolean => {
|
||||
if (rejected) return false;
|
||||
@@ -272,7 +275,7 @@ export function planSpeculativeLoop(
|
||||
else if (e.kind === "bin" && CONSUMING_OPS.has(e.op)) {
|
||||
consume(e.left);
|
||||
consume(e.right);
|
||||
if (e.op === "*" || e.op === "/" || e.op === "%")
|
||||
if (!inCondition && (e.op === "*" || e.op === "/" || e.op === "%"))
|
||||
for (const operand of [e.left, e.right])
|
||||
if (operand.kind === "varRef") multiplied.add(operand.localId);
|
||||
} else if (e.kind === "arrayGet" || e.kind === "arrayHas" || e.kind === "arrayState")
|
||||
@@ -321,7 +324,11 @@ export function planSpeculativeLoop(
|
||||
return everyStmtChild(s, expr, stmt);
|
||||
};
|
||||
|
||||
if (loop.cond) expr(loop.cond);
|
||||
if (loop.cond) {
|
||||
inCondition = true;
|
||||
expr(loop.cond);
|
||||
inCondition = false;
|
||||
}
|
||||
if (loop.kind === "for" && loop.update) stmt(loop.update);
|
||||
for (const s of loop.body) stmt(s);
|
||||
if (rejected || nodes > MAX_LOOP_NODES) return null;
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"order": [
|
||||
"<repo>/tests/corpus/speculative-integer-reads.ts"
|
||||
],
|
||||
"diags": []
|
||||
}
|
||||
Reference in New Issue
Block a user