mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Add SSA-ify pass
The algorithm is described in detail here: https://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf Note that the SSA form generated is not minimal. A follow on RedundantPhiElimination pass is required to prune the graph.
This commit is contained in:
@@ -94,6 +94,8 @@ export type BasicBlock = {
|
||||
id: BlockId;
|
||||
instructions: Array<Instruction>;
|
||||
terminal: Terminal;
|
||||
preds: Set<BasicBlock>;
|
||||
phis: Set<Phi>;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -162,6 +164,12 @@ export enum InstructionKind {
|
||||
*/
|
||||
export type InstructionValue = (InstructionData & { path: NodePath }) | Place;
|
||||
|
||||
export type Phi = {
|
||||
kind: "Phi";
|
||||
lvalue: LValue;
|
||||
operands: Map<BasicBlock, Place>;
|
||||
};
|
||||
|
||||
export type InstructionData =
|
||||
| { kind: "Primitive"; value: number | boolean | string | null | undefined }
|
||||
| { kind: "JSXText"; value: string }
|
||||
|
||||
@@ -114,6 +114,8 @@ export default class HIRBuilder {
|
||||
id: blockId,
|
||||
instructions,
|
||||
terminal: { kind: "return", value: null },
|
||||
preds: new Set(),
|
||||
phis: new Set(),
|
||||
});
|
||||
// First reduce indirections and prune unreachable blocks
|
||||
let reduced = shrink({
|
||||
@@ -121,7 +123,9 @@ export default class HIRBuilder {
|
||||
entry: this.#entry,
|
||||
});
|
||||
// then convert to reverse postorder
|
||||
return reversePostorderBlocks(reduced);
|
||||
const blocks = reversePostorderBlocks(reduced);
|
||||
markPredecessors(blocks);
|
||||
return blocks;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -133,6 +137,8 @@ export default class HIRBuilder {
|
||||
id: blockId,
|
||||
instructions,
|
||||
terminal,
|
||||
preds: new Set(),
|
||||
phis: new Set(),
|
||||
});
|
||||
const nextId = makeBlockId(this.#nextId++);
|
||||
this.#current = newBlock(nextId);
|
||||
@@ -148,6 +154,8 @@ export default class HIRBuilder {
|
||||
id: blockId,
|
||||
instructions,
|
||||
terminal,
|
||||
preds: new Set(),
|
||||
phis: new Set(),
|
||||
});
|
||||
this.#current = continuation;
|
||||
}
|
||||
@@ -166,7 +174,13 @@ export default class HIRBuilder {
|
||||
*/
|
||||
complete(block: WipBlock, terminal: Terminal) {
|
||||
const { id: blockId, instructions } = block;
|
||||
this.#completed.set(blockId, { id: blockId, instructions, terminal });
|
||||
this.#completed.set(blockId, {
|
||||
id: blockId,
|
||||
instructions,
|
||||
terminal,
|
||||
preds: new Set(),
|
||||
phis: new Set(),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -181,7 +195,13 @@ export default class HIRBuilder {
|
||||
this.#current = newBlock(nextId);
|
||||
const terminal = fn(nextId);
|
||||
const { id: blockId, instructions } = this.#current;
|
||||
this.#completed.set(blockId, { id: blockId, instructions, terminal });
|
||||
this.#completed.set(blockId, {
|
||||
id: blockId,
|
||||
instructions,
|
||||
terminal,
|
||||
preds: new Set(),
|
||||
phis: new Set(),
|
||||
});
|
||||
this.#current = current;
|
||||
return nextId;
|
||||
}
|
||||
@@ -336,6 +356,8 @@ function shrink(func: HIR): HIR {
|
||||
id: blockId,
|
||||
instructions,
|
||||
terminal,
|
||||
preds: new Set(),
|
||||
phis: new Set(),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -438,6 +460,54 @@ function reversePostorderBlocks(func: HIR): HIR {
|
||||
};
|
||||
}
|
||||
|
||||
function markPredecessors(func: HIR) {
|
||||
const visited: Set<BlockId> = new Set();
|
||||
function visit(blockId: BlockId, prevBlock?: BasicBlock) {
|
||||
const block = func.blocks.get(blockId)!;
|
||||
if (prevBlock) {
|
||||
block.preds.add(prevBlock);
|
||||
}
|
||||
|
||||
if (visited.has(blockId)) {
|
||||
return;
|
||||
}
|
||||
visited.add(blockId);
|
||||
|
||||
const { terminal } = block;
|
||||
|
||||
switch (terminal.kind) {
|
||||
case "return":
|
||||
case "throw": {
|
||||
break;
|
||||
}
|
||||
case "goto": {
|
||||
visit(terminal.block, block);
|
||||
break;
|
||||
}
|
||||
case "if": {
|
||||
const { consequent, alternate } = terminal;
|
||||
visit(alternate, block);
|
||||
visit(consequent, block);
|
||||
break;
|
||||
}
|
||||
case "switch": {
|
||||
const { cases } = terminal;
|
||||
for (const case_ of [...cases]) {
|
||||
visit(case_.block, block);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
assertExhaustive(
|
||||
terminal,
|
||||
`Unexpected terminal kind '${(terminal as any).kind}'`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
visit(func.entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the given block is a simple indirection (empty terminated with a goto),
|
||||
* returns the block being pointed to. Otherwise returns null
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
InstructionKind,
|
||||
InstructionValue,
|
||||
LValue,
|
||||
Phi,
|
||||
Place,
|
||||
Terminal,
|
||||
} from "./HIR";
|
||||
@@ -31,6 +32,16 @@ export default function printHIR(
|
||||
};
|
||||
for (const [blockId, block] of ir.blocks) {
|
||||
output.push(`bb${blockId}:`);
|
||||
if (block.preds.size > 0) {
|
||||
const preds = ["predecessor blocks:"];
|
||||
for (const pred of block.preds) {
|
||||
preds.push(`bb${pred.id}`);
|
||||
}
|
||||
push(preds.join(" "));
|
||||
}
|
||||
for (const phi of block.phis) {
|
||||
push(printPhi(phi));
|
||||
}
|
||||
for (const instr of block.instructions) {
|
||||
push(printInstruction(instr));
|
||||
}
|
||||
@@ -78,6 +89,20 @@ function printInstruction(instr: Instruction): string {
|
||||
}
|
||||
}
|
||||
|
||||
function printPhi(phi: Phi): string {
|
||||
const items = [];
|
||||
items.push(printLValue(phi.lvalue));
|
||||
items.push(": phi(");
|
||||
const phis = [];
|
||||
for (const [block, place] of phi.operands) {
|
||||
phis.push(`bb${block.id}: ${printPlace(place)}`);
|
||||
}
|
||||
|
||||
items.push(phis.join(", "));
|
||||
items.push(")");
|
||||
return items.join("");
|
||||
}
|
||||
|
||||
function printTerminal(terminal: Terminal): Array<string> | string {
|
||||
let value;
|
||||
switch (terminal.kind) {
|
||||
|
||||
@@ -0,0 +1,333 @@
|
||||
import invariant from "invariant";
|
||||
import { assertExhaustive } from "../Common/utils";
|
||||
import {
|
||||
BasicBlock,
|
||||
BlockId,
|
||||
Effect,
|
||||
HIRFunction,
|
||||
IdentifierId,
|
||||
Instruction,
|
||||
InstructionKind,
|
||||
makeIdentifierId,
|
||||
Phi,
|
||||
Place,
|
||||
} from "./HIR";
|
||||
|
||||
type IncompletePhi = {
|
||||
old: Place;
|
||||
new: Place;
|
||||
};
|
||||
|
||||
type State = {
|
||||
defs: Map<IdentifierId, Place>;
|
||||
incompletePhis: IncompletePhi[];
|
||||
};
|
||||
|
||||
const unsealedPreds: Map<BasicBlock, number> = new Map();
|
||||
|
||||
class SSABuilder {
|
||||
#states: Map<BasicBlock, State> = new Map();
|
||||
#current: BasicBlock | null = null;
|
||||
visitedBlocks: Set<BasicBlock> = new Set();
|
||||
|
||||
// Hack(gsn): Start from the last stored id in HIRBuilder.
|
||||
// Need to refactor makeTemporary and relevant state out of HIR Builder.
|
||||
#id = 1000;
|
||||
|
||||
state(): State {
|
||||
invariant(
|
||||
this.#current !== null,
|
||||
"we need to be in a block to access state!"
|
||||
);
|
||||
return this.#states.get(this.#current)!;
|
||||
}
|
||||
|
||||
// This tries to reuse all existing information about the oldPlace in case there's
|
||||
// useful information from previous compiler passes.
|
||||
makePlace(oldPlace: Place): Place {
|
||||
const identifier = {
|
||||
...oldPlace.identifier,
|
||||
id: makeIdentifierId(this.#id++),
|
||||
};
|
||||
return {
|
||||
...oldPlace,
|
||||
identifier,
|
||||
};
|
||||
}
|
||||
|
||||
makePlaceForPhi(oldPlace: Place): Place {
|
||||
const identifier = {
|
||||
...oldPlace.identifier,
|
||||
id: makeIdentifierId(this.#id++),
|
||||
};
|
||||
return {
|
||||
identifier,
|
||||
kind: "Identifier",
|
||||
memberPath: null,
|
||||
effect: Effect.Mutate,
|
||||
path: null as any,
|
||||
};
|
||||
}
|
||||
|
||||
definePlace(oldPlace: Place): Place {
|
||||
const newPlace = this.makePlace(oldPlace);
|
||||
this.state().defs.set(oldPlace.identifier.id, newPlace);
|
||||
return newPlace;
|
||||
}
|
||||
|
||||
getPlace(oldPlace: Place): Place {
|
||||
return this.getPlaceAt(oldPlace, this.#current!);
|
||||
}
|
||||
|
||||
getPlaceAt(oldPlace: Place, block: BasicBlock): Place {
|
||||
// check if Place is defined locally
|
||||
const state = this.#states.get(block)!;
|
||||
|
||||
if (state.defs.has(oldPlace.identifier.id)) {
|
||||
return state.defs.get(oldPlace.identifier.id)!;
|
||||
}
|
||||
|
||||
if (block.preds.size == 0) {
|
||||
// We're at the entry block and haven't found our defintion yet.
|
||||
throw new Error(`Unable to find \$${oldPlace.identifier.id}`);
|
||||
}
|
||||
|
||||
if (unsealedPreds.get(block)! > 0) {
|
||||
// We haven't visited all our predecessors, let's place an incomplete phi
|
||||
// for now.
|
||||
const newPlace = this.makePlaceForPhi(oldPlace);
|
||||
state.incompletePhis.push({ old: oldPlace, new: newPlace });
|
||||
state.defs.set(oldPlace.identifier.id, newPlace);
|
||||
return newPlace;
|
||||
}
|
||||
|
||||
// Only one predecessor, let's check there
|
||||
if (block.preds.size == 1) {
|
||||
const [pred] = block.preds;
|
||||
const newPlace = this.getPlaceAt(oldPlace, pred);
|
||||
state.defs.set(oldPlace.identifier.id, newPlace);
|
||||
return newPlace;
|
||||
}
|
||||
|
||||
// There are multiple predecessors, we need a phi.
|
||||
const newPlace = this.makePlaceForPhi(oldPlace);
|
||||
// Adding a phi may loop back to our block if there is a loop in the CFG. We
|
||||
// update our defs before adding the phi to terminate the recursion rather than
|
||||
// looping infinitely.
|
||||
state.defs.set(oldPlace.identifier.id, newPlace);
|
||||
this.addPhi(block, oldPlace, newPlace);
|
||||
|
||||
// TODO(gsn): Can we just return `newPlace` rather than looking it up?
|
||||
// `addPhi` _can_ mutate it, but _will_ it?
|
||||
return state.defs.get(oldPlace.identifier.id)!;
|
||||
}
|
||||
|
||||
addPhi(block: BasicBlock, oldPlace: Place, newPlace: Place) {
|
||||
const predDefs: Map<BasicBlock, Place> = new Map();
|
||||
for (const predBlock of block.preds) {
|
||||
const predPlace = this.getPlaceAt(oldPlace, predBlock);
|
||||
predDefs.set(predBlock, predPlace);
|
||||
}
|
||||
|
||||
const phi: Phi = {
|
||||
kind: "Phi",
|
||||
lvalue: { place: newPlace, kind: InstructionKind.Const },
|
||||
operands: predDefs,
|
||||
};
|
||||
|
||||
block.phis.add(phi);
|
||||
}
|
||||
|
||||
fixIncompletePhis(block: BasicBlock) {
|
||||
const state = this.#states.get(block)!;
|
||||
for (const phi of state.incompletePhis) {
|
||||
this.addPhi(block, phi.old, phi.new);
|
||||
}
|
||||
}
|
||||
|
||||
startBlock(block: BasicBlock) {
|
||||
this.#current = block;
|
||||
this.#states.set(block, {
|
||||
defs: new Map(),
|
||||
incompletePhis: [],
|
||||
});
|
||||
}
|
||||
|
||||
print() {
|
||||
const text = [];
|
||||
for (const [block, state] of this.#states) {
|
||||
text.push(`bb${block.id}:`);
|
||||
for (const [id, place] of state.defs) {
|
||||
text.push(` \$${id} = \$${place.identifier.id}`);
|
||||
}
|
||||
|
||||
for (const incompletePhi of state.incompletePhis) {
|
||||
text.push(
|
||||
` iphi \$${incompletePhi.new.identifier} = \$${incompletePhi.old.identifier}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
text.push(`current block: bb${this.#current?.id}`);
|
||||
console.log(text.join("\n"));
|
||||
}
|
||||
}
|
||||
|
||||
export default function buildSSA(func: HIRFunction) {
|
||||
const builder = new SSABuilder();
|
||||
|
||||
function visit(blockId: BlockId) {
|
||||
const block = func.body.blocks.get(blockId)!;
|
||||
if (builder.visitedBlocks.has(block)) {
|
||||
return;
|
||||
}
|
||||
builder.visitedBlocks.add(block);
|
||||
|
||||
builder.startBlock(block);
|
||||
for (const instr of block.instructions) {
|
||||
const uses = collectUses(instr);
|
||||
for (const { place, updateFn } of uses) {
|
||||
updateFn(builder.getPlace(place));
|
||||
}
|
||||
|
||||
if (instr.lvalue != null) {
|
||||
const oldPlace = instr.lvalue.place;
|
||||
const newPlace: Place = builder.definePlace(oldPlace);
|
||||
instr.lvalue.place = newPlace;
|
||||
}
|
||||
}
|
||||
|
||||
const { uses, outputs } = collectOutputs(block);
|
||||
for (const { place, updateFn } of uses) {
|
||||
updateFn(builder.getPlace(place));
|
||||
}
|
||||
|
||||
const outputBlocks = outputs.map((id) => func.body.blocks.get(id)!);
|
||||
for (const output of outputBlocks) {
|
||||
let count;
|
||||
if (unsealedPreds.has(output)) {
|
||||
count = unsealedPreds.get(output)! - 1;
|
||||
} else {
|
||||
count = output.preds.size - 1;
|
||||
}
|
||||
unsealedPreds.set(output, count);
|
||||
|
||||
if (count == 0 && builder.visitedBlocks.has(output)) {
|
||||
builder.fixIncompletePhis(output);
|
||||
}
|
||||
}
|
||||
|
||||
for (const output of outputs) {
|
||||
visit(output);
|
||||
}
|
||||
}
|
||||
|
||||
visit(func.body.entry);
|
||||
}
|
||||
|
||||
function collectOutputs(block: BasicBlock): {
|
||||
uses: Array<Uses>;
|
||||
outputs: Array<BlockId>;
|
||||
} {
|
||||
const outputs: Array<BlockId> = [];
|
||||
const uses: Array<Uses> = [];
|
||||
const { terminal } = block;
|
||||
switch (terminal.kind) {
|
||||
case "return":
|
||||
case "throw": {
|
||||
if (terminal.value) {
|
||||
uses.push({
|
||||
place: terminal.value,
|
||||
updateFn: (newPlace) => {
|
||||
terminal.value = newPlace;
|
||||
},
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "goto": {
|
||||
outputs.push(terminal.block);
|
||||
break;
|
||||
}
|
||||
case "if": {
|
||||
const { test, consequent, alternate } = terminal;
|
||||
uses.push({
|
||||
place: test,
|
||||
updateFn: (newPlace) => {
|
||||
terminal.test = newPlace;
|
||||
},
|
||||
});
|
||||
outputs.push(alternate);
|
||||
outputs.push(consequent);
|
||||
break;
|
||||
}
|
||||
case "switch": {
|
||||
const { test, cases } = terminal;
|
||||
uses.push({
|
||||
place: test,
|
||||
updateFn: (newPlace) => {
|
||||
terminal.test = newPlace;
|
||||
},
|
||||
});
|
||||
for (const case_ of [...cases].reverse()) {
|
||||
if (case_.test) {
|
||||
uses.push({
|
||||
place: case_.test,
|
||||
updateFn: (newPlace) => {
|
||||
case_.test = newPlace;
|
||||
},
|
||||
});
|
||||
}
|
||||
outputs.push(case_.block);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
assertExhaustive(
|
||||
terminal,
|
||||
`Unexpected terminal kind '${(terminal as any).kind}'`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return { uses, outputs };
|
||||
}
|
||||
|
||||
type Uses = {
|
||||
place: Place;
|
||||
updateFn: (place: Place) => void;
|
||||
};
|
||||
|
||||
function collectUses(instr: Instruction): Array<Uses> {
|
||||
const uses: Array<Uses> = [];
|
||||
const instrValue = instr.value;
|
||||
|
||||
// TODO(gsn): Handle more kinds of Instructions
|
||||
switch (instrValue.kind) {
|
||||
case "BinaryExpression": {
|
||||
uses.push({
|
||||
place: instrValue.left,
|
||||
updateFn: (newPlace) => {
|
||||
instrValue.left = newPlace;
|
||||
},
|
||||
});
|
||||
uses.push({
|
||||
place: instrValue.right,
|
||||
updateFn: (newPlace) => {
|
||||
instrValue.right = newPlace;
|
||||
},
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "Identifier": {
|
||||
uses.push({
|
||||
place: instrValue,
|
||||
updateFn: (newPlace) => {
|
||||
instr.value = newPlace;
|
||||
},
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
return uses;
|
||||
}
|
||||
@@ -43,20 +43,26 @@ bb0:
|
||||
Const mutate max$7 = Call mutate Math$8.max(read $9, read maxItems$3)
|
||||
Goto bb1
|
||||
bb1:
|
||||
predecessor blocks: bb0 bb4 bb7
|
||||
If (read items$2) then:bb3 else:bb2
|
||||
bb3:
|
||||
predecessor blocks: bb1
|
||||
Const mutate $11 = null
|
||||
Const mutate $12 = Binary read item$10 == read $11
|
||||
If (read $12) then:bb8 else:bb9
|
||||
bb8:
|
||||
predecessor blocks: bb3
|
||||
Const mutate $13 = read $12
|
||||
Goto bb7
|
||||
bb9:
|
||||
predecessor blocks: bb3
|
||||
Const mutate $13 = Call mutate seen$5.has(mutate item$10)
|
||||
Goto bb7
|
||||
bb7:
|
||||
predecessor blocks: bb9 bb8
|
||||
If (read $13) then:bb1 else:bb4
|
||||
bb4:
|
||||
predecessor blocks: bb7
|
||||
Call mutate seen$5.add(mutate item$10)
|
||||
Const mutate $14 = "div"
|
||||
Const mutate $15 = JSX <read $14>{read item$10}</read $14>
|
||||
@@ -64,6 +70,7 @@ bb4:
|
||||
Const mutate $16 = Binary read renderedItems$4.length >= read max$7
|
||||
If (read $16) then:bb2 else:bb1
|
||||
bb2:
|
||||
predecessor blocks: bb1 bb4
|
||||
Const mutate count$17 = read renderedItems$4.length
|
||||
Const mutate $18 = "div"
|
||||
Const mutate $19 = "\n "
|
||||
|
||||
@@ -82,9 +82,11 @@ bb0:
|
||||
Call mutate a_DEBUG$2.push(read props$1.a)
|
||||
If (read props$1.b) then:bb2 else:bb1
|
||||
bb2:
|
||||
predecessor blocks: bb0
|
||||
Const mutate $3 = null
|
||||
Return read $3
|
||||
bb1:
|
||||
predecessor blocks: bb0
|
||||
Call mutate a_DEBUG$2.push(read props$1.d)
|
||||
Return freeze a_DEBUG$2
|
||||
```
|
||||
@@ -111,9 +113,11 @@ bb0:
|
||||
Call mutate a$2.push(read props$1.a)
|
||||
If (read props$1.b) then:bb2 else:bb1
|
||||
bb2:
|
||||
predecessor blocks: bb0
|
||||
Call mutate a$2.push(read props$1.c)
|
||||
Goto bb1
|
||||
bb1:
|
||||
predecessor blocks: bb0 bb2
|
||||
Call mutate a$2.push(read props$1.d)
|
||||
Return freeze a$2
|
||||
```
|
||||
@@ -141,10 +145,12 @@ bb0:
|
||||
Call mutate a$2.push(read props$1.a)
|
||||
If (read props$1.b) then:bb2 else:bb1
|
||||
bb2:
|
||||
predecessor blocks: bb0
|
||||
Call mutate a$2.push(read props$1.c)
|
||||
Const mutate $3 = null
|
||||
Return read $3
|
||||
bb1:
|
||||
predecessor blocks: bb0
|
||||
Call mutate a$2.push(read props$1.d)
|
||||
Return freeze a$2
|
||||
```
|
||||
@@ -172,9 +178,11 @@ bb0:
|
||||
Call mutate a$2.push(read props$1.a)
|
||||
If (read props$1.b) then:bb2 else:bb1
|
||||
bb2:
|
||||
predecessor blocks: bb0
|
||||
Call mutate a$2.push(read props$1.c)
|
||||
Return freeze a$2
|
||||
bb1:
|
||||
predecessor blocks: bb0
|
||||
Call mutate a$2.push(read props$1.d)
|
||||
Return freeze a$2
|
||||
```
|
||||
@@ -202,9 +210,11 @@ bb0:
|
||||
Call mutate a$2.push(read props$1.a)
|
||||
If (read props$1.b) then:bb1 else:bb2
|
||||
bb2:
|
||||
predecessor blocks: bb0
|
||||
Call mutate a$2.push(read props$1.c)
|
||||
Goto bb1
|
||||
bb1:
|
||||
predecessor blocks: bb2 bb0
|
||||
Call mutate a$2.push(read props$1.d)
|
||||
Return freeze a$2
|
||||
```
|
||||
|
||||
@@ -71,14 +71,18 @@ bb0:
|
||||
Const mutate b$3 = Array []
|
||||
If (read b$3) then:bb2 else:bb1
|
||||
bb2:
|
||||
predecessor blocks: bb0
|
||||
Call mutate a$2.push(read props$1.p0)
|
||||
Goto bb1
|
||||
bb1:
|
||||
predecessor blocks: bb0 bb2
|
||||
If (read props$1.p1) then:bb4 else:bb3
|
||||
bb4:
|
||||
predecessor blocks: bb1
|
||||
Call mutate b$3.push(read props$1.p2)
|
||||
Goto bb3
|
||||
bb3:
|
||||
predecessor blocks: bb1 bb4
|
||||
Const mutate $5 = JSX <read Foo$4 a={freeze a$2} b={freeze b$3} ></read Foo$4>
|
||||
Return read $5
|
||||
```
|
||||
@@ -110,14 +114,18 @@ bb0:
|
||||
Const mutate $5 = Call mutate mayMutate$4(mutate b$3)
|
||||
If (read $5) then:bb2 else:bb1
|
||||
bb2:
|
||||
predecessor blocks: bb0
|
||||
Call mutate a$2.push(read props$1.p0)
|
||||
Goto bb1
|
||||
bb1:
|
||||
predecessor blocks: bb0 bb2
|
||||
If (read props$1.p1) then:bb4 else:bb3
|
||||
bb4:
|
||||
predecessor blocks: bb1
|
||||
Call mutate b$3.push(read props$1.p2)
|
||||
Goto bb3
|
||||
bb3:
|
||||
predecessor blocks: bb1 bb4
|
||||
Const mutate $7 = JSX <read Foo$6 a={freeze a$2} b={freeze b$3} ></read Foo$6>
|
||||
Return read $7
|
||||
```
|
||||
|
||||
+3
@@ -31,12 +31,15 @@ bb0:
|
||||
Let mutate a$4 = undefined
|
||||
If (read cond$2) then:bb2 else:bb3
|
||||
bb2:
|
||||
predecessor blocks: bb0
|
||||
Reassign mutate a$4 = read x$3
|
||||
Goto bb1
|
||||
bb3:
|
||||
predecessor blocks: bb0
|
||||
Reassign mutate a$4 = Array []
|
||||
Goto bb1
|
||||
bb1:
|
||||
predecessor blocks: bb3 bb2
|
||||
Call read useFreeze$5(freeze a$4)
|
||||
Call read useFreeze$5(read a$4)
|
||||
Call mutate call$6(read a$4)
|
||||
|
||||
@@ -101,10 +101,12 @@ bb0:
|
||||
Const mutate b$4 = Call mutate compute$3(read props$1.b)
|
||||
If (read props$1.c) then:bb2 else:bb1
|
||||
bb2:
|
||||
predecessor blocks: bb0
|
||||
Call mutate mutate$5(mutate a$2)
|
||||
Call mutate mutate$5(mutate b$4)
|
||||
Goto bb1
|
||||
bb1:
|
||||
predecessor blocks: bb0 bb2
|
||||
Const mutate $7 = JSX <read Foo$6 a={freeze a$2} b={freeze b$4} ></read Foo$6>
|
||||
Return read $7
|
||||
```
|
||||
|
||||
@@ -80,9 +80,11 @@ bb0:
|
||||
Const mutate b$4 = Call mutate compute$3(read props$1.b)
|
||||
If (read props$1.c) then:bb2 else:bb1
|
||||
bb2:
|
||||
predecessor blocks: bb0
|
||||
Call mutate foo$5(mutate a$2, mutate b$4)
|
||||
Goto bb1
|
||||
bb1:
|
||||
predecessor blocks: bb0 bb2
|
||||
Const mutate $7 = JSX <read Foo$6 a={freeze a$2} b={freeze b$4} ></read Foo$6>
|
||||
Return read $7
|
||||
```
|
||||
|
||||
@@ -79,9 +79,11 @@ bb0:
|
||||
Let mutate d$5 = Object { }
|
||||
Goto bb1
|
||||
bb1:
|
||||
predecessor blocks: bb0 bb3
|
||||
Const mutate $10 = true
|
||||
If (read $10) then:bb3 else:bb2
|
||||
bb3:
|
||||
predecessor blocks: bb1
|
||||
Let mutate z$6 = read a$2
|
||||
Reassign mutate a$2 = read b$3
|
||||
Reassign mutate b$3 = read c$4
|
||||
@@ -91,14 +93,19 @@ bb3:
|
||||
Const mutate $9 = Call mutate cond$8(mutate a$2)
|
||||
If (read $9) then:bb2 else:bb1
|
||||
bb2:
|
||||
predecessor blocks: bb1 bb3
|
||||
If (read a$2) then:bb7 else:bb7
|
||||
bb7:
|
||||
predecessor blocks: bb2
|
||||
If (read b$3) then:bb9 else:bb9
|
||||
bb9:
|
||||
predecessor blocks: bb7
|
||||
If (read c$4) then:bb11 else:bb11
|
||||
bb11:
|
||||
predecessor blocks: bb9
|
||||
If (read d$5) then:bb13 else:bb13
|
||||
bb13:
|
||||
predecessor blocks: bb11
|
||||
Const mutate $11 = null
|
||||
Call mutate mutate$7(mutate d$5, read $11)
|
||||
Return
|
||||
|
||||
@@ -63,14 +63,19 @@ bb0:
|
||||
Const mutate y$7 = Call mutate mutate$8(mutate x$6, mutate d$5)
|
||||
If (read a$2) then:bb1 else:bb1
|
||||
bb1:
|
||||
predecessor blocks: bb0
|
||||
If (read b$3) then:bb3 else:bb3
|
||||
bb3:
|
||||
predecessor blocks: bb1
|
||||
If (read c$4) then:bb5 else:bb5
|
||||
bb5:
|
||||
predecessor blocks: bb3
|
||||
If (read d$5) then:bb7 else:bb7
|
||||
bb7:
|
||||
predecessor blocks: bb5
|
||||
If (read y$7) then:bb9 else:bb9
|
||||
bb9:
|
||||
predecessor blocks: bb7
|
||||
Const mutate $9 = null
|
||||
Call mutate mutate$8(mutate x$6, read $9)
|
||||
Return
|
||||
|
||||
@@ -28,9 +28,11 @@ bb0:
|
||||
Let mutate y$3 = read x$2
|
||||
If (read props$1.p1) then:bb2 else:bb1
|
||||
bb2:
|
||||
predecessor blocks: bb0
|
||||
Reassign mutate x$2 = Array []
|
||||
Goto bb1
|
||||
bb1:
|
||||
predecessor blocks: bb0 bb2
|
||||
Let mutate _$4 = JSX <read Component$0 x={freeze x$2} ></read Component$0>
|
||||
Call read y$3.push(read props$1.p2)
|
||||
Const mutate $5 = JSX <read Component$0 x={read x$2} y={read y$3} ></read Component$0>
|
||||
|
||||
@@ -39,6 +39,7 @@ bb0:
|
||||
Let mutate x$2 = undefined
|
||||
If (read props$1.cond) then:bb2 else:bb10
|
||||
bb2:
|
||||
predecessor blocks: bb0
|
||||
Const mutate $3 = 2
|
||||
Const mutate $4 = 1
|
||||
Const mutate $5 = 0
|
||||
@@ -48,23 +49,30 @@ bb2:
|
||||
Case read $3: bb4
|
||||
Default: bb4
|
||||
bb8:
|
||||
predecessor blocks: bb2
|
||||
Reassign mutate x$2 = read props$1.v0
|
||||
Goto bb1
|
||||
bb6:
|
||||
predecessor blocks: bb2
|
||||
Reassign mutate x$2 = read props$1.v1
|
||||
Goto bb1
|
||||
bb4:
|
||||
predecessor blocks: bb2
|
||||
Reassign mutate x$2 = read props$1.v2
|
||||
Goto bb1
|
||||
bb10:
|
||||
predecessor blocks: bb0
|
||||
If (read props$1.cond2) then:bb12 else:bb13
|
||||
bb12:
|
||||
predecessor blocks: bb10
|
||||
Reassign mutate x$2 = read props$1.b
|
||||
Goto bb1
|
||||
bb13:
|
||||
predecessor blocks: bb10
|
||||
Reassign mutate x$2 = read props$1.c
|
||||
Goto bb1
|
||||
bb1:
|
||||
predecessor blocks: bb13 bb12 bb8 bb6 bb4
|
||||
read x$2
|
||||
Return
|
||||
```
|
||||
|
||||
@@ -17,10 +17,12 @@ function foo(x, y) {
|
||||
bb0:
|
||||
If (read x$1) then:bb2 else:bb1
|
||||
bb2:
|
||||
predecessor blocks: bb0
|
||||
Const mutate $3 = false
|
||||
Const mutate $4 = Call read foo$0(read $3, read y$2)
|
||||
Return freeze $4
|
||||
bb1:
|
||||
predecessor blocks: bb0
|
||||
Const mutate $5 = 10
|
||||
Const mutate $6 = Binary read y$2 * read $5
|
||||
Const mutate $7 = Array [read $6]
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function foo() {
|
||||
let x = 1;
|
||||
let y = 2;
|
||||
if (y === 2) {
|
||||
x = 3;
|
||||
}
|
||||
|
||||
if (y === 3) {
|
||||
x = 5;
|
||||
}
|
||||
y = x;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## HIR
|
||||
|
||||
```
|
||||
bb0:
|
||||
Let mutate x$1000 = 1
|
||||
Let mutate y$1001 = 2
|
||||
Const mutate $1002 = 2
|
||||
Const mutate $1003 = Binary mutate y$1001 === mutate $1002
|
||||
If (mutate $1003) then:bb2 else:bb1
|
||||
bb2:
|
||||
predecessor blocks: bb0
|
||||
Reassign mutate x$1011 = 3
|
||||
Goto bb1
|
||||
bb1:
|
||||
predecessor blocks: bb0 bb2
|
||||
Const mutate y$1005: phi(bb0: mutate y$1001, bb2: mutate y$1001)
|
||||
Const mutate x$1010: phi(bb0: mutate x$1000, bb2: mutate x$1011)
|
||||
Const mutate $1004 = 3
|
||||
Const mutate $1006 = Binary mutate y$1005 === mutate $1004
|
||||
If (mutate $1006) then:bb4 else:bb3
|
||||
bb4:
|
||||
predecessor blocks: bb1
|
||||
Reassign mutate x$1009 = 5
|
||||
Goto bb3
|
||||
bb3:
|
||||
predecessor blocks: bb1 bb4
|
||||
Const mutate x$1007: phi(bb1: mutate x$1010, bb4: mutate x$1009)
|
||||
Reassign mutate y$1008 = mutate x$1007
|
||||
Return
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
function foo$0() {
|
||||
let x$1000 = 1;
|
||||
let y$1001 = 2;
|
||||
if (y$1001 === 2) {
|
||||
x$1011 = 3;
|
||||
("<<TODO: handle complex control flow in codegen>>");
|
||||
}
|
||||
if (y$1005 === 3) {
|
||||
x$1009 = 5;
|
||||
("<<TODO: handle complex control flow in codegen>>");
|
||||
}
|
||||
y$1008 = x$1007;
|
||||
return;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
function foo() {
|
||||
let x = 1;
|
||||
let y = 2;
|
||||
if (y === 2) {
|
||||
x = 3;
|
||||
}
|
||||
|
||||
if (y === 3) {
|
||||
x = 5;
|
||||
}
|
||||
y = x;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function foo() {
|
||||
let x = 1;
|
||||
let y = 2;
|
||||
if (y === 2) {
|
||||
x = 3;
|
||||
}
|
||||
|
||||
y = x;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## HIR
|
||||
|
||||
```
|
||||
bb0:
|
||||
Let mutate x$1000 = 1
|
||||
Let mutate y$1001 = 2
|
||||
Const mutate $1002 = 2
|
||||
Const mutate $1003 = Binary mutate y$1001 === mutate $1002
|
||||
If (mutate $1003) then:bb2 else:bb1
|
||||
bb2:
|
||||
predecessor blocks: bb0
|
||||
Reassign mutate x$1006 = 3
|
||||
Goto bb1
|
||||
bb1:
|
||||
predecessor blocks: bb0 bb2
|
||||
Const mutate x$1004: phi(bb0: mutate x$1000, bb2: mutate x$1006)
|
||||
Reassign mutate y$1005 = mutate x$1004
|
||||
Return
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
function foo$0() {
|
||||
let x$1000 = 1;
|
||||
let y$1001 = 2;
|
||||
if (y$1001 === 2) {
|
||||
x$1006 = 3;
|
||||
("<<TODO: handle complex control flow in codegen>>");
|
||||
}
|
||||
y$1005 = x$1004;
|
||||
return;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
function foo() {
|
||||
let x = 1;
|
||||
let y = 2;
|
||||
if (y === 2) {
|
||||
x = 3;
|
||||
}
|
||||
|
||||
y = x;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function foo() {
|
||||
let x = 0;
|
||||
for (; x < 10; ) {
|
||||
x = x + 1;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## HIR
|
||||
|
||||
```
|
||||
bb0:
|
||||
Let mutate x$1000 = 0
|
||||
Goto bb1
|
||||
bb1:
|
||||
predecessor blocks: bb0 bb4
|
||||
Const mutate x$1002: phi(bb0: mutate x$1000, bb4: mutate x$1005)
|
||||
Const mutate $1001 = 10
|
||||
Const mutate $1003 = Binary mutate x$1002 < mutate $1001
|
||||
If (mutate $1003) then:bb4 else:bb2
|
||||
bb4:
|
||||
predecessor blocks: bb1
|
||||
Const mutate $1004 = 1
|
||||
Reassign mutate x$1005 = Binary mutate x$1002 + mutate $1004
|
||||
Goto bb1
|
||||
bb2:
|
||||
predecessor blocks: bb1
|
||||
Return mutate x$1002
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
function foo$0() {
|
||||
let x$1000 = 0;
|
||||
("<<TODO: handle complex control flow in codegen>>");
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
function foo() {
|
||||
let x = 0;
|
||||
for (; x < 10; ) {
|
||||
x = x + 1;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function foo() {
|
||||
let x = 1;
|
||||
let y = 2;
|
||||
|
||||
if (y) {
|
||||
let z = x + y;
|
||||
} else {
|
||||
let z = x;
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## HIR
|
||||
|
||||
```
|
||||
bb0:
|
||||
Let mutate x$1000 = 1
|
||||
Let mutate y$1001 = 2
|
||||
If (mutate y$1001) then:bb2 else:bb3
|
||||
bb2:
|
||||
predecessor blocks: bb0
|
||||
Let mutate z$1003 = Binary mutate x$1000 + mutate y$1001
|
||||
Goto bb1
|
||||
bb3:
|
||||
predecessor blocks: bb0
|
||||
Let mutate z$1002 = mutate x$1000
|
||||
Goto bb1
|
||||
bb1:
|
||||
predecessor blocks: bb3 bb2
|
||||
Return
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
function foo$0() {
|
||||
let x$1000 = 1;
|
||||
let y$1001 = 2;
|
||||
if (y$1001) {
|
||||
let z$1003 = x$1000 + y$1001;
|
||||
("<<TODO: handle complex control flow in codegen>>");
|
||||
} else {
|
||||
let z$1002 = x$1000;
|
||||
("<<TODO: handle complex control flow in codegen>>");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
function foo() {
|
||||
let x = 1;
|
||||
let y = 2;
|
||||
|
||||
if (y) {
|
||||
let z = x + y;
|
||||
} else {
|
||||
let z = x;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function foo() {
|
||||
let x = 1;
|
||||
if (x === 1) {
|
||||
x = 2;
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## HIR
|
||||
|
||||
```
|
||||
bb0:
|
||||
Let mutate x$1000 = 1
|
||||
Const mutate $1001 = 1
|
||||
Const mutate $1002 = Binary mutate x$1000 === mutate $1001
|
||||
If (mutate $1002) then:bb2 else:bb1
|
||||
bb2:
|
||||
predecessor blocks: bb0
|
||||
Reassign mutate x$1004 = 2
|
||||
Goto bb1
|
||||
bb1:
|
||||
predecessor blocks: bb0 bb2
|
||||
Const mutate x$1003: phi(bb0: mutate x$1000, bb2: mutate x$1004)
|
||||
Return mutate x$1003
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
function foo$0() {
|
||||
let x$1000 = 1;
|
||||
if (x$1000 === 1) {
|
||||
x$1004 = 2;
|
||||
("<<TODO: handle complex control flow in codegen>>");
|
||||
}
|
||||
return x$1003;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
function foo() {
|
||||
let x = 1;
|
||||
if (x === 1) {
|
||||
x = 2;
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function foo() {
|
||||
let y = 2;
|
||||
|
||||
if (y > 1) {
|
||||
y = 1;
|
||||
} else {
|
||||
y = 2;
|
||||
}
|
||||
|
||||
let x = y;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## HIR
|
||||
|
||||
```
|
||||
bb0:
|
||||
Let mutate y$1000 = 2
|
||||
Const mutate $1001 = 1
|
||||
Const mutate $1002 = Binary mutate y$1000 > mutate $1001
|
||||
If (mutate $1002) then:bb2 else:bb3
|
||||
bb2:
|
||||
predecessor blocks: bb0
|
||||
Reassign mutate y$1006 = 1
|
||||
Goto bb1
|
||||
bb3:
|
||||
predecessor blocks: bb0
|
||||
Reassign mutate y$1003 = 2
|
||||
Goto bb1
|
||||
bb1:
|
||||
predecessor blocks: bb3 bb2
|
||||
Const mutate y$1004: phi(bb3: mutate y$1003, bb2: mutate y$1006)
|
||||
Let mutate x$1005 = mutate y$1004
|
||||
Return
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
function foo$0() {
|
||||
let y$1000 = 2;
|
||||
if (y$1000 > 1) {
|
||||
y$1006 = 1;
|
||||
("<<TODO: handle complex control flow in codegen>>");
|
||||
} else {
|
||||
y$1003 = 2;
|
||||
("<<TODO: handle complex control flow in codegen>>");
|
||||
}
|
||||
let x$1005 = y$1004;
|
||||
return;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
function foo() {
|
||||
let y = 2;
|
||||
|
||||
if (y > 1) {
|
||||
y = 1;
|
||||
} else {
|
||||
y = 2;
|
||||
}
|
||||
|
||||
let x = y;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function foo() {
|
||||
let x = 1;
|
||||
let y = 2;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## HIR
|
||||
|
||||
```
|
||||
bb0:
|
||||
Let mutate x$1000 = 1
|
||||
Let mutate y$1001 = 2
|
||||
Return
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
function foo$0() {
|
||||
let x$1000 = 1;
|
||||
let y$1001 = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
function foo() {
|
||||
let x = 1;
|
||||
let y = 2;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function foo() {
|
||||
let x = 1;
|
||||
let y = 2;
|
||||
|
||||
if (y) {
|
||||
let z = x + y;
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## HIR
|
||||
|
||||
```
|
||||
bb0:
|
||||
Let mutate x$1000 = 1
|
||||
Let mutate y$1001 = 2
|
||||
If (mutate y$1001) then:bb2 else:bb1
|
||||
bb2:
|
||||
predecessor blocks: bb0
|
||||
Let mutate z$1002 = Binary mutate x$1000 + mutate y$1001
|
||||
Goto bb1
|
||||
bb1:
|
||||
predecessor blocks: bb0 bb2
|
||||
Return
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
function foo$0() {
|
||||
let x$1000 = 1;
|
||||
let y$1001 = 2;
|
||||
if (y$1001) {
|
||||
let z$1002 = x$1000 + y$1001;
|
||||
("<<TODO: handle complex control flow in codegen>>");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
function foo() {
|
||||
let x = 1;
|
||||
let y = 2;
|
||||
|
||||
if (y) {
|
||||
let z = x + y;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function foo() {
|
||||
let x = 1;
|
||||
|
||||
switch (x) {
|
||||
case x === 1: {
|
||||
x = x + 1;
|
||||
break;
|
||||
}
|
||||
case x === 2: {
|
||||
x = x + 2;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
x = x + 3;
|
||||
}
|
||||
}
|
||||
|
||||
let y = x;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## HIR
|
||||
|
||||
```
|
||||
bb0:
|
||||
Let mutate x$1000 = 1
|
||||
Const mutate $1001 = 2
|
||||
Const mutate $1002 = Binary mutate x$1000 === mutate $1001
|
||||
Const mutate $1003 = 1
|
||||
Const mutate $1004 = Binary mutate x$1000 === mutate $1003
|
||||
Switch (mutate x$1000)
|
||||
Case mutate $1004: bb5
|
||||
Case mutate $1002: bb3
|
||||
Default: bb2
|
||||
bb5:
|
||||
predecessor blocks: bb0
|
||||
Const mutate $1011 = 1
|
||||
Reassign mutate x$1012 = Binary mutate x$1000 + mutate $1011
|
||||
Goto bb1
|
||||
bb3:
|
||||
predecessor blocks: bb0
|
||||
Const mutate $1009 = 2
|
||||
Reassign mutate x$1010 = Binary mutate x$1000 + mutate $1009
|
||||
Goto bb1
|
||||
bb2:
|
||||
predecessor blocks: bb0
|
||||
Const mutate $1005 = 3
|
||||
Reassign mutate x$1006 = Binary mutate x$1000 + mutate $1005
|
||||
Goto bb1
|
||||
bb1:
|
||||
predecessor blocks: bb5 bb3 bb2
|
||||
Const mutate x$1007: phi(bb5: mutate x$1012, bb3: mutate x$1010, bb2: mutate x$1006)
|
||||
Let mutate y$1008 = mutate x$1007
|
||||
Return
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
function foo$0() {
|
||||
let x$1000 = 1;
|
||||
switch (x$1000) {
|
||||
case x$1000 === 1: {
|
||||
x$1012 = x$1000 + 1;
|
||||
("<<TODO: handle complex control flow in codegen>>");
|
||||
}
|
||||
case x$1000 === 2: {
|
||||
x$1010 = x$1000 + 2;
|
||||
("<<TODO: handle complex control flow in codegen>>");
|
||||
}
|
||||
default: {
|
||||
x$1006 = x$1000 + 3;
|
||||
("<<TODO: handle complex control flow in codegen>>");
|
||||
}
|
||||
}
|
||||
let y$1008 = x$1007;
|
||||
return;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
function foo() {
|
||||
let x = 1;
|
||||
|
||||
switch (x) {
|
||||
case x === 1: {
|
||||
x = x + 1;
|
||||
break;
|
||||
}
|
||||
case x === 2: {
|
||||
x = x + 2;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
x = x + 3;
|
||||
}
|
||||
}
|
||||
|
||||
let y = x;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function foo() {
|
||||
let x = 1;
|
||||
if (x === 1) {
|
||||
x = 2;
|
||||
}
|
||||
throw x;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## HIR
|
||||
|
||||
```
|
||||
bb0:
|
||||
Let mutate x$1000 = 1
|
||||
Const mutate $1001 = 1
|
||||
Const mutate $1002 = Binary mutate x$1000 === mutate $1001
|
||||
If (mutate $1002) then:bb2 else:bb1
|
||||
bb2:
|
||||
predecessor blocks: bb0
|
||||
Reassign mutate x$1004 = 2
|
||||
Goto bb1
|
||||
bb1:
|
||||
predecessor blocks: bb0 bb2
|
||||
Const mutate x$1003: phi(bb0: mutate x$1000, bb2: mutate x$1004)
|
||||
Throw mutate x$1003
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
function foo$0() {
|
||||
let x$1000 = 1;
|
||||
if (x$1000 === 1) {
|
||||
x$1004 = 2;
|
||||
("<<TODO: handle complex control flow in codegen>>");
|
||||
}
|
||||
throw x$1003;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
function foo() {
|
||||
let x = 1;
|
||||
if (x === 1) {
|
||||
x = 2;
|
||||
}
|
||||
throw x;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function foo() {
|
||||
let x = 1;
|
||||
while (x < 10) {
|
||||
x = x + 1;
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## HIR
|
||||
|
||||
```
|
||||
bb0:
|
||||
Let mutate x$1000 = 1
|
||||
Goto bb1
|
||||
bb1:
|
||||
predecessor blocks: bb0 bb3
|
||||
Const mutate x$1002: phi(bb0: mutate x$1000, bb3: mutate x$1005)
|
||||
Const mutate $1001 = 10
|
||||
Const mutate $1003 = Binary mutate x$1002 < mutate $1001
|
||||
If (mutate $1003) then:bb3 else:bb2
|
||||
bb3:
|
||||
predecessor blocks: bb1
|
||||
Const mutate $1004 = 1
|
||||
Reassign mutate x$1005 = Binary mutate x$1002 + mutate $1004
|
||||
Goto bb1
|
||||
bb2:
|
||||
predecessor blocks: bb1
|
||||
Return mutate x$1002
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
function foo$0() {
|
||||
let x$1000 = 1;
|
||||
("<<TODO: handle complex control flow in codegen>>");
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
function foo() {
|
||||
let x = 1;
|
||||
while (x < 10) {
|
||||
x = x + 1;
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
@@ -43,13 +43,16 @@ bb0:
|
||||
Default: bb1
|
||||
Case read $4: bb2
|
||||
bb6:
|
||||
predecessor blocks: bb0
|
||||
Call mutate x$2.push(read props$1.p2)
|
||||
Reassign mutate y$3 = Array []
|
||||
Goto bb1
|
||||
bb2:
|
||||
predecessor blocks: bb0
|
||||
Reassign mutate y$3 = read x$2
|
||||
Goto bb1
|
||||
bb1:
|
||||
predecessor blocks: bb0 bb6 bb2
|
||||
Const mutate child$7 = JSX <read Component$0 data={freeze x$2} ></read Component$0>
|
||||
Call read y$3.push(read props$1.p4)
|
||||
Const mutate $8 = JSX <read Component$0 data={freeze y$3} >{read child$7}</read Component$0>
|
||||
|
||||
@@ -37,14 +37,17 @@ bb0:
|
||||
Case read $4: bb2
|
||||
Default: bb1
|
||||
bb4:
|
||||
predecessor blocks: bb0
|
||||
Call mutate x$2.push(read props$1.p2)
|
||||
Call mutate x$2.push(read props$1.p3)
|
||||
Reassign mutate y$3 = Array []
|
||||
Goto bb2
|
||||
bb2:
|
||||
predecessor blocks: bb4 bb0
|
||||
Reassign mutate y$3 = read x$2
|
||||
Goto bb1
|
||||
bb1:
|
||||
predecessor blocks: bb2 bb0
|
||||
Const mutate child$6 = JSX <read Component$0 data={freeze x$2} ></read Component$0>
|
||||
Call read y$3.push(read props$1.p4)
|
||||
Const mutate $7 = JSX <read Component$0 data={read y$3} >{read child$6}</read Component$0>
|
||||
|
||||
@@ -19,6 +19,7 @@ import codegen from "../HIR/Codegen";
|
||||
import { HIRFunction } from "../HIR/HIR";
|
||||
import inferReferenceEffects from "../HIR/InferReferenceEffects";
|
||||
import printHIR from "../HIR/PrintHIR";
|
||||
import buildSSA from "../HIR/SSAify";
|
||||
import generateTestsFromFixtures from "./test-utils/generateTestsFromFixtures";
|
||||
|
||||
function wrapWithTripleBackticks(s: string, ext?: string) {
|
||||
@@ -45,6 +46,9 @@ describe("React Forget (HIR version)", () => {
|
||||
enter(nodePath) {
|
||||
const ir: HIRFunction = lower(nodePath);
|
||||
inferReferenceEffects(ir);
|
||||
if (file.startsWith("ssa")) {
|
||||
buildSSA(ir);
|
||||
}
|
||||
// const lifetimeGraph = buildDefUseGraph(ir);
|
||||
const textHIR = printHIR(ir.body);
|
||||
// const textLifetimeGraph = printGraph(lifetimeGraph);
|
||||
|
||||
Reference in New Issue
Block a user