From b087635e5db273309930ace018c58cf705989b45 Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Wed, 5 Apr 2023 16:26:36 -0700 Subject: [PATCH] LabelTerminal scaffolding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a new `LabelTerminal` which will be used to represent LabeledStatements that contain a statement other than a loop. What we do for these cases is basically break the containing block in two, with a goto after the inner statement to the fallthrough. This allows us to model the label, and any `break` to it, in the HIR. However this fails in codegen because we can't find the fallthrough branch — we need a high level terminal that knows about this structure. Hence LabelTerminal. Now, instead of just a continuation block and a goto, we have a structured terminal. The LabelTerminal expresses the block for the labeled statement and the continuation, and we can use this to put it back together when constructing a ReactiveFunction. Note that this PR is just the scaffolding for LabelTerminal, the next PR is the interesting bits. --- compiler/forget/src/HIR/HIR.ts | 11 ++++++++++- compiler/forget/src/HIR/HIRBuilder.ts | 4 ++++ compiler/forget/src/HIR/PrintHIR.ts | 7 +++++++ compiler/forget/src/HIR/visitors.ts | 18 ++++++++++++++++++ .../ReactiveScopes/BuildReactiveFunction.ts | 4 ++++ .../forget/src/Utils/VisualizeHIRMermaid.ts | 13 +++++++++++++ 6 files changed, 56 insertions(+), 1 deletion(-) diff --git a/compiler/forget/src/HIR/HIR.ts b/compiler/forget/src/HIR/HIR.ts index 348115d57c..b3f5d8199e 100644 --- a/compiler/forget/src/HIR/HIR.ts +++ b/compiler/forget/src/HIR/HIR.ts @@ -269,7 +269,8 @@ export type Terminal = | WhileTerminal | LogicalTerminal | TernaryTerminal - | OptionalCallTerminal; + | OptionalCallTerminal + | LabelTerminal; /** * Terminal nodes allowed for a value block @@ -379,6 +380,14 @@ export type TernaryTerminal = { loc: SourceLocation; }; +export type LabelTerminal = { + kind: "label"; + block: BlockId; + fallthrough: BlockId | null; + id: InstructionId; + loc: SourceLocation; +}; + export type OptionalCallTerminal = { kind: "optional-call"; // Whether the call itself is optional. If false, this means that the callee itself diff --git a/compiler/forget/src/HIR/HIRBuilder.ts b/compiler/forget/src/HIR/HIRBuilder.ts index dccabab5af..7f77329872 100644 --- a/compiler/forget/src/HIR/HIRBuilder.ts +++ b/compiler/forget/src/HIR/HIRBuilder.ts @@ -667,6 +667,10 @@ export function reversePostorderBlocks(func: HIR): void { visit(terminal.init); break; } + case "label": { + visit(terminal.block); + break; + } case "unsupported": { break; } diff --git a/compiler/forget/src/HIR/PrintHIR.ts b/compiler/forget/src/HIR/PrintHIR.ts index f5d0b465d2..3b74d61154 100644 --- a/compiler/forget/src/HIR/PrintHIR.ts +++ b/compiler/forget/src/HIR/PrintHIR.ts @@ -79,6 +79,7 @@ export function printMixedHIR( return printInstruction(value); } switch (value.kind) { + case "label": case "optional-call": case "branch": case "if": @@ -213,6 +214,12 @@ export function printTerminal(terminal: Terminal): Array | string { value = `[${terminal.id}] ForOf init=bb${terminal.init} loop=bb${terminal.loop} fallthrough=bb${terminal.fallthrough}`; break; } + case "label": { + value = `[${terminal.id}] Label block=bb${terminal.block} fallthrough=${ + terminal.fallthrough ? `bb${terminal.fallthrough}` : "" + }`; + break; + } case "unsupported": { value = `Unsupported`; break; diff --git a/compiler/forget/src/HIR/visitors.ts b/compiler/forget/src/HIR/visitors.ts index 93a2d2be3a..44deff2d99 100644 --- a/compiler/forget/src/HIR/visitors.ts +++ b/compiler/forget/src/HIR/visitors.ts @@ -659,6 +659,18 @@ export function mapTerminalSuccessors( id: makeInstructionId(0), }; } + case "label": { + const block = fn(terminal.block); + const fallthrough = + terminal.fallthrough !== null ? fn(terminal.fallthrough) : null; + return { + kind: "label", + block, + fallthrough, + id: makeInstructionId(0), + loc: terminal.loc, + }; + } case "unsupported": { return terminal; } @@ -726,6 +738,10 @@ export function* eachTerminalSuccessor(terminal: Terminal): Iterable { yield terminal.init; break; } + case "label": { + yield terminal.block; + break; + } case "unsupported": break; default: { @@ -767,6 +783,7 @@ export function mapTerminalOperands( } break; } + case "label": case "optional-call": case "ternary": case "logical": @@ -815,6 +832,7 @@ export function* eachTerminalOperand(terminal: Terminal): Iterable { } break; } + case "label": case "optional-call": case "ternary": case "logical": diff --git a/compiler/forget/src/ReactiveScopes/BuildReactiveFunction.ts b/compiler/forget/src/ReactiveScopes/BuildReactiveFunction.ts index 00d5f5f5ad..597fb086e1 100644 --- a/compiler/forget/src/ReactiveScopes/BuildReactiveFunction.ts +++ b/compiler/forget/src/ReactiveScopes/BuildReactiveFunction.ts @@ -29,6 +29,7 @@ import { ReactiveValue, Terminal, } from "../HIR/HIR"; +import todo from "../Utils/todo"; import { assertExhaustive } from "../Utils/utils"; /** @@ -529,6 +530,9 @@ class Driver { break; } + case "label": { + todo("Support label terminals"); + } case "optional-call": case "ternary": case "logical": { diff --git a/compiler/forget/src/Utils/VisualizeHIRMermaid.ts b/compiler/forget/src/Utils/VisualizeHIRMermaid.ts index 4e703fd8fb..a265bb5361 100644 --- a/compiler/forget/src/Utils/VisualizeHIRMermaid.ts +++ b/compiler/forget/src/Utils/VisualizeHIRMermaid.ts @@ -131,6 +131,10 @@ function printTerminalLabel(terminal: Terminal): string { case "for-of": buffer.push("ForOf"); break; + case "label": { + buffer.push("Label"); + break; + } case "unsupported": { break; } @@ -224,6 +228,15 @@ function printTerminalArrows(blockId: BlockId, terminal: Terminal): string { buffer.push(printJumpArrow(blockId, terminal.loop, "loop")); break; } + case "label": { + buffer.push(printJumpArrow(blockId, terminal.block, "block")); + if (terminal.fallthrough != null) { + buffer.push( + printJumpArrow(blockId, terminal.fallthrough, "fallthrough") + ); + } + break; + } case "throw": case "return": case "unsupported": {