compiler/packages/babel-plugin-react-compiler/docs/passes/04-constantPropagation.md MARKDOWN 111 lines View on github.com → Search inside
1# constantPropagation23## File4`src/Optimization/ConstantPropagation.ts`56## Purpose7Applies Sparse Conditional Constant Propagation (SCCP) to fold compile-time evaluable expressions to constant values, propagate those constants through the program, and eliminate unreachable branches when conditionals have known constant values.89## Input Invariants10- HIR must be in SSA form (runs after `enterSSA`)11- Redundant phi nodes should be eliminated (runs after `eliminateRedundantPhi`)12- Consistent identifiers must be ensured (`assertConsistentIdentifiers`)13- Terminal successors must exist (`assertTerminalSuccessorsExist`)1415## Output Guarantees16- Instructions with compile-time evaluable operands are replaced with `Primitive` constants17- `ComputedLoad`/`ComputedStore` with constant string/number properties are converted to `PropertyLoad`/`PropertyStore`18- `LoadLocal` and `StoreLocal` propagate known constant values19- `IfTerminal` with constant boolean test values are replaced with `goto` terminals20- Unreachable blocks are removed and the CFG is minimized21- Phi nodes with unreachable predecessor operands are pruned22- Nested functions (`FunctionExpression`, `ObjectMethod`) are recursively processed2324## Algorithm25The pass uses Sparse Conditional Constant Propagation (SCCP) with fixpoint iteration:26271. **Data Structure**: A `Constants` map (`Map<IdentifierId, Constant>`) tracks known constant values (either `Primitive` or `LoadGlobal`)28292. **Single Pass per Iteration**: Visits all blocks in order:30   - Evaluates phi nodes - if all operands have the same constant value, the phi result is constant31   - Evaluates instructions - replaces evaluable expressions with constants32   - Evaluates terminals - if an `IfTerminal` test is a constant, replaces it with a `goto`33343. **Fixpoint Loop**: If any terminals changed (branch elimination):35   - Recomputes block ordering (`reversePostorderBlocks`)36   - Removes unreachable code (`removeUnreachableForUpdates`, `removeDeadDoWhileStatements`, `removeUnnecessaryTryCatch`)37   - Renumbers instructions (`markInstructionIds`)38   - Updates predecessors (`markPredecessors`)39   - Prunes phi operands from unreachable predecessors40   - Eliminates newly-redundant phis (`eliminateRedundantPhi`)41   - Merges consecutive blocks (`mergeConsecutiveBlocks`)42   - Repeats until no more changes43444. **Instruction Evaluation**: Handles various instruction types:45   - **Primitives/LoadGlobal**: Directly constant46   - **BinaryExpression**: Folds arithmetic (`+`, `-`, `*`, `/`, `%`, `**`), bitwise (`|`, `&`, `^`, `<<`, `>>`, `>>>`), and comparison (`<`, `<=`, `>`, `>=`, `==`, `===`, `!=`, `!==`) operators47   - **UnaryExpression**: Folds `!` (boolean negation) and `-` (numeric negation)48   - **PostfixUpdate/PrefixUpdate**: Folds `++`/`--` on constant numbers49   - **PropertyLoad**: Folds `.length` on constant strings50   - **TemplateLiteral**: Folds template strings with constant interpolations51   - **ComputedLoad/ComputedStore**: Converts to property access when property is constant string/number5253## Key Data Structures54- `Constant = Primitive | LoadGlobal` - The lattice values (no top/bottom, absence means unknown)55- `Constants = Map<IdentifierId, Constant>` - Maps identifier IDs to their known constant values56- Uses HIR types: `Instruction`, `Phi`, `Place`, `Primitive`, `LoadGlobal`, `InstructionValue`5758## Edge Cases59- **Last instruction of sequence blocks**: Skipped to preserve evaluation order60- **Phi nodes with back-edges**: Single-pass analysis means loop back-edges won't have constant values propagated61- **Template literals with Symbol**: Not folded (would throw at runtime)62- **Template literals with objects/arrays**: Not folded (custom toString behavior)63- **Division results**: Computed at compile time (may produce `NaN`, `Infinity`, etc.)64- **LoadGlobal in phis**: Only propagated if all operands reference the same global name65- **Nested functions**: Constants from outer scope are propagated into nested function expressions6667## TODOs68- `// TODO: handle more cases` - The default case in `evaluateInstruction` has room for additional instruction types6970## Example7172**Input:**73```javascript74function Component() {75  let a = 1;7677  let b;78  if (a === 1) {79    b = true;80  } else {81    b = false;82  }8384  let c;85  if (b) {86    c = 'hello';87  } else {88    c = null;89  }9091  return c;92}93```9495**After ConstantPropagation:**96- `a === 1` evaluates to `true`97- The `if (a === 1)` branch is eliminated, only consequent remains98- `b` is known to be `true`99- `if (b)` branch is eliminated, only consequent remains100- `c` is known to be `'hello'`101- All intermediate blocks are merged102103**Output:**104```javascript105function Component() {106  return "hello";107}108```109110The pass performs iterative simplification: first iteration determines `a === 1` is `true` and eliminates that branch. The CFG is updated, phi for `b` is pruned to single operand making `b = true`. Second iteration uses `b = true` to eliminate the next branch. This continues until no more branches can be eliminated.

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.