From db740366f821c10350d3eb94b384ef8911dedefd Mon Sep 17 00:00:00 2001 From: Jan Kassens Date: Tue, 6 Dec 2022 11:28:15 -0500 Subject: [PATCH] "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. --- compiler/forget/src/HIR/Codegen.ts | 23 +++++++++++++++++++ compiler/forget/src/HIR/HIRTreeVisitor.ts | 23 +++++++++++++------ .../src/HIR/InferReactiveScopeDependencies.ts | 4 ++++ .../forget/src/HIR/InferReactiveScopes.ts | 14 +++++++++++ compiler/forget/src/HIR/PrintHIRTree.ts | 6 +++++ .../hir/_bug_while-with-assignment.expect.md | 9 ++++---- .../hir/mutable-lifetime-loops.expect.md | 4 ++-- .../hir/mutable-liverange-loop.expect.md | 4 ++-- .../hir/ssa-while-no-reassign.expect.md | 10 ++++---- .../fixtures/hir/ssa-while.expect.md | 6 ++--- 10 files changed, 79 insertions(+), 24 deletions(-) diff --git a/compiler/forget/src/HIR/Codegen.ts b/compiler/forget/src/HIR/Codegen.ts index ca3d62f412..624d24c6b1 100644 --- a/compiler/forget/src/HIR/Codegen.ts +++ b/compiler/forget/src/HIR/Codegen.ts @@ -100,6 +100,10 @@ class CodegenVisitor this.depth++; return []; } + enterValueBlock(): t.Statement[] { + this.depth++; + return []; + } visitValue(value: InstructionValue): t.Expression { return codegenInstructionValue(this.temp, value); } @@ -237,6 +241,25 @@ class CodegenVisitor this.depth--; return t.blockStatement(block); } + leaveValueBlock(block: t.Statement[], place: t.Expression): t.Expression { + this.depth--; + if (block.length === 0) { + return place; + } + const expressions = block.map((stmt) => { + switch (stmt.type) { + case "ExpressionStatement": + return stmt.expression; + default: + todoInvariant( + false, + `Handle conversion of ${stmt.type} to expression` + ); + } + }); + expressions.push(place); + return t.sequenceExpression(expressions); + } } function codegenLabel(id: BlockId): string { diff --git a/compiler/forget/src/HIR/HIRTreeVisitor.ts b/compiler/forget/src/HIR/HIRTreeVisitor.ts index a6f3bd0c9e..17644976fa 100644 --- a/compiler/forget/src/HIR/HIRTreeVisitor.ts +++ b/compiler/forget/src/HIR/HIRTreeVisitor.ts @@ -239,15 +239,20 @@ class Driver { testTerminal.kind === "if", "Expected while loop test block to end in an if" ); - // const bodyLength = blockValue.length; + const testValueBlock = this.visitor.enterValueBlock(); for (const instr of testBlock.instructions) { - this.visitInstr(instr, blockValue); + const value = this.visitor.visitValue(instr.value, instr.id); + const item = this.visitor.visitInstruction(instr, value); + this.visitor.appendBlock(testValueBlock, item); } - // invariant( - // body.length === bodyLength, - // "Expected test to produce only temporaries" - // ); - const testValue = this.visitPlace(testTerminal.test, terminal.id); + const testValueLast = this.visitor.visitValue( + testTerminal.test, + testTerminal.id + ); + const testValue = this.visitor.leaveValueBlock( + testValueBlock, + testValueLast + ); const fallthroughId = terminal.fallthrough !== null && !this.cx.isScheduled(terminal.fallthrough) @@ -644,6 +649,10 @@ export interface Visitor { */ enterBlock(): TBlock; + enterValueBlock(): TBlock; + + leaveValueBlock(block: TBlock, value: TValue): TValue; + /** * Convert an InstructionValue into the visitor's own representation * of a value. diff --git a/compiler/forget/src/HIR/InferReactiveScopeDependencies.ts b/compiler/forget/src/HIR/InferReactiveScopeDependencies.ts index 7aee03ebbf..1798d9d11f 100644 --- a/compiler/forget/src/HIR/InferReactiveScopeDependencies.ts +++ b/compiler/forget/src/HIR/InferReactiveScopeDependencies.ts @@ -189,8 +189,12 @@ class ScopeDependenciesVisitor } enterBlock(): void {} + enterValueBlock(): void {} visitImplicitTerminal(): void | null {} visitCase(test: InstructionValue, block: void): void {} appendBlock(block: void, item: void, label?: BlockId | undefined): void {} leaveBlock(block: void): void {} + leaveValueBlock(block: void, value: InstructionValue): InstructionValue { + return value; + } } diff --git a/compiler/forget/src/HIR/InferReactiveScopes.ts b/compiler/forget/src/HIR/InferReactiveScopes.ts index 362f846ec9..484eb39967 100644 --- a/compiler/forget/src/HIR/InferReactiveScopes.ts +++ b/compiler/forget/src/HIR/InferReactiveScopes.ts @@ -254,6 +254,12 @@ class MergeOverlappingReactiveScopesVisitor enterBlock(): void { this.scopes.push(new BlockScope()); } + enterValueBlock(): void { + this.enterBlock(); + } + leaveValueBlock(block: void, value: void): void { + this.leaveBlock(); + } visitValue(value: InstructionValue, id: InstructionId): void { this.visitId(id); for (const operand of eachInstructionValueOperand(value)) { @@ -355,6 +361,14 @@ class AlignReactiveScopesToBlockScopeRangeVisitor } } + enterValueBlock(): void { + this.enterBlock(); + } + + leaveValueBlock(block: void, value: void): void { + this.leaveBlock(); + } + visitInstruction(instruction: Instruction, value: void): void { const scope = getInstructionScope(instruction); if (scope !== null) { diff --git a/compiler/forget/src/HIR/PrintHIRTree.ts b/compiler/forget/src/HIR/PrintHIRTree.ts index cc5bcbde1a..a2c21f1b25 100644 --- a/compiler/forget/src/HIR/PrintHIRTree.ts +++ b/compiler/forget/src/HIR/PrintHIRTree.ts @@ -32,6 +32,12 @@ class PrintVisitor implements Visitor, string, string, string> { this.depth++; return []; } + enterValueBlock(): string[] { + return this.enterBlock(); + } + leaveValueBlock(block: string[], value: string): string { + return this.leaveBlock(block); + } visitValue(value: InstructionValue): string { return printMixedHIR(value); } diff --git a/compiler/forget/src/__tests__/fixtures/hir/_bug_while-with-assignment.expect.md b/compiler/forget/src/__tests__/fixtures/hir/_bug_while-with-assignment.expect.md index d1bdf051a0..5a5062c6ed 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/_bug_while-with-assignment.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/_bug_while-with-assignment.expect.md @@ -31,7 +31,7 @@ bb1: sum$21_@3[0:14]: phi(bb0: sum$16_@3, bb3: sum$22_@3) [8] Reassign mutate value$18_@3[0:14] = Call mutate queue$14_@3.pop() [9] Const mutate $19_@6 = null - [10] Const mutate $20_@7[10:14] = Binary read value$18_@3 != read $19_@6 + [10] Const mutate $20_@7[10:12] = Binary read value$18_@3 != read $19_@6 [11] If (read $20_@7) then:bb3 else:bb2 bb3: predecessor blocks: bb1 @@ -40,7 +40,7 @@ bb3: bb2: predecessor blocks: bb1 [14] Return read sum$21_@3 -scope7 [10:14]: +scope7 [10:12]: - read $19_@6 ``` @@ -64,7 +64,7 @@ flowchart TB bb1_instrs[" [8] Reassign mutate value$18_@3[0:14] = Call mutate queue$14_@3.pop() [9] Const mutate $19_@6 = null - [10] Const mutate $20_@7[10:14] = Binary read value$18_@3 != read $19_@6 + [10] Const mutate $20_@7[10:12] = Binary read value$18_@3 != read $19_@6 "] bb1_instrs --> bb1_terminal(["If (read $20_@7)"]) end @@ -95,8 +95,7 @@ function f$0(reader$1) { const queue$2 = [1, 2, 3]; let value$6 = 0; let sum$7 = 0; - value$6 = queue$2.pop(); - bb2: while (value$6 != null) { + bb2: while (((value$6 = queue$2.pop()), value$6 != null)) { sum$7 = sum$7 + value$6; } diff --git a/compiler/forget/src/__tests__/fixtures/hir/mutable-lifetime-loops.expect.md b/compiler/forget/src/__tests__/fixtures/hir/mutable-lifetime-loops.expect.md index 5e1b57c395..f10d9bb39d 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/mutable-lifetime-loops.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/mutable-lifetime-loops.expect.md @@ -108,7 +108,7 @@ bb1: b$20_@0[0:23]: phi(bb0: b$14_@0, bb4: b$23_@0) c$22_@0[0:23]: phi(bb0: c$15_@0, bb4: c$25_@0) d$24_@0[0:23]: phi(bb0: d$16_@0, bb4: d$26_@0) - [6] Const mutate $17_@1[6:17] = true + [6] Const mutate $17_@1[6:8] = true [7] If (read $17_@1) then:bb3 else:bb2 bb3: predecessor blocks: bb1 @@ -163,7 +163,7 @@ flowchart TB end subgraph bb1 bb1_instrs[" - [6] Const mutate $17_@1[6:17] = true + [6] Const mutate $17_@1[6:8] = true "] bb1_instrs --> bb1_terminal(["If (read $17_@1)"]) end diff --git a/compiler/forget/src/__tests__/fixtures/hir/mutable-liverange-loop.expect.md b/compiler/forget/src/__tests__/fixtures/hir/mutable-liverange-loop.expect.md index 51d64c31eb..63374ae199 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/mutable-liverange-loop.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/mutable-liverange-loop.expect.md @@ -99,7 +99,7 @@ bb0: [5] While test=bb1 loop=bb3 fallthrough=bb2 bb1: predecessor blocks: bb0 bb4 - [6] Const mutate $16_@2[6:12] = true + [6] Const mutate $16_@2[6:8] = true [7] If (read $16_@2) then:bb3 else:bb2 bb3: predecessor blocks: bb1 @@ -145,7 +145,7 @@ flowchart TB end subgraph bb1 bb1_instrs[" - [6] Const mutate $16_@2[6:12] = true + [6] Const mutate $16_@2[6:8] = true "] bb1_instrs --> bb1_terminal(["If (read $16_@2)"]) end diff --git a/compiler/forget/src/__tests__/fixtures/hir/ssa-while-no-reassign.expect.md b/compiler/forget/src/__tests__/fixtures/hir/ssa-while-no-reassign.expect.md index 6497abc7ff..31d2037c47 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/ssa-while-no-reassign.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/ssa-while-no-reassign.expect.md @@ -17,12 +17,12 @@ function foo() { ``` bb0: - [1] Let mutate x$5_@0[1:3] = 1 + [1] Let mutate x$5_@0 = 1 [2] While test=bb1 loop=bb3 fallthrough=bb2 bb1: predecessor blocks: bb0 bb3 [3] Const mutate $6_@1 = 10 - [4] Const mutate $8_@2[4:9] = Binary read x$5_@0 < read $6_@1 + [4] Const mutate $8_@2[4:6] = Binary read x$5_@0 < read $6_@1 [5] If (read $8_@2) then:bb3 else:bb2 bb3: predecessor blocks: bb1 @@ -32,7 +32,7 @@ bb3: bb2: predecessor blocks: bb1 [9] Return read x$5_@0 -scope2 [4:9]: +scope2 [4:6]: - read x$5_@0 - read $6_@1 scope3 [6:7]: @@ -46,14 +46,14 @@ flowchart TB %% Basic Blocks subgraph bb0 bb0_instrs[" - [1] Let mutate x$5_@0[1:3] = 1 + [1] Let mutate x$5_@0 = 1 "] bb0_instrs --> bb0_terminal(["While"]) end subgraph bb1 bb1_instrs[" [3] Const mutate $6_@1 = 10 - [4] Const mutate $8_@2[4:9] = Binary read x$5_@0 < read $6_@1 + [4] Const mutate $8_@2[4:6] = Binary read x$5_@0 < read $6_@1 "] bb1_instrs --> bb1_terminal(["If (read $8_@2)"]) end diff --git a/compiler/forget/src/__tests__/fixtures/hir/ssa-while.expect.md b/compiler/forget/src/__tests__/fixtures/hir/ssa-while.expect.md index 1e912727da..8bb036c3d3 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/ssa-while.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/ssa-while.expect.md @@ -23,7 +23,7 @@ bb1: predecessor blocks: bb0 bb3 x$7_@0[0:9]: phi(bb0: x$5_@0, bb3: x$10_@0) [3] Const mutate $6_@1 = 10 - [4] Const mutate $8_@2[4:9] = Binary read x$7_@0 < read $6_@1 + [4] Const mutate $8_@2[4:6] = Binary read x$7_@0 < read $6_@1 [5] If (read $8_@2) then:bb3 else:bb2 bb3: predecessor blocks: bb1 @@ -33,7 +33,7 @@ bb3: bb2: predecessor blocks: bb1 [9] Return read x$7_@0 -scope2 [4:9]: +scope2 [4:6]: - read $6_@1 ``` @@ -51,7 +51,7 @@ flowchart TB subgraph bb1 bb1_instrs[" [3] Const mutate $6_@1 = 10 - [4] Const mutate $8_@2[4:9] = Binary read x$7_@0 < read $6_@1 + [4] Const mutate $8_@2[4:6] = Binary read x$7_@0 < read $6_@1 "] bb1_instrs --> bb1_terminal(["If (read $8_@2)"]) end