Repository: facebook/react
Pull request: feat(compiler): Implement constant folding for more binary expressions

## 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.

Changed files:
filename: compiler/packages/babel-plugin-react-compiler/src/Optimization/ConstantPropagation.ts
patch: @@ -369,6 +369,58 @@ function evaluateInstruction(
             }
             break;
           }
+          case "|": {
+            if (typeof lhs === "number" && typeof rhs === "number") {
+              result = { kind: "Primitive", value: lhs | rhs, loc: value.loc };
+            }
+            break;
+          }
+          case "&": {
+            if (typeof lhs === "number" && typeof rhs === "number") {
+              result = { kind: "Primitive", value: lhs & rhs, loc: value.loc };
+            }
+            break;
+          }
+          case "^": {
+            if (typeof lhs === "number" && typeof rhs === "number") {
+              result = { kind: "Primitive", value: lhs ^ rhs, loc: value.loc };
+            }
+            break;
+          }
+          case "<<": {
+            if (typeof lhs === "number" && typeof rhs === "number") {
+              result = { kind: "Primitive", value: lhs << rhs, loc: value.loc };
+            }
+            break;
+          }
+          case ">>": {
+            if (typeof lhs === "number" && typeof rhs === "number") {
+              result = { kind: "Primitive", value: lhs >> rhs, loc: value.loc };
+            }
+            break;
+          }
+          case ">>>": {
+            if (typeof lhs === "number" && typeof rhs === "number") {
+              result = {
+                kind: "Primitive",
+                value: lhs >>> rhs,
+                loc: value.loc,
+              };
+            }
+            break;
+          }
+          case "%": {
+            if (typeof lhs === "number" && typeof rhs === "number") {
+              result = { kind: "Primitive", value: lhs % rhs, loc: value.loc };
+            }
+            break;
+          }
+          case "**": {
+            if (typeof lhs === "number" && typeof rhs === "number") {
+              result = { kind: "Primitive", value: lhs ** rhs, loc: value.loc };
+            }
+            break;
+          }
           case "<": {
             if (typeof lhs === "number" && typeof rhs === "number") {
               result = { kind: "Primitive", value: lhs < rhs, loc: value.loc };

filename: compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/assignment-variations.expect.md
patch: @@ -22,10 +22,7 @@ export const FIXTURE_ENTRYPOINT = {
 
 ```javascript
 function f() {
-  let x;
-
-  x = 3 >>> 1;
-  return x;
+  return 1;
 }
 
 export const FIXTURE_ENTRYPOINT = {

filename: compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/constant-propagation-bit-ops.expect.md
patch: @@ -0,0 +1,78 @@
+
+## Input
+
+```javascript
+import { Stringify } from "shared-runtime";
+
+function foo() {
+  return (
+    <Stringify
+      value={[
+        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,
+      ]}
+    />
+  );
+}
+
+export const FIXTURE_ENTRYPOINT = {
+  fn: foo,
+  params: [],
+  isComponent: false,
+};
+
+```
+
+## Code
+
+```javascript
+import { c as _c } from "react/compiler-runtime";
+import { Stringify } from "shared-runtime";
+
+function foo() {
+  const $ = _c(1);
+  let t0;
+  if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
+    t0 = (
+      <Stringify
+        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,
+        ]}
+      />
+    );
+    $[0] = t0;
+  } else {
+    t0 = $[0];
+  }
+  return t0;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+  fn: foo,
+  params: [],
+  isComponent: false,
+};
+
+```
+      
+### Eval output
+(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

filename: compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/constant-propagation-bit-ops.js
patch: @@ -0,0 +1,36 @@
+import { Stringify } from "shared-runtime";
+
+function foo() {
+  return (
+    <Stringify
+      value={[
+        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,
+      ]}
+    />
+  );
+}
+
+export const FIXTURE_ENTRYPOINT = {
+  fn: foo,
+  params: [],
+  isComponent: false,
+};