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

Make LValue non-nullable in HIR

Joe Savona committed Jan 4, 2023 at 09:51 UTC e4642326d3d8c27ff0639412ffd953b7606cde18
20 files changed +74 -98
compiler/forget/src/HIR/BuildHIR.ts
+11 -2
@@ -697,7 +697,13 @@ function lowerStatement(
697 case "WithStatement": {
698 builder.push({
699 id: makeInstructionId(0),
700 - lvalue: null,
700 + lvalue: {
701 + place: buildTemporaryPlace(
702 + builder,
703 + stmtPath.node.loc ?? GeneratedSource
704 + ),
705 + kind: InstructionKind.Const,
706 + },
707 loc: stmtPath.node.loc ?? GeneratedSource,
708 value: {
709 kind: "OtherStatement",
@@ -1330,7 +1336,10 @@ function lowerExpressionToVoid(
1336 id: makeInstructionId(0),
1337 value: instr,
1338 loc: exprLoc,
1333 - lvalue: null,
1339 + lvalue: {
1340 + place: buildTemporaryPlace(builder, exprLoc),
1341 + kind: InstructionKind.Const,
1342 + },
1343 });
1344 }
1345
compiler/forget/src/HIR/Codegen.ts
+2 -1
@@ -21,6 +21,7 @@ import {
21 InstructionValue,
22 LValue,
23 Place,
24 + ReactiveInstruction,
25 SourceLocation,
26 } from "./HIR";
27 import { BlockTerminal, Visitor, visitTree } from "./HIRTreeVisitor";
@@ -293,7 +294,7 @@ export function codegenLabel(id: BlockId): string {
294
295 export function codegenInstruction(
296 temp: Temporaries,
296 - instr: Instruction,
297 + instr: ReactiveInstruction,
298 value: t.Expression
299 ): t.Statement {
300 if (t.isStatement(value)) {
compiler/forget/src/HIR/HIR.ts
+9 -2
@@ -65,10 +65,17 @@ export type ReactiveValueBlock = {
65 };
66
67 export type ReactiveStatement =
68 - | { kind: "instruction"; instruction: Instruction }
68 + | { kind: "instruction"; instruction: ReactiveInstruction }
69 | { kind: "terminal"; terminal: ReactiveTerminal; label: BlockId | null }
70 | ReactiveScopeBlock;
71
72 +export type ReactiveInstruction = {
73 + id: InstructionId;
74 + lvalue: LValue | null;
75 + value: InstructionValue;
76 + loc: SourceLocation;
77 +};
78 +
79 export type ReactiveTerminal =
80 | { kind: "break"; label: BlockId | null }
81 | { kind: "continue"; label: BlockId | null }
@@ -225,7 +232,7 @@ export type ForTerminal = {
232 */
233 export type Instruction = {
234 id: InstructionId;
228 - lvalue: LValue | null;
235 + lvalue: LValue;
236 value: InstructionValue;
237 loc: SourceLocation;
238 };
compiler/forget/src/HIR/HIRTreeVisitor.ts
-8
@@ -497,14 +497,6 @@ class Driver<
497 let lastValue: { value: InstructionValue; id: InstructionId } | null = null;
498 if (terminalValue != null) {
499 lastValue = terminalValue;
500 - } else {
501 - if (
502 - instructions.length &&
503 - instructions[instructions.length - 1].lvalue === null
504 - ) {
505 - const last = instructions.pop()!;
506 - lastValue = { value: last.value, id: last.id };
507 - }
500 }
501 for (const instr of instructions) {
502 const value = this.visitor.visitValue(instr.value, instr.id);
compiler/forget/src/HIR/InferAlias.ts
-4
@@ -38,9 +38,5 @@ function inferInstr(instr: Instruction, state: AliasAnalyser) {
38 return;
39 }
40
41 - if (lvalue === null) {
42 - return;
43 - }
44 -
41 state.alias(lvalue, alias);
42 }
compiler/forget/src/HIR/InferAliasForStores.ts
+1 -1
@@ -14,7 +14,7 @@ export function inferAliasForStores(
14 for (const [_, block] of func.body.blocks) {
15 for (const instr of block.instructions) {
16 const { value, lvalue } = instr;
17 - if (lvalue === null || lvalue.place.effect !== Effect.Store) {
17 + if (lvalue.place.effect !== Effect.Store) {
18 continue;
19 }
20 switch (value.kind) {
compiler/forget/src/HIR/InferMutableLifetimes.ts
+7 -9
@@ -121,17 +121,15 @@ export function inferMutableLifetimes(
121 inferPlace(input, instr, inferMutableRangeForStores);
122 }
123
124 - if (instr.lvalue !== null) {
125 - const lvalueId = instr.lvalue.place.identifier;
124 + const lvalueId = instr.lvalue.place.identifier;
125
127 - // lvalue start being mutable when they're initially assigned a
128 - // value.
129 - lvalueId.mutableRange.start = instr.id;
126 + // lvalue start being mutable when they're initially assigned a
127 + // value.
128 + lvalueId.mutableRange.start = instr.id;
129
131 - // Let's be optimistic and assume this lvalue is not mutable by
132 - // default.
133 - lvalueId.mutableRange.end = makeInstructionId(instr.id + 1);
134 - }
130 + // Let's be optimistic and assume this lvalue is not mutable by
131 + // default.
132 + lvalueId.mutableRange.end = makeInstructionId(instr.id + 1);
133 }
134 }
135 }
compiler/forget/src/HIR/InferReferenceEffects.ts
+13 -25
@@ -581,10 +581,8 @@ function inferBlock(env: Environment, block: BasicBlock) {
581 env.reference(instrValue.object, effect);
582
583 const lvalue = instr.lvalue;
584 - if (lvalue !== null) {
585 - env.alias(lvalue.place, instrValue.value);
586 - lvalue.place.effect = Effect.Store;
587 - }
584 + env.alias(lvalue.place, instrValue.value);
585 + lvalue.place.effect = Effect.Store;
586 continue;
587 }
588 case "PropertyLoad": {
@@ -601,10 +599,8 @@ function inferBlock(env: Environment, block: BasicBlock) {
599
600 env.reference(instrValue.object, Effect.Read);
601 const lvalue = instr.lvalue;
604 - if (lvalue !== null) {
605 - env.initialize(instrValue, env.kind(instrValue.object));
606 - env.define(lvalue.place, instrValue);
607 - }
602 + env.initialize(instrValue, env.kind(instrValue.object));
603 + env.define(lvalue.place, instrValue);
604 continue;
605 }
606 case "ComputedStore": {
@@ -616,10 +612,8 @@ function inferBlock(env: Environment, block: BasicBlock) {
612 env.reference(instrValue.object, effect);
613
614 const lvalue = instr.lvalue;
619 - if (lvalue !== null) {
620 - env.alias(lvalue.place, instrValue.value);
621 - lvalue.place.effect = Effect.Store;
622 - }
615 + env.alias(lvalue.place, instrValue.value);
616 + lvalue.place.effect = Effect.Store;
617 continue;
618 }
619 case "ComputedLoad": {
@@ -637,20 +631,16 @@ function inferBlock(env: Environment, block: BasicBlock) {
631 env.reference(instrValue.object, Effect.Read);
632 env.reference(instrValue.property, Effect.Read);
633 const lvalue = instr.lvalue;
640 - if (lvalue !== null) {
641 - env.initialize(instrValue, env.kind(instrValue.object));
642 - env.define(lvalue.place, instrValue);
643 - }
634 + env.initialize(instrValue, env.kind(instrValue.object));
635 + env.define(lvalue.place, instrValue);
636 continue;
637 }
638 case "Identifier": {
639 env.reference(instrValue, Effect.Read);
640 const lvalue = instr.lvalue;
649 - if (lvalue !== null) {
650 - lvalue.place.effect = Effect.Mutate;
651 - // direct aliasing: `a = b`;
652 - env.alias(lvalue.place, instrValue);
653 - }
641 + lvalue.place.effect = Effect.Mutate;
642 + // direct aliasing: `a = b`;
643 + env.alias(lvalue.place, instrValue);
644 continue;
645 }
646 default: {
@@ -668,10 +658,8 @@ function inferBlock(env: Environment, block: BasicBlock) {
658 }
659
660 env.initialize(instrValue, valueKind);
671 - if (instr.lvalue !== null) {
672 - env.define(instr.lvalue.place, instrValue);
673 - instr.lvalue.place.effect = lvalueEffect;
674 - }
661 + env.define(instr.lvalue.place, instrValue);
662 + instr.lvalue.place.effect = lvalueEffect;
663 }
664
665 const effect =
compiler/forget/src/HIR/InferTypes.ts
+1 -5
@@ -55,11 +55,7 @@ function apply(func: HIRFunction, unifier: Unifier) {
55 place.identifier.type = unifier.get(place.identifier.type);
56 }
57 const { lvalue } = instr;
58 - if (lvalue !== null) {
59 - lvalue.place.identifier.type = unifier.get(
60 - lvalue.place.identifier.type
61 - );
62 - }
58 + lvalue.place.identifier.type = unifier.get(lvalue.place.identifier.type);
59 }
60 }
61 }
compiler/forget/src/HIR/PrintHIR.ts
+2 -1
@@ -20,6 +20,7 @@ import {
20 MutableRange,
21 Phi,
22 Place,
23 + ReactiveInstruction,
24 ReactiveScope,
25 SourceLocation,
26 Terminal,
@@ -96,7 +97,7 @@ export function printMixedHIR(
97 }
98 }
99
99 -export function printInstruction(instr: Instruction): string {
100 +export function printInstruction(instr: ReactiveInstruction): string {
101 const id = `[${instr.id}]`;
102 const value = printInstructionValue(instr.value);
103
compiler/forget/src/ReactiveScopes/BuildReactiveFunction.ts
-2
@@ -301,9 +301,7 @@ class ReactiveFunctionBuilder
301 }
302
303 function getInstructionScope(instr: Instruction): ReactiveScope | null {
304 - let scope: ReactiveScope | null = null;
304 if (
306 - instr.lvalue !== null &&
305 instr.lvalue.place.identifier.scope !== null &&
306 isScopeActive(instr.lvalue.place.identifier.scope, instr.id)
307 ) {
compiler/forget/src/ReactiveScopes/CodegenReactiveFunction.ts
+2 -2
@@ -18,10 +18,10 @@ import {
18 } from "../HIR/Codegen";
19 import {
20 Identifier,
21 - Instruction,
21 InstructionKind,
22 ReactiveBlock,
23 ReactiveFunction,
24 + ReactiveInstruction,
25 ReactiveScope,
26 ReactiveScopeDependency,
27 ReactiveTerminal,
@@ -301,7 +301,7 @@ function codegenTerminal(cx: Context, terminal: ReactiveTerminal): t.Statement {
301
302 export function codegenInstructionNullable(
303 cx: Context,
304 - instr: Instruction,
304 + instr: ReactiveInstruction,
305 value: t.Expression
306 ): t.Statement | null {
307 let statement;
compiler/forget/src/ReactiveScopes/InferReactiveScopeVariables.ts
+3 -5
@@ -78,11 +78,9 @@ export function inferReactiveScopeVariables(fn: HIRFunction) {
78
79 for (const instr of block.instructions) {
80 const operands: Array<Identifier> = [];
81 - if (instr.lvalue !== null) {
82 - const range = instr.lvalue.place.identifier.mutableRange;
83 - if (range.end > range.start + 1 || mayAllocate(instr.value)) {
84 - operands.push(instr.lvalue!.place.identifier);
85 - }
81 + const range = instr.lvalue.place.identifier.mutableRange;
82 + if (range.end > range.start + 1 || mayAllocate(instr.value)) {
83 + operands.push(instr.lvalue!.place.identifier);
84 }
85 for (const operand of eachInstructionOperand(instr)) {
86 if (
compiler/forget/src/ReactiveScopes/InferReactiveScopes.ts
-2
@@ -286,7 +286,6 @@ class MergeOverlappingReactiveScopesVisitor
286 visitInstruction(instruction: Instruction, value: void): void {
287 this.visitId(instruction.id);
288 if (
289 - instruction.lvalue !== null &&
289 instruction.lvalue.place.identifier.scope !== null &&
290 instruction.id >= instruction.lvalue.place.identifier.scope.range.start &&
291 instruction.id < instruction.lvalue.place.identifier.scope.range.end
@@ -443,7 +442,6 @@ class AlignReactiveScopesToBlockScopeRangeVisitor
442
443 function getInstructionScope(instr: Instruction): ReactiveScope | null {
444 if (
446 - instr.lvalue !== null &&
445 instr.lvalue.place.identifier.scope !== null &&
446 isActive(instr, instr.lvalue.place.identifier.scope.range)
447 ) {
compiler/forget/src/ReactiveScopes/PropagateScopeDependencies.ts
+2 -2
@@ -7,7 +7,6 @@
7
8 import {
9 Identifier,
10 - Instruction,
10 InstructionId,
11 InstructionKind,
12 InstructionValue,
@@ -16,6 +15,7 @@ import {
15 Place,
16 ReactiveBlock,
17 ReactiveFunction,
18 + ReactiveInstruction,
19 ReactiveScope,
20 ReactiveScopeDependency,
21 ReactiveValueBlock,
@@ -280,7 +280,7 @@ function visitInstructionValue(
280 }
281 }
282
283 -function visitInstruction(context: Context, instr: Instruction): void {
283 +function visitInstruction(context: Context, instr: ReactiveInstruction): void {
284 const { lvalue } = instr;
285 visitInstructionValue(context, instr.value, lvalue);
286 if (lvalue !== null && lvalue.kind !== InstructionKind.Reassign) {
compiler/forget/src/ReactiveScopes/PruneTemporaryLValues.ts
+2 -2
@@ -7,9 +7,9 @@
7
8 import {
9 Identifier,
10 - Instruction,
10 InstructionKind,
11 ReactiveFunction,
12 + ReactiveInstruction,
13 } from "../HIR/HIR";
14 import { visitFunction } from "./visitors";
15
@@ -18,7 +18,7 @@ import { visitFunction } from "./visitors";
18 * nulls out the lvalue itself, it does not remove the corresponding instructions.
19 */
20 export function pruneTemporaryLValues(fn: ReactiveFunction): void {
21 - const lvalues = new Map<Identifier, Instruction>();
21 + const lvalues = new Map<Identifier, ReactiveInstruction>();
22 visitFunction(fn, {
23 visitInstruction: (instr) => {
24 if (
compiler/forget/src/ReactiveScopes/RenameVariables.ts
+4 -5
@@ -13,10 +13,7 @@ import {
13 ReactiveTerminal,
14 ReactiveValueBlock,
15 } from "../HIR/HIR";
16 -import {
17 - eachInstructionOperand,
18 - eachInstructionValueOperand,
19 -} from "../HIR/visitors";
16 +import { eachInstructionValueOperand } from "../HIR/visitors";
17 import { invariant } from "../Utils/CompilerError";
18 import { assertExhaustive } from "../Utils/utils";
19
@@ -49,7 +46,9 @@ function visitBlockInner(scopes: Scopes, block: ReactiveBlock): void {
46 for (const stmt of block) {
47 switch (stmt.kind) {
48 case "instruction": {
52 - for (const operand of eachInstructionOperand(stmt.instruction)) {
49 + for (const operand of eachInstructionValueOperand(
50 + stmt.instruction.value
51 + )) {
52 scopes.visit(operand.identifier);
53 }
54 if (stmt.instruction.lvalue !== null) {
compiler/forget/src/ReactiveScopes/visitors.ts
+2 -2
@@ -6,11 +6,11 @@
6 */
7
8 import {
9 - Instruction,
9 InstructionValue,
10 Place,
11 ReactiveBlock,
12 ReactiveFunction,
13 + ReactiveInstruction,
14 ReactiveScope,
15 ReactiveTerminal,
16 ReactiveValueBlock,
@@ -22,7 +22,7 @@ export function visitFunction(
22 fn: ReactiveFunction,
23 visitors: {
24 visitValue?: (value: InstructionValue) => void;
25 - visitInstruction?: (instr: Instruction) => void;
25 + visitInstruction?: (instr: ReactiveInstruction) => void;
26 visitTerminal?: (terminal: ReactiveTerminal) => void;
27 visitScope?: (scope: ReactiveScope) => void;
28 }
compiler/forget/src/SSA/EliminateRedundantPhi.ts
+1 -4
@@ -82,10 +82,7 @@ export function eliminateRedundantPhi(fn: HIRFunction) {
82 for (const place of eachInstructionOperand(instr)) {
83 rewritePlace(place, rewrites);
84 }
85 - const { lvalue } = instr;
86 - if (lvalue !== null) {
87 - rewritePlace(lvalue.place, rewrites);
88 - }
85 + rewritePlace(instr.lvalue.place, rewrites);
86 }
87
88 // Rewrite all terminal operands
compiler/forget/src/SSA/LeaveSSA.ts
+12 -14
@@ -281,21 +281,19 @@ export function leaveSSA(fn: HIRFunction) {
281 // SSA variables to `const` where possible
282 for (const instr of block.instructions) {
283 const { lvalue } = instr;
284 - if (lvalue !== null) {
285 - if (
286 - lvalue.kind === InstructionKind.Const &&
287 - rewrites.has(lvalue.place.identifier)
288 - ) {
289 - // For rewrites, the declaration of the canonical identifier has to be `let`,
290 - // all other assignments are reassignments (which we annotate for codegen
291 - // purposes).
292 - lvalue.kind =
293 - rewrites.get(lvalue.place.identifier) === lvalue.place.identifier
294 - ? InstructionKind.Let
295 - : InstructionKind.Reassign;
296 - }
297 - rewritePlace(lvalue.place, rewrites);
284 + if (
285 + lvalue.kind === InstructionKind.Const &&
286 + rewrites.has(lvalue.place.identifier)
287 + ) {
288 + // For rewrites, the declaration of the canonical identifier has to be `let`,
289 + // all other assignments are reassignments (which we annotate for codegen
290 + // purposes).
291 + lvalue.kind =
292 + rewrites.get(lvalue.place.identifier) === lvalue.place.identifier
293 + ? InstructionKind.Let
294 + : InstructionKind.Reassign;
295 }
296 + rewritePlace(lvalue.place, rewrites);
297 for (const operand of eachInstructionValueOperand(instr.value)) {
298 rewritePlace(operand, rewrites);
299 }