Fix previous examples, alias across phis
Within the InferMutableRanges fixpoint iteration, we need to alias phi operands with the phi id if the phi id is later mutated.
Joe Savona committed
Feb 21, 2023 at 15:29 UTC
9a25b5a12aa3b8c4874f31c53ce614f7eb039dfe
5 files changed
+30
-38
compiler/forget/src/Inference/InferMutableRanges.ts
+2
-2
@@ -24,7 +24,7 @@ export function inferMutableRanges(ir: HIRFunction) {
24
do {
25
size = aliases.size;
26
// Infer mutable ranges for aliases that are not fields
27
- inferMutableRangesForAlias(aliases);
27
+ inferMutableRangesForAlias(ir, aliases);
28
29
// Update aliasing information of fields
30
inferAliasForStores(ir, aliases);
@@ -34,5 +34,5 @@ export function inferMutableRanges(ir: HIRFunction) {
34
inferMutableLifetimes(ir, true);
35
36
// Re-infer mutable ranges for aliases
37
- inferMutableRangesForAlias(aliases);
37
+ inferMutableRangesForAlias(ir, aliases);
38
}
compiler/forget/src/Inference/InferMutableRangesForAlias.ts
+18
-2
@@ -1,7 +1,23 @@
1
+import { HIRFunction, Identifier, InstructionId } from "../HIR/HIR";
2
import DisjointSet from "../Utils/DisjointSet";
2
-import { Identifier, InstructionId } from "../HIR/HIR";
3
4
-export function inferMutableRangesForAlias(aliases: DisjointSet<Identifier>) {
4
+export function inferMutableRangesForAlias(
5
+ fn: HIRFunction,
6
+ aliases: DisjointSet<Identifier>
7
+) {
8
+ for (const [_, block] of fn.body.blocks) {
9
+ for (const phi of block.phis) {
10
+ const isPhiMutatedAfterCreation: boolean =
11
+ phi.id.mutableRange.end >
12
+ (block.instructions.at(0)?.id ?? block.terminal.id);
13
+ if (isPhiMutatedAfterCreation) {
14
+ for (const [, operand] of phi.operands) {
15
+ aliases.union([phi.id, operand]);
16
+ }
17
+ }
18
+ }
19
+ }
20
+
21
const aliasSets = aliases.buildSets();
22
for (const aliasSet of aliasSets) {
23
// Update mutableRange.end only if the identifiers have actually been
compiler/forget/src/__tests__/fixtures/hir/obj-mutated-after-if-else-with-alias.expect.md
+2
-8
@@ -22,19 +22,13 @@ function foo(a, b, c, d) {
22
23
```javascript
24
function foo(a, b, c, d) {
25
- const $ = React.unstable_useMemoCache(3);
25
+ const $ = React.unstable_useMemoCache(2);
26
const c_0 = $[0] !== a;
27
let x;
28
if (c_0) {
29
x = someObj();
30
if (a) {
31
- let y;
32
- if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
33
- y = someObj();
34
- $[2] = y;
35
- } else {
36
- y = $[2];
37
- }
31
+ const y = someObj();
32
const z = y;
33
x = z;
34
} else {
compiler/forget/src/__tests__/fixtures/hir/obj-mutated-after-nested-if-else-with-alias.expect.md
+3
-14
@@ -28,7 +28,7 @@ function foo(a, b, c, d) {
28
29
```javascript
30
function foo(a, b, c, d) {
31
- const $ = React.unstable_useMemoCache(5);
31
+ const $ = React.unstable_useMemoCache(3);
32
const c_0 = $[0] !== a;
33
const c_1 = $[1] !== b;
34
let x;
@@ -37,21 +37,10 @@ function foo(a, b, c, d) {
37
if (a) {
38
let z = undefined;
39
if (b) {
40
- let w;
41
- if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
42
- w = someObj();
43
- $[3] = w;
44
- } else {
45
- w = $[3];
46
- }
40
+ const w = someObj();
41
z = w;
42
} else {
49
- if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
50
- z = someObj();
51
- $[4] = z;
52
- } else {
53
- z = $[4];
54
- }
43
+ z = someObj();
44
}
45
46
x = z;
compiler/forget/src/__tests__/fixtures/hir/sequence-expression.expect.md
+5
-12
@@ -18,25 +18,18 @@ function foo() {}
18
19
```javascript
20
function sequence(props) {
21
- const $ = React.unstable_useMemoCache(2);
21
+ const $ = React.unstable_useMemoCache(1);
22
Math.max(1, 2);
23
- let t0;
24
- if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
25
- t0 = foo();
26
- $[0] = t0;
27
- } else {
28
- t0 = $[0];
29
- }
23
let x;
31
- if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
32
- x = t0;
24
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
25
+ x = foo();
26
while ((foo(), true)) {
27
foo();
28
x = 2;
29
}
37
- $[1] = x;
30
+ $[0] = x;
31
} else {
39
- x = $[1];
32
+ x = $[0];
33
}
34
return x;
35
}