Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
6bfb37d
perf(ir): trial bound constructor case folding
MicroProofs Sep 28, 2026
d9c949c
perf(ir): adopt bound constructor folding
MicroProofs Sep 28, 2026
411d5fe
perf(ir): trial native list case folding
MicroProofs Sep 28, 2026
8e09b66
perf(ir): adopt native list case folding
MicroProofs Sep 28, 2026
9a5499f
perf(ir): trial literal Data case folding
MicroProofs Sep 28, 2026
c3773e3
refactor(test): consolidate optimizer coverage
MicroProofs Sep 28, 2026
e0434ba
perf(ir): adopt literal Data case folding
MicroProofs Sep 28, 2026
d3d917b
perf(ir): trial Data wrapper case folding
MicroProofs Sep 28, 2026
44ac57f
perf(ir): adopt Data wrapper case folding
MicroProofs Sep 28, 2026
1767c54
perf(ir): trial collection Data case folding
MicroProofs Sep 28, 2026
be58371
perf(ir): adopt collection Data case folding
MicroProofs Sep 28, 2026
656e197
perf(ir): trial ConstrData case folding
MicroProofs Sep 29, 2026
a46da51
perf(ir): adopt ConstrData case folding
MicroProofs Sep 29, 2026
31f8119
perf(ir): fold fields of known native constructors
MicroProofs Sep 29, 2026
365ec7e
perf(ir): fold known integer and byte cases
MicroProofs Sep 29, 2026
d362d7f
perf(ir): trial direct integer representation cancellation
MicroProofs Sep 29, 2026
1ef1f88
feat(codegen): default builds and tests to trace-preserving O1
MicroProofs Sep 29, 2026
07c328f
fix(codegen): use heap work lists throughout assembly
MicroProofs Sep 29, 2026
a192b18
fix(ir): print Core with heap work lists
MicroProofs Sep 30, 2026
a14c3c6
perf(ir): cancel proven representation round trips
MicroProofs Oct 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 5 additions & 0 deletions .sampo/changesets/integer-inverse-trial.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
cargo/nash-ir: minor
---

Add an isolated integer representation cancellation pass with structural runtime-shape evidence and preserved operand evaluation.
7 changes: 7 additions & 0 deletions .sampo/changesets/iterative-assembly.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
cargo/nash-ir: patch
cargo/nash-codegen: patch
cargo/nash-plutus: patch
---

Replace recursive Core and UPLC assembly traversals with heap work lists. Remove the O1 stack enlargement while preserving traversal order, generated code, traces, and lowering diagnostics.
5 changes: 5 additions & 0 deletions .sampo/changesets/iterative-core-printing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
cargo/nash-ir: patch
---

Render deep Core term trees with a heap work list while preserving diagnostic and snapshot formatting.
5 changes: 5 additions & 0 deletions .sampo/changesets/known-constructor-fields.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
cargo/nash-ir: minor
---

Fold field accesses on known native constructors while preserving strict field evaluation, escaping values, and malformed runtime shapes.
5 changes: 5 additions & 0 deletions .sampo/changesets/known-literal-cases.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
cargo/nash-ir: minor
---

Fold known native integer and byte case subjects while preserving invalid tables, runtime failures, and strict evaluation.
12 changes: 12 additions & 0 deletions .sampo/changesets/o1-build-default.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
cargo/nash-config: minor
cargo/nash-codegen: minor
cargo/nash-driver: minor
cargo/nash-cli: minor
cargo/nash-ir: patch
cargo/nash-plutus: patch
---

Make trace-preserving O1 optimization the default for builds and tests, with explicit O0/O1 CLI and project settings. Share the accepted optimizer with snapshots and measurements, and include direct integer representation cancellation before ANF.

Print deep UPLC term trees with an explicit work stack.
6 changes: 6 additions & 0 deletions .sampo/changesets/representation-cancellation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
cargo/nash-ir: patch
cargo/nash-codegen: patch
---

