@samitouri / QOS-React-1 / commits / c2b45ef0dd

feat(compiler): Implement constant folding for more binary expressions (#29650)

## Summary There are already most arithmetic operators in constant propagation: `+`, `-`, `*`, `/`. We could add more, namely: `|`, `&`, `^`, `<<`, `>>`, `>>>` and `%`: Input: ```js function f() { return [ 123.45 | 0, 123.45 & 0, 123.45 ^ 0, 123 << 0, 123 >> 0, 123 >>> 0, 123.45 | 1, 123.45 & 1, 123.45 ^ 1, 123 << 1, 123 >> 1, 123 >>> 1, 3 ** 2, 3 ** 2.5, 3.5 ** 2, 2 ** 3 ** 0.5, 4 % 2, 4 % 2.5, 4 % 3, 4.5 % 2, ]; } ``` Output: ```js function f() { return [ 123, 0, 123, 123, 123, 123, 123, 1, 122, 246, 61, 61, 9, 15.588457268119896, 12.25, 3.3219970854839125, 0, 1.5, 1, 0.5, ]; } ``` Resolves #29649 ## How did you test this change? See tests. Note: This PR was done without waiting for approval in #29649, so feel free to just close it without any comment.

Niklas Mollenhauer committed May 29, 2024 at 19:35 UTC c2b45ef0dd06a67365444cdef904701a863e5051
4 files changed +167 -4
compiler/packages/babel-plugin-react-compiler/src/Optimization/ConstantPropagation.ts
+52
@@ -369,6 +369,58 @@ function evaluateInstruction(
369 }
370 break;
371 }
372 + case "|": {
373 + if (typeof lhs === "number" && typeof rhs === "number") {
374 + result = { kind: "Primitive", value: lhs | rhs, loc: value.loc };
375 + }
376 + break;
377 + }
378 + case "&": {
379 + if (typeof lhs === "number" && typeof rhs === "number") {
380 + result = { kind: "Primitive", value: lhs & rhs, loc: value.loc };
381 + }
382 + break;
383 + }
384 + case "^": {
385 + if (typeof lhs === "number" && typeof rhs === "number") {
386 + result = { kind: "Primitive", value: lhs ^ rhs, loc: value.loc };
387 + }
388 + break;
389 + }
390 + case "<<": {
391 + if (typeof lhs === "number" && typeof rhs === "number") {
392 + result = { kind: "Primitive", value: lhs << rhs, loc: value.loc };
393 + }
394 + break;
395 + }
396 + case ">>": {
397 + if (typeof lhs === "number" && typeof rhs === "number") {
398 + result = { kind: "Primitive", value: lhs >> rhs, loc: value.loc };
399 + }
400 + break;
401 + }
402 + case ">>>": {
403 + if (typeof lhs === "number" && typeof rhs === "number") {
404 + result = {
405 + kind: "Primitive",
406 + value: lhs >>> rhs,
407 + loc: value.loc,
408 + };
409 + }
410 + break;
411 + }
412 + case "%": {
413 + if (typeof lhs === "number" && typeof rhs === "number") {
414 + result = { kind: "Primitive", value: lhs % rhs, loc: value.loc };
415 + }
416 + break;
417 + }
418 + case "**": {
419 + if (typeof lhs === "number" && typeof rhs === "number") {
420 + result = { kind: "Primitive", value: lhs ** rhs, loc: value.loc };
421 + }
422 + break;
423 + }
424 case "<": {
425 if (typeof lhs === "number" && typeof rhs === "number") {
426 result = { kind: "Primitive", value: lhs < rhs, loc: value.loc };
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/assignment-variations.expect.md
+1 -4
@@ -22,10 +22,7 @@ export const FIXTURE_ENTRYPOINT = {
22
23 ```javascript
24 function f() {
25 - let x;
26 -
27 - x = 3 >>> 1;
28 - return x;
25 + return 1;
26 }
27
28 export const FIXTURE_ENTRYPOINT = {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/constant-propagation-bit-ops.expect.md new
+78
@@ -0,0 +1,78 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +import { Stringify } from "shared-runtime";
6 +
7 +function foo() {
8 + return (
9 + <Stringify
10 + value={[
11 + 123.45 | 0,
12 + 123.45 & 0,
13 + 123.45 ^ 0,
14 + 123 << 0,
15 + 123 >> 0,
16 + 123 >>> 0,
17 + 123.45 | 1,
18 + 123.45 & 1,
19 + 123.45 ^ 1,
20 + 123 << 1,
21 + 123 >> 1,
22 + 123 >>> 1,
23 + 3 ** 2,
24 + 3 ** 2.5,
25 + 3.5 ** 2,
26 + 2 ** (3 ** 0.5),
27 + 4 % 2,
28 + 4 % 2.5,
29 + 4 % 3,
30 + 4.5 % 2,
31 + ]}
32 + />
33 + );
34 +}
35 +
36 +export const FIXTURE_ENTRYPOINT = {
37 + fn: foo,
38 + params: [],
39 + isComponent: false,
40 +};
41 +
42 +```
43 +
44 +## Code
45 +
46 +```javascript
47 +import { c as _c } from "react/compiler-runtime";
48 +import { Stringify } from "shared-runtime";
49 +
50 +function foo() {
51 + const $ = _c(1);
52 + let t0;
53 + if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
54 + t0 = (
55 + <Stringify
56 + value={[
57 + 123, 0, 123, 123, 123, 123, 123, 1, 122, 246, 61, 61, 9,
58 + 15.588457268119896, 12.25, 3.3219970854839125, 0, 1.5, 1, 0.5,
59 + ]}
60 + />
61 + );
62 + $[0] = t0;
63 + } else {
64 + t0 = $[0];
65 + }
66 + return t0;
67 +}
68 +
69 +export const FIXTURE_ENTRYPOINT = {
70 + fn: foo,
71 + params: [],
72 + isComponent: false,
73 +};
74 +
75 +```
76 +
77 +### Eval output
78 +(kind: ok) <div>{"value":[123,0,123,123,123,123,123,1,122,246,61,61,9,15.588457268119896,12.25,3.3219970854839125,0,1.5,1,0.5]}</div>
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/constant-propagation-bit-ops.js new
+36
@@ -0,0 +1,36 @@
1 +import { Stringify } from "shared-runtime";
2 +
3 +function foo() {
4 + return (
5 + <Stringify
6 + value={[
7 + 123.45 | 0,
8 + 123.45 & 0,
9 + 123.45 ^ 0,
10 + 123 << 0,
11 + 123 >> 0,
12 + 123 >>> 0,
13 + 123.45 | 1,
14 + 123.45 & 1,
15 + 123.45 ^ 1,
16 + 123 << 1,
17 + 123 >> 1,
18 + 123 >>> 1,
19 + 3 ** 2,
20 + 3 ** 2.5,
21 + 3.5 ** 2,
22 + 2 ** (3 ** 0.5),
23 + 4 % 2,
24 + 4 % 2.5,
25 + 4 % 3,
26 + 4.5 % 2,
27 + ]}
28 + />
29 + );
30 +}
31 +
32 +export const FIXTURE_ENTRYPOINT = {
33 + fn: foo,
34 + params: [],
35 + isComponent: false,
36 +};