Skip to content

Commit fd22d69

Browse files
committed
feat: FastProcessor outputs a list of checkpoints
1 parent ee5b00d commit fd22d69

File tree

14 files changed

+766
-88
lines changed

14 files changed

+766
-88
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
- [BREAKING] The serialized representation for `Package` was changed to include procedure type information. Older packages will not work with the new serialization code, and vice versa. The version of the binary format was incremented accordingly ([#2028](https://github.com/0xMiden/miden-vm/pull/2028)).
3434
- [BREAKING] Procedure-related metadata types in the `miden-assembly` crate in some cases now require an optional type signature argument. If that information is not available, you can simply pass `None` to retain current behavior ([#2028](https://github.com/0xMiden/miden-vm/pull/2028)).
3535
- Remove basic block clock cycle optimization from `FastProcessor` ([#2054](https://github.com/0xMiden/miden-vm/pull/2054)).
36+
- Added `FastProcessor::execute_for_trace()`, which outputs a series of checkpoints necessary to build the trace in parallel ([#2023](https://github.com/0xMiden/miden-vm/pull/2023))
3637

3738
## 0.16.4 (2025-07-24)
3839

air/src/trace/rows.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub enum RowIndexError {
1919
// ================================================================================================
2020

2121
/// A newtype wrapper around a usize value representing a step in the execution trace.
22-
#[derive(Debug, Copy, Clone, Eq, Ord, PartialOrd)]
22+
#[derive(Debug, Default, Copy, Clone, Eq, Ord, PartialOrd)]
2323
pub struct RowIndex(u32);
2424

2525
impl RowIndex {

processor/src/continuation_stack.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const CONTINUATION_STACK_SIZE_HINT: usize = 64;
1212
///
1313
/// This enum defines the different types of continuations that can be performed on MAST nodes
1414
/// during program execution.
15-
#[derive(Debug)]
15+
#[derive(Debug, Clone)]
1616
pub enum Continuation {
1717
/// Start processing a node in the MAST forest.
1818
StartNode(MastNodeId),
@@ -39,7 +39,7 @@ pub enum Continuation {
3939
/// This allows the processor to execute a program iteratively in a loop rather than recursively
4040
/// traversing the nodes. It also allows the processor to pass the state of execution to another
4141
/// processor for further processing, which is useful for parallel execution of MAST forests.
42-
#[derive(Debug)]
42+
#[derive(Debug, Default, Clone)]
4343
pub struct ContinuationStack {
4444
stack: Vec<Continuation>,
4545
}

processor/src/decoder/block_stack.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::system::ContextId;
77
// ================================================================================================
88

99
/// Keeps track of code blocks which are currently being executed by the VM.
10-
#[derive(Debug, Default)]
10+
#[derive(Debug, Default, Clone)]
1111
pub struct BlockStack {
1212
blocks: Vec<BlockInfo>,
1313
}
@@ -98,7 +98,7 @@ impl BlockStack {
9898
// ================================================================================================
9999

100100
/// Contains basic information about a code block.
101-
#[derive(Debug)]
101+
#[derive(Debug, Clone)]
102102
pub struct BlockInfo {
103103
pub addr: Felt,
104104
block_type: BlockType,

processor/src/fast/checkpoints.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ impl StackState {
124124

125125
/// Derives the stack depth (b0 helper column) from the overflow table
126126
pub fn stack_depth(&self) -> Felt {
127-
Felt::new((MIN_STACK_DEPTH + self.overflow.total_num_elements()) as u64)
127+
Felt::new((MIN_STACK_DEPTH + self.overflow.num_elements_in_current_ctx()) as u64)
128128
}
129129

130130
/// Derives the overflow address (b1 helper column) from the overflow table
@@ -136,6 +136,11 @@ impl StackState {
136136
self.overflow.num_elements_in_current_ctx()
137137
}
138138

139+
pub fn advance_clock(&mut self) {
140+
// Advance the overflow table clock to the next row
141+
self.overflow.advance_clock();
142+
}
143+
139144
pub fn push_overflow(&mut self, element: Felt) {
140145
self.overflow.push(element);
141146
}

processor/src/fast/circuit_eval.rs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use miden_air::RowIndex;
22
use miden_core::{Felt, FieldElement, QuadFelt};
33

4-
use super::{FastProcessor, memory::Memory};
4+
use super::{FastProcessor, memory::Memory, trace_state_builder::CoreTraceStateBuilder};
55
use crate::{
66
ContextId, ExecutionError,
77
chiplets::{CircuitEvaluation, MAX_NUM_ACE_WIRES, PTR_OFFSET_ELEM, PTR_OFFSET_WORD},
@@ -32,9 +32,18 @@ impl FastProcessor {
3232
let num_read = self.stack_get(1);
3333
let ptr = self.stack_get(0);
3434
let ctx = self.ctx;
35-
let circuit_evaluation =
36-
eval_circuit_fast_(ctx, ptr, self.clk, num_read, num_eval, &mut self.memory, err_ctx)?;
37-
self.ace.add_circuit_evaluation(self.clk, circuit_evaluation);
35+
let clk = self.clk;
36+
let circuit_evaluation = eval_circuit_fast_(
37+
ctx,
38+
ptr,
39+
self.clk,
40+
num_read,
41+
num_eval,
42+
&mut self.memory,
43+
err_ctx,
44+
&mut self.trace_state_builder,
45+
)?;
46+
self.ace.add_circuit_evaluation(clk, circuit_evaluation);
3847

3948
Ok(())
4049
}
@@ -50,6 +59,7 @@ pub fn eval_circuit_fast_(
5059
num_eval: Felt,
5160
mem: &mut Memory,
5261
err_ctx: &impl ErrorContext,
62+
trace_state_builder: &mut Option<CoreTraceStateBuilder>,
5363
) -> Result<CircuitEvaluation, ExecutionError> {
5464
let num_vars = num_vars.as_int();
5565
let num_eval = num_eval.as_int();
@@ -87,14 +97,17 @@ pub fn eval_circuit_fast_(
8797
let mut ptr = ptr;
8898
// perform READ operations
8999
for _ in 0..num_read_rows {
90-
let word = mem.read_word(ctx, ptr, clk, err_ctx).map_err(ExecutionError::MemoryError)?;
100+
let word = mem
101+
.read_word(ctx, ptr, clk, err_ctx, trace_state_builder)
102+
.map_err(ExecutionError::MemoryError)?;
91103
evaluation_context.do_read(ptr, word)?;
92104
ptr += PTR_OFFSET_WORD;
93105
}
94106
// perform EVAL operations
95107
for _ in 0..num_eval_rows {
96-
let instruction =
97-
mem.read_element(ctx, ptr, err_ctx).map_err(ExecutionError::MemoryError)?;
108+
let instruction = mem
109+
.read_element(ctx, ptr, err_ctx, trace_state_builder)
110+
.map_err(ExecutionError::MemoryError)?;
98111
evaluation_context.do_eval(ptr, instruction, err_ctx)?;
99112
ptr += PTR_OFFSET_ELEM;
100113
}

processor/src/fast/crypto_ops.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ impl FastProcessor {
2121
};
2222

2323
self.stack[state_range].copy_from_slice(&hashed_state);
24+
25+
if let Some(trace_state_builder) = &mut self.trace_state_builder {
26+
trace_state_builder.hasher.record_permute(hashed_state);
27+
}
2428
}
2529

2630
/// Analogous to `Process::op_mpverify`.
@@ -42,6 +46,10 @@ impl FastProcessor {
4246
.get_merkle_path(root, &depth, &index)
4347
.map_err(|err| ExecutionError::advice_error(err, self.clk, err_ctx))?;
4448

49+
if let Some(trace_state_builder) = &mut self.trace_state_builder {
50+
trace_state_builder.hasher.record_build_merkle_root(&path, root);
51+
}
52+
4553
// verify the path
4654
match path.verify(index.as_int(), node, &root) {
4755
Ok(_) => Ok(()),
@@ -84,6 +92,10 @@ impl FastProcessor {
8492
// Replace the old node value with computed new root; everything else remains the same.
8593
self.stack_write_word(0, &new_root);
8694

95+
if let Some(trace_state_builder) = &mut self.trace_state_builder {
96+
trace_state_builder.hasher.record_update_merkle_root(&path, old_root, new_root);
97+
}
98+
8799
Ok(())
88100
}
89101
}

processor/src/fast/horner_ops.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ impl FastProcessor {
107107
let addr = self.stack_get(ALPHA_ADDR_INDEX);
108108
let word = self
109109
.memory
110-
.read_word(self.ctx, addr, self.clk, err_ctx)
110+
.read_word(self.ctx, addr, self.clk, err_ctx, &mut self.trace_state_builder)
111111
.map_err(ExecutionError::MemoryError)?;
112112

113113
(word[0], word[1])

processor/src/fast/io_ops.rs

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,37 @@ impl FastProcessor {
1111
/// Analogous to `Process::op_advpop`.
1212
#[inline(always)]
1313
pub fn op_advpop(&mut self, err_ctx: &impl ErrorContext) -> Result<(), ExecutionError> {
14-
let value = self
15-
.advice
16-
.pop_stack()
17-
.map_err(|err| ExecutionError::advice_error(err, self.clk, err_ctx))?;
14+
let value = {
15+
let value = self
16+
.advice
17+
.pop_stack()
18+
.map_err(|err| ExecutionError::advice_error(err, self.clk, err_ctx))?;
19+
if let Some(trace_state_builder) = &mut self.trace_state_builder {
20+
trace_state_builder.advice.record_pop_stack(value);
21+
}
22+
value
23+
};
24+
1825
self.increment_stack_size();
1926
self.stack_write(0, value);
27+
2028
Ok(())
2129
}
2230

2331
/// Analogous to `Process::op_advpopw`.
2432
#[inline(always)]
2533
pub fn op_advpopw(&mut self, err_ctx: &impl ErrorContext) -> Result<(), ExecutionError> {
26-
let word = self
27-
.advice
28-
.pop_stack_word()
29-
.map_err(|err| ExecutionError::advice_error(err, self.clk, err_ctx))?;
34+
let word = {
35+
let word = self
36+
.advice
37+
.pop_stack_word()
38+
.map_err(|err| ExecutionError::advice_error(err, self.clk, err_ctx))?;
39+
if let Some(trace_state_builder) = &mut self.trace_state_builder {
40+
trace_state_builder.advice.record_pop_stack_word(word);
41+
}
42+
word
43+
};
44+
3045
self.stack_write_word(0, &word);
3146

3247
Ok(())
@@ -40,7 +55,7 @@ impl FastProcessor {
4055

4156
let word = self
4257
.memory
43-
.read_word(self.ctx, addr, self.clk, err_ctx)
58+
.read_word(self.ctx, addr, self.clk, err_ctx, &mut self.trace_state_builder)
4459
.map_err(ExecutionError::MemoryError)?;
4560
self.stack_write_word(0, &word);
4661

@@ -66,7 +81,7 @@ impl FastProcessor {
6681
let element = {
6782
let addr = self.stack_get(0);
6883
self.memory
69-
.read_element(self.ctx, addr, err_ctx)
84+
.read_element(self.ctx, addr, err_ctx, &mut self.trace_state_builder)
7085
.map_err(ExecutionError::MemoryError)?
7186
};
7287

@@ -100,10 +115,22 @@ impl FastProcessor {
100115
let addr_second_word = addr_first_word + WORD_SIZE_FELT;
101116
let words = [
102117
self.memory
103-
.read_word(self.ctx, addr_first_word, self.clk, err_ctx)
118+
.read_word(
119+
self.ctx,
120+
addr_first_word,
121+
self.clk,
122+
err_ctx,
123+
&mut self.trace_state_builder,
124+
)
104125
.map_err(ExecutionError::MemoryError)?,
105126
self.memory
106-
.read_word(self.ctx, addr_second_word, self.clk, err_ctx)
127+
.read_word(
128+
self.ctx,
129+
addr_second_word,
130+
self.clk,
131+
err_ctx,
132+
&mut self.trace_state_builder,
133+
)
107134
.map_err(ExecutionError::MemoryError)?,
108135
];
109136

@@ -133,6 +160,10 @@ impl FastProcessor {
133160
.pop_stack_dword()
134161
.map_err(|err| ExecutionError::advice_error(err, self.clk, err_ctx))?;
135162

163+
if let Some(trace_state_builder) = &mut self.trace_state_builder {
164+
trace_state_builder.advice.record_pop_stack_dword(words);
165+
}
166+
136167
// write the words to memory
137168
self.memory
138169
.write_word(self.ctx, addr_first_word, self.clk, words[0], err_ctx)

processor/src/fast/memory.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ use alloc::{collections::BTreeMap, vec::Vec};
33
use miden_air::RowIndex;
44
use miden_core::{EMPTY_WORD, Felt, WORD_SIZE, Word, ZERO};
55

6-
use crate::{ContextId, ErrorContext, MemoryAddress, MemoryError};
6+
use crate::{
7+
ContextId, ErrorContext, MemoryAddress, MemoryError,
8+
fast::trace_state_builder::CoreTraceStateBuilder,
9+
};
710

811
/// The memory for the processor.
912
///
@@ -30,8 +33,14 @@ impl Memory {
3033
ctx: ContextId,
3134
addr: Felt,
3235
err_ctx: &impl ErrorContext,
36+
trace_state_builder: &mut Option<CoreTraceStateBuilder>,
3337
) -> Result<Felt, MemoryError> {
3438
let element = self.read_element_impl(ctx, clean_addr(addr, err_ctx)?).unwrap_or(ZERO);
39+
40+
if let Some(trace_state_builder) = trace_state_builder {
41+
trace_state_builder.memory.record_element(element, addr);
42+
}
43+
3544
Ok(element)
3645
}
3746

@@ -46,10 +55,15 @@ impl Memory {
4655
addr: Felt,
4756
clk: RowIndex,
4857
err_ctx: &impl ErrorContext,
58+
trace_state_builder: &mut Option<CoreTraceStateBuilder>,
4959
) -> Result<Word, MemoryError> {
5060
let addr = clean_addr(addr, err_ctx)?;
5161
let word = self.read_word_impl(ctx, addr, Some(clk), err_ctx)?.unwrap_or(EMPTY_WORD);
5262

63+
if let Some(trace_state_builder) = trace_state_builder {
64+
trace_state_builder.memory.record_word(word, addr.into());
65+
}
66+
5367
Ok(word)
5468
}
5569

0 commit comments

Comments
 (0)