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

Distinguish regular/value blocks

Joe Savona committed Jan 10, 2023 at 09:37 UTC f3168d020ff24d3530e6d4984c8ce9247bd97939
7 files changed +73 -93
compiler/forget/src/HIR/BuildHIR.ts
+29 -21
@@ -122,7 +122,7 @@ function lowerStatement(
122 value,
123 id: makeInstructionId(0),
124 };
125 - builder.terminate(terminal);
125 + builder.terminate("block", terminal);
126 return;
127 }
128 case "ReturnStatement": {
@@ -138,7 +138,7 @@ function lowerStatement(
138 value,
139 id: makeInstructionId(0),
140 };
141 - builder.terminateWithContinuation(terminal, fallthrough);
141 + builder.terminateWithContinuation("block", terminal, fallthrough);
142 return;
143 }
144 case "IfStatement": {
@@ -146,7 +146,7 @@ function lowerStatement(
146 // Block for code following the if
147 const continuationBlock = builder.reserve();
148 // Block for the consequent (if the test is truthy)
149 - const consequentBlock = builder.enter((blockId) => {
149 + const consequentBlock = builder.enter("block", (blockId) => {
150 lowerStatement(builder, stmt.get("consequent"));
151 return {
152 kind: "goto",
@@ -159,7 +159,7 @@ function lowerStatement(
159 let alternateBlock = null;
160 const alternate = stmt.get("alternate");
161 if (alternate.hasNode()) {
162 - alternateBlock = builder.enter((blockId) => {
162 + alternateBlock = builder.enter("block", (blockId) => {
163 lowerStatement(builder, alternate);
164 return {
165 kind: "goto",
@@ -181,7 +181,7 @@ function lowerStatement(
181 fallthrough: continuationBlock.id,
182 id: makeInstructionId(0),
183 };
184 - builder.terminateWithContinuation(terminal, continuationBlock);
184 + builder.terminateWithContinuation("block", terminal, continuationBlock);
185 return;
186 }
187 case "BlockStatement": {
@@ -192,7 +192,7 @@ function lowerStatement(
192 case "BreakStatement": {
193 const stmt = stmtPath as NodePath<t.BreakStatement>;
194 const block = builder.lookupBreak(stmt.node.label?.name ?? null);
195 - builder.terminate({
195 + builder.terminate("block", {
196 kind: "goto",
197 block,
198 variant: GotoVariant.Break,
@@ -203,7 +203,7 @@ function lowerStatement(
203 case "ContinueStatement": {
204 const stmt = stmtPath as NodePath<t.ContinueStatement>;
205 const block = builder.lookupContinue(stmt.node.label?.name ?? null);
206 - builder.terminate({
206 + builder.terminate("block", {
207 kind: "goto",
208 block,
209 variant: GotoVariant.Continue,
@@ -217,7 +217,7 @@ function lowerStatement(
217 const conditionalBlock = builder.reserve();
218 // Block for code following the loop
219 const continuationBlock = builder.reserve();
220 - const loopBlock = builder.enter((blockId) => {
220 + const loopBlock = builder.enter("block", (blockId) => {
221 return builder.loop(
222 label,
223 conditionalBlock.id,
@@ -235,6 +235,7 @@ function lowerStatement(
235 });
236 // End the block leading up to the loop and jump to the conditional block
237 builder.terminateWithContinuation(
238 + "block",
239 {
240 kind: "goto",
241 block: conditionalBlock.id,
@@ -257,7 +258,7 @@ function lowerStatement(
258 fallthrough: continuationBlock.id,
259 id: makeInstructionId(0),
260 };
260 - builder.terminateWithContinuation(terminal, continuationBlock);
261 + builder.terminateWithContinuation("block", terminal, continuationBlock);
262 return;
263 }
264 case "ForOfStatement": {
@@ -270,7 +271,7 @@ function lowerStatement(
271 * Build the loop body, each iteration loops back to the conditional block
272 * to check whether to continue or exit
273 */
273 - const loopBlock = builder.enter((blockId) => {
274 + const loopBlock = builder.enter("block", (blockId) => {
275 return builder.loop(
276 label,
277 conditionalBlock.id,
@@ -288,6 +289,7 @@ function lowerStatement(
289 });
290 // End the block leading up to the loop and jump to the conditional block
291 builder.terminateWithContinuation(
292 + "block",
293 {
294 kind: "goto",
295 block: conditionalBlock.id,
@@ -310,7 +312,7 @@ function lowerStatement(
312 fallthrough: continuationBlock.id,
313 id: makeInstructionId(0),
314 };
313 - builder.terminateWithContinuation(terminal, continuationBlock);
315 + builder.terminateWithContinuation("block", terminal, continuationBlock);
316 return;
317 }
318 case "ForStatement": {
@@ -320,7 +322,7 @@ function lowerStatement(
322 // Block for code following the loop
323 const continuationBlock = builder.reserve();
324
323 - const initBlock = builder.enter((blockId) => {
325 + const initBlock = builder.enter("value", (blockId) => {
326 const init = stmt.get("init") as NodePath<t.VariableDeclaration>;
327 todoInvariant(
328 t.isVariableDeclaration(init.node),
@@ -335,7 +337,7 @@ function lowerStatement(
337 };
338 });
339
338 - const updateBlock = builder.enter((blockId) => {
340 + const updateBlock = builder.enter("value", (blockId) => {
341 const update = stmt.get("update");
342 todoInvariant(update.hasNode(), "Handle empty for updater");
343 if (update.hasNode()) {
@@ -349,7 +351,7 @@ function lowerStatement(
351 };
352 });
353
352 - const bodyBlock = builder.enter((blockId) => {
354 + const bodyBlock = builder.enter("block", (blockId) => {
355 return builder.loop(label, updateBlock, continuationBlock.id, () => {
356 lowerStatement(builder, stmt.get("body"));
357 return {
@@ -362,6 +364,7 @@ function lowerStatement(
364 });
365
366 builder.terminateWithContinuation(
367 + "block",
368 {
369 kind: "for",
370 init: initBlock,
@@ -377,6 +380,7 @@ function lowerStatement(
380 const test = stmt.get("test");
381 todoInvariant(test.hasNode(), "ForStatement without test");
382 builder.terminateWithContinuation(
383 + "value",
384 {
385 kind: "if",
386 test: lowerExpressionToPlace(builder, test),
@@ -394,7 +398,7 @@ function lowerStatement(
398 // Block for code following the loop
399 const continuationBlock = builder.reserve();
400 // Loop body
397 - const loopBlock = builder.enter((loopBlock) => {
401 + const loopBlock = builder.enter("block", (loopBlock) => {
402 return builder.loop(label, loopBlock, continuationBlock.id, () => {
403 lowerStatement(builder, stmt.get("body"));
404 /**
@@ -415,6 +419,7 @@ function lowerStatement(
419 });
420 // do-while unconditionally enters the loop
421 builder.terminateWithContinuation(
422 + "block",
423 {
424 kind: "goto",
425 block: loopBlock,
@@ -432,7 +437,7 @@ function lowerStatement(
437 // Block for code following the loop
438 const continuationBlock = builder.reserve();
439 // Loop body
435 - const loopBlock = builder.enter((blockId) => {
440 + const loopBlock = builder.enter("block", (blockId) => {
441 return builder.loop(
442 label,
443 conditionalBlock.id,
@@ -455,6 +460,7 @@ function lowerStatement(
460 const loc = stmt.node.loc;
461 invariant(loc, "while statement must have a location");
462 builder.terminateWithContinuation(
463 + "block",
464 {
465 kind: "while",
466 loc,
@@ -479,7 +485,7 @@ function lowerStatement(
485 id: makeInstructionId(0),
486 };
487 // Complete the conditional and continue with code after the loop
482 - builder.terminateWithContinuation(terminal, continuationBlock);
488 + builder.terminateWithContinuation("value", terminal, continuationBlock);
489 return;
490 }
491 case "LabeledStatement": {
@@ -505,6 +511,7 @@ function lowerStatement(
511 lowerStatement(builder, stmt.get("body"));
512 });
513 builder.terminateWithContinuation(
514 + "block",
515 {
516 kind: "goto",
517 block: continuationBlock.id,
@@ -543,7 +550,7 @@ function lowerStatement(
550 );
551 hasDefault = true;
552 }
546 - const block = builder.enter((_blockId) => {
553 + const block = builder.enter("block", (_blockId) => {
554 return builder.switch(label, continuationBlock.id, () => {
555 case_
556 .get("consequent")
@@ -581,6 +588,7 @@ function lowerStatement(
588
589 const test = lowerExpressionToPlace(builder, stmt.get("discriminant"));
590 builder.terminateWithContinuation(
591 + "block",
592 {
593 kind: "switch",
594 test,
@@ -1192,7 +1200,7 @@ function lowerConditional(
1200 // Block for code following the if
1201 const continuationBlock = builder.reserve();
1202 // Block for the consequent (if the test is truthy)
1195 - const consequentBlock = builder.enter((blockId) => {
1203 + const consequentBlock = builder.enter("value", (blockId) => {
1204 let value = consequent();
1205 builder.push({
1206 id: makeInstructionId(0),
@@ -1208,7 +1216,7 @@ function lowerConditional(
1216 };
1217 });
1218 // Block for the alternate (if the test is not truthy)
1211 - const alternateBlock = builder.enter((blockId) => {
1219 + const alternateBlock = builder.enter("value", (blockId) => {
1220 let value = alternate();
1221 builder.push({
1222 id: makeInstructionId(0),
@@ -1231,7 +1239,7 @@ function lowerConditional(
1239 fallthrough: continuationBlock.id,
1240 id: makeInstructionId(0),
1241 };
1234 - builder.terminateWithContinuation(terminal, continuationBlock);
1242 + builder.terminateWithContinuation("value", terminal, continuationBlock);
1243 return place;
1244 }
1245
compiler/forget/src/HIR/HIR.ts
+7
@@ -141,7 +141,9 @@ export type HIR = {
141 * an exception occurs, therefore the block model only represents explicit throw
142 * statements and not implicit exceptions which may occur.
143 */
144 +export type BlockKind = "block" | "value";
145 export type BasicBlock = {
146 + kind: BlockKind;
147 id: BlockId;
148 instructions: Array<Instruction>;
149 terminal: Terminal;
@@ -162,6 +164,11 @@ export type Terminal =
164 | ForTerminal
165 | WhileTerminal;
166
167 +/**
168 + * Terminal nodes allowed for a value block
169 + */
170 +export type ValueTerminal = IfTerminal | GotoTerminal;
171 +
172 export type ThrowTerminal = { kind: "throw"; value: Place; id: InstructionId };
173
174 export type ReturnTerminal = {
compiler/forget/src/HIR/HIRBuilder.ts
+15 -5
@@ -12,6 +12,7 @@ import { assertExhaustive } from "../Utils/utils";
12 import {
13 BasicBlock,
14 BlockId,
15 + BlockKind,
16 GeneratedSource,
17 GotoVariant,
18 HIR,
@@ -146,6 +147,7 @@ export default class HIRBuilder {
147 build(): HIR {
148 const { id: blockId, instructions } = this.#current;
149 this.#completed.set(blockId, {
150 + kind: "block",
151 id: blockId,
152 instructions,
153 terminal: {
@@ -177,9 +179,10 @@ export default class HIRBuilder {
179 /**
180 * Terminate the current block w the given terminal, and start a new block
181 */
180 - terminate(terminal: Terminal) {
182 + terminate(kind: BlockKind, terminal: Terminal) {
183 const { id: blockId, instructions } = this.#current;
184 this.#completed.set(blockId, {
185 + kind,
186 id: blockId,
187 instructions,
188 terminal,
@@ -194,12 +197,17 @@ export default class HIRBuilder {
197 * Terminate the current block w the given terminal, and set the previously
198 * reserved block as the new current block
199 */
197 - terminateWithContinuation(terminal: Terminal, continuation: WipBlock) {
200 + terminateWithContinuation(
201 + kind: BlockKind,
202 + terminal: Terminal,
203 + continuation: WipBlock
204 + ) {
205 const { id: blockId, instructions } = this.#current;
206 this.#completed.set(blockId, {
207 + kind: kind,
208 id: blockId,
209 instructions,
202 - terminal,
210 + terminal: terminal,
211 preds: new Set(),
212 phis: new Set(),
213 });
@@ -218,9 +226,10 @@ export default class HIRBuilder {
226 /**
227 * Save a previously reserved block as completed
228 */
221 - complete(block: WipBlock, terminal: Terminal) {
229 + complete(kind: BlockKind, block: WipBlock, terminal: Terminal) {
230 const { id: blockId, instructions } = block;
231 this.#completed.set(blockId, {
232 + kind,
233 id: blockId,
234 instructions,
235 terminal,
@@ -235,13 +244,14 @@ export default class HIRBuilder {
244 * The lambda must return a terminal node, which is used to terminate the
245 * newly constructed block.
246 */
238 - enter(fn: (blockId: BlockId) => Terminal): BlockId {
247 + enter(kind: BlockKind, fn: (blockId: BlockId) => Terminal): BlockId {
248 const current = this.#current;
249 const nextId = makeBlockId(this.#nextId++);
250 this.#current = newBlock(nextId);
251 const terminal = fn(nextId);
252 const { id: blockId, instructions } = this.#current;
253 this.#completed.set(blockId, {
254 + kind,
255 id: blockId,
256 instructions,
257 terminal,
compiler/forget/src/HIR/MergeConsecutiveBlocks.ts
+1 -32
@@ -6,7 +6,6 @@
6 */
7
8 import { invariant } from "../Utils/CompilerError";
9 -import { assertExhaustive } from "../Utils/utils";
9 import {
10 BlockId,
11 Effect,
@@ -30,40 +29,10 @@ import {
29 */
30 export function mergeConsecutiveBlocks(fn: HIRFunction): void {
31 const merged = new MergedBlocks();
33 - const valueBlocks = new Set<BlockId>();
32 for (const [, block] of fn.body.blocks) {
35 - // Before evaluating the block itself, determine which other blocks
36 - // are value blocks. See above TODO which would allow us to bypass this.
37 - const terminal = block.terminal;
38 - switch (terminal.kind) {
39 - case "while": {
40 - valueBlocks.add(terminal.test);
41 - break;
42 - }
43 - case "for": {
44 - valueBlocks.add(terminal.init);
45 - valueBlocks.add(terminal.test);
46 - valueBlocks.add(terminal.update);
47 - break;
48 - }
49 - case "if":
50 - case "goto":
51 - case "return":
52 - case "throw":
53 - case "switch": {
54 - break;
55 - }
56 - default: {
57 - assertExhaustive(
58 - terminal,
59 - `Unexpected terminal kind '${(terminal as any).kind}'`
60 - );
61 - }
62 - }
63 -
33 // Can only merge blocks with a single predecessor, can't merge
34 // value blocks
66 - if (block.preds.size !== 1 || valueBlocks.has(block.id)) {
35 + if (block.kind === "value" || block.preds.size !== 1) {
36 continue;
37 }
38 const originalPredecessorId = Array.from(block.preds)[0]!;
compiler/forget/src/HIR/PrintHIR.ts
+1 -1
@@ -47,7 +47,7 @@ export default function printHIR(
47 output.push(`${indent}${text}`);
48 };
49 for (const [blockId, block] of ir.blocks) {
50 - output.push(`bb${blockId}:`);
50 + output.push(`bb${blockId} (${block.kind}):`);
51 if (block.preds.size > 0) {
52 const preds = ["predecessor blocks:"];
53 for (const pred of block.preds) {
compiler/forget/src/Optimization/ConstantPropagation.ts
+1 -15
@@ -6,7 +6,6 @@
6 */
7
8 import {
9 - BlockId,
9 GotoVariant,
10 HIRFunction,
11 IdentifierId,
@@ -72,9 +71,6 @@ export function constantPropagation(fn: HIRFunction): void {
71 function applyConstantPropagation(fn: HIRFunction): boolean {
72 let hasChanges = false;
73
75 - // A set of blocks whose terminals can't (yet) be safely rewritten
76 - const valueBlocks = new Set<BlockId>();
77 -
74 const constants: Constants = new Map();
75 for (const [, block] of fn.body.blocks) {
76 // Initialize phi values if all operands have the same known constant value.
@@ -108,7 +104,7 @@ function applyConstantPropagation(fn: HIRFunction): boolean {
104 }
105 }
106
111 - if (valueBlocks.has(block.id)) {
107 + if (block.kind === "value") {
108 // can't rewrite terminals in value blocks yet
109 continue;
110 }
@@ -130,16 +126,6 @@ function applyConstantPropagation(fn: HIRFunction): boolean {
126 }
127 break;
128 }
133 - case "while": {
134 - valueBlocks.add(terminal.test);
135 - break;
136 - }
137 - case "for": {
138 - valueBlocks.add(terminal.init);
139 - valueBlocks.add(terminal.test);
140 - valueBlocks.add(terminal.update);
141 - break;
142 - }
129 default: {
130 // no-op
131 }
compiler/forget/yarn.lock
+19 -19
@@ -83,12 +83,12 @@
83 "@jridgewell/gen-mapping" "^0.3.2"
84 jsesc "^2.5.1"
85
86 -"@babel/generator@^7.20.5":
87 - version "7.20.5"
88 - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.20.5.tgz#cb25abee3178adf58d6814b68517c62bdbfdda95"
89 - integrity sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==
86 +"@babel/generator@^7.20.7":
87 + version "7.20.7"
88 + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.20.7.tgz#f8ef57c8242665c5929fe2e8d82ba75460187b4a"
89 + integrity sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==
90 dependencies:
91 - "@babel/types" "^7.20.5"
91 + "@babel/types" "^7.20.7"
92 "@jridgewell/gen-mapping" "^0.3.2"
93 jsesc "^2.5.1"
94
@@ -260,10 +260,10 @@
260 resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.19.3.tgz#8dd36d17c53ff347f9e55c328710321b49479a9a"
261 integrity sha512-pJ9xOlNWHiy9+FuFP09DEAFbAn4JskgRsVcc169w2xRBC3FRGuQEwjeIMMND9L2zc0iEhO/tGv4Zq+km+hxNpQ==
262
263 -"@babel/parser@^7.20.5":
264 - version "7.20.5"
265 - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.5.tgz#7f3c7335fe417665d929f34ae5dceae4c04015e8"
266 - integrity sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==
263 +"@babel/parser@^7.20.7":
264 + version "7.20.7"
265 + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.7.tgz#66fe23b3c8569220817d5feb8b9dcdc95bb4f71b"
266 + integrity sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==
267
268 "@babel/plugin-syntax-async-generators@^7.8.4":
269 version "7.8.4"
@@ -484,18 +484,18 @@
484 lodash "^4.17.10"
485
486 "@babel/traverse@^7.19.1":
487 - version "7.20.5"
488 - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.20.5.tgz#78eb244bea8270fdda1ef9af22a5d5e5b7e57133"
489 - integrity sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==
487 + version "7.20.12"
488 + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.20.12.tgz#7f0f787b3a67ca4475adef1f56cb94f6abd4a4b5"
489 + integrity sha512-MsIbFN0u+raeja38qboyF8TIT7K0BFzz/Yd/77ta4MsUsmP2RAnidIlwq7d5HFQrH/OZJecGV6B71C4zAgpoSQ==
490 dependencies:
491 "@babel/code-frame" "^7.18.6"
492 - "@babel/generator" "^7.20.5"
492 + "@babel/generator" "^7.20.7"
493 "@babel/helper-environment-visitor" "^7.18.9"
494 "@babel/helper-function-name" "^7.19.0"
495 "@babel/helper-hoist-variables" "^7.18.6"
496 "@babel/helper-split-export-declaration" "^7.18.6"
497 - "@babel/parser" "^7.20.5"
498 - "@babel/types" "^7.20.5"
497 + "@babel/parser" "^7.20.7"
498 + "@babel/types" "^7.20.7"
499 debug "^4.1.0"
500 globals "^11.1.0"
501
@@ -534,10 +534,10 @@
534 "@babel/helper-validator-identifier" "^7.19.1"
535 to-fast-properties "^2.0.0"
536
537 -"@babel/types@^7.20.5":
538 - version "7.20.5"
539 - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.5.tgz#e206ae370b5393d94dfd1d04cd687cace53efa84"
540 - integrity sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==
537 +"@babel/types@^7.20.7":
538 + version "7.20.7"
539 + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.7.tgz#54ec75e252318423fc07fb644dc6a58a64c09b7f"
540 + integrity sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==
541 dependencies:
542 "@babel/helper-string-parser" "^7.19.4"
543 "@babel/helper-validator-identifier" "^7.19.1"