[valueblocks] Scaffolding for branch terminal

Scaffolding for a new 'branch' terminal, which is the lower-level form of 'if' 
meant for use in value blocks. See design at 
https://fb.quip.com/b7N6AjkDcl2a#temp:C:bAO904b0cf06f154de4a7287af6d
This commit is contained in:
Joe Savona
2023-01-25 17:05:22 -05:00
parent 1014727d41
commit f88fa006e7
6 changed files with 58 additions and 0 deletions
+9
View File
@@ -214,6 +214,7 @@ export type Terminal =
| ReturnTerminal
| GotoTerminal
| IfTerminal
| BranchTerminal
| SwitchTerminal
| ForTerminal
| WhileTerminal
@@ -256,6 +257,14 @@ export type IfTerminal = {
id: InstructionId;
};
export type BranchTerminal = {
kind: "branch";
test: Place;
consequent: BlockId;
alternate: BlockId;
id: InstructionId;
};
export type SwitchTerminal = {
kind: "switch";
test: Place;
+6
View File
@@ -553,6 +553,12 @@ export function reversePostorderBlocks(func: HIR): void {
visit(consequent);
break;
}
case "branch": {
const { consequent, alternate } = terminal;
visit(alternate);
visit(consequent);
break;
}
case "switch": {
// can ignore fallthrough, if its reachable it will be reached through
// a case
+7
View File
@@ -75,6 +75,7 @@ export function printMixedHIR(
return printInstruction(value);
}
switch (value.kind) {
case "branch":
case "if":
case "logical":
case "return":
@@ -134,6 +135,12 @@ export function printTerminal(terminal: Terminal): Array<string> | string {
}`;
break;
}
case "branch": {
value = `[${terminal.id}] Branch (${printPlace(terminal.test)}) then:bb${
terminal.consequent
} else:bb${terminal.alternate}`;
break;
}
case "logical": {
value = `[${terminal.id}] Logical ${terminal.operator} test:bb${terminal.test} fallthrough=bb${terminal.fallthrough}`;
break;
+24
View File
@@ -253,6 +253,17 @@ export function mapTerminalSuccessors(
id: makeInstructionId(0),
};
}
case "branch": {
const consequent = fn(terminal.consequent);
const alternate = fn(terminal.alternate);
return {
kind: "branch",
test: terminal.test,
consequent,
alternate,
id: makeInstructionId(0),
};
}
case "switch": {
const cases = terminal.cases.map((case_) => {
const target = fn(case_.block);
@@ -350,6 +361,11 @@ export function* eachTerminalSuccessor(terminal: Terminal): Iterable<BlockId> {
yield terminal.alternate;
break;
}
case "branch": {
yield terminal.consequent;
yield terminal.alternate;
break;
}
case "switch": {
for (const case_ of terminal.cases) {
yield case_.block;
@@ -394,6 +410,10 @@ export function mapTerminalOperands(
terminal.test = fn(terminal.test);
break;
}
case "branch": {
terminal.test = fn(terminal.test);
break;
}
case "switch": {
terminal.test = fn(terminal.test);
for (const case_ of terminal.cases) {
@@ -434,6 +454,10 @@ export function* eachTerminalOperand(terminal: Terminal): Iterable<Place> {
yield terminal.test;
break;
}
case "branch": {
yield terminal.test;
break;
}
case "switch": {
yield terminal.test;
for (const case_ of terminal.cases) {
@@ -360,6 +360,9 @@ class Driver {
}
break;
}
case "branch": {
todo("Implement tree visitor for branch terminal");
}
case "logical": {
todo("Implement tree visitor for logical terminal");
}
@@ -77,6 +77,10 @@ function printTerminalLabel(terminal: Terminal): string {
buffer.push(`If (${printPlace(terminal.test)})`);
break;
}
case "branch": {
buffer.push(`Branch (${printPlace(terminal.test)})`);
break;
}
case "goto": {
buffer.push("Goto");
break;
@@ -130,6 +134,11 @@ function printTerminalArrows(blockId: BlockId, terminal: Terminal): string {
}
break;
}
case "branch": {
buffer.push(printJumpArrow(blockId, terminal.consequent, "then"));
buffer.push(printJumpArrow(blockId, terminal.alternate, "else"));
break;
}
case "logical": {
buffer.push(printJumpArrow(blockId, terminal.test, "test"));
buffer.push(printJumpArrow(blockId, terminal.fallthrough, "fallthrough"));