Skip to content

Commit

Permalink
refactor: code optimizations, renamings, minor improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
Fumuran committed Aug 29, 2024
1 parent fdd68c4 commit 2c23e12
Show file tree
Hide file tree
Showing 28 changed files with 272 additions and 250 deletions.
16 changes: 8 additions & 8 deletions air/src/constraints/stack/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use alloc::vec::Vec;

use vm_core::{stack::STACK_TOP_SIZE, StackOutputs};
use vm_core::{stack::MIN_STACK_DEPTH, StackOutputs};

use super::super::{
Assertion, EvaluationFrame, Felt, FieldElement, TransitionConstraintDegree, CLK_COL_IDX,
Expand All @@ -22,15 +22,15 @@ pub mod u32_ops;
// CONSTANTS
// ================================================================================================

const B0_COL_IDX: usize = STACK_TRACE_OFFSET + STACK_TOP_SIZE;
const B0_COL_IDX: usize = STACK_TRACE_OFFSET + MIN_STACK_DEPTH;
const B1_COL_IDX: usize = B0_COL_IDX + 1;
const H0_COL_IDX: usize = B1_COL_IDX + 1;

// --- Main constraints ---------------------------------------------------------------------------

/// The number of boundary constraints required by the Stack, which is all stack positions for
/// inputs and outputs as well as the initial values of the bookkeeping columns.
pub const NUM_ASSERTIONS: usize = 2 * STACK_TOP_SIZE + 2;
pub const NUM_ASSERTIONS: usize = 2 * MIN_STACK_DEPTH + 2;

/// The number of general constraints in the stack operations.
pub const NUM_GENERAL_CONSTRAINTS: usize = 17;
Expand Down Expand Up @@ -193,19 +193,19 @@ pub fn enforce_general_constraints<E: FieldElement>(
/// Returns the stack's boundary assertions for the main trace at the first step.
pub fn get_assertions_first_step(result: &mut Vec<Assertion<Felt>>, stack_inputs: &[Felt]) {
// stack columns at the first step should be set to stack inputs, excluding overflow inputs.
for (i, &value) in stack_inputs.iter().take(STACK_TOP_SIZE).enumerate() {
for (i, &value) in stack_inputs.iter().take(MIN_STACK_DEPTH).enumerate() {
result.push(Assertion::single(STACK_TRACE_OFFSET + i, 0, value));
}

// if there are remaining slots on top of the stack without specified values, set them to ZERO.
for i in stack_inputs.len()..STACK_TOP_SIZE {
for i in stack_inputs.len()..MIN_STACK_DEPTH {
result.push(Assertion::single(STACK_TRACE_OFFSET + i, 0, ZERO));
}

// get the initial values for the bookkeeping columns.
let mut depth = STACK_TOP_SIZE;
let mut depth = MIN_STACK_DEPTH;
let mut overflow_addr = ZERO;
if stack_inputs.len() > STACK_TOP_SIZE {
if stack_inputs.len() > MIN_STACK_DEPTH {
depth = stack_inputs.len();
overflow_addr = -ONE;
}
Expand All @@ -225,7 +225,7 @@ pub fn get_assertions_last_step(
stack_outputs: &StackOutputs,
) {
// stack columns at the last step should be set to stack outputs, excluding overflow outputs
for (i, value) in stack_outputs.stack().iter().enumerate() {
for (i, value) in stack_outputs.elements().iter().enumerate() {
result.push(Assertion::single(STACK_TRACE_OFFSET + i, step, *value));
}
}
Expand Down
2 changes: 1 addition & 1 deletion air/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ impl Air for ProcessorAir {
result.push(Assertion::single(FMP_COL_IDX, 0, Felt::new(2u64.pow(30))));

// add initial assertions for the stack.
stack::get_assertions_first_step(&mut result, self.stack_inputs.values());
stack::get_assertions_first_step(&mut result, self.stack_inputs.elements());

// Add initial assertions for the range checker.
range::get_assertions_first_step(&mut result);
Expand Down
2 changes: 1 addition & 1 deletion core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,4 +128,4 @@ pub mod utils;
// TYPE ALIASES
// ================================================================================================

pub type StackTopState = [Felt; stack::STACK_TOP_SIZE];
pub type StackTopState = [Felt; stack::MIN_STACK_DEPTH];
50 changes: 26 additions & 24 deletions core/src/stack/inputs.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
use alloc::vec::Vec;
use core::slice;

use super::{super::ZERO, ByteWriter, Felt, InputError, Serializable, ToElements, STACK_DEPTH};
use super::{
super::ZERO, get_stack_values_num, ByteWriter, Felt, InputError, Serializable, ToElements,
MIN_STACK_DEPTH,
};
use crate::utils::{ByteReader, Deserializable, DeserializationError};

// STACK INPUTS
// ================================================================================================

/// Initial state of the stack to support program execution.
/// Defines the initial state of the VM's operand stack.
///
/// The program execution expects the inputs to be a stack on the VM, and it will be stored in
/// reversed order on this struct.
/// The values in the struct are stored in the "stack order" - i.e., the last input is at the top
/// of the stack (in position 0).
#[derive(Clone, Debug, Default)]
pub struct StackInputs {
values: [Felt; STACK_DEPTH],
elements: [Felt; MIN_STACK_DEPTH],
}

impl StackInputs {
Expand All @@ -25,15 +28,13 @@ impl StackInputs {
/// # Errors
/// Returns an error if the number of input values exceeds the allowed maximum.
pub fn new(mut values: Vec<Felt>) -> Result<Self, InputError> {
if values.len() > STACK_DEPTH {
return Err(InputError::InputLengthExceeded(STACK_DEPTH, values.len()));
if values.len() > MIN_STACK_DEPTH {
return Err(InputError::InputLengthExceeded(MIN_STACK_DEPTH, values.len()));
}
values.reverse();
values.resize(MIN_STACK_DEPTH, ZERO);

let mut values_arr = [ZERO; STACK_DEPTH];
values.iter().enumerate().for_each(|(i, v)| values_arr[i] = *v);

Ok(Self { values: values_arr })
Ok(Self { elements: values.try_into().unwrap() })
}

/// Attempts to create stack inputs from an iterator of integers.
Expand All @@ -57,9 +58,9 @@ impl StackInputs {
// PUBLIC ACCESSORS
// --------------------------------------------------------------------------------------------

/// Returns the initial stack values in stack/reversed order.
pub fn values(&self) -> &[Felt] {
&self.values
/// Returns the initial stack elements in stack/reversed order.
pub fn elements(&self) -> &[Felt] {
&self.elements
}
}

Expand All @@ -68,7 +69,7 @@ impl<'a> IntoIterator for &'a StackInputs {
type IntoIter = slice::Iter<'a, Felt>;

fn into_iter(self) -> Self::IntoIter {
self.values.iter()
self.elements.iter()
}
}

Expand All @@ -77,13 +78,13 @@ impl IntoIterator for StackInputs {
type IntoIter = core::array::IntoIter<Felt, 16>;

fn into_iter(self) -> Self::IntoIter {
self.values.into_iter()
self.elements.into_iter()
}
}

impl ToElements<Felt> for StackInputs {
fn to_elements(&self) -> Vec<Felt> {
self.values.to_vec()
self.elements.to_vec()
}
}

Expand All @@ -92,17 +93,18 @@ impl ToElements<Felt> for StackInputs {

impl Serializable for StackInputs {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
debug_assert!(self.values.len() == STACK_DEPTH);
target.write_many(self.values);
target.write_u8(get_stack_values_num(self.elements()));
target.write_many(self.elements);
}
}

impl Deserializable for StackInputs {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
let values = source
.read_many::<Felt>(STACK_DEPTH)?
.try_into()
.expect("Invalid input stack depth: expected 16");
Ok(StackInputs { values })
let elements_num = source.read_u8()?;
let mut elements = source.read_many::<Felt>(elements_num.into())?;

elements.resize(MIN_STACK_DEPTH, ZERO);

Ok(StackInputs { elements: elements.try_into().unwrap() })
}
}
28 changes: 23 additions & 5 deletions core/src/stack/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,27 @@ pub use outputs::StackOutputs;
// CONSTANTS
// ================================================================================================

/// The number of stack registers which can be accessed by the VM directly. This is also the
/// minimum stack depth enforced by the VM.
pub const STACK_TOP_SIZE: usize = 16;
/// Represents:
/// - Number of elements that can be initialized at the start of execution and remain populated at
/// the end of execution.
/// - Number of elements that can be accessed directly via instructions.
/// - Number of elements that remain visible to the callee when the context is switched via `call`
/// or `syscall` instructions.
/// - Number of elements below which the depth of the stack never drops.
pub const MIN_STACK_DEPTH: usize = 16;

/// Maximum number of elements allowed for the input and output stack.
pub const STACK_DEPTH: usize = 16;
// HELPER FUNCTIONS
// ================================================================================================

/// Get the number of non-zero stack elements.
fn get_stack_values_num(values: &[Felt]) -> u8 {
let mut acc = 0;
for v in values.iter().rev() {
if v.as_int() == 0 {
acc += 1;
} else {
break;
}
}
(MIN_STACK_DEPTH - acc) as u8
}
52 changes: 25 additions & 27 deletions core/src/stack/outputs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ use alloc::vec::Vec;

use miden_crypto::{Word, ZERO};

use super::{ByteWriter, Felt, OutputError, Serializable, ToElements, STACK_DEPTH};
use super::{
get_stack_values_num, ByteWriter, Felt, OutputError, Serializable, ToElements, MIN_STACK_DEPTH,
};
use crate::utils::{range, ByteReader, Deserializable, DeserializationError};

// STACK OUTPUTS
Expand All @@ -17,8 +19,7 @@ use crate::utils::{range, ByteReader, Deserializable, DeserializationError};
/// of the rest of the output elements will also match the order on the stack.
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct StackOutputs {
/// The elements on the stack at the end of execution.
stack: [Felt; STACK_DEPTH],
elements: [Felt; MIN_STACK_DEPTH],
}

impl StackOutputs {
Expand All @@ -28,18 +29,15 @@ impl StackOutputs {
/// Constructs a new [StackOutputs] struct from the provided stack elements.
///
/// # Errors
/// Returns an error if the number of stack elements is greater than `STACK_DEPTH` (16).
pub fn new(stack: Vec<Felt>) -> Result<Self, OutputError> {
/// Returns an error if the number of stack elements is greater than `MIN_STACK_DEPTH` (16).
pub fn new(mut stack: Vec<Felt>) -> Result<Self, OutputError> {
// validate stack length
if stack.len() > STACK_DEPTH {
if stack.len() > MIN_STACK_DEPTH {
return Err(OutputError::OutputSizeTooBig(stack.len()));
}
stack.resize(MIN_STACK_DEPTH, ZERO);

let mut stack_arr = [ZERO; 16];
// pad stack to the `STACK_DEPTH`
stack.iter().enumerate().for_each(|(i, v)| stack_arr[i] = *v);

Ok(Self { stack: stack_arr })
Ok(Self { elements: stack.try_into().unwrap() })
}

/// Attempts to create [StackOutputs] struct from the provided stack elements represented as
Expand All @@ -65,7 +63,7 @@ impl StackOutputs {
/// Returns the element located at the specified position on the stack or `None` if out of
/// bounds.
pub fn get_stack_item(&self, idx: usize) -> Option<Felt> {
self.stack.get(idx).cloned()
self.elements.get(idx).cloned()
}

/// Returns the word located starting at the specified Felt position on the stack or `None` if
Expand All @@ -86,17 +84,16 @@ impl StackOutputs {
Some(word_elements)
}

/// Returns the stack outputs, which is state of the stack at the end of execution converted to
/// integers.
pub fn stack(&self) -> &[Felt] {
&self.stack
/// Returns the stack outputs, which is state of the stack at the end of execution.
pub fn elements(&self) -> &[Felt] {
&self.elements
}

/// Returns the number of requested stack outputs or returns the full stack if fewer than the
/// requested number of stack values exist.
pub fn stack_truncated(&self, num_outputs: usize) -> &[Felt] {
let len = self.stack.len().min(num_outputs);
&self.stack[..len]
let len = self.elements.len().min(num_outputs);
&self.elements[..len]
}

// PUBLIC MUTATORS
Expand All @@ -106,7 +103,7 @@ impl StackOutputs {
/// TODO: this should be marked with #[cfg(test)] attribute, but that currently won't work with
/// the integration test handler util.
pub fn stack_mut(&mut self) -> &mut [Felt] {
&mut self.stack
&mut self.elements
}
}

Expand All @@ -115,7 +112,7 @@ impl StackOutputs {

impl ToElements<Felt> for StackOutputs {
fn to_elements(&self) -> Vec<Felt> {
self.stack.to_vec()
self.elements.to_vec()
}
}

Expand All @@ -124,17 +121,18 @@ impl ToElements<Felt> for StackOutputs {

impl Serializable for StackOutputs {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
debug_assert!(self.stack.len() == STACK_DEPTH);
target.write_many(self.stack);
target.write_u8(get_stack_values_num(self.elements()));
target.write_many(self.elements);
}
}

impl Deserializable for StackOutputs {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
let stack = source
.read_many::<Felt>(STACK_DEPTH)?
.try_into()
.expect("Invalid output stack depth: expected 16");
Ok(Self { stack })
let elements_num = source.read_u8()?;
let mut elements = source.read_many::<Felt>(elements_num.into())?;

elements.resize(MIN_STACK_DEPTH, ZERO);

Ok(Self { elements: elements.try_into().unwrap() })
}
}
2 changes: 1 addition & 1 deletion miden/src/cli/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ impl OutputFile {
/// Returns a new [OutputFile] from the specified outputs vectors
pub fn new(stack_outputs: &StackOutputs) -> Self {
Self {
stack: stack_outputs.stack().iter().map(|&v| v.to_string()).collect::<Vec<String>>(),
stack: stack_outputs.elements().iter().map(|&v| v.to_string()).collect::<Vec<String>>(),
}
}

Expand Down
2 changes: 1 addition & 1 deletion miden/tests/integration/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ mod operations;

#[test]
fn simple_program() {
build_test!("begin push.1 push.2 add swap drop swap drop end").expect_stack(&[3]);
build_test!("begin push.1 push.2 add swap drop end").expect_stack(&[3]);
}

#[test]
Expand Down
6 changes: 3 additions & 3 deletions miden/tests/integration/operations/io_ops/env_ops.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use assembly::SourceManager;
use processor::FMP_MIN;
use test_utils::{build_op_test, build_test, StackInputs, Test, Word, STACK_TOP_SIZE};
use test_utils::{build_op_test, build_test, StackInputs, Test, Word, MIN_STACK_DEPTH};
use vm_core::{
mast::{MastForest, MastNode},
Operation,
Expand All @@ -15,11 +15,11 @@ fn sdepth() {

// --- empty stack ----------------------------------------------------------------------------
let test = build_op_test!(test_op);
test.expect_stack(&[STACK_TOP_SIZE as u64]);
test.expect_stack(&[MIN_STACK_DEPTH as u64]);

// --- multi-element stack --------------------------------------------------------------------
let test = build_op_test!(test_op, &[2, 4, 6, 8, 10]);
test.expect_stack(&[STACK_TOP_SIZE as u64, 10, 8, 6, 4, 2]);
test.expect_stack(&[MIN_STACK_DEPTH as u64, 10, 8, 6, 4, 2]);

// --- overflowed stack -----------------------------------------------------------------------
// push 2 values to increase the lenth of the stack beyond 16
Expand Down
Loading

0 comments on commit 2c23e12

Please sign in to comment.