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

[hir] Generalize alias analysis for Effect.Store

Rather than special casing for field stores, look for Effect.Store to alias fields. In the future, this will be extended to other constructs like Array#push.

Sathya Gunasekaran committed Dec 21, 2022 at 12:04 UTC 538883935787ec70273995adf962696d1d742ab2
4 files changed +33 -28
compiler/forget/src/HIR/InferAliasForStores.ts renamed
+9 -16
@@ -4,33 +4,26 @@
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7 +import invariant from "invariant";
8 import DisjointSet from "../Utils/DisjointSet";
8 -import { HIRFunction, Identifier } from "./HIR";
9 +import { Effect, HIRFunction, Identifier } from "./HIR";
10
10 -export function inferAliasForFields(
11 +export function inferAliasForStores(
12 func: HIRFunction,
13 aliases: DisjointSet<Identifier>
14 ) {
15 for (const [_, block] of func.body.blocks) {
16 for (const instr of block.instructions) {
16 - let { lvalue, value } = instr;
17 -
18 - // Not an aliasing instruction.
19 - if (value.kind !== "Identifier") {
20 - continue;
21 - }
22 -
23 - // No lvalue, no aliasing.
24 - if (lvalue === null) {
17 + const { value, lvalue } = instr;
18 + if (lvalue === null || lvalue.place.effect !== Effect.Store) {
19 continue;
20 }
21
28 - // No field aliasing.
29 - if (lvalue.place.memberPath === null) {
30 - continue;
31 - }
22 + invariant(
23 + value.kind === "Identifier",
24 + "only identifiers can be aliased by stores"
25 + );
26
33 - // lvalue or value get mutated later, so this aliasing is observable.
27 if (
28 lvalue.place.identifier.mutableRange.end > instr.id ||
29 value.identifier.mutableRange.end > instr.id
compiler/forget/src/HIR/InferMutableLifetimes.ts
+18 -6
@@ -60,7 +60,15 @@ import { eachInstructionOperand } from "./visitors";
60 * ```
61 */
62
63 -function inferPlace(place: Place, instr: Instruction) {
63 +function infer(place: Place, instr: Instruction) {
64 + place.identifier.mutableRange.end = makeInstructionId(instr.id + 1);
65 +}
66 +
67 +function inferPlace(
68 + place: Place,
69 + instr: Instruction,
70 + inferMutableRangeForStores: boolean
71 +) {
72 switch (place.effect) {
73 case Effect.Unknown: {
74 throw new Error(
@@ -73,8 +81,12 @@ function inferPlace(place: Place, instr: Instruction) {
81 case Effect.Freeze:
82 return;
83 case Effect.Store:
84 + if (inferMutableRangeForStores) {
85 + infer(place, instr);
86 + }
87 + return;
88 case Effect.Mutate: {
77 - place.identifier.mutableRange.end = makeInstructionId(instr.id + 1);
89 + infer(place, instr);
90 return;
91 }
92 default:
@@ -84,7 +96,7 @@ function inferPlace(place: Place, instr: Instruction) {
96
97 export function inferMutableLifetimes(
98 func: HIRFunction,
87 - inferMutableRangeForFields: boolean
99 + inferMutableRangeForStores: boolean
100 ) {
101 for (const [_, block] of func.body.blocks) {
102 for (const phi of block.phis) {
@@ -106,7 +118,7 @@ export function inferMutableLifetimes(
118
119 for (const instr of block.instructions) {
120 for (const input of eachInstructionOperand(instr)) {
109 - inferPlace(input, instr);
121 + inferPlace(input, instr, inferMutableRangeForStores);
122 }
123
124 if (instr.lvalue !== null) {
@@ -120,8 +132,8 @@ export function inferMutableLifetimes(
132 // Let's be optimistic and assume this lvalue is not mutable by
133 // default.
134 lvalueId.mutableRange.end = makeInstructionId(instr.id + 1);
123 - } else if (inferMutableRangeForFields) {
124 - inferPlace(instr.lvalue.place, instr);
135 + } else {
136 + inferPlace(instr.lvalue.place, instr, inferMutableRangeForStores);
137 }
138 }
139 }
compiler/forget/src/HIR/InferMutableRanges.ts
+2 -2
@@ -1,6 +1,6 @@
1 import { HIRFunction } from "./HIR";
2 import { inferAliases } from "./InferAlias";
3 -import { inferAliasForFields } from "./InferAliasForFields";
3 +import { inferAliasForStores } from "./InferAliasForStores";
4 import { inferMutableLifetimes } from "./InferMutableLifetimes";
5 import { inferMutableRangesForAlias } from "./InferMutableRangesForAlias";
6
@@ -17,7 +17,7 @@ export function inferMutableRanges(ir: HIRFunction) {
17 inferMutableRangesForAlias(aliases);
18
19 // Update aliasing information of fields
20 - inferAliasForFields(ir, aliases);
20 + inferAliasForStores(ir, aliases);
21 } while (aliases.size > size);
22
23 // Re-infer mutable ranges for all values
compiler/forget/src/__tests__/fixtures/hir/assignment-variations.expect.md
+4 -4
@@ -63,8 +63,8 @@ function f$0() {
63 ```
64 bb0:
65 [1] Const mutate $6:TPrimitive = 1
66 - [2] Const mutate $7:TPrimitive = Binary read a$5_@0.b.c + read $6:TPrimitive
67 - [3] Reassign store a$5_@0.b.c[0:6] = read $7:TPrimitive
66 + [2] Const mutate $7_@0:TPrimitive[0:6] = Binary read a$5_@0.b.c + read $6:TPrimitive
67 + [3] Reassign store a$5_@0.b.c[0:6] = read $7_@0:TPrimitive
68 [4] Const mutate $8:TPrimitive = 2
69 [5] Reassign mutate a$5_@0.b.c[0:6] = Binary read a$5_@0.b.c * read $8:TPrimitive
70 [6] Return
@@ -77,8 +77,8 @@ function g(
77 a,
78 ) {
79 [1] Const mutate $6:TPrimitive = 1
80 - [2] Const mutate $7:TPrimitive = Binary read a$5_@0.b.c + read $6:TPrimitive
81 - [3] Reassign store a$5_@0.b.c[0:6] = read $7:TPrimitive
80 + [2] Const mutate $7_@0:TPrimitive[0:6] = Binary read a$5_@0.b.c + read $6:TPrimitive
81 + [3] Reassign store a$5_@0.b.c[0:6] = read $7_@0:TPrimitive
82 [4] Const mutate $8:TPrimitive = 2
83 [5] Reassign mutate a$5_@0.b.c[0:6] = Binary read a$5_@0.b.c * read $8:TPrimitive
84 return