Skip to content

Commit 5dc1c3d

Browse files
committed
Fix #276
1 parent 4b613d3 commit 5dc1c3d

File tree

5 files changed

+73
-8
lines changed

5 files changed

+73
-8
lines changed

src/compiler/iroptimizer.js

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,6 @@ class IROptimizer {
550550
case StackOpcode.CONTROL_WHILE:
551551
case StackOpcode.CONTROL_FOR:
552552
case StackOpcode.CONTROL_REPEAT:
553-
modified = this.analyzeInputs(inputs, state) || modified;
554553
modified = this.analyzeLoopedStack(inputs.do, state, stackBlock) || modified;
555554
break;
556555
case StackOpcode.CONTROL_IF_ELSE: {
@@ -642,8 +641,8 @@ class IROptimizer {
642641
return this.analyzeStack(stack, state) || modified;
643642
}
644643

644+
let modified = this.analyzeInputs(block.inputs, state);
645645
let iterations = 0;
646-
let modified = false;
647646
let keepLooping;
648647
do {
649648
// If we are stuck in an apparent infinite loop, give up and assume the worst.
@@ -657,11 +656,20 @@ class IROptimizer {
657656
}
658657
iterations++;
659658

660-
const newState = state.clone();
661-
modified = this.analyzeStack(stack, newState) || modified;
662-
modified = this.analyzeInputs(block.inputs, newState) || modified;
663-
modified = (keepLooping = state.or(newState)) || modified;
659+
// Used to detect change to overarching state
660+
const originalStateClone = state.clone();
661+
662+
const afterBody = state.clone();
663+
modified = this.analyzeStack(stack, afterBody) || modified;
664+
665+
// Inputs are also evaluated before the loop body ever runs at all. Can't lose that state
666+
// or we will make unfounded assumptions.
667+
modified = state.or(afterBody) || modified;
668+
modified = this.analyzeInputs(block.inputs, state) || modified;
669+
670+
modified = (keepLooping = originalStateClone.or(state)) || modified;
664671
} while (keepLooping);
672+
665673
block.entryState = state.clone();
666674
return modified;
667675
}
3.2 KB
Binary file not shown.

test/snapshot/__snapshots__/tw-gh-249-quicksort.sb3.tw-snapshot

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,10 @@ b0.value = (b1.value[(((((+p1 || 0) + (+p0 || 0)) || 0) / 2) | 0) - 1] ?? "");
6767
b2.value = p0;
6868
b3.value = p1;
6969
while (true) {
70-
while (compareLessThan((b1.value[(b2.value | 0) - 1] ?? ""), b0.value)) {
70+
while (compareLessThan(listGet(b1.value, b2.value), b0.value)) {
7171
b2.value = ((+b2.value || 0) + 1);
7272
}
73-
while (compareGreaterThan((b1.value[(b3.value | 0) - 1] ?? ""), b0.value)) {
73+
while (compareGreaterThan(listGet(b1.value, b3.value), b0.value)) {
7474
b3.value = ((+b3.value || 0) + -1);
7575
}
7676
if (compareGreaterThan(b2.value, b3.value)) {
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// TW Snapshot
2+
// Input SHA-256: 3c81a01417b9a927457132a5f89b63e54b2499714376246739535b51dbce2d45
3+
4+
// Sprite1 script
5+
(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage();
6+
const b0 = runtime.getOpcodeFunction("looks_say");
7+
const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"];
8+
return function* genXYZ () {
9+
yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "g", null);
10+
thread.procedures["Wtest %s"]("random");
11+
if ((("" + b1.value).toLowerCase() === "random".toLowerCase())) {
12+
yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "p", null);
13+
}
14+
yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "n", null);
15+
retire(); return;
16+
}; })
17+
18+
// Sprite1 Wtest %s
19+
(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage();
20+
const b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"];
21+
const b1 = stage.variables["t)]?yi[*8XU73qhMqOa8"];
22+
return function funXYZ_test_ (p0) {
23+
b0.value = p0;
24+
while (!(("" + listGet(b1.value, b0.value)).toLowerCase() === "something".toLowerCase())) {
25+
b0.value = ((+b0.value || 0) + 1);
26+
}
27+
return "";
28+
}; })
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// TW Snapshot
2+
// Input SHA-256: 3c81a01417b9a927457132a5f89b63e54b2499714376246739535b51dbce2d45
3+
4+
// Sprite1 script
5+
(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage();
6+
const b0 = runtime.getOpcodeFunction("looks_say");
7+
const b1 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"];
8+
return function* genXYZ () {
9+
yield* executeInCompatibilityLayer({"MESSAGE":"plan 1",}, b0, false, false, "g", null);
10+
yield* thread.procedures["Wtest %s"]("random");
11+
if ((("" + b1.value).toLowerCase() === "random".toLowerCase())) {
12+
yield* executeInCompatibilityLayer({"MESSAGE":"pass",}, b0, false, false, "p", null);
13+
}
14+
yield* executeInCompatibilityLayer({"MESSAGE":"end",}, b0, false, false, "n", null);
15+
retire(); return;
16+
}; })
17+
18+
// Sprite1 Wtest %s
19+
(function factoryXYZ(thread) { const target = thread.target; const runtime = target.runtime; const stage = runtime.getTargetForStage();
20+
const b0 = stage.variables["`jEk@4|i[#Fk?(8x)AV.-my variable"];
21+
const b1 = stage.variables["t)]?yi[*8XU73qhMqOa8"];
22+
return function* genXYZ_test_ (p0) {
23+
b0.value = p0;
24+
while (!(("" + listGet(b1.value, b0.value)).toLowerCase() === "something".toLowerCase())) {
25+
b0.value = ((+b0.value || 0) + 1);
26+
if (isStuck()) yield;
27+
}
28+
return "";
29+
}; })

0 commit comments

Comments
 (0)