From 7522087a1a1c69646ca35a9a40068151ed3149e2 Mon Sep 17 00:00:00 2001 From: Outcry <843648230@qq.com> Date: Tue, 14 Apr 2026 12:21:46 +0000 Subject: [PATCH 1/2] fix(compiler): move register tracking side-effect out of ZEN_ASSERT in copyParam Co-authored-by: Aone Copilot --- src/singlepass/common/codegen.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/singlepass/common/codegen.h b/src/singlepass/common/codegen.h index 24a27a906..964271c67 100644 --- a/src/singlepass/common/codegen.h +++ b/src/singlepass/common/codegen.h @@ -1068,9 +1068,9 @@ class OnePassCodeGen { Info.getType(), Operand(Info.getType(), Reg, Operand::FLAG_NONE), Opnd); if (Kind == WASMTypeKind::INTEGER) { - ZEN_ASSERT(GpRegUsed |= (1 << Reg)); + GpRegUsed |= (1 << Reg); } else { - ZEN_ASSERT(FpRegUsed |= (1 << Reg)); + FpRegUsed |= (1 << Reg); } } else { ZEN_ASSERT(Info.getOffset() < StackOffset); From 6507d11c0f51d7935599bcd262758019e56bbc56 Mon Sep 17 00:00:00 2001 From: Outcry <843648230@qq.com> Date: Sat, 9 May 2026 08:29:40 +0000 Subject: [PATCH 2/2] chore(docs): add change doc and regression test for copyParam register tracking fix --- .../README.md | 33 +++++++++ docs/changes/README.md | 1 + .../spec_extra/copyparam_multi_reg_args.wast | 70 +++++++++++++++++++ 3 files changed, 104 insertions(+) create mode 100644 docs/changes/2026-04-14-copyparam-register-tracking/README.md create mode 100644 tests/wast/spec_extra/copyparam_multi_reg_args.wast diff --git a/docs/changes/2026-04-14-copyparam-register-tracking/README.md b/docs/changes/2026-04-14-copyparam-register-tracking/README.md new file mode 100644 index 000000000..6a490003f --- /dev/null +++ b/docs/changes/2026-04-14-copyparam-register-tracking/README.md @@ -0,0 +1,33 @@ +# Change: Move register tracking side-effect out of ZEN_ASSERT in copyParam + +- **Status**: Implemented +- **Date**: 2026-04-14 +- **Tier**: Light + +## Overview + +Move the `GpRegUsed` and `FpRegUsed` register tracking bit-or assignments out of `ZEN_ASSERT()` macros in `OnePassCodeGen::copyParam()`, so they execute in both debug and release builds. + +## Motivation + +The original code placed side-effect expressions inside `ZEN_ASSERT`: + +```cpp +ZEN_ASSERT(GpRegUsed |= (1 << Reg)); +ZEN_ASSERT(FpRegUsed |= (1 << Reg)); +``` + +In release builds (`NDEBUG`), `ZEN_ASSERT` is compiled out entirely, which means the register tracking updates are silently skipped. This causes the singlepass JIT to lose track of which registers are in use during parameter copying, potentially leading to register allocation conflicts and incorrect code generation. + +## Impact + +- **Module**: `src/singlepass/common/codegen.h` — `OnePassCodeGen::copyParam()` +- **Contracts affected**: None (internal implementation detail; no API change) +- **Behavior change**: Register tracking now works correctly in release builds. No change in debug builds. + +## Checklist + +- [x] Implementation complete +- [x] Tests added/updated +- [x] Module specs in `docs/modules/` updated (if affected) +- [x] Build and tests pass diff --git a/docs/changes/README.md b/docs/changes/README.md index 00bfb118d..cbdba0e90 100644 --- a/docs/changes/README.md +++ b/docs/changes/README.md @@ -49,6 +49,7 @@ Typical triggers: |------|------|--------|------|-------------| | 2026-03-10 | [evm-stack-ssa-lifting](2026-03-10-evm-stack-ssa-lifting/README.md) | Implemented | Full | True-SSA stack lifting for EVM multipass JIT | | 2026-04-14 | [handlecompare-bounds-check](2026-04-14-handlecompare-bounds-check/README.md) | Implemented | Light | Add bounds check before macro-fusion read in handleCompare | +| 2026-04-14 | [copyparam-register-tracking](2026-04-14-copyparam-register-tracking/README.md) | Implemented | Light | Move register tracking side-effect out of ZEN_ASSERT in copyParam | | 2026-04-14 | [from-raw-pointer-safety-checks](2026-04-14-from-raw-pointer-safety-checks/README.md) | Accepted | Light | Add null/alignment safety checks to `from_raw_pointer` in Rust bindings | Each active proposal lives in its own subdirectory. Browse `docs/changes/*/README.md` diff --git a/tests/wast/spec_extra/copyparam_multi_reg_args.wast b/tests/wast/spec_extra/copyparam_multi_reg_args.wast new file mode 100644 index 000000000..66c5c31d9 --- /dev/null +++ b/tests/wast/spec_extra/copyparam_multi_reg_args.wast @@ -0,0 +1,70 @@ +;; Test that register tracking in copyParam works correctly. +;; This exercises the code path where multiple register parameters +;; are copied during a function call, ensuring GpRegUsed/FpRegUsed +;; tracking is not lost (regression test for side-effect inside ZEN_ASSERT). + +(module + ;; Function with many integer parameters to exercise GP register tracking + (func $sum_i32_6 (param i32 i32 i32 i32 i32 i32) (result i32) + local.get 0 + local.get 1 + i32.add + local.get 2 + i32.add + local.get 3 + i32.add + local.get 4 + i32.add + local.get 5 + i32.add) + + ;; Function with many f64 parameters to exercise FP register tracking + (func $sum_f64_4 (param f64 f64 f64 f64) (result f64) + local.get 0 + local.get 1 + f64.add + local.get 2 + f64.add + local.get 3 + f64.add) + + ;; Caller that passes distinct values to verify correct register assignment + (func (export "test_gp_reg_tracking") (result i32) + i32.const 1 + i32.const 2 + i32.const 3 + i32.const 4 + i32.const 5 + i32.const 6 + call $sum_i32_6) + + (func (export "test_fp_reg_tracking") (result f64) + f64.const 1.5 + f64.const 2.5 + f64.const 3.5 + f64.const 4.5 + call $sum_f64_4) + + ;; Mixed integer and float parameters + (func $mixed (param i32 f64 i32 f64) (result f64) + local.get 0 + f64.convert_i32_s + local.get 1 + f64.add + local.get 2 + f64.convert_i32_s + f64.add + local.get 3 + f64.add) + + (func (export "test_mixed_reg_tracking") (result f64) + i32.const 10 + f64.const 20.5 + i32.const 30 + f64.const 40.5 + call $mixed) +) + +(assert_return (invoke "test_gp_reg_tracking") (i32.const 21)) +(assert_return (invoke "test_fp_reg_tracking") (f64.const 12.0)) +(assert_return (invoke "test_mixed_reg_tracking") (f64.const 101.0))