Cancel proven integer, byte, list, map and UTF-8 representation round trips, including let-bound operands and constructor Data projections/reconstruction, while preserving validation, traces and evaluation order. Run cancellation in the O1 cleanup loop as well as before normalization.
5 changes: 3 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,9 @@ pass's layer. All codegen snapshots that generate executable Core group unoptimi
unoptimized UPLC, followed by optimized Core then optimized UPLC. The unoptimized
side uses original compiled or hand-built Core and ordinary lowering, with only required
recursion encoding: no optimization passes or builtin/constant sharing.
Use the shared test-only accepted pipeline in `crates/nash-codegen/tests/support/optimizer.rs`
so each accepted optimization updates the whole fixture corpus. Pass tests retain
Use the shared production O1 pipeline in `crates/nash-codegen/src/optimizer.rs`,
rendered by `crates/nash-codegen/tests/support/optimizer.rs`, so each accepted
optimization updates the whole fixture corpus. Pass tests retain
isolated-pass evidence after that comparison. Diagnostic/metadata snapshots stay
focused; invalid Core records lowering errors, open Core is closed explicitly for
pipeline rendering, and deliberate divergence is rendered without evaluation.
Expand Down
2 changes: 1 addition & 1 deletion SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ Implementation plans (Plan 08 is in progress; Plans 09 and 10 are complete):
- [x] 05 Exhaustiveness (`Nitpick/PatternMatches` port) — [plans/05-nitpick.md](plans/05-nitpick.md)
- [x] 06 Diagnostics (`nash-report`, concise source labels, stable codes, JSON/LSP) — [plans/06-diagnostics.md](plans/06-diagnostics.md); [concise diagnostics refactor](plans/diagnostics-refactor.md) complete
- [x] 07 Codegen: Core IR, monomorphization, decision trees, recursion, Data casts, UPLC lowering — [plans/07-codegen.md](plans/07-codegen.md)
- [ ] 08 Optimizer: Single ANF normalization and optimization before recursion rewrite, inlining, builtin force caching, DCE, case-of-known-ctor/constant folding — [plans/08-optimizer.md](plans/08-optimizer.md) (Chunks 1–3 complete: analysis, hygiene, typed Core, pre-ANF static lifting, ANF and the isolated performance runner; Chunk 4 rules 1–3 accepted)
- [ ] 08 Optimizer: Single ANF normalization and optimization before recursion rewrite, inlining, builtin force caching, DCE, case-of-known-ctor/constant folding — [plans/08-optimizer.md](plans/08-optimizer.md) (Retained scope of Chunks 1–8 accepted; representation cancellation and O0/O1 build/test/config integration available; recursive unused-parameter removal, Chunks 9–10 and final composition review open)
- [x] 09 Validators + `nash build` — [plans/09-validators-build.md](plans/09-validators-build.md)
- [x] 10 Testing: `tests` block, props, generators, shrinking, power-assert, `nash test` — [plans/10-testing.md](plans/10-testing.md)
- [ ] 11 Macros + comptime — [plans/11-macros-comptime.md](plans/11-macros-comptime.md); includes explicit integer-dispatch AST and positional library macro (chunk 13), reusable call/binding/case-shaped macro inputs required in chunk 14 (library semantics deferred)
Expand Down
17 changes: 17 additions & 0 deletions crates/nash-cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,23 @@ mod tests {
use super::*;
use clap::CommandFactory;

#[test]
fn optimization_flags() {
for command in ["build", "test"] {
for flag in ["-O0", "-O1"] {
let cli = Cli::try_parse_from(["nash", command, flag]).unwrap();
let level = match cli.cmd {
crate::cmd::Cmd::Build(args) => args.optimize,
crate::cmd::Cmd::Test(args) => args.optimize,
_ => unreachable!(),
};
assert_eq!(u8::from(level.unwrap()), flag.as_bytes()[2] - b'0');
}
assert!(Cli::try_parse_from(["nash", command, "--optimize", "1"]).is_ok());
assert!(Cli::try_parse_from(["nash", command, "-O2"]).is_err());
}
}

#[test]
fn command_schema_is_consistent() {
Cli::command().debug_assert();
Expand Down
6 changes: 6 additions & 0 deletions crates/nash-cli/src/cmd/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ use tokio::sync::Mutex;

#[derive(clap::Args)]
pub struct Args {
/// Optimization level: 0 (baseline) or 1 (preserves enabled traces).
#[arg(short = 'O', long)]
pub optimize: Option<nash_config::OptimizationLevel>,
/// Path to the project.
#[arg(default_value = ".")]
pub path: PathBuf,
Expand Down Expand Up @@ -85,6 +88,9 @@ impl Args {
PlutusVersionArg::V3 => nash_config::PlutusVersion::V3,
};
}
if let Some(level) = self.optimize {
config.optimize = level;
}
if let Some(level) = self.trace_level {
config.trace_level = match level {
TraceLevelArg::Silent => nash_config::TraceLevel::Silent,
Expand Down
6 changes: 6 additions & 0 deletions crates/nash-cli/src/cmd/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ pub enum Coverage {

#[derive(clap::Args)]
pub struct Args {
/// Optimization level: 0 (baseline) or 1 (preserves enabled traces).
#[arg(short = 'O', long)]
pub optimize: Option<nash_config::OptimizationLevel>,
#[arg(default_value = ".")]
pub path: PathBuf,
#[arg(long)]
Expand Down Expand Up @@ -105,6 +108,9 @@ impl Args {
.filter(|(directory, _)| path.starts_with(directory))
.max_by_key(|(directory, _)| directory.components().count())
.map_or_else(|| project.config.build().for_tests(), |(_, config)| *config);
if let Some(level) = self.optimize {
config.optimize = level;
}
if let Some(level) = self.trace_level {
config.trace_level_explicit = true;
config.trace_level = match level {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
---
source: crates/nash-codegen/src/build/tests.rs
assertion_line: 239
description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\nmain : (unit, bool)\nmain =\n let\n (identity, second) = (\\x -> x, \\x -> x)\n in\n (identity (), second True)\n"
---
--- unoptimized Core
Expand Down Expand Up @@ -45,25 +44,9 @@ main#1
(lam value_18 value_18)])
(lam value_17 value_17)])
--- optimized Core
let destruct#26 : ('erased -> 'erased, 'erased -> 'erased) = constr 0 (\x#24 : 'erased -> x#24) (\x#25 : 'erased -> x#25) in
let anf#39 : unit -> unit = case@Tag destruct#26 of
0 field#28 field#29 -> field#28 in
let evaluated#32 : unit = anf#39 () in
let anf#41 : bool -> bool = case@Tag destruct#26 of
0 field#34 field#35 -> field#35 in
let anf#43 : bool = anf#41 true in
constr 0 evaluated#32 anf#43
constr 0 () true
--- optimized UPLC
(program 1.1.0
[(lam destruct_3
[(lam anf_6
[(lam evaluated_7
[(lam anf_10
[(lam anf_11 (constr 0 evaluated_7 anf_11)) [anf_10 (con bool True)]])
(case destruct_3 (lam field_8 (lam field_9 field_9)))])
[anf_6 (con unit ())]])
(case destruct_3 (lam field_4 (lam field_5 field_4)))])
(constr 0 (lam x_1 x_1) (lam x_2 x_2))])
(program 1.1.0 (constr 0 (con unit ()) (con bool True)))
--- result
(constr 0 (con unit ()) (con bool True))
--- logs
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
---
source: crates/nash-codegen/src/build/tests.rs
assertion_line: 239
description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\ntype alias box 'a = { value : 'a }\ntrait Pass 'f where\n pass : 'f 'a -> 'f 'a\n pass x = x\n other : 'f 'a -> 'f 'a\nimpl Pass box where\n other x = x\nboxed : box unit\nboxed = { value = () }\nmain = (pass boxed).value\n"
---
--- unoptimized Core
Expand All @@ -24,12 +23,9 @@ main#1
(lam value_6 value_6)])
(lam x_4 x_4)])
--- optimized Core
let boxed#13 : { _0 : unit } = constr 0 () in
field@0/1 boxed#13
()
--- optimized UPLC
(program 1.1.0
[(lam boxed_1 (case boxed_1 (lam generated_2 generated_2)))
(constr 0 (con unit ()))])
(program 1.1.0 (con unit ()))
--- result
(con unit ())
--- logs
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
---
source: crates/nash-codegen/src/build/tests.rs
assertion_line: 1450
description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\ntype entry = Entry { count : int, enabled : bool, label : bytes }\nmain =\n let\n item = Entry { label = #\"aabb\", enabled = True, count = 42 }\n in\n if item.enabled then addInteger item.count (lengthOfByteString item.label) else 0\n"
---
--- unoptimized Core
Expand Down Expand Up @@ -47,33 +46,12 @@ main#1
(lam value_10 value_10)])
(lam value_9 value_9)])
--- optimized Core
let item#24 : Main.entry = constr 0 42 true (con bytestring #aabb) in
let projection#25 : bool = field@1/3 item#24 in
case@Bool projection#25 of
True -> let projection#26 : int = field@0/3 item#24 in
let projection#27 : bytes = field@2/3 item#24 in
let anf#34 : int = lengthOfByteString projection#27 in
addInteger projection#26 anf#34
False -> 0
let anf#34 : int = lengthOfByteString (con bytestring #aabb) in
addInteger 42 anf#34
--- optimized UPLC
(program 1.1.0
[(lam item_1
[(lam projection_2
(case
projection_2
(con integer 0)
[(lam projection_3
[(lam projection_4
[(lam anf_5 [[(builtin addInteger) projection_3] anf_5])
[(builtin lengthOfByteString) projection_4]])
(case item_1 (lam generated_6 (lam generated_7 (lam generated_8 generated_8))))])
(case
item_1
(lam generated_9 (lam generated_10 (lam generated_11 generated_9))))]))
(case
item_1
(lam generated_12 (lam generated_13 (lam generated_14 generated_13))))])
(constr 0 (con integer 42) (con bool True) (con bytestring #aabb))])
[(lam anf_1 [[(builtin addInteger) (con integer 42)] anf_1])
[(builtin lengthOfByteString) (con bytestring #aabb)]])
--- result
(con integer 44)
--- logs
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
---
source: crates/nash-codegen/src/build/tests.rs
assertion_line: 239
description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\nimport Literal exposing (..)\nimport Eq exposing (..)\nencoded : Map Int Int\nencoded = Builtin.mapData [Builtin.mkPairData 1 2]\nnative = Builtin.unMapData encoded\nmain = eq native native\n"
---
--- unoptimized Core
Expand Down Expand Up @@ -33,25 +32,20 @@ let anf#19 : pair Int Int = mkPairData anf#17 anf#18 in
let anf#20 : list (pair Int Int) = mkCons anf#19 (con (list (pair data data)) []) in
let encoded#12 : Map Int Int = mapData anf#20 in
let native#13 : list (pair Int Int) = unMapData encoded#12 in
let anf#15 : Map 'erased 'erased = mapData native#13 in
let anf#16 : Map 'erased 'erased = mapData native#13 in
equalsData anf#15 anf#16
equalsData encoded#12 encoded#12
--- optimized UPLC
(program 1.1.0
[(lam builtin_10
[(lam builtin_8
[(lam fromInt_1
[(lam anf_2
[(lam anf_3
[(lam anf_4
[(lam anf_5
[(lam encoded_6
[(lam native_7
[(lam anf_8
[(lam anf_9 [[(builtin equalsData) anf_8] anf_9]) [(builtin mapData) native_7]])
[(builtin mapData) native_7]])
[(lam native_7 [[(builtin equalsData) encoded_6] encoded_6])
[(builtin unMapData) encoded_6]])
[(builtin mapData) anf_5]])
[[builtin_10 anf_4] (con (list (pair data data)) [])]])
[[builtin_8 anf_4] (con (list (pair data data)) [])]])
[[(builtin mkPairData) anf_2] anf_3]])
[fromInt_1 (con integer 2)]])
[fromInt_1 (con integer 1)]])
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
---
source: crates/nash-codegen/src/build/tests.rs
assertion_line: 239
description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\ntype alias person = { age : int, active : bool }\nread : person -> int\nread = .age\noriginal : person\noriginal = { active = True, age = 1 }\nmain : int\nmain = read { original | age = 42 }\n"
---
--- unoptimized Core
Expand Down Expand Up @@ -34,18 +33,9 @@ main#1
[(lam projection_10 projection_10)
(case record_6 (lam generated_15 (lam generated_16 generated_15)))])])
--- optimized Core
let original#20 : { _0 : int, _1 : bool } = constr 0 1 true in
let projection#23 : bool = field@1/2 original#20 in
let anf#27 : { _0 : int, _1 : bool } = constr 0 42 projection#23 in
field@0/2 anf#27
42
--- optimized UPLC
(program 1.1.0
[(lam original_1
[(lam projection_2
[(lam anf_3 (case anf_3 (lam generated_4 (lam generated_5 generated_4))))
(constr 0 (con integer 42) projection_2)])
(case original_1 (lam generated_6 (lam generated_7 generated_7)))])
(constr 0 (con integer 1) (con bool True))])
(program 1.1.0 (con integer 42))
--- result
(con integer 42)
--- logs
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
---
source: crates/nash-codegen/src/build/tests.rs
assertion_line: 239
description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\ntype option 'a = None | Some 'a\nunwrap fallback opt =\n case opt of\n None -> fallback\n Some x -> x\nmain : unit\nmain = unwrap () (Some ())\n"
---
--- unoptimized Core
Expand All @@ -25,14 +24,9 @@ main#1
[(lam match_8 (case match_8 fallback_5 (lam field_9 [(lam x_7 x_7) field_9])))
opt_6]))])
--- optimized Core
let anf#24 : Main.option unit = constr 1 () in
case@Tag anf#24 of
0 -> ()
1 field#14 -> field#14
()
--- optimized UPLC
(program 1.1.0
[(lam anf_1 (case anf_1 (con unit ()) (lam field_2 field_2)))
(constr 1 (con unit ()))])
(program 1.1.0 (con unit ()))
--- result
(con unit ())
--- logs
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
---
source: crates/nash-codegen/src/build/tests.rs
assertion_line: 1281
description: "module Main exposing (..)\nimport Primitive exposing (..)\nimport Builtin exposing (..)\nmain : bool\nmain =\n case (False, False) of\n (True, True) -> True\n _ -> trace \"default\" False\n"
---
--- unoptimized Core
Expand Down Expand Up @@ -41,26 +40,11 @@ main#1
(lam value_10 value_10)])
(con string "default")])
--- optimized Core
let match#16 : (bool, bool) = constr 0 false false in
let leaf#17 : @delay bool = delay (trace "default" in false) in
case@Tag match#16 of
0 field#18 field#19 -> case@Bool field#18 of
False -> force leaf#17
True -> case@Bool field#19 of
False -> force leaf#17
True -> true
trace "default" in false
--- optimized UPLC
(program 1.1.0
[(lam builtin_5
[(lam match_1
[(lam leaf_2
(case
match_1
(lam field_3
(lam field_4
(case field_3 (force leaf_2) (case field_4 (force leaf_2) (con bool True)))))))
(delay (force [[builtin_5 (con string "default")] (delay (con bool False))]))])
(constr 0 (con bool False) (con bool False))])
[(lam builtin_1
(force [[builtin_1 (con string "default")] (delay (con bool False))]))
(force (builtin trace))])
--- result
(con bool False)
Expand Down
Loading
Loading