@samitouri / QOS-React-2 / commits / 379251c65f

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.

Sathya Gunasekaran committed Oct 18, 2022 at 18:45 UTC 379251c65f39039ace1d2e5a80bdb5938cf3427c
40 files changed +1193 -3
compiler/forget/src/HIR/HIR.ts
+8
@@ -94,6 +94,8 @@ export type BasicBlock = {
94 id: BlockId;
95 instructions: Array<Instruction>;
96 terminal: Terminal;
97 + preds: Set<BasicBlock>;
98 + phis: Set<Phi>;
99 };
100
101 /**
@@ -162,6 +164,12 @@ export enum InstructionKind {
164 */
165 export type InstructionValue = (InstructionData & { path: NodePath }) | Place;
166
167 +export type Phi = {
168 + kind: "Phi";
169 + lvalue: LValue;
170 + operands: Map<BasicBlock, Place>;
171 +};
172 +
173 export type InstructionData =
174 | { kind: "Primitive"; value: number | boolean | string | null | undefined }
175 | { kind: "JSXText"; value: string }
compiler/forget/src/HIR/HIRBuilder.ts
+73 -3
@@ -114,6 +114,8 @@ export default class HIRBuilder {
114 id: blockId,
115 instructions,
116 terminal: { kind: "return", value: null },
117 + preds: new Set(),
118 + phis: new Set(),
119 });
120 // First reduce indirections and prune unreachable blocks
121 let reduced = shrink({
@@ -121,7 +123,9 @@ export default class HIRBuilder {
123 entry: this.#entry,
124 });
125 // then convert to reverse postorder
124 - return reversePostorderBlocks(reduced);
126 + const blocks = reversePostorderBlocks(reduced);
127 + markPredecessors(blocks);
128 + return blocks;
129 }
130
131 /**
@@ -133,6 +137,8 @@ export default class HIRBuilder {
137 id: blockId,
138 instructions,
139 terminal,
140 + preds: new Set(),
141 + phis: new Set(),
142 });
143 const nextId = makeBlockId(this.#nextId++);
144 this.#current = newBlock(nextId);
@@ -148,6 +154,8 @@ export default class HIRBuilder {
154 id: blockId,
155 instructions,
156 terminal,
157 + preds: new Set(),
158 + phis: new Set(),
159 });
160 this.#current = continuation;
161 }
@@ -166,7 +174,13 @@ export default class HIRBuilder {
174 */
175 complete(block: WipBlock, terminal: Terminal) {
176 const { id: blockId, instructions } = block;
169 - this.#completed.set(blockId, { id: blockId, instructions, terminal });
177 + this.#completed.set(blockId, {
178 + id: blockId,
179 + instructions,
180 + terminal,
181 + preds: new Set(),
182 + phis: new Set(),
183 + });
184 }
185
186 /**
@@ -181,7 +195,13 @@ export default class HIRBuilder {
195 this.#current = newBlock(nextId);
196 const terminal = fn(nextId);
197 const { id: blockId, instructions } = this.#current;
184 - this.#completed.set(blockId, { id: blockId, instructions, terminal });
198 + this.#completed.set(blockId, {
199 + id: blockId,
200 + instructions,
201 + terminal,
202 + preds: new Set(),
203 + phis: new Set(),
204 + });
205 this.#current = current;
206 return nextId;
207 }
@@ -336,6 +356,8 @@ function shrink(func: HIR): HIR {
356 id: blockId,
357 instructions,
358 terminal,
359 + preds: new Set(),
360 + phis: new Set(),
361 });
362 }
363
@@ -438,6 +460,54 @@ function reversePostorderBlocks(func: HIR): HIR {
460 };
461 }
462
463 +function markPredecessors(func: HIR) {
464 + const visited: Set<BlockId> = new Set();
465 + function visit(blockId: BlockId, prevBlock?: BasicBlock) {
466 + const block = func.blocks.get(blockId)!;
467 + if (prevBlock) {
468 + block.preds.add(prevBlock);
469 + }
470 +
471 + if (visited.has(blockId)) {
472 + return;
473 + }
474 + visited.add(blockId);
475 +
476 + const { terminal } = block;
477 +
478 + switch (terminal.kind) {
479 + case "return":
480 + case "throw": {
481 + break;
482 + }
483 + case "goto": {
484 + visit(terminal.block, block);
485 + break;
486 + }
487 + case "if": {
488 + const { consequent, alternate } = terminal;
489 + visit(alternate, block);
490 + visit(consequent, block);
491 + break;
492 + }
493 + case "switch": {
494 + const { cases } = terminal;
495 + for (const case_ of [...cases]) {
496 + visit(case_.block, block);
497 + }
498 + break;
499 + }
500 + default: {
501 + assertExhaustive(
502 + terminal,
503 + `Unexpected terminal kind '${(terminal as any).kind}'`
504 + );
505 + }
506 + }
507 + }
508 + visit(func.entry);
509 +}
510 +
511 /**
512 * If the given block is a simple indirection (empty terminated with a goto),
513 * returns the block being pointed to. Otherwise returns null
compiler/forget/src/HIR/PrintHIR.ts
+25
@@ -12,6 +12,7 @@ import {
12 InstructionKind,
13 InstructionValue,
14 LValue,
15 + Phi,
16 Place,
17 Terminal,
18 } from "./HIR";
@@ -31,6 +32,16 @@ export default function printHIR(
32 };
33 for (const [blockId, block] of ir.blocks) {
34 output.push(`bb${blockId}:`);
35 + if (block.preds.size > 0) {
36 + const preds = ["predecessor blocks:"];
37 + for (const pred of block.preds) {
38 + preds.push(`bb${pred.id}`);
39 + }
40 + push(preds.join(" "));
41 + }
42 + for (const phi of block.phis) {
43 + push(printPhi(phi));
44 + }
45 for (const instr of block.instructions) {
46 push(printInstruction(instr));
47 }
@@ -78,6 +89,20 @@ function printInstruction(instr: Instruction): string {
89 }
90 }
91
92 +function printPhi(phi: Phi): string {
93 + const items = [];
94 + items.push(printLValue(phi.lvalue));
95 + items.push(": phi(");
96 + const phis = [];
97 + for (const [block, place] of phi.operands) {
98 + phis.push(`bb${block.id}: ${printPlace(place)}`);
99 + }
100 +
101 + items.push(phis.join(", "));
102 + items.push(")");
103 + return items.join("");
104 +}
105 +
106 function printTerminal(terminal: Terminal): Array<string> | string {
107 let value;
108 switch (terminal.kind) {
compiler/forget/src/HIR/SSAify.ts new
+333
@@ -0,0 +1,333 @@
1 +import invariant from "invariant";
2 +import { assertExhaustive } from "../Common/utils";
3 +import {
4 + BasicBlock,
5 + BlockId,
6 + Effect,
7 + HIRFunction,
8 + IdentifierId,
9 + Instruction,
10 + InstructionKind,
11 + makeIdentifierId,
12 + Phi,
13 + Place,
14 +} from "./HIR";
15 +
16 +type IncompletePhi = {
17 + old: Place;
18 + new: Place;
19 +};
20 +
21 +type State = {
22 + defs: Map<IdentifierId, Place>;
23 + incompletePhis: IncompletePhi[];
24 +};
25 +
26 +const unsealedPreds: Map<BasicBlock, number> = new Map();
27 +
28 +class SSABuilder {
29 + #states: Map<BasicBlock, State> = new Map();
30 + #current: BasicBlock | null = null;
31 + visitedBlocks: Set<BasicBlock> = new Set();
32 +
33 + // Hack(gsn): Start from the last stored id in HIRBuilder.
34 + // Need to refactor makeTemporary and relevant state out of HIR Builder.
35 + #id = 1000;
36 +
37 + state(): State {
38 + invariant(
39 + this.#current !== null,
40 + "we need to be in a block to access state!"
41 + );
42 + return this.#states.get(this.#current)!;
43 + }
44 +
45 + // This tries to reuse all existing information about the oldPlace in case there's
46 + // useful information from previous compiler passes.
47 + makePlace(oldPlace: Place): Place {
48 + const identifier = {
49 + ...oldPlace.identifier,
50 + id: makeIdentifierId(this.#id++),
51 + };
52 + return {
53 + ...oldPlace,
54 + identifier,
55 + };
56 + }
57 +
58 + makePlaceForPhi(oldPlace: Place): Place {
59 + const identifier = {
60 + ...oldPlace.identifier,
61 + id: makeIdentifierId(this.#id++),
62 + };
63 + return {
64 + identifier,
65 + kind: "Identifier",
66 + memberPath: null,
67 + effect: Effect.Mutate,
68 + path: null as any,
69 + };
70 + }
71 +
72 + definePlace(oldPlace: Place): Place {
73 + const newPlace = this.makePlace(oldPlace);
74 + this.state().defs.set(oldPlace.identifier.id, newPlace);
75 + return newPlace;
76 + }
77 +
78 + getPlace(oldPlace: Place): Place {
79 + return this.getPlaceAt(oldPlace, this.#current!);
80 + }
81 +
82 + getPlaceAt(oldPlace: Place, block: BasicBlock): Place {
83 + // check if Place is defined locally
84 + const state = this.#states.get(block)!;
85 +
86 + if (state.defs.has(oldPlace.identifier.id)) {
87 + return state.defs.get(oldPlace.identifier.id)!;
88 + }
89 +
90 + if (block.preds.size == 0) {
91 + // We're at the entry block and haven't found our defintion yet.
92 + throw new Error(`Unable to find \$${oldPlace.identifier.id}`);
93 + }
94 +
95 + if (unsealedPreds.get(block)! > 0) {
96 + // We haven't visited all our predecessors, let's place an incomplete phi
97 + // for now.
98 + const newPlace = this.makePlaceForPhi(oldPlace);
99 + state.incompletePhis.push({ old: oldPlace, new: newPlace });
100 + state.defs.set(oldPlace.identifier.id, newPlace);
101 + return newPlace;
102 + }
103 +
104 + // Only one predecessor, let's check there
105 + if (block.preds.size == 1) {
106 + const [pred] = block.preds;
107 + const newPlace = this.getPlaceAt(oldPlace, pred);
108 + state.defs.set(oldPlace.identifier.id, newPlace);
109 + return newPlace;
110 + }
111 +
112 + // There are multiple predecessors, we need a phi.
113 + const newPlace = this.makePlaceForPhi(oldPlace);
114 + // Adding a phi may loop back to our block if there is a loop in the CFG. We
115 + // update our defs before adding the phi to terminate the recursion rather than
116 + // looping infinitely.
117 + state.defs.set(oldPlace.identifier.id, newPlace);
118 + this.addPhi(block, oldPlace, newPlace);
119 +
120 + // TODO(gsn): Can we just return `newPlace` rather than looking it up?
121 + // `addPhi` _can_ mutate it, but _will_ it?
122 + return state.defs.get(oldPlace.identifier.id)!;
123 + }
124 +
125 + addPhi(block: BasicBlock, oldPlace: Place, newPlace: Place) {
126 + const predDefs: Map<BasicBlock, Place> = new Map();
127 + for (const predBlock of block.preds) {
128 + const predPlace = this.getPlaceAt(oldPlace, predBlock);
129 + predDefs.set(predBlock, predPlace);
130 + }
131 +
132 + const phi: Phi = {
133 + kind: "Phi",
134 + lvalue: { place: newPlace, kind: InstructionKind.Const },
135 + operands: predDefs,
136 + };
137 +
138 + block.phis.add(phi);
139 + }
140 +
141 + fixIncompletePhis(block: BasicBlock) {
142 + const state = this.#states.get(block)!;
143 + for (const phi of state.incompletePhis) {
144 + this.addPhi(block, phi.old, phi.new);
145 + }
146 + }
147 +
148 + startBlock(block: BasicBlock) {
149 + this.#current = block;
150 + this.#states.set(block, {
151 + defs: new Map(),
152 + incompletePhis: [],
153 + });
154 + }
155 +
156 + print() {
157 + const text = [];
158 + for (const [block, state] of this.#states) {
159 + text.push(`bb${block.id}:`);
160 + for (const [id, place] of state.defs) {
161 + text.push(` \$${id} = \$${place.identifier.id}`);
162 + }
163 +
164 + for (const incompletePhi of state.incompletePhis) {
165 + text.push(
166 + ` iphi \$${incompletePhi.new.identifier} = \$${incompletePhi.old.identifier}`
167 + );
168 + }
169 + }
170 +
171 + text.push(`current block: bb${this.#current?.id}`);
172 + console.log(text.join("\n"));
173 + }
174 +}
175 +
176 +export default function buildSSA(func: HIRFunction) {
177 + const builder = new SSABuilder();
178 +
179 + function visit(blockId: BlockId) {
180 + const block = func.body.blocks.get(blockId)!;
181 + if (builder.visitedBlocks.has(block)) {
182 + return;
183 + }
184 + builder.visitedBlocks.add(block);
185 +
186 + builder.startBlock(block);
187 + for (const instr of block.instructions) {
188 + const uses = collectUses(instr);
189 + for (const { place, updateFn } of uses) {
190 + updateFn(builder.getPlace(place));
191 + }
192 +
193 + if (instr.lvalue != null) {
194 + const oldPlace = instr.lvalue.place;
195 + const newPlace: Place = builder.definePlace(oldPlace);
196 + instr.lvalue.place = newPlace;
197 + }
198 + }
199 +
200 + const { uses, outputs } = collectOutputs(block);
201 + for (const { place, updateFn } of uses) {
202 + updateFn(builder.getPlace(place));
203 + }
204 +
205 + const outputBlocks = outputs.map((id) => func.body.blocks.get(id)!);
206 + for (const output of outputBlocks) {
207 + let count;
208 + if (unsealedPreds.has(output)) {
209 + count = unsealedPreds.get(output)! - 1;
210 + } else {
211 + count = output.preds.size - 1;
212 + }
213 + unsealedPreds.set(output, count);
214 +
215 + if (count == 0 && builder.visitedBlocks.has(output)) {
216 + builder.fixIncompletePhis(output);
217 + }
218 + }
219 +
220 + for (const output of outputs) {
221 + visit(output);
222 + }
223 + }
224 +
225 + visit(func.body.entry);
226 +}
227 +
228 +function collectOutputs(block: BasicBlock): {
229 + uses: Array<Uses>;
230 + outputs: Array<BlockId>;
231 +} {
232 + const outputs: Array<BlockId> = [];
233 + const uses: Array<Uses> = [];
234 + const { terminal } = block;
235 + switch (terminal.kind) {
236 + case "return":
237 + case "throw": {
238 + if (terminal.value) {
239 + uses.push({
240 + place: terminal.value,
241 + updateFn: (newPlace) => {
242 + terminal.value = newPlace;
243 + },
244 + });
245 + }
246 + break;
247 + }
248 + case "goto": {
249 + outputs.push(terminal.block);
250 + break;
251 + }
252 + case "if": {
253 + const { test, consequent, alternate } = terminal;
254 + uses.push({
255 + place: test,
256 + updateFn: (newPlace) => {
257 + terminal.test = newPlace;
258 + },
259 + });
260 + outputs.push(alternate);
261 + outputs.push(consequent);
262 + break;
263 + }
264 + case "switch": {
265 + const { test, cases } = terminal;
266 + uses.push({
267 + place: test,
268 + updateFn: (newPlace) => {
269 + terminal.test = newPlace;
270 + },
271 + });
272 + for (const case_ of [...cases].reverse()) {
273 + if (case_.test) {
274 + uses.push({
275 + place: case_.test,
276 + updateFn: (newPlace) => {
277 + case_.test = newPlace;
278 + },
279 + });
280 + }
281 + outputs.push(case_.block);
282 + }
283 + break;
284 + }
285 + default: {
286 + assertExhaustive(
287 + terminal,
288 + `Unexpected terminal kind '${(terminal as any).kind}'`
289 + );
290 + }
291 + }
292 +
293 + return { uses, outputs };
294 +}
295 +
296 +type Uses = {
297 + place: Place;
298 + updateFn: (place: Place) => void;
299 +};
300 +
301 +function collectUses(instr: Instruction): Array<Uses> {
302 + const uses: Array<Uses> = [];
303 + const instrValue = instr.value;
304 +
305 + // TODO(gsn): Handle more kinds of Instructions
306 + switch (instrValue.kind) {
307 + case "BinaryExpression": {
308 + uses.push({
309 + place: instrValue.left,
310 + updateFn: (newPlace) => {
311 + instrValue.left = newPlace;
312 + },
313 + });
314 + uses.push({
315 + place: instrValue.right,
316 + updateFn: (newPlace) => {
317 + instrValue.right = newPlace;
318 + },
319 + });
320 + break;
321 + }
322 + case "Identifier": {
323 + uses.push({
324 + place: instrValue,
325 + updateFn: (newPlace) => {
326 + instr.value = newPlace;
327 + },
328 + });
329 + break;
330 + }
331 + }
332 + return uses;
333 +}
compiler/forget/src/__tests__/fixtures/hir/component.expect.md
+7
@@ -43,20 +43,26 @@ bb0:
43 Const mutate max$7 = Call mutate Math$8.max(read $9, read maxItems$3)
44 Goto bb1
45 bb1:
46 + predecessor blocks: bb0 bb4 bb7
47 If (read items$2) then:bb3 else:bb2
48 bb3:
49 + predecessor blocks: bb1
50 Const mutate $11 = null
51 Const mutate $12 = Binary read item$10 == read $11
52 If (read $12) then:bb8 else:bb9
53 bb8:
54 + predecessor blocks: bb3
55 Const mutate $13 = read $12
56 Goto bb7
57 bb9:
58 + predecessor blocks: bb3
59 Const mutate $13 = Call mutate seen$5.has(mutate item$10)
60 Goto bb7
61 bb7:
62 + predecessor blocks: bb9 bb8
63 If (read $13) then:bb1 else:bb4
64 bb4:
65 + predecessor blocks: bb7
66 Call mutate seen$5.add(mutate item$10)
67 Const mutate $14 = "div"
68 Const mutate $15 = JSX <read $14>{read item$10}</read $14>
@@ -64,6 +70,7 @@ bb4:
70 Const mutate $16 = Binary read renderedItems$4.length >= read max$7
71 If (read $16) then:bb2 else:bb1
72 bb2:
73 + predecessor blocks: bb1 bb4
74 Const mutate count$17 = read renderedItems$4.length
75 Const mutate $18 = "div"
76 Const mutate $19 = "\n "
compiler/forget/src/__tests__/fixtures/hir/conditional-break.expect.md
+10
@@ -82,9 +82,11 @@ bb0:
82 Call mutate a_DEBUG$2.push(read props$1.a)
83 If (read props$1.b) then:bb2 else:bb1
84 bb2:
85 + predecessor blocks: bb0
86 Const mutate $3 = null
87 Return read $3
88 bb1:
89 + predecessor blocks: bb0
90 Call mutate a_DEBUG$2.push(read props$1.d)
91 Return freeze a_DEBUG$2
92 ```
@@ -111,9 +113,11 @@ bb0:
113 Call mutate a$2.push(read props$1.a)
114 If (read props$1.b) then:bb2 else:bb1
115 bb2:
116 + predecessor blocks: bb0
117 Call mutate a$2.push(read props$1.c)
118 Goto bb1
119 bb1:
120 + predecessor blocks: bb0 bb2
121 Call mutate a$2.push(read props$1.d)
122 Return freeze a$2
123 ```
@@ -141,10 +145,12 @@ bb0:
145 Call mutate a$2.push(read props$1.a)
146 If (read props$1.b) then:bb2 else:bb1
147 bb2:
148 + predecessor blocks: bb0
149 Call mutate a$2.push(read props$1.c)
150 Const mutate $3 = null
151 Return read $3
152 bb1:
153 + predecessor blocks: bb0
154 Call mutate a$2.push(read props$1.d)
155 Return freeze a$2
156 ```
@@ -172,9 +178,11 @@ bb0:
178 Call mutate a$2.push(read props$1.a)
179 If (read props$1.b) then:bb2 else:bb1
180 bb2:
181 + predecessor blocks: bb0
182 Call mutate a$2.push(read props$1.c)
183 Return freeze a$2
184 bb1:
185 + predecessor blocks: bb0
186 Call mutate a$2.push(read props$1.d)
187 Return freeze a$2
188 ```
@@ -202,9 +210,11 @@ bb0:
210 Call mutate a$2.push(read props$1.a)
211 If (read props$1.b) then:bb1 else:bb2
212 bb2:
213 + predecessor blocks: bb0
214 Call mutate a$2.push(read props$1.c)
215 Goto bb1
216 bb1:
217 + predecessor blocks: bb2 bb0
218 Call mutate a$2.push(read props$1.d)
219 Return freeze a$2
220 ```
compiler/forget/src/__tests__/fixtures/hir/conditional-on-mutable.expect.md
+8
@@ -71,14 +71,18 @@ bb0:
71 Const mutate b$3 = Array []
72 If (read b$3) then:bb2 else:bb1
73 bb2:
74 + predecessor blocks: bb0
75 Call mutate a$2.push(read props$1.p0)
76 Goto bb1
77 bb1:
78 + predecessor blocks: bb0 bb2
79 If (read props$1.p1) then:bb4 else:bb3
80 bb4:
81 + predecessor blocks: bb1
82 Call mutate b$3.push(read props$1.p2)
83 Goto bb3
84 bb3:
85 + predecessor blocks: bb1 bb4
86 Const mutate $5 = JSX <read Foo$4 a={freeze a$2} b={freeze b$3} ></read Foo$4>
87 Return read $5
88 ```
@@ -110,14 +114,18 @@ bb0:
114 Const mutate $5 = Call mutate mayMutate$4(mutate b$3)
115 If (read $5) then:bb2 else:bb1
116 bb2:
117 + predecessor blocks: bb0
118 Call mutate a$2.push(read props$1.p0)
119 Goto bb1
120 bb1:
121 + predecessor blocks: bb0 bb2
122 If (read props$1.p1) then:bb4 else:bb3
123 bb4:
124 + predecessor blocks: bb1
125 Call mutate b$3.push(read props$1.p2)
126 Goto bb3
127 bb3:
128 + predecessor blocks: bb1 bb4
129 Const mutate $7 = JSX <read Foo$6 a={freeze a$2} b={freeze b$3} ></read Foo$6>
130 Return read $7
131 ```
compiler/forget/src/__tests__/fixtures/hir/hooks-freeze-possibly-mutable-arguments.expect.md
+3
@@ -31,12 +31,15 @@ bb0:
31 Let mutate a$4 = undefined
32 If (read cond$2) then:bb2 else:bb3
33 bb2:
34 + predecessor blocks: bb0
35 Reassign mutate a$4 = read x$3
36 Goto bb1
37 bb3:
38 + predecessor blocks: bb0
39 Reassign mutate a$4 = Array []
40 Goto bb1
41 bb1:
42 + predecessor blocks: bb3 bb2
43 Call read useFreeze$5(freeze a$4)
44 Call read useFreeze$5(read a$4)
45 Call mutate call$6(read a$4)
compiler/forget/src/__tests__/fixtures/hir/independent-across-if.expect.md
+2
@@ -101,10 +101,12 @@ bb0:
101 Const mutate b$4 = Call mutate compute$3(read props$1.b)
102 If (read props$1.c) then:bb2 else:bb1
103 bb2:
104 + predecessor blocks: bb0
105 Call mutate mutate$5(mutate a$2)
106 Call mutate mutate$5(mutate b$4)
107 Goto bb1
108 bb1:
109 + predecessor blocks: bb0 bb2
110 Const mutate $7 = JSX <read Foo$6 a={freeze a$2} b={freeze b$4} ></read Foo$6>
111 Return read $7
112 ```
compiler/forget/src/__tests__/fixtures/hir/interdependent-across-if.expect.md
+2
@@ -80,9 +80,11 @@ bb0:
80 Const mutate b$4 = Call mutate compute$3(read props$1.b)
81 If (read props$1.c) then:bb2 else:bb1
82 bb2:
83 + predecessor blocks: bb0
84 Call mutate foo$5(mutate a$2, mutate b$4)
85 Goto bb1
86 bb1:
87 + predecessor blocks: bb0 bb2
88 Const mutate $7 = JSX <read Foo$6 a={freeze a$2} b={freeze b$4} ></read Foo$6>
89 Return read $7
90 ```
compiler/forget/src/__tests__/fixtures/hir/mutable-lifetime-loops.expect.md
+7
@@ -79,9 +79,11 @@ bb0:
79 Let mutate d$5 = Object { }
80 Goto bb1
81 bb1:
82 + predecessor blocks: bb0 bb3
83 Const mutate $10 = true
84 If (read $10) then:bb3 else:bb2
85 bb3:
86 + predecessor blocks: bb1
87 Let mutate z$6 = read a$2
88 Reassign mutate a$2 = read b$3
89 Reassign mutate b$3 = read c$4
@@ -91,14 +93,19 @@ bb3:
93 Const mutate $9 = Call mutate cond$8(mutate a$2)
94 If (read $9) then:bb2 else:bb1
95 bb2:
96 + predecessor blocks: bb1 bb3
97 If (read a$2) then:bb7 else:bb7
98 bb7:
99 + predecessor blocks: bb2
100 If (read b$3) then:bb9 else:bb9
101 bb9:
102 + predecessor blocks: bb7
103 If (read c$4) then:bb11 else:bb11
104 bb11:
105 + predecessor blocks: bb9
106 If (read d$5) then:bb13 else:bb13
107 bb13:
108 + predecessor blocks: bb11
109 Const mutate $11 = null
110 Call mutate mutate$7(mutate d$5, read $11)
111 Return
compiler/forget/src/__tests__/fixtures/hir/mutable-lifetime-with-aliasing.expect.md
+5
@@ -63,14 +63,19 @@ bb0:
63 Const mutate y$7 = Call mutate mutate$8(mutate x$6, mutate d$5)
64 If (read a$2) then:bb1 else:bb1
65 bb1:
66 + predecessor blocks: bb0
67 If (read b$3) then:bb3 else:bb3
68 bb3:
69 + predecessor blocks: bb1
70 If (read c$4) then:bb5 else:bb5
71 bb5:
72 + predecessor blocks: bb3
73 If (read d$5) then:bb7 else:bb7
74 bb7:
75 + predecessor blocks: bb5
76 If (read y$7) then:bb9 else:bb9
77 bb9:
78 + predecessor blocks: bb7
79 Const mutate $9 = null
80 Call mutate mutate$8(mutate x$6, read $9)
81 Return
compiler/forget/src/__tests__/fixtures/hir/reassignment-conditional.expect.md
+2
@@ -28,9 +28,11 @@ bb0:
28 Let mutate y$3 = read x$2
29 If (read props$1.p1) then:bb2 else:bb1
30 bb2:
31 + predecessor blocks: bb0
32 Reassign mutate x$2 = Array []
33 Goto bb1
34 bb1:
35 + predecessor blocks: bb0 bb2
36 Let mutate _$4 = JSX <read Component$0 x={freeze x$2} ></read Component$0>
37 Call read y$3.push(read props$1.p2)
38 Const mutate $5 = JSX <read Component$0 x={read x$2} y={read y$3} ></read Component$0>
compiler/forget/src/__tests__/fixtures/hir/reverse-postorder.expect.md
+8
@@ -39,6 +39,7 @@ bb0:
39 Let mutate x$2 = undefined
40 If (read props$1.cond) then:bb2 else:bb10
41 bb2:
42 + predecessor blocks: bb0
43 Const mutate $3 = 2
44 Const mutate $4 = 1
45 Const mutate $5 = 0
@@ -48,23 +49,30 @@ bb2:
49 Case read $3: bb4
50 Default: bb4
51 bb8:
52 + predecessor blocks: bb2
53 Reassign mutate x$2 = read props$1.v0
54 Goto bb1
55 bb6:
56 + predecessor blocks: bb2
57 Reassign mutate x$2 = read props$1.v1
58 Goto bb1
59 bb4:
60 + predecessor blocks: bb2
61 Reassign mutate x$2 = read props$1.v2
62 Goto bb1
63 bb10:
64 + predecessor blocks: bb0
65 If (read props$1.cond2) then:bb12 else:bb13
66 bb12:
67 + predecessor blocks: bb10
68 Reassign mutate x$2 = read props$1.b
69 Goto bb1
70 bb13:
71 + predecessor blocks: bb10
72 Reassign mutate x$2 = read props$1.c
73 Goto bb1
74 bb1:
75 + predecessor blocks: bb13 bb12 bb8 bb6 bb4
76 read x$2
77 Return
78 ```
compiler/forget/src/__tests__/fixtures/hir/simple.expect.md
+2
@@ -17,10 +17,12 @@ function foo(x, y) {
17 bb0:
18 If (read x$1) then:bb2 else:bb1
19 bb2:
20 + predecessor blocks: bb0
21 Const mutate $3 = false
22 Const mutate $4 = Call read foo$0(read $3, read y$2)
23 Return freeze $4
24 bb1:
25 + predecessor blocks: bb0
26 Const mutate $5 = 10
27 Const mutate $6 = Binary read y$2 * read $5
28 Const mutate $7 = Array [read $6]
compiler/forget/src/__tests__/fixtures/hir/ssa-complex-multiple-if.expect.md new
+70
@@ -0,0 +1,70 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function foo() {
6 + let x = 1;
7 + let y = 2;
8 + if (y === 2) {
9 + x = 3;
10 + }
11 +
12 + if (y === 3) {
13 + x = 5;
14 + }
15 + y = x;
16 +}
17 +
18 +```
19 +
20 +## HIR
21 +
22 +```
23 +bb0:
24 + Let mutate x$1000 = 1
25 + Let mutate y$1001 = 2
26 + Const mutate $1002 = 2
27 + Const mutate $1003 = Binary mutate y$1001 === mutate $1002
28 + If (mutate $1003) then:bb2 else:bb1
29 +bb2:
30 + predecessor blocks: bb0
31 + Reassign mutate x$1011 = 3
32 + Goto bb1
33 +bb1:
34 + predecessor blocks: bb0 bb2
35 + Const mutate y$1005: phi(bb0: mutate y$1001, bb2: mutate y$1001)
36 + Const mutate x$1010: phi(bb0: mutate x$1000, bb2: mutate x$1011)
37 + Const mutate $1004 = 3
38 + Const mutate $1006 = Binary mutate y$1005 === mutate $1004
39 + If (mutate $1006) then:bb4 else:bb3
40 +bb4:
41 + predecessor blocks: bb1
42 + Reassign mutate x$1009 = 5
43 + Goto bb3
44 +bb3:
45 + predecessor blocks: bb1 bb4
46 + Const mutate x$1007: phi(bb1: mutate x$1010, bb4: mutate x$1009)
47 + Reassign mutate y$1008 = mutate x$1007
48 + Return
49 +```
50 +
51 +## Code
52 +
53 +```javascript
54 +function foo$0() {
55 + let x$1000 = 1;
56 + let y$1001 = 2;
57 + if (y$1001 === 2) {
58 + x$1011 = 3;
59 + ("<<TODO: handle complex control flow in codegen>>");
60 + }
61 + if (y$1005 === 3) {
62 + x$1009 = 5;
63 + ("<<TODO: handle complex control flow in codegen>>");
64 + }
65 + y$1008 = x$1007;
66 + return;
67 +}
68 +
69 +```
70 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/ssa-complex-multiple-if.js new
+12
@@ -0,0 +1,12 @@
1 +function foo() {
2 + let x = 1;
3 + let y = 2;
4 + if (y === 2) {
5 + x = 3;
6 + }
7 +
8 + if (y === 3) {
9 + x = 5;
10 + }
11 + y = x;
12 +}
compiler/forget/src/__tests__/fixtures/hir/ssa-complex-single-if.expect.md new
+52
@@ -0,0 +1,52 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function foo() {
6 + let x = 1;
7 + let y = 2;
8 + if (y === 2) {
9 + x = 3;
10 + }
11 +
12 + y = x;
13 +}
14 +
15 +```
16 +
17 +## HIR
18 +
19 +```
20 +bb0:
21 + Let mutate x$1000 = 1
22 + Let mutate y$1001 = 2
23 + Const mutate $1002 = 2
24 + Const mutate $1003 = Binary mutate y$1001 === mutate $1002
25 + If (mutate $1003) then:bb2 else:bb1
26 +bb2:
27 + predecessor blocks: bb0
28 + Reassign mutate x$1006 = 3
29 + Goto bb1
30 +bb1:
31 + predecessor blocks: bb0 bb2
32 + Const mutate x$1004: phi(bb0: mutate x$1000, bb2: mutate x$1006)
33 + Reassign mutate y$1005 = mutate x$1004
34 + Return
35 +```
36 +
37 +## Code
38 +
39 +```javascript
40 +function foo$0() {
41 + let x$1000 = 1;
42 + let y$1001 = 2;
43 + if (y$1001 === 2) {
44 + x$1006 = 3;
45 + ("<<TODO: handle complex control flow in codegen>>");
46 + }
47 + y$1005 = x$1004;
48 + return;
49 +}
50 +
51 +```
52 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/ssa-complex-single-if.js new
+9
@@ -0,0 +1,9 @@
1 +function foo() {
2 + let x = 1;
3 + let y = 2;
4 + if (y === 2) {
5 + x = 3;
6 + }
7 +
8 + y = x;
9 +}
compiler/forget/src/__tests__/fixtures/hir/ssa-for.expect.md new
+46
@@ -0,0 +1,46 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function foo() {
6 + let x = 0;
7 + for (; x < 10; ) {
8 + x = x + 1;
9 + }
10 + return x;
11 +}
12 +
13 +```
14 +
15 +## HIR
16 +
17 +```
18 +bb0:
19 + Let mutate x$1000 = 0
20 + Goto bb1
21 +bb1:
22 + predecessor blocks: bb0 bb4
23 + Const mutate x$1002: phi(bb0: mutate x$1000, bb4: mutate x$1005)
24 + Const mutate $1001 = 10
25 + Const mutate $1003 = Binary mutate x$1002 < mutate $1001
26 + If (mutate $1003) then:bb4 else:bb2
27 +bb4:
28 + predecessor blocks: bb1
29 + Const mutate $1004 = 1
30 + Reassign mutate x$1005 = Binary mutate x$1002 + mutate $1004
31 + Goto bb1
32 +bb2:
33 + predecessor blocks: bb1
34 + Return mutate x$1002
35 +```
36 +
37 +## Code
38 +
39 +```javascript
40 +function foo$0() {
41 + let x$1000 = 0;
42 + ("<<TODO: handle complex control flow in codegen>>");
43 +}
44 +
45 +```
46 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/ssa-for.js new
+7
@@ -0,0 +1,7 @@
1 +function foo() {
2 + let x = 0;
3 + for (; x < 10; ) {
4 + x = x + 1;
5 + }
6 + return x;
7 +}
compiler/forget/src/__tests__/fixtures/hir/ssa-if-else.expect.md new
+55
@@ -0,0 +1,55 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function foo() {
6 + let x = 1;
7 + let y = 2;
8 +
9 + if (y) {
10 + let z = x + y;
11 + } else {
12 + let z = x;
13 + }
14 +}
15 +
16 +```
17 +
18 +## HIR
19 +
20 +```
21 +bb0:
22 + Let mutate x$1000 = 1
23 + Let mutate y$1001 = 2
24 + If (mutate y$1001) then:bb2 else:bb3
25 +bb2:
26 + predecessor blocks: bb0
27 + Let mutate z$1003 = Binary mutate x$1000 + mutate y$1001
28 + Goto bb1
29 +bb3:
30 + predecessor blocks: bb0
31 + Let mutate z$1002 = mutate x$1000
32 + Goto bb1
33 +bb1:
34 + predecessor blocks: bb3 bb2
35 + Return
36 +```
37 +
38 +## Code
39 +
40 +```javascript
41 +function foo$0() {
42 + let x$1000 = 1;
43 + let y$1001 = 2;
44 + if (y$1001) {
45 + let z$1003 = x$1000 + y$1001;
46 + ("<<TODO: handle complex control flow in codegen>>");
47 + } else {
48 + let z$1002 = x$1000;
49 + ("<<TODO: handle complex control flow in codegen>>");
50 + }
51 + return;
52 +}
53 +
54 +```
55 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/ssa-if-else.js new
+10
@@ -0,0 +1,10 @@
1 +function foo() {
2 + let x = 1;
3 + let y = 2;
4 +
5 + if (y) {
6 + let z = x + y;
7 + } else {
8 + let z = x;
9 + }
10 +}
compiler/forget/src/__tests__/fixtures/hir/ssa-return.expect.md new
+47
@@ -0,0 +1,47 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function foo() {
6 + let x = 1;
7 + if (x === 1) {
8 + x = 2;
9 + }
10 +
11 + return x;
12 +}
13 +
14 +```
15 +
16 +## HIR
17 +
18 +```
19 +bb0:
20 + Let mutate x$1000 = 1
21 + Const mutate $1001 = 1
22 + Const mutate $1002 = Binary mutate x$1000 === mutate $1001
23 + If (mutate $1002) then:bb2 else:bb1
24 +bb2:
25 + predecessor blocks: bb0
26 + Reassign mutate x$1004 = 2
27 + Goto bb1
28 +bb1:
29 + predecessor blocks: bb0 bb2
30 + Const mutate x$1003: phi(bb0: mutate x$1000, bb2: mutate x$1004)
31 + Return mutate x$1003
32 +```
33 +
34 +## Code
35 +
36 +```javascript
37 +function foo$0() {
38 + let x$1000 = 1;
39 + if (x$1000 === 1) {
40 + x$1004 = 2;
41 + ("<<TODO: handle complex control flow in codegen>>");
42 + }
43 + return x$1003;
44 +}
45 +
46 +```
47 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/ssa-return.js new
+8
@@ -0,0 +1,8 @@
1 +function foo() {
2 + let x = 1;
3 + if (x === 1) {
4 + x = 2;
5 + }
6 +
7 + return x;
8 +}
compiler/forget/src/__tests__/fixtures/hir/ssa-simple-phi.expect.md new
+59
@@ -0,0 +1,59 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function foo() {
6 + let y = 2;
7 +
8 + if (y > 1) {
9 + y = 1;
10 + } else {
11 + y = 2;
12 + }
13 +
14 + let x = y;
15 +}
16 +
17 +```
18 +
19 +## HIR
20 +
21 +```
22 +bb0:
23 + Let mutate y$1000 = 2
24 + Const mutate $1001 = 1
25 + Const mutate $1002 = Binary mutate y$1000 > mutate $1001
26 + If (mutate $1002) then:bb2 else:bb3
27 +bb2:
28 + predecessor blocks: bb0
29 + Reassign mutate y$1006 = 1
30 + Goto bb1
31 +bb3:
32 + predecessor blocks: bb0
33 + Reassign mutate y$1003 = 2
34 + Goto bb1
35 +bb1:
36 + predecessor blocks: bb3 bb2
37 + Const mutate y$1004: phi(bb3: mutate y$1003, bb2: mutate y$1006)
38 + Let mutate x$1005 = mutate y$1004
39 + Return
40 +```
41 +
42 +## Code
43 +
44 +```javascript
45 +function foo$0() {
46 + let y$1000 = 2;
47 + if (y$1000 > 1) {
48 + y$1006 = 1;
49 + ("<<TODO: handle complex control flow in codegen>>");
50 + } else {
51 + y$1003 = 2;
52 + ("<<TODO: handle complex control flow in codegen>>");
53 + }
54 + let x$1005 = y$1004;
55 + return;
56 +}
57 +
58 +```
59 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/ssa-simple-phi.js new
+11
@@ -0,0 +1,11 @@
1 +function foo() {
2 + let y = 2;
3 +
4 + if (y > 1) {
5 + y = 1;
6 + } else {
7 + y = 2;
8 + }
9 +
10 + let x = y;
11 +}
compiler/forget/src/__tests__/fixtures/hir/ssa-simple.expect.md new
+31
@@ -0,0 +1,31 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function foo() {
6 + let x = 1;
7 + let y = 2;
8 +}
9 +
10 +```
11 +
12 +## HIR
13 +
14 +```
15 +bb0:
16 + Let mutate x$1000 = 1
17 + Let mutate y$1001 = 2
18 + Return
19 +```
20 +
21 +## Code
22 +
23 +```javascript
24 +function foo$0() {
25 + let x$1000 = 1;
26 + let y$1001 = 2;
27 + return;
28 +}
29 +
30 +```
31 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/ssa-simple.js new
+4
@@ -0,0 +1,4 @@
1 +function foo() {
2 + let x = 1;
3 + let y = 2;
4 +}
compiler/forget/src/__tests__/fixtures/hir/ssa-single-if.expect.md new
+46
@@ -0,0 +1,46 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function foo() {
6 + let x = 1;
7 + let y = 2;
8 +
9 + if (y) {
10 + let z = x + y;
11 + }
12 +}
13 +
14 +```
15 +
16 +## HIR
17 +
18 +```
19 +bb0:
20 + Let mutate x$1000 = 1
21 + Let mutate y$1001 = 2
22 + If (mutate y$1001) then:bb2 else:bb1
23 +bb2:
24 + predecessor blocks: bb0
25 + Let mutate z$1002 = Binary mutate x$1000 + mutate y$1001
26 + Goto bb1
27 +bb1:
28 + predecessor blocks: bb0 bb2
29 + Return
30 +```
31 +
32 +## Code
33 +
34 +```javascript
35 +function foo$0() {
36 + let x$1000 = 1;
37 + let y$1001 = 2;
38 + if (y$1001) {
39 + let z$1002 = x$1000 + y$1001;
40 + ("<<TODO: handle complex control flow in codegen>>");
41 + }
42 + return;
43 +}
44 +
45 +```
46 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/ssa-single-if.js new
+8
@@ -0,0 +1,8 @@
1 +function foo() {
2 + let x = 1;
3 + let y = 2;
4 +
5 + if (y) {
6 + let z = x + y;
7 + }
8 +}
compiler/forget/src/__tests__/fixtures/hir/ssa-switch.expect.md new
+86
@@ -0,0 +1,86 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function foo() {
6 + let x = 1;
7 +
8 + switch (x) {
9 + case x === 1: {
10 + x = x + 1;
11 + break;
12 + }
13 + case x === 2: {
14 + x = x + 2;
15 + break;
16 + }
17 + default: {
18 + x = x + 3;
19 + }
20 + }
21 +
22 + let y = x;
23 +}
24 +
25 +```
26 +
27 +## HIR
28 +
29 +```
30 +bb0:
31 + Let mutate x$1000 = 1
32 + Const mutate $1001 = 2
33 + Const mutate $1002 = Binary mutate x$1000 === mutate $1001
34 + Const mutate $1003 = 1
35 + Const mutate $1004 = Binary mutate x$1000 === mutate $1003
36 + Switch (mutate x$1000)
37 + Case mutate $1004: bb5
38 + Case mutate $1002: bb3
39 + Default: bb2
40 +bb5:
41 + predecessor blocks: bb0
42 + Const mutate $1011 = 1
43 + Reassign mutate x$1012 = Binary mutate x$1000 + mutate $1011
44 + Goto bb1
45 +bb3:
46 + predecessor blocks: bb0
47 + Const mutate $1009 = 2
48 + Reassign mutate x$1010 = Binary mutate x$1000 + mutate $1009
49 + Goto bb1
50 +bb2:
51 + predecessor blocks: bb0
52 + Const mutate $1005 = 3
53 + Reassign mutate x$1006 = Binary mutate x$1000 + mutate $1005
54 + Goto bb1
55 +bb1:
56 + predecessor blocks: bb5 bb3 bb2
57 + Const mutate x$1007: phi(bb5: mutate x$1012, bb3: mutate x$1010, bb2: mutate x$1006)
58 + Let mutate y$1008 = mutate x$1007
59 + Return
60 +```
61 +
62 +## Code
63 +
64 +```javascript
65 +function foo$0() {
66 + let x$1000 = 1;
67 + switch (x$1000) {
68 + case x$1000 === 1: {
69 + x$1012 = x$1000 + 1;
70 + ("<<TODO: handle complex control flow in codegen>>");
71 + }
72 + case x$1000 === 2: {
73 + x$1010 = x$1000 + 2;
74 + ("<<TODO: handle complex control flow in codegen>>");
75 + }
76 + default: {
77 + x$1006 = x$1000 + 3;
78 + ("<<TODO: handle complex control flow in codegen>>");
79 + }
80 + }
81 + let y$1008 = x$1007;
82 + return;
83 +}
84 +
85 +```
86 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/ssa-switch.js new
+19
@@ -0,0 +1,19 @@
1 +function foo() {
2 + let x = 1;
3 +
4 + switch (x) {
5 + case x === 1: {
6 + x = x + 1;
7 + break;
8 + }
9 + case x === 2: {
10 + x = x + 2;
11 + break;
12 + }
13 + default: {
14 + x = x + 3;
15 + }
16 + }
17 +
18 + let y = x;
19 +}
compiler/forget/src/__tests__/fixtures/hir/ssa-throw.expect.md new
+46
@@ -0,0 +1,46 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function foo() {
6 + let x = 1;
7 + if (x === 1) {
8 + x = 2;
9 + }
10 + throw x;
11 +}
12 +
13 +```
14 +
15 +## HIR
16 +
17 +```
18 +bb0:
19 + Let mutate x$1000 = 1
20 + Const mutate $1001 = 1
21 + Const mutate $1002 = Binary mutate x$1000 === mutate $1001
22 + If (mutate $1002) then:bb2 else:bb1
23 +bb2:
24 + predecessor blocks: bb0
25 + Reassign mutate x$1004 = 2
26 + Goto bb1
27 +bb1:
28 + predecessor blocks: bb0 bb2
29 + Const mutate x$1003: phi(bb0: mutate x$1000, bb2: mutate x$1004)
30 + Throw mutate x$1003
31 +```
32 +
33 +## Code
34 +
35 +```javascript
36 +function foo$0() {
37 + let x$1000 = 1;
38 + if (x$1000 === 1) {
39 + x$1004 = 2;
40 + ("<<TODO: handle complex control flow in codegen>>");
41 + }
42 + throw x$1003;
43 +}
44 +
45 +```
46 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/ssa-throw.js new
+7
@@ -0,0 +1,7 @@
1 +function foo() {
2 + let x = 1;
3 + if (x === 1) {
4 + x = 2;
5 + }
6 + throw x;
7 +}
compiler/forget/src/__tests__/fixtures/hir/ssa-while.expect.md new
+47
@@ -0,0 +1,47 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function foo() {
6 + let x = 1;
7 + while (x < 10) {
8 + x = x + 1;
9 + }
10 +
11 + return x;
12 +}
13 +
14 +```
15 +
16 +## HIR
17 +
18 +```
19 +bb0:
20 + Let mutate x$1000 = 1
21 + Goto bb1
22 +bb1:
23 + predecessor blocks: bb0 bb3
24 + Const mutate x$1002: phi(bb0: mutate x$1000, bb3: mutate x$1005)
25 + Const mutate $1001 = 10
26 + Const mutate $1003 = Binary mutate x$1002 < mutate $1001
27 + If (mutate $1003) then:bb3 else:bb2
28 +bb3:
29 + predecessor blocks: bb1
30 + Const mutate $1004 = 1
31 + Reassign mutate x$1005 = Binary mutate x$1002 + mutate $1004
32 + Goto bb1
33 +bb2:
34 + predecessor blocks: bb1
35 + Return mutate x$1002
36 +```
37 +
38 +## Code
39 +
40 +```javascript
41 +function foo$0() {
42 + let x$1000 = 1;
43 + ("<<TODO: handle complex control flow in codegen>>");
44 +}
45 +
46 +```
47 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/ssa-while.js new
+8
@@ -0,0 +1,8 @@
1 +function foo() {
2 + let x = 1;
3 + while (x < 10) {
4 + x = x + 1;
5 + }
6 +
7 + return x;
8 +}
compiler/forget/src/__tests__/fixtures/hir/switch-non-final-default.expect.md
+3
@@ -43,13 +43,16 @@ bb0:
43 Default: bb1
44 Case read $4: bb2
45 bb6:
46 + predecessor blocks: bb0
47 Call mutate x$2.push(read props$1.p2)
48 Reassign mutate y$3 = Array []
49 Goto bb1
50 bb2:
51 + predecessor blocks: bb0
52 Reassign mutate y$3 = read x$2
53 Goto bb1
54 bb1:
55 + predecessor blocks: bb0 bb6 bb2
56 Const mutate child$7 = JSX <read Component$0 data={freeze x$2} ></read Component$0>
57 Call read y$3.push(read props$1.p4)
58 Const mutate $8 = JSX <read Component$0 data={freeze y$3} >{read child$7}</read Component$0>
compiler/forget/src/__tests__/fixtures/hir/switch.expect.md
+3
@@ -37,14 +37,17 @@ bb0:
37 Case read $4: bb2
38 Default: bb1
39 bb4:
40 + predecessor blocks: bb0
41 Call mutate x$2.push(read props$1.p2)
42 Call mutate x$2.push(read props$1.p3)
43 Reassign mutate y$3 = Array []
44 Goto bb2
45 bb2:
46 + predecessor blocks: bb4 bb0
47 Reassign mutate y$3 = read x$2
48 Goto bb1
49 bb1:
50 + predecessor blocks: bb2 bb0
51 Const mutate child$6 = JSX <read Component$0 data={freeze x$2} ></read Component$0>
52 Call read y$3.push(read props$1.p4)
53 Const mutate $7 = JSX <read Component$0 data={read y$3} >{read child$6}</read Component$0>
compiler/forget/src/__tests__/hir-test.ts
+4
@@ -19,6 +19,7 @@ import codegen from "../HIR/Codegen";
19 import { HIRFunction } from "../HIR/HIR";
20 import inferReferenceEffects from "../HIR/InferReferenceEffects";
21 import printHIR from "../HIR/PrintHIR";
22 +import buildSSA from "../HIR/SSAify";
23 import generateTestsFromFixtures from "./test-utils/generateTestsFromFixtures";
24
25 function wrapWithTripleBackticks(s: string, ext?: string) {
@@ -45,6 +46,9 @@ describe("React Forget (HIR version)", () => {
46 enter(nodePath) {
47 const ir: HIRFunction = lower(nodePath);
48 inferReferenceEffects(ir);
49 + if (file.startsWith("ssa")) {
50 + buildSSA(ir);
51 + }
52 // const lifetimeGraph = buildDefUseGraph(ir);
53 const textHIR = printHIR(ir.body);
54 // const textLifetimeGraph = printGraph(lifetimeGraph);