Skip to content

An array parameter that cannot be bound is passed by value - #2745

Merged
gHashTag merged 2 commits into
masterfrom
w699-array-by-value
Aug 28, 2026
Merged

An array parameter that cannot be bound is passed by value#2745
gHashTag merged 2 commits into
masterfrom
w699-array-by-value

Conversation

@gHashTag

Copy link
Copy Markdown
Owner

Closes #2743

W458 binds an array parameter to one module-level array name and lets the body reference that name directly — which is why such parameters vanish from the emitted port list. Three situations have no single name to bind, and all three refused the whole function:

  • no call site at all
  • call sites that disagree — neuronN(acts, w0, …) and neuronN(acts, w1, …)
  • an argument that is not a plain identifier

That refusal is what produced the contradiction in specs/ternary/bitnet_layer.t27, where the emitter printed

// ERROR: function on_comb has array parameter(s) but no call site

and four lines below wrote

assign result = on_comb(acts, w0, w1, nchunks, threshold);

— the call it had just said did not exist.

None of the three is a defect

An array parameter that cannot be bound is simply passed by value: it stays a real input [W-1:0] and the body indexes it by element slice, which #1745 already implements and which every one of these specs' testbenches was already written against.

So the fix deletes the three refusals rather than adding machinery: 18 insertions, 22 deletions, one file.

I first built the elaborate version — monomorphising the conflicting function into neuronN__acts_w0 / neuronN__acts_w1, binding the entry point's parameters to their own ports, and teaching the index path that a bound name can be packed. It worked, and it was wrong: it fixed one of the five failures and left the by-value path — which the testbenches assume — still refused. The small answer subsumes it.

Measured

Whole test suite, --no-fail-fast:

before after
tests 2419 passed / 5 failed 2424 passed / 0 failed

The five were bitnet_layer, bitnet_mlp, bitnet_mlp3, bitnet_neuron_nchunk and verilog_array_param_index. Four of them generate Verilog, compile it with iverilog, run it, and check numbers against a reference model — a two-layer MLP, a three-layer MLP, a two-neuron layer, an n-chunk neuron. No test file is touched by this commit.

Blast radius, generating Verilog for all 650 corpus specs with the before binary and the after binary and diffing per file:

10 specs changed, every one in the same direction:
19 refusals removed, 19 functions gained, nothing lost

Corpus acceptance unchanged: Zig 217, cc 157, Zig-AND-Verilog 194.

A correction to the record

Earlier reports in this loop of "1786 passed / 1 failed" came from cargo test runs that stop at the first failing binary. With --no-fail-fast the repository baseline was 2419 / 5, and four of those five failures had never been printed by anything I ran. The numbers above are the whole suite.

🤖 Generated with Claude Code

gHashTag and others added 2 commits August 28, 2026 07:20
…y value

W458 binds an array parameter to ONE module-level array name and lets the body
reference that name directly, which is why such parameters vanish from the
emitted port list. Three situations had no single name to bind, and all three
REFUSED the whole function:

  * no call site at all
  * call sites that disagree -- `neuronN(acts, w0, ..)` and `neuronN(acts, w1, ..)`
  * an argument that is not a plain identifier

Refusing is what produced the contradiction in specs/ternary/bitnet_layer.t27,
where the emitter printed

    // ERROR: function on_comb has array parameter(s) but no call site

and four lines below wrote

    assign result = on_comb(acts, w0, w1, nchunks, threshold);

-- the call it had just said did not exist.

None of the three is a defect. An array parameter that cannot be bound is simply
passed BY VALUE: it stays a real `input [W-1:0]` and the body indexes it by
element slice, which #1745 already implements and which every one of these
specs' testbenches was already written against. So the fix deletes the three
refusals rather than adding machinery.

MEASURED, whole test suite with --no-fail-fast:

    2419 passed / 5 failed  ->  2424 passed / 0 failed

The five were bitnet_layer, bitnet_mlp, bitnet_mlp3, bitnet_neuron_nchunk and
verilog_array_param_index -- four of them generate Verilog, compile it with
iverilog, RUN it and check numbers against a reference model. No test file is
touched by this commit.

Blast radius, generating Verilog for all 650 corpus specs with the before and
after binaries and diffing per file: 10 specs changed, every one in the same
direction -- 19 refusals removed, 19 functions gained, nothing lost. Corpus
acceptance is unchanged at Zig 217, cc 157, Zig-AND-Verilog 194.

A correction to the record: earlier reports in this loop of "1786 passed / 1
failed" came from `cargo test` runs that stop at the first failing binary. With
--no-fail-fast the repository baseline was 2419/5, and four of those five had
never been printed.

Closes #2743

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…tals

Closes #2743

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

📓 NotebookLM Notebook linked to this PR

This notebook contains session context, decisions, and artifacts for this work.

@github-actions

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-08-28 00:20:59 UTC

Summary

Status Count
Total Open PRs 8
PRs with Failing Checks 7
PRs with All Checks Green 1
READY 0
FAILING 7
PENDING 0

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=25a9c40dc273 != manifest seal=87e5cbd3ad94.
    The committed NMSE numbers were certified against an older compiler.rs.
    Run scripts/reseal-check.sh locally for the two-step reseal command (advisory; not a merge gate).

@gHashTag
gHashTag merged commit 9481279 into master Aug 28, 2026
32 of 34 checks passed
@gHashTag
gHashTag deleted the w699-array-by-value branch August 28, 2026 00:37
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.

gen-verilog: a function called only from another function is refused, and the emitter writes the call anyway

1 participant