Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## 0.22.3 (2026-05-01)

- Change value of `Path::MAX_COMPONENT_LENGTH` to `u16::MAX - 2` [#3087](https://github.com/0xMiden/miden-vm/pull/3087)
- Optimized range check lookup tracking to avoid heap allocations during trace generation ([#2793](https://github.com/0xMiden/miden-vm/issues/2793)).

## 0.22.2 (2026-04-028)

Expand Down
5 changes: 3 additions & 2 deletions processor/src/trace/range/aux_trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use miden_air::trace::{
range::{M_COL_IDX, V_COL_IDX},
};

use super::CycleLookupValues;
use crate::{
Felt, ZERO,
field::ExtensionField,
Expand All @@ -23,7 +24,7 @@ pub struct AuxTraceBuilder {
lookup_values: Vec<u16>,
/// Range check lookups performed by all user operations, grouped and sorted by the clock cycle
/// at which they are requested.
cycle_lookups: BTreeMap<RowIndex, Vec<u16>>,
cycle_lookups: BTreeMap<RowIndex, CycleLookupValues>,
// The index of the first row of Range Checker's trace when the padded rows end and values to
// be range checked start.
values_start: usize,
Expand All @@ -34,7 +35,7 @@ impl AuxTraceBuilder {
// --------------------------------------------------------------------------------------------
pub fn new(
lookup_values: Vec<u16>,
cycle_lookups: BTreeMap<RowIndex, Vec<u16>>,
cycle_lookups: BTreeMap<RowIndex, CycleLookupValues>,
values_start: usize,
) -> Self {
Self {
Expand Down
51 changes: 41 additions & 10 deletions processor/src/trace/range/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ pub struct RangeChecker {
/// Tracks lookup count for each checked value.
lookups: BTreeMap<u16, usize>,
/// Range check lookups performed by all user operations, grouped and sorted by clock cycle.
/// Each cycle is mapped to a vector of the range checks requested at that cycle, which can
/// come from the stack, memory, or both.
cycle_lookups: BTreeMap<RowIndex, Vec<u16>>,
/// Each cycle is mapped to the range checks requested at that cycle, which can come from the
/// stack, memory, or both.
cycle_lookups: BTreeMap<RowIndex, CycleLookupValues>,
}

impl RangeChecker {
Expand Down Expand Up @@ -93,15 +93,10 @@ impl RangeChecker {
}

// track the range check requests at each cycle
// TODO: optimize this to use a struct instead of vectors, e.g. (#2793):
// struct MemoryLookupValues {
// num_lookups: u8,
// lookup_values: [u16; 6],
// }
self.cycle_lookups
.entry(clk)
.and_modify(|entry| entry.append(&mut values.to_vec()))
.or_insert_with(|| values.to_vec());
.and_modify(|entry| entry.extend(values))
.or_insert_with(|| CycleLookupValues::new(values));
}

// EXECUTION TRACE GENERATION (INTERNAL)
Expand Down Expand Up @@ -214,6 +209,42 @@ impl Default for RangeChecker {
}
}

// CYCLE LOOKUP VALUES
// ================================================================================================

/// The maximum number of range check lookups that can be requested at a single clock cycle.
///
/// Range checks can come from memory, which requests 2 lookups, and from the stack, which requests
/// 4 lookups.
const MAX_CYCLE_LOOKUPS: usize = 6;

#[derive(Debug, Clone, Default)]
pub(crate) struct CycleLookupValues {
num_lookups: u8,
lookup_values: [u16; MAX_CYCLE_LOOKUPS],
}

impl CycleLookupValues {
fn new(values: &[u16]) -> Self {
let mut result = Self::default();
result.extend(values);
result
}

fn extend(&mut self, values: &[u16]) {
let start = usize::from(self.num_lookups);
let end = start + values.len();
assert!(end <= MAX_CYCLE_LOOKUPS, "too many range check lookups at a single cycle");

self.lookup_values[start..end].copy_from_slice(values);
self.num_lookups = end as u8;
}

pub(crate) fn iter(&self) -> impl Iterator<Item = &u16> {
self.lookup_values[..usize::from(self.num_lookups)].iter()
}
}

// HELPER FUNCTIONS
// ================================================================================================

Expand Down
10 changes: 9 additions & 1 deletion processor/src/trace/range/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use alloc::{collections::BTreeMap, vec::Vec};

use miden_utils_testing::rand::rand_array;

use super::{RangeCheckTrace, RangeChecker};
use super::{CycleLookupValues, RangeCheckTrace, RangeChecker};
use crate::{Felt, ZERO, utils::ToElements};

// TESTS
Expand Down Expand Up @@ -73,6 +73,14 @@ fn into_trace_with_table_panics_on_mismatched_len() {
let _ = checker.into_trace_with_table(table_len + 1, target_len);
}

#[test]
fn cycle_lookup_values_tracks_memory_and_stack_lookups() {
let mut values = CycleLookupValues::new(&[1, 2]);
values.extend(&[3, 4, 5, 6]);

assert_eq!(values.iter().copied().collect::<Vec<_>>(), vec![1, 2, 3, 4, 5, 6]);
}

// HELPER FUNCTIONS
// ================================================================================================

Expand Down
Loading