Skip to content

Commit 262f3cd

Browse files
authored
vm: reorg memory (#19)
1 parent c402569 commit 262f3cd

File tree

5 files changed

+182
-177
lines changed

5 files changed

+182
-177
lines changed

crates/vm/src/bytecode/operand.rs

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::{
55

66
use p3_field::PrimeCharacteristicRing;
77

8-
use crate::F;
8+
use crate::{F, Memory, RunnerError};
99

1010
/// Represents a value that can either be a constant or a value from memory.
1111
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -50,6 +50,27 @@ impl MemOrConstant {
5050
}
5151
}
5252

53+
impl MemOrConstant {
54+
pub fn read_value(&self, memory: &Memory, fp: usize) -> Result<F, RunnerError> {
55+
match self {
56+
Self::Constant(c) => Ok(*c),
57+
Self::MemoryAfterFp { offset } => memory.get(fp + *offset),
58+
}
59+
}
60+
61+
#[must_use]
62+
pub fn is_value_unknown(&self, memory: &Memory, fp: usize) -> bool {
63+
self.read_value(memory, fp).is_err()
64+
}
65+
66+
pub const fn memory_address(&self, fp: usize) -> Result<usize, RunnerError> {
67+
match self {
68+
Self::Constant(_) => Err(RunnerError::NotAPointer),
69+
Self::MemoryAfterFp { offset } => Ok(fp + *offset),
70+
}
71+
}
72+
}
73+
5374
impl Display for MemOrConstant {
5475
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
5576
match self {
@@ -73,6 +94,28 @@ pub enum MemOrFpOrConstant {
7394
Constant(F),
7495
}
7596

97+
impl MemOrFpOrConstant {
98+
pub fn read_value(&self, memory: &Memory, fp: usize) -> Result<F, RunnerError> {
99+
match self {
100+
Self::MemoryAfterFp { offset } => memory.get(fp + *offset),
101+
Self::Fp => Ok(F::from_usize(fp)),
102+
Self::Constant(c) => Ok(*c),
103+
}
104+
}
105+
106+
#[must_use]
107+
pub fn is_value_unknown(&self, memory: &Memory, fp: usize) -> bool {
108+
self.read_value(memory, fp).is_err()
109+
}
110+
111+
pub const fn memory_address(&self, fp: usize) -> Result<usize, RunnerError> {
112+
match self {
113+
Self::MemoryAfterFp { offset } => Ok(fp + *offset),
114+
Self::Fp | Self::Constant(_) => Err(RunnerError::NotAPointer),
115+
}
116+
}
117+
}
118+
76119
impl Display for MemOrFpOrConstant {
77120
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
78121
match self {
@@ -112,6 +155,27 @@ impl MemOrFp {
112155
}
113156
}
114157

158+
impl MemOrFp {
159+
pub fn read_value(&self, memory: &Memory, fp: usize) -> Result<F, RunnerError> {
160+
match self {
161+
Self::MemoryAfterFp { offset } => memory.get(fp + *offset),
162+
Self::Fp => Ok(F::from_usize(fp)),
163+
}
164+
}
165+
166+
#[must_use]
167+
pub fn is_value_unknown(&self, memory: &Memory, fp: usize) -> bool {
168+
self.read_value(memory, fp).is_err()
169+
}
170+
171+
pub const fn memory_address(&self, fp: usize) -> Result<usize, RunnerError> {
172+
match self {
173+
Self::MemoryAfterFp { offset } => Ok(fp + *offset),
174+
Self::Fp => Err(RunnerError::NotAPointer),
175+
}
176+
}
177+
}
178+
115179
impl Display for MemOrFp {
116180
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
117181
match self {

crates/vm/src/error.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
use thiserror::Error;
2+
3+
use crate::F;
4+
5+
#[derive(Debug, Clone, Error)]
6+
pub enum RunnerError {
7+
#[error("Out of memory")]
8+
OutOfMemory,
9+
#[error("Memory already set")]
10+
MemoryAlreadySet,
11+
#[error("Not a pointer")]
12+
NotAPointer,
13+
#[error("Division by zero")]
14+
DivByZero,
15+
#[error("Computation invalid: {0} != {1}")]
16+
NotEqual(F, F),
17+
#[error("Undefined memory access")]
18+
UndefinedMemory,
19+
#[error("Program counter out of bounds")]
20+
PCOutOfBounds,
21+
}

crates/vm/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@ use p3_field::extension::BinomialExtensionField;
22
use p3_koala_bear::KoalaBear;
33

44
mod bytecode;
5+
mod error;
6+
mod memory;
57
mod runner;
68
pub use bytecode::*;
9+
pub use error::*;
10+
pub use memory::*;
711
pub use runner::*;
812

913
pub const DIMENSION: usize = 8;

crates/vm/src/memory.rs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
use p3_field::{BasedVectorSpace, ExtensionField};
2+
use rayon::prelude::*;
3+
4+
use crate::{DIMENSION, EF, F, RunnerError};
5+
6+
pub(crate) const MAX_MEMORY_SIZE: usize = 1 << 23;
7+
8+
#[derive(Debug, Clone, Default)]
9+
pub struct Memory(pub Vec<Option<F>>);
10+
11+
impl Memory {
12+
pub fn new(public_memory: Vec<F>) -> Self {
13+
Self(public_memory.into_par_iter().map(Some).collect())
14+
}
15+
16+
pub fn get(&self, index: usize) -> Result<F, RunnerError> {
17+
self.0
18+
.get(index)
19+
.copied()
20+
.flatten()
21+
.ok_or(RunnerError::UndefinedMemory)
22+
}
23+
24+
pub fn set(&mut self, index: usize, value: F) -> Result<(), RunnerError> {
25+
if index >= self.0.len() {
26+
if index >= MAX_MEMORY_SIZE {
27+
return Err(RunnerError::OutOfMemory);
28+
}
29+
self.0.resize(index + 1, None);
30+
}
31+
if let Some(existing) = &mut self.0[index] {
32+
if *existing != value {
33+
return Err(RunnerError::MemoryAlreadySet);
34+
}
35+
} else {
36+
self.0[index] = Some(value);
37+
}
38+
Ok(())
39+
}
40+
41+
pub fn get_vector(&self, index: usize) -> Result<[F; DIMENSION], RunnerError> {
42+
Ok(self.get_vectorized_slice(index, 1)?.try_into().unwrap())
43+
}
44+
45+
pub fn get_extension(&self, index: usize) -> Result<EF, RunnerError> {
46+
Ok(EF::from_basis_coefficients_slice(&self.get_vector(index)?).unwrap())
47+
}
48+
49+
pub fn get_vectorized_slice(&self, index: usize, len: usize) -> Result<Vec<F>, RunnerError> {
50+
let mut vector = Vec::with_capacity(len * DIMENSION);
51+
for i in 0..len * DIMENSION {
52+
vector.push(self.get(index * DIMENSION + i)?);
53+
}
54+
Ok(vector)
55+
}
56+
57+
pub fn get_vectorized_slice_extension<EF: ExtensionField<F>>(
58+
&self,
59+
index: usize,
60+
len: usize,
61+
) -> Result<Vec<EF>, RunnerError> {
62+
let mut vector = Vec::with_capacity(len);
63+
for i in 0..len {
64+
let v = self.get_vector(index + i)?;
65+
vector.push(EF::from_basis_coefficients_slice(&v).unwrap());
66+
}
67+
Ok(vector)
68+
}
69+
70+
pub fn slice(&self, index: usize, len: usize) -> Result<Vec<F>, RunnerError> {
71+
(0..len).map(|i| self.get(index + i)).collect()
72+
}
73+
74+
pub fn set_vector(&mut self, index: usize, value: [F; DIMENSION]) -> Result<(), RunnerError> {
75+
value
76+
.iter()
77+
.enumerate()
78+
.try_for_each(|(i, &v)| self.set(index * DIMENSION + i, v))
79+
}
80+
81+
pub fn set_vectorized_slice(&mut self, index: usize, value: &[F]) -> Result<(), RunnerError> {
82+
assert!(value.len().is_multiple_of(DIMENSION));
83+
value
84+
.iter()
85+
.enumerate()
86+
.try_for_each(|(i, &v)| self.set(index * DIMENSION + i, v))
87+
}
88+
}

0 commit comments

Comments
 (0)