Skip to content

Commit 1501466

Browse files
committed
Update on "[compiler] Instruction reordering"
Adds a pass just after DCE to reorder safely reorderable instructions (jsx, primitives, globals) closer to where they are used, to allow other optimization passes to be more effective. Notably, the reordering allows scope merging to be more effective, since that pass relies on two scopes not having intervening instructions — in many cases we can now reorder such instructions out of the way and unlock merging, as demonstrated in the changed fixtures. The algorithm itself is described in the docblock. note: This is a cleaned up version of #29579 that is ready for review. [ghstack-poisoned]
2 parents e9c1bd0 + a04f48e commit 1501466

21 files changed

+310
-262
lines changed

compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ const EnvironmentConfigSchema = z.object({
269269
* Enable instruction reordering. See InstructionReordering.ts for the details
270270
* of the approach.
271271
*/
272-
enableInstructionReordering: z.boolean().default(true),
272+
enableInstructionReordering: z.boolean().default(false),
273273

274274
/*
275275
* Enables instrumentation codegen. This emits a dev-mode only call to an

compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ export function isStatementBlockKind(kind: BlockKind): boolean {
350350
* Returns true for "value", "loop", and "sequence" block kinds which correspond to
351351
* expressions in the source, such as ConditionalExpression, LogicalExpression, loop
352352
* initializer/test/updaters, etc
353-
353+
*
354354
* Inverse of isStatementBlockKind()
355355
*/
356356
export function isExpressionBlockKind(kind: BlockKind): boolean {

compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/align-scopes-within-nested-valueblock-in-array.expect.md

+6-6
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,11 @@ import { Stringify, identity, makeArray, mutate } from "shared-runtime";
5252
* handles this correctly.
5353
*/
5454
function Foo(t0) {
55-
const $ = _c(3);
55+
const $ = _c(4);
5656
const { cond1, cond2 } = t0;
57+
const arr = makeArray({ a: 2 }, 2, []);
5758
let t1;
58-
if ($[0] !== cond1 || $[1] !== cond2) {
59-
const arr = makeArray({ a: 2 }, 2, []);
60-
59+
if ($[0] !== cond1 || $[1] !== cond2 || $[2] !== arr) {
6160
t1 = cond1 ? (
6261
<>
6362
<div>{identity("foo")}</div>
@@ -66,9 +65,10 @@ function Foo(t0) {
6665
) : null;
6766
$[0] = cond1;
6867
$[1] = cond2;
69-
$[2] = t1;
68+
$[2] = arr;
69+
$[3] = t1;
7070
} else {
71-
t1 = $[2];
71+
t1 = $[3];
7272
}
7373
return t1;
7474
}

compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-global-mutation-in-effect-indirect.expect.md

+29-23
Original file line numberDiff line numberDiff line change
@@ -39,51 +39,57 @@ import { useEffect, useState } from "react";
3939
let someGlobal = {};
4040

4141
function Component() {
42-
const $ = _c(6);
42+
const $ = _c(7);
4343
const [state, setState] = useState(someGlobal);
4444
let t0;
45-
let t1;
4645
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
47-
const setGlobal = () => {
46+
t0 = () => {
4847
someGlobal.value = true;
4948
};
50-
51-
t0 = () => {
49+
$[0] = t0;
50+
} else {
51+
t0 = $[0];
52+
}
53+
const setGlobal = t0;
54+
let t1;
55+
let t2;
56+
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
57+
t1 = () => {
5258
setGlobal();
5359
};
54-
t1 = [];
55-
$[0] = t0;
60+
t2 = [];
5661
$[1] = t1;
62+
$[2] = t2;
5763
} else {
58-
t0 = $[0];
5964
t1 = $[1];
65+
t2 = $[2];
6066
}
61-
useEffect(t0, t1);
62-
let t2;
67+
useEffect(t1, t2);
6368
let t3;
64-
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
65-
t2 = () => {
69+
let t4;
70+
if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
71+
t3 = () => {
6672
setState(someGlobal.value);
6773
};
68-
t3 = [someGlobal];
69-
$[2] = t2;
74+
t4 = [someGlobal];
7075
$[3] = t3;
76+
$[4] = t4;
7177
} else {
72-
t2 = $[2];
7378
t3 = $[3];
79+
t4 = $[4];
7480
}
75-
useEffect(t2, t3);
81+
useEffect(t3, t4);
7682

77-
const t4 = String(state);
78-
let t5;
79-
if ($[4] !== t4) {
80-
t5 = <div>{t4}</div>;
81-
$[4] = t4;
83+
const t5 = String(state);
84+
let t6;
85+
if ($[5] !== t5) {
86+
t6 = <div>{t5}</div>;
8287
$[5] = t5;
88+
$[6] = t6;
8389
} else {
84-
t5 = $[5];
90+
t6 = $[6];
8591
}
86-
return t5;
92+
return t6;
8793
}
8894

8995
export const FIXTURE_ENTRYPOINT = {

compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-global-reassignment-in-effect-indirect.expect.md

+29-23
Original file line numberDiff line numberDiff line change
@@ -39,51 +39,57 @@ import { useEffect, useState } from "react";
3939
let someGlobal = false;
4040

4141
function Component() {
42-
const $ = _c(6);
42+
const $ = _c(7);
4343
const [state, setState] = useState(someGlobal);
4444
let t0;
45-
let t1;
4645
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
47-
const setGlobal = () => {
46+
t0 = () => {
4847
someGlobal = true;
4948
};
50-
51-
t0 = () => {
49+
$[0] = t0;
50+
} else {
51+
t0 = $[0];
52+
}
53+
const setGlobal = t0;
54+
let t1;
55+
let t2;
56+
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
57+
t1 = () => {
5258
setGlobal();
5359
};
54-
t1 = [];
55-
$[0] = t0;
60+
t2 = [];
5661
$[1] = t1;
62+
$[2] = t2;
5763
} else {
58-
t0 = $[0];
5964
t1 = $[1];
65+
t2 = $[2];
6066
}
61-
useEffect(t0, t1);
62-
let t2;
67+
useEffect(t1, t2);
6368
let t3;
64-
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
65-
t2 = () => {
69+
let t4;
70+
if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
71+
t3 = () => {
6672
setState(someGlobal);
6773
};
68-
t3 = [someGlobal];
69-
$[2] = t2;
74+
t4 = [someGlobal];
7075
$[3] = t3;
76+
$[4] = t4;
7177
} else {
72-
t2 = $[2];
7378
t3 = $[3];
79+
t4 = $[4];
7480
}
75-
useEffect(t2, t3);
81+
useEffect(t3, t4);
7682

77-
const t4 = String(state);
78-
let t5;
79-
if ($[4] !== t4) {
80-
t5 = <div>{t4}</div>;
81-
$[4] = t4;
83+
const t5 = String(state);
84+
let t6;
85+
if ($[5] !== t5) {
86+
t6 = <div>{t5}</div>;
8287
$[5] = t5;
88+
$[6] = t6;
8389
} else {
84-
t5 = $[5];
90+
t6 = $[6];
8591
}
86-
return t5;
92+
return t6;
8793
}
8894

8995
export const FIXTURE_ENTRYPOINT = {

compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/dont-merge-if-dep-is-inner-declaration-of-previous-scope.expect.md

+14-14
Original file line numberDiff line numberDiff line change
@@ -99,41 +99,41 @@ function Component(t0) {
9999
t2 = $[12];
100100
}
101101
let t3;
102-
if ($[13] !== a || $[14] !== b) {
103-
t3 = [a, b];
104-
$[13] = a;
105-
$[14] = b;
102+
if ($[13] !== t2 || $[14] !== x) {
103+
t3 = <ValidateMemoization inputs={t2} output={x} />;
104+
$[13] = t2;
105+
$[14] = x;
106106
$[15] = t3;
107107
} else {
108108
t3 = $[15];
109109
}
110110
let t4;
111-
if ($[16] !== t2 || $[17] !== x) {
112-
t4 = <ValidateMemoization inputs={t2} output={x} />;
113-
$[16] = t2;
114-
$[17] = x;
111+
if ($[16] !== a || $[17] !== b) {
112+
t4 = [a, b];
113+
$[16] = a;
114+
$[17] = b;
115115
$[18] = t4;
116116
} else {
117117
t4 = $[18];
118118
}
119119
let t5;
120-
if ($[19] !== t3 || $[20] !== z) {
121-
t5 = <ValidateMemoization inputs={t3} output={z} />;
122-
$[19] = t3;
120+
if ($[19] !== t4 || $[20] !== z) {
121+
t5 = <ValidateMemoization inputs={t4} output={z} />;
122+
$[19] = t4;
123123
$[20] = z;
124124
$[21] = t5;
125125
} else {
126126
t5 = $[21];
127127
}
128128
let t6;
129-
if ($[22] !== t4 || $[23] !== t5) {
129+
if ($[22] !== t3 || $[23] !== t5) {
130130
t6 = (
131131
<>
132-
{t4}
132+
{t3}
133133
{t5}
134134
</>
135135
);
136-
$[22] = t4;
136+
$[22] = t3;
137137
$[23] = t5;
138138
$[24] = t6;
139139
} else {

compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-repro-trycatch-nested-overlapping-range.expect.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ function Foo() {
2020
## Error
2121

2222
```
23-
Invariant: Invalid nesting in program blocks or scopes. Items overlap but are not nested: 2:23(17:25)
23+
Invariant: Invalid nesting in program blocks or scopes. Items overlap but are not nested: 2:24(18:26)
2424
```
2525
2626

compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.repro-bug-ref-mutable-range.expect.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ function Foo(props, ref) {
2121
## Error
2222

2323
```
24-
Invariant: Invalid nesting in program blocks or scopes. Items overlap but are not nested: 1:20(16:23)
24+
Invariant: Invalid nesting in program blocks or scopes. Items overlap but are not nested: 1:21(16:23)
2525
```
2626
2727

compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-reactive-scope-overlaps-try.expect.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export const FIXTURE_ENTRYPOINT = {
3030
## Error
3131

3232
```
33-
Invariant: Invalid nesting in program blocks or scopes. Items overlap but are not nested: 3:17(4:20)
33+
Invariant: Invalid nesting in program blocks or scopes. Items overlap but are not nested: 4:19(5:22)
3434
```
3535
3636

compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbtparam-with-jsx-element-content.expect.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ function Component(t0) {
3232
const $ = _c(4);
3333
const { name, data, icon } = t0;
3434
let t1;
35-
if ($[0] !== name || $[1] !== data || $[2] !== icon) {
35+
if ($[0] !== name || $[1] !== icon || $[2] !== data) {
3636
t1 = (
3737
<Text type="body4">
3838
{fbt._(
@@ -62,8 +62,8 @@ function Component(t0) {
6262
</Text>
6363
);
6464
$[0] = name;
65-
$[1] = data;
66-
$[2] = icon;
65+
$[1] = icon;
66+
$[2] = data;
6767
$[3] = t1;
6868
} else {
6969
t1 = $[3];

compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/lambda-with-fbt.expect.md

+13-7
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,10 @@ import { c as _c } from "react/compiler-runtime";
4242
import { fbt } from "fbt";
4343

4444
function Component() {
45-
const $ = _c(1);
45+
const $ = _c(2);
4646
let t0;
4747
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
48-
const buttonLabel = () => {
48+
t0 = () => {
4949
if (!someCondition) {
5050
return fbt._("Purchase as a gift", null, { hk: "1gHj4g" });
5151
} else {
@@ -66,17 +66,23 @@ function Component() {
6666
}
6767
}
6868
};
69-
70-
t0 = (
69+
$[0] = t0;
70+
} else {
71+
t0 = $[0];
72+
}
73+
const buttonLabel = t0;
74+
let t1;
75+
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
76+
t1 = (
7177
<View>
7278
<Button text={buttonLabel()} />
7379
</View>
7480
);
75-
$[0] = t0;
81+
$[1] = t1;
7682
} else {
77-
t0 = $[0];
83+
t1 = $[1];
7884
}
79-
return t0;
85+
return t1;
8086
}
8187

8288
```

0 commit comments

Comments
 (0)