"ValueBlock" for while test node
The instructions of a while test node cannot just be pushed to the previous block. This creates a new block for the test node and then during code gen converts the statements pushed to the "value block" into expressions.
Jan Kassens committed
Dec 6, 2022 at 11:28 UTC
db740366f821c10350d3eb94b384ef8911dedefd
10 files changed
+79
-24
compiler/forget/src/HIR/Codegen.ts
+23
@@ -100,6 +100,10 @@ class CodegenVisitor
100
this.depth++;
101
return [];
102
}
103
+ enterValueBlock(): t.Statement[] {
104
+ this.depth++;
105
+ return [];
106
+ }
107
visitValue(value: InstructionValue): t.Expression {
108
return codegenInstructionValue(this.temp, value);
109
}
@@ -237,6 +241,25 @@ class CodegenVisitor
241
this.depth--;
242
return t.blockStatement(block);
243
}
244
+ leaveValueBlock(block: t.Statement[], place: t.Expression): t.Expression {
245
+ this.depth--;
246
+ if (block.length === 0) {
247
+ return place;
248
+ }
249
+ const expressions = block.map((stmt) => {
250
+ switch (stmt.type) {
251
+ case "ExpressionStatement":
252
+ return stmt.expression;
253
+ default:
254
+ todoInvariant(
255
+ false,
256
+ `Handle conversion of ${stmt.type} to expression`
257
+ );
258
+ }
259
+ });
260
+ expressions.push(place);
261
+ return t.sequenceExpression(expressions);
262
+ }
263
}
264
265
function codegenLabel(id: BlockId): string {
compiler/forget/src/HIR/HIRTreeVisitor.ts
+16
-7
@@ -239,15 +239,20 @@ class Driver<TBlock, TValue, TItem, TCase> {
239
testTerminal.kind === "if",
240
"Expected while loop test block to end in an if"
241
);
242
- // const bodyLength = blockValue.length;
242
+ const testValueBlock = this.visitor.enterValueBlock();
243
for (const instr of testBlock.instructions) {
244
- this.visitInstr(instr, blockValue);
244
+ const value = this.visitor.visitValue(instr.value, instr.id);
245
+ const item = this.visitor.visitInstruction(instr, value);
246
+ this.visitor.appendBlock(testValueBlock, item);
247
}
246
- // invariant(
247
- // body.length === bodyLength,
248
- // "Expected test to produce only temporaries"
249
- // );
250
- const testValue = this.visitPlace(testTerminal.test, terminal.id);
248
+ const testValueLast = this.visitor.visitValue(
249
+ testTerminal.test,
250
+ testTerminal.id
251
+ );
252
+ const testValue = this.visitor.leaveValueBlock(
253
+ testValueBlock,
254
+ testValueLast
255
+ );
256
const fallthroughId =
257
terminal.fallthrough !== null &&
258
!this.cx.isScheduled(terminal.fallthrough)
@@ -644,6 +649,10 @@ export interface Visitor<TBlock, TValue, TItem, TCase> {
649
*/
650
enterBlock(): TBlock;
651
652
+ enterValueBlock(): TBlock;
653
+
654
+ leaveValueBlock(block: TBlock, value: TValue): TValue;
655
+
656
/**
657
* Convert an InstructionValue into the visitor's own representation
658
* of a value.
compiler/forget/src/HIR/InferReactiveScopeDependencies.ts
+4
@@ -189,8 +189,12 @@ class ScopeDependenciesVisitor
189
}
190
191
enterBlock(): void {}
192
+ enterValueBlock(): void {}
193
visitImplicitTerminal(): void | null {}
194
visitCase(test: InstructionValue, block: void): void {}
195
appendBlock(block: void, item: void, label?: BlockId | undefined): void {}
196
leaveBlock(block: void): void {}
197
+ leaveValueBlock(block: void, value: InstructionValue): InstructionValue {
198
+ return value;
199
+ }
200
}
compiler/forget/src/HIR/InferReactiveScopes.ts
+14
@@ -254,6 +254,12 @@ class MergeOverlappingReactiveScopesVisitor
254
enterBlock(): void {
255
this.scopes.push(new BlockScope());
256
}
257
+ enterValueBlock(): void {
258
+ this.enterBlock();
259
+ }
260
+ leaveValueBlock(block: void, value: void): void {
261
+ this.leaveBlock();
262
+ }
263
visitValue(value: InstructionValue, id: InstructionId): void {
264
this.visitId(id);
265
for (const operand of eachInstructionValueOperand(value)) {
@@ -355,6 +361,14 @@ class AlignReactiveScopesToBlockScopeRangeVisitor
361
}
362
}
363
364
+ enterValueBlock(): void {
365
+ this.enterBlock();
366
+ }
367
+
368
+ leaveValueBlock(block: void, value: void): void {
369
+ this.leaveBlock();
370
+ }
371
+
372
visitInstruction(instruction: Instruction, value: void): void {
373
const scope = getInstructionScope(instruction);
374
if (scope !== null) {
compiler/forget/src/HIR/PrintHIRTree.ts
+6
@@ -32,6 +32,12 @@ class PrintVisitor implements Visitor<Array<string>, string, string, string> {
32
this.depth++;
33
return [];
34
}
35
+ enterValueBlock(): string[] {
36
+ return this.enterBlock();
37
+ }
38
+ leaveValueBlock(block: string[], value: string): string {
39
+ return this.leaveBlock(block);
40
+ }
41
visitValue(value: InstructionValue): string {
42
return printMixedHIR(value);
43
}
compiler/forget/src/__tests__/fixtures/hir/_bug_while-with-assignment.expect.md
+4
-5
@@ -31,7 +31,7 @@ bb1:
31
sum$21_@3[0:14]: phi(bb0: sum$16_@3, bb3: sum$22_@3)
32
[8] Reassign mutate value$18_@3[0:14] = Call mutate queue$14_@3.pop()
33
[9] Const mutate $19_@6 = null
34
- [10] Const mutate $20_@7[10:14] = Binary read value$18_@3 != read $19_@6
34
+ [10] Const mutate $20_@7[10:12] = Binary read value$18_@3 != read $19_@6
35
[11] If (read $20_@7) then:bb3 else:bb2
36
bb3:
37
predecessor blocks: bb1
@@ -40,7 +40,7 @@ bb3:
40
bb2:
41
predecessor blocks: bb1
42
[14] Return read sum$21_@3
43
-scope7 [10:14]:
43
+scope7 [10:12]:
44
- read $19_@6
45
```
46
@@ -64,7 +64,7 @@ flowchart TB
64
bb1_instrs["
65
[8] Reassign mutate value$18_@3[0:14] = Call mutate queue$14_@3.pop()
66
[9] Const mutate $19_@6 = null
67
- [10] Const mutate $20_@7[10:14] = Binary read value$18_@3 != read $19_@6
67
+ [10] Const mutate $20_@7[10:12] = Binary read value$18_@3 != read $19_@6
68
"]
69
bb1_instrs --> bb1_terminal(["If (read $20_@7)"])
70
end
@@ -95,8 +95,7 @@ function f$0(reader$1) {
95
const queue$2 = [1, 2, 3];
96
let value$6 = 0;
97
let sum$7 = 0;
98
- value$6 = queue$2.pop();
99
- bb2: while (value$6 != null) {
98
+ bb2: while (((value$6 = queue$2.pop()), value$6 != null)) {
99
sum$7 = sum$7 + value$6;
100
}
101
compiler/forget/src/__tests__/fixtures/hir/mutable-lifetime-loops.expect.md
+2
-2
@@ -108,7 +108,7 @@ bb1:
108
b$20_@0[0:23]: phi(bb0: b$14_@0, bb4: b$23_@0)
109
c$22_@0[0:23]: phi(bb0: c$15_@0, bb4: c$25_@0)
110
d$24_@0[0:23]: phi(bb0: d$16_@0, bb4: d$26_@0)
111
- [6] Const mutate $17_@1[6:17] = true
111
+ [6] Const mutate $17_@1[6:8] = true
112
[7] If (read $17_@1) then:bb3 else:bb2
113
bb3:
114
predecessor blocks: bb1
@@ -163,7 +163,7 @@ flowchart TB
163
end
164
subgraph bb1
165
bb1_instrs["
166
- [6] Const mutate $17_@1[6:17] = true
166
+ [6] Const mutate $17_@1[6:8] = true
167
"]
168
bb1_instrs --> bb1_terminal(["If (read $17_@1)"])
169
end
compiler/forget/src/__tests__/fixtures/hir/mutable-liverange-loop.expect.md
+2
-2
@@ -99,7 +99,7 @@ bb0:
99
[5] While test=bb1 loop=bb3 fallthrough=bb2
100
bb1:
101
predecessor blocks: bb0 bb4
102
- [6] Const mutate $16_@2[6:12] = true
102
+ [6] Const mutate $16_@2[6:8] = true
103
[7] If (read $16_@2) then:bb3 else:bb2
104
bb3:
105
predecessor blocks: bb1
@@ -145,7 +145,7 @@ flowchart TB
145
end
146
subgraph bb1
147
bb1_instrs["
148
- [6] Const mutate $16_@2[6:12] = true
148
+ [6] Const mutate $16_@2[6:8] = true
149
"]
150
bb1_instrs --> bb1_terminal(["If (read $16_@2)"])
151
end
compiler/forget/src/__tests__/fixtures/hir/ssa-while-no-reassign.expect.md
+5
-5
@@ -17,12 +17,12 @@ function foo() {
17
18
```
19
bb0:
20
- [1] Let mutate x$5_@0[1:3] = 1
20
+ [1] Let mutate x$5_@0 = 1
21
[2] While test=bb1 loop=bb3 fallthrough=bb2
22
bb1:
23
predecessor blocks: bb0 bb3
24
[3] Const mutate $6_@1 = 10
25
- [4] Const mutate $8_@2[4:9] = Binary read x$5_@0 < read $6_@1
25
+ [4] Const mutate $8_@2[4:6] = Binary read x$5_@0 < read $6_@1
26
[5] If (read $8_@2) then:bb3 else:bb2
27
bb3:
28
predecessor blocks: bb1
@@ -32,7 +32,7 @@ bb3:
32
bb2:
33
predecessor blocks: bb1
34
[9] Return read x$5_@0
35
-scope2 [4:9]:
35
+scope2 [4:6]:
36
- read x$5_@0
37
- read $6_@1
38
scope3 [6:7]:
@@ -46,14 +46,14 @@ flowchart TB
46
%% Basic Blocks
47
subgraph bb0
48
bb0_instrs["
49
- [1] Let mutate x$5_@0[1:3] = 1
49
+ [1] Let mutate x$5_@0 = 1
50
"]
51
bb0_instrs --> bb0_terminal(["While"])
52
end
53
subgraph bb1
54
bb1_instrs["
55
[3] Const mutate $6_@1 = 10
56
- [4] Const mutate $8_@2[4:9] = Binary read x$5_@0 < read $6_@1
56
+ [4] Const mutate $8_@2[4:6] = Binary read x$5_@0 < read $6_@1
57
"]
58
bb1_instrs --> bb1_terminal(["If (read $8_@2)"])
59
end
compiler/forget/src/__tests__/fixtures/hir/ssa-while.expect.md
+3
-3
@@ -23,7 +23,7 @@ bb1:
23
predecessor blocks: bb0 bb3
24
x$7_@0[0:9]: phi(bb0: x$5_@0, bb3: x$10_@0)
25
[3] Const mutate $6_@1 = 10
26
- [4] Const mutate $8_@2[4:9] = Binary read x$7_@0 < read $6_@1
26
+ [4] Const mutate $8_@2[4:6] = Binary read x$7_@0 < read $6_@1
27
[5] If (read $8_@2) then:bb3 else:bb2
28
bb3:
29
predecessor blocks: bb1
@@ -33,7 +33,7 @@ bb3:
33
bb2:
34
predecessor blocks: bb1
35
[9] Return read x$7_@0
36
-scope2 [4:9]:
36
+scope2 [4:6]:
37
- read $6_@1
38
```
39
@@ -51,7 +51,7 @@ flowchart TB
51
subgraph bb1
52
bb1_instrs["
53
[3] Const mutate $6_@1 = 10
54
- [4] Const mutate $8_@2[4:9] = Binary read x$7_@0 < read $6_@1
54
+ [4] Const mutate $8_@2[4:6] = Binary read x$7_@0 < read $6_@1
55
"]
56
bb1_instrs --> bb1_terminal(["If (read $8_@2)"])
57
end