Skip to content

Conversation

@avrabe
Copy link
Contributor

@avrabe avrabe commented Nov 29, 2025

Fixes #33

Summary

  • Fixed custom section encoding bug causing non-deterministic WASM output
  • Made inline_functions run to fixed point for true idempotence
  • Re-enabled the idempotence test

Root Cause

The idempotence test was failing because custom sections (specifically the "name" section) were duplicating the name field on each encode/parse cycle:

  1. Parsing used reader.range() which included the name field in the payload
  2. Re-encoding added the name field again via CustomSection { name, data }
  3. Result: 89 bytes → 94 bytes on second encoding

Changes

  1. loom-core/src/lib.rs:687 - Use reader.data() instead of reader.range() for custom sections
  2. loom-core/src/lib.rs:6809 - Wrap inline logic in loop until no candidates found
  3. loom-core/tests/optimization_tests.rs:1798 - Remove #[ignore] from idempotence test

Testing

  • ✅ All existing tests pass
  • ✅ Idempotence test passes
  • ✅ WASM encoding is deterministic

Note

advanced_math.wat and crypto_utils.wat still fail due to a separate stack discipline bug (not idempotence related). They remain skipped in CI.

## Root Cause
The idempotence test was failing because of a bug in how custom sections
(specifically the "name" section) were being encoded during WASM round-trips:

1. When parsing WASM, we used `reader.range()` to extract custom section bytes
2. The range included the section payload WITH the name field
3. When re-encoding, wasm-encoder added the name field again
4. Result: Each encode/parse cycle duplicated the name field, growing the file

This caused parse → encode → parse → encode to produce different sizes
(89 bytes → 94 bytes), making the idempotence test fail.

## Fix
1. Changed custom section parsing to use `reader.data()` instead of `reader.range()`
   - This extracts only the section data WITHOUT the name field
   - The encoder properly adds the name field during re-encoding
   - Now encode/parse cycles are deterministic

2. Made inline_functions run to fixed point
   - Loops until no more inlining candidates found
   - Ensures true idempotence even if new opportunities arise
   - More robust optimization behavior

3. Re-enabled the idempotence test
   - Removed #[ignore] attribute
   - Test now passes consistently

## Testing
- All existing tests pass
- Idempotence test now passes
- WASM encoding is deterministic across multiple round-trips

Note: advanced_math.wat and crypto_utils.wat still fail validation due to
a separate stack discipline bug in the inlining logic itself (not related
to idempotence). These remain skipped in CI per the existing workaround.
## Problem
The `eliminate_redundant_sets` optimization in `simplify-locals` was
incorrectly removing stack-producing instructions, causing invalid WASM
output with "values remaining on stack" errors.

## Root Cause
The optimization assumed that the value for a `local.set` was always
produced by the immediately preceding instruction (`result.len() - 1`).
This is incorrect in stack-based WASM where values can come from complex
expression trees spanning multiple instructions.

Example of buggy behavior:
```wat
Input:
  local.get $base
  i32.const 3
  i32.shl            # ← Produces value for local.set
  local.set $temp1

Output (broken):
  local.get $base
  i32.const 3
  # i32.shl REMOVED!  ← Bug: incorrectly removed
  local.set $temp1
```

## Fix
Disabled the `eliminate_redundant_sets` optimization by commenting it out
in `simplify_locals` (loom-core/src/lib.rs:4155).

The optimization needs to be rewritten to properly understand the stack
discipline and track which instructions actually produce values for sets.

## Changes
1. **loom-core/src/lib.rs:4155** - Commented out eliminate_redundant_sets call
2. **loom-core/src/lib.rs:4369** - Added `#[allow(dead_code)]` to function
3. **loom-core/tests/optimization_tests.rs** - Marked RSE tests as `#[ignore]`
4. **.github/workflows/ci.yml** - Removed skips for advanced_math.wat and crypto_utils.wat

## Testing
- ✅ Both advanced_math.wat and crypto_utils.wat now validate correctly
- ✅ All other tests pass
- ✅ Idempotence test still passes

## Impact
The `simplify-locals` pass still performs other optimizations (local variable
equivalence, redundant get/set elimination). Only the buggy redundant set
elimination is disabled.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fix function inlining idempotence test failure

2 participants