@samitouri / QOS-React-2 / commits / b087635e5d

LabelTerminal scaffolding

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.

Joe Savona committed Apr 5, 2023 at 16:26 UTC b087635e5db273309930ace018c58cf705989b45
6 files changed +56 -1
compiler/forget/src/HIR/HIR.ts
+10 -1
@@ -269,7 +269,8 @@ export type Terminal =
269 | WhileTerminal
270 | LogicalTerminal
271 | TernaryTerminal
272 - | OptionalCallTerminal;
272 + | OptionalCallTerminal
273 + | LabelTerminal;
274
275 /**
276 * Terminal nodes allowed for a value block
@@ -379,6 +380,14 @@ export type TernaryTerminal = {
380 loc: SourceLocation;
381 };
382
383 +export type LabelTerminal = {
384 + kind: "label";
385 + block: BlockId;
386 + fallthrough: BlockId | null;
387 + id: InstructionId;
388 + loc: SourceLocation;
389 +};
390 +
391 export type OptionalCallTerminal = {
392 kind: "optional-call";
393 // Whether the call itself is optional. If false, this means that the callee itself
compiler/forget/src/HIR/HIRBuilder.ts
+4
@@ -667,6 +667,10 @@ export function reversePostorderBlocks(func: HIR): void {
667 visit(terminal.init);
668 break;
669 }
670 + case "label": {
671 + visit(terminal.block);
672 + break;
673 + }
674 case "unsupported": {
675 break;
676 }
compiler/forget/src/HIR/PrintHIR.ts
+7
@@ -79,6 +79,7 @@ export function printMixedHIR(
79 return printInstruction(value);
80 }
81 switch (value.kind) {
82 + case "label":
83 case "optional-call":
84 case "branch":
85 case "if":
@@ -213,6 +214,12 @@ export function printTerminal(terminal: Terminal): Array<string> | string {
214 value = `[${terminal.id}] ForOf init=bb${terminal.init} loop=bb${terminal.loop} fallthrough=bb${terminal.fallthrough}`;
215 break;
216 }
217 + case "label": {
218 + value = `[${terminal.id}] Label block=bb${terminal.block} fallthrough=${
219 + terminal.fallthrough ? `bb${terminal.fallthrough}` : ""
220 + }`;
221 + break;
222 + }
223 case "unsupported": {
224 value = `Unsupported`;
225 break;
compiler/forget/src/HIR/visitors.ts
+18
@@ -659,6 +659,18 @@ export function mapTerminalSuccessors(
659 id: makeInstructionId(0),
660 };
661 }
662 + case "label": {
663 + const block = fn(terminal.block);
664 + const fallthrough =
665 + terminal.fallthrough !== null ? fn(terminal.fallthrough) : null;
666 + return {
667 + kind: "label",
668 + block,
669 + fallthrough,
670 + id: makeInstructionId(0),
671 + loc: terminal.loc,
672 + };
673 + }
674 case "unsupported": {
675 return terminal;
676 }
@@ -726,6 +738,10 @@ export function* eachTerminalSuccessor(terminal: Terminal): Iterable<BlockId> {
738 yield terminal.init;
739 break;
740 }
741 + case "label": {
742 + yield terminal.block;
743 + break;
744 + }
745 case "unsupported":
746 break;
747 default: {
@@ -767,6 +783,7 @@ export function mapTerminalOperands(
783 }
784 break;
785 }
786 + case "label":
787 case "optional-call":
788 case "ternary":
789 case "logical":
@@ -815,6 +832,7 @@ export function* eachTerminalOperand(terminal: Terminal): Iterable<Place> {
832 }
833 break;
834 }
835 + case "label":
836 case "optional-call":
837 case "ternary":
838 case "logical":
compiler/forget/src/ReactiveScopes/BuildReactiveFunction.ts
+4
@@ -29,6 +29,7 @@ import {
29 ReactiveValue,
30 Terminal,
31 } from "../HIR/HIR";
32 +import todo from "../Utils/todo";
33 import { assertExhaustive } from "../Utils/utils";
34
35 /**
@@ -529,6 +530,9 @@ class Driver {
530
531 break;
532 }
533 + case "label": {
534 + todo("Support label terminals");
535 + }
536 case "optional-call":
537 case "ternary":
538 case "logical": {
compiler/forget/src/Utils/VisualizeHIRMermaid.ts
+13
@@ -131,6 +131,10 @@ function printTerminalLabel(terminal: Terminal): string {
131 case "for-of":
132 buffer.push("ForOf");
133 break;
134 + case "label": {
135 + buffer.push("Label");
136 + break;
137 + }
138 case "unsupported": {
139 break;
140 }
@@ -224,6 +228,15 @@ function printTerminalArrows(blockId: BlockId, terminal: Terminal): string {
228 buffer.push(printJumpArrow(blockId, terminal.loop, "loop"));
229 break;
230 }
231 + case "label": {
232 + buffer.push(printJumpArrow(blockId, terminal.block, "block"));
233 + if (terminal.fallthrough != null) {
234 + buffer.push(
235 + printJumpArrow(blockId, terminal.fallthrough, "fallthrough")
236 + );
237 + }
238 + break;
239 + }
240 case "throw":
241 case "return":
242 case "unsupported": {