Skip to content

feat(passes): leverage snarkVM aggregate ternary opcodes#29349

Draft
mohammadfawaz wants to merge 1 commit into
masterfrom
mohammadfawaz/ternary_ops
Draft

feat(passes): leverage snarkVM aggregate ternary opcodes#29349
mohammadfawaz wants to merge 1 commit into
masterfrom
mohammadfawaz/ternary_ops

Conversation

@mohammadfawaz
Copy link
Copy Markdown
Collaborator

@mohammadfawaz mohammadfawaz commented Apr 18, 2026

Summary

Switch the snarkvm dependency to the mohammadfawaz/complex_ternary branch (snarkVM PR #3222), which extends the ternary instruction to accept literal, array, and plaintext struct operands in addition to registers. The Leo flattening pass is updated to take advantage of this:

  • Aggregate ternaries over arrays, plaintext structs, primitives, identifiers, and literals are now preserved in emitted bytecode rather than decomposed field-by-field.
  • Records are still decomposed per-field, because their ciphertext components cannot appear directly as ternary operands.
  • The pass docstring is updated to reflect the new behaviour in both transition and finalize contexts.

rand / rand_chacha are bumped to 0.10 to match snarkVM, with the corresponding CLI call-site adjustments.

New compiler and execution tests cover ternaries over structs, nested structs, arrays, arrays of structs, records, primitives, and the identifier type, in both transition and finalize contexts.

Bytecode impact (compiler test suite)

Measured across the 1,408 expectation files under tests/expectations/compiler/**/*.out that are present on both master and this branch:

Before After Δ
Total bytes 1,445,043 1,332,058 −112,985 (−7.8%)
Bytecode lines −1,648
Files changed 20 of 1,408

Top savers (bytes saved):

  • option/unwrap_or_deep.out — 64,668
  • storage/external_storage.out — 15,020
  • storage/aggregates.out — 9,529
  • function/flatten_test.out — 6,161
  • option/in_modules.out — 3,154
  • storage/{primitives,signed,unsigned,external_storage_multi_deps}.out — 2,186–2,492 each
  • function/flatten_arrays.out — 1,254
  • examples/tictactoe.out — 1,076
  • option/implicit_wrapping.out — 1,021

Savings concentrate on code that previously forced field-by-field destructuring of ternaries — struct/array conditionals, option-like wrappers, and external storage aggregates.

Bytecode impact (leo-examples)

Measured by running leo build on each of the 34 programs under examples/ with the master CLI and with this branch's CLI, comparing build/main.aleo byte sizes:

Before After Δ
Total bytes 132,513 131,389 −1,124 (−0.85%)
Programs changed 1 of 34

Only tictactoe/main.aleo changed: 6,525 → 5,401 B (−17.2%), 207 → 183 lines. The per-row/per-cell decomposition of the Board struct now folds into three aggregate ternary ops over Row/Board.

All other 33 example programs produce byte-identical bytecode — they don't conditionally select over composite types, so the new opcodes have nothing to fold.

Bytecode impact (compliant-stablecoin)

Measured by running leo build on the 5 programs of ProvableHQ/compliant-stablecoin (ported to Leo 4.x) with the base CLI and with this branch's CLI:

Program Before After Δ
merkle_tree 10,394 7,984 −2,410 (−23.19%)
multisig_core 39,624 39,624 0
freezelist_program 6,432 6,432 0
stablecoin_program 18,309 18,309 0
bridge_program 18,601 18,601 0
Total 93,360 90,950 −2,410 (−2.58%)

All savings come from merkle_tree, which is the only module conditionally selecting over composite types ([field; 3] arrays inside the sibling-hash loop). The other four programs compile to byte-identical bytecode — they don't use aggregate ternaries, so the new opcodes have nothing to fold.

Test plan

  • cargo test -p leo-passes
  • cargo test -p leo-compiler --lib test_compiler
  • cargo test -p leo-compiler --lib test_execute (new ternary_* cases)
  • cargo clippy -- -D warnings
  • cargo +nightly fmt --check

Switch snarkVM to the `mohammadfawaz/complex_ternary` branch (PR #3222),
which extends the `ternary` instruction to accept literal, array, and
plaintext struct operands in addition to registers.

The flattening pass is updated to preserve aggregate ternaries over
arrays, plaintext structs, and primitives / identifiers / literals rather
than decomposing them field-by-field. Records are still decomposed
per-field because their ciphertext components cannot appear directly as
`ternary` operands. The pass docstring is updated to reflect the new
behaviour in both transition and finalize contexts.

Also bumps `rand` and `rand_chacha` to `0.10` to match snarkVM, with the
corresponding CLI call-site adjustments.

New compiler and execution tests exercise ternaries over structs, nested
structs, arrays, arrays of structs, records, primitives, and the
`identifier` type, in both transition and finalize contexts.
@mohammadfawaz mohammadfawaz force-pushed the mohammadfawaz/ternary_ops branch from d971f26 to 7dcbd63 Compare April 18, 2026 20:28
@mohammadfawaz mohammadfawaz self-assigned this Apr 20, 2026
@mohammadfawaz mohammadfawaz added dependencies Pull requests that update a dependency file, 🧱 Core Compiler Anything related to the core compiler including parsing, analysis, transforms, codegen, etc. 🚀 feature A new feature. labels Apr 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🧱 Core Compiler Anything related to the core compiler including parsing, analysis, transforms, codegen, etc. dependencies Pull requests that update a dependency file, 🚀 feature A new feature.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant