Skip to content

Commit b85bfc2

Browse files
feat(new-execution): AdapterTraceStep trait and rv32 ALU refactor (#1589)
Co-authored-by: Alexander Golovanov <Golovanov12345@gmail.com>
1 parent 13d6234 commit b85bfc2

File tree

21 files changed

+1060
-962
lines changed

21 files changed

+1060
-962
lines changed

crates/vm/src/arch/execution.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,17 @@ use openvm_instructions::{
66
};
77
use openvm_stark_backend::{
88
interaction::{BusIndex, InteractionBuilder, PermutationCheckBus},
9-
p3_field::{FieldAlgebra, PrimeField32},
9+
p3_field::{Field, FieldAlgebra, PrimeField32},
1010
};
1111
use serde::{Deserialize, Serialize};
1212
use thiserror::Error;
1313

1414
use super::{Streams, VmExecutionState};
1515
use crate::system::{
16-
memory::{online::GuestMemory, MemoryController},
16+
memory::{
17+
online::{GuestMemory, TracingMemory},
18+
MemoryController,
19+
},
1720
program::ProgramBus,
1821
};
1922

@@ -82,6 +85,15 @@ pub struct VmStateMut<'a, MEM, CTX> {
8285
pub ctx: &'a mut CTX,
8386
}
8487

88+
impl<CTX> VmStateMut<'_, TracingMemory, CTX> {
89+
// TODO: store as u32 directly
90+
#[inline(always)]
91+
pub fn ins_start<F: Field>(&self, from_state: &mut ExecutionState<F>) {
92+
from_state.pc = F::from_canonical_u32(*self.pc);
93+
from_state.timestamp = F::from_canonical_u32(self.memory.timestamp);
94+
}
95+
}
96+
8597
// TODO: old
8698
pub trait InstructionExecutor<F> {
8799
/// Runtime execution of the instruction, if the instruction is owned by the

crates/vm/src/arch/integration_api.rs

Lines changed: 57 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -246,27 +246,27 @@ pub trait SingleTraceStep<F, CTX> {
246246
fn get_opcode_name(&self, opcode: usize) -> String;
247247
}
248248

249-
pub struct NewVmChipWrapper<F, AIR, C> {
249+
pub struct NewVmChipWrapper<F, AIR, STEP> {
250250
pub air: AIR,
251-
pub inner: C,
251+
pub step: STEP,
252252
pub trace_buffer: Vec<F>,
253253
width: usize,
254254
buffer_idx: usize,
255255
mem_helper: SharedMemoryHelper<F>,
256256
}
257257

258-
impl<F, AIR, C> NewVmChipWrapper<F, AIR, C>
258+
impl<F, AIR, STEP> NewVmChipWrapper<F, AIR, STEP>
259259
where
260260
F: Field,
261261
AIR: BaseAir<F>,
262262
{
263-
pub fn new(air: AIR, inner: C, height: usize, mem_helper: SharedMemoryHelper<F>) -> Self {
263+
pub fn new(air: AIR, step: STEP, height: usize, mem_helper: SharedMemoryHelper<F>) -> Self {
264264
assert!(height == 0 || height.is_power_of_two());
265265
let width = air.width();
266266
let trace_buffer = F::zero_vec(height * width);
267267
Self {
268268
air,
269-
inner,
269+
step,
270270
trace_buffer,
271271
width,
272272
buffer_idx: 0,
@@ -275,10 +275,10 @@ where
275275
}
276276
}
277277

278-
impl<F, Air, C> InstructionExecutor<F> for NewVmChipWrapper<F, Air, C>
278+
impl<F, AIR, STEP> InstructionExecutor<F> for NewVmChipWrapper<F, AIR, STEP>
279279
where
280280
F: PrimeField32,
281-
C: SingleTraceStep<F, ()>, // TODO: CTX?
281+
STEP: SingleTraceStep<F, ()>, // TODO: CTX?
282282
{
283283
fn execute(
284284
&mut self,
@@ -305,27 +305,27 @@ where
305305
self.trace_buffer
306306
.get_unchecked_mut(start_idx..self.buffer_idx)
307307
};
308-
self.inner.execute(state, instruction, row_slice)?;
308+
self.step.execute(state, instruction, row_slice)?;
309309
Ok(ExecutionState {
310310
pc,
311311
timestamp: memory.memory.timestamp,
312312
})
313313
}
314314

315315
fn get_opcode_name(&self, opcode: usize) -> String {
316-
self.inner.get_opcode_name(opcode)
316+
self.step.get_opcode_name(opcode)
317317
}
318318
}
319319

320320
// Note[jpw]: the statement we want is:
321321
// - `Air` is an `Air<AB>` for all `AB: AirBuilder`s needed by stark-backend
322322
// which is equivalent to saying it implements AirRef<SC>
323323
// The where clauses to achieve this statement is unfortunately really verbose.
324-
impl<SC, AIR, C> Chip<SC> for NewVmChipWrapper<Val<SC>, AIR, C>
324+
impl<SC, AIR, STEP> Chip<SC> for NewVmChipWrapper<Val<SC>, AIR, STEP>
325325
where
326326
SC: StarkGenericConfig,
327327
Val<SC>: PrimeField32,
328-
C: SingleTraceStep<Val<SC>, ()> + Send + Sync,
328+
STEP: SingleTraceStep<Val<SC>, ()> + Send + Sync,
329329
AIR: Clone + AnyRap<SC> + 'static,
330330
{
331331
fn air(&self) -> AirRef<SC> {
@@ -346,13 +346,13 @@ where
346346
self.trace_buffer[..rows_used * self.width]
347347
.par_chunks_exact_mut(self.width)
348348
.for_each(|row_slice| {
349-
self.inner.fill_trace_row(&mem_helper, row_slice);
349+
self.step.fill_trace_row(&mem_helper, row_slice);
350350
});
351351
drop(self.mem_helper);
352352
let trace = RowMajorMatrix::new(self.trace_buffer, self.width);
353353
// self.inner.finalize(&mut trace, num_records);
354354

355-
AirProofInput::simple(trace, self.inner.generate_public_values())
355+
AirProofInput::simple(trace, self.step.generate_public_values())
356356
}
357357
}
358358

@@ -371,6 +371,47 @@ where
371371
}
372372
}
373373

374+
// TODO[jpw]: switch read,write to store into abstract buffer, then fill_trace_row using buffer
375+
/// A helper trait for expressing generic state accesses within the implementation of
376+
/// [SingleTraceStep]. Note that this is only a helper trait when the same interface of state access
377+
/// is reused or shared by multiple implementations. It is not required to implement this trait if
378+
/// it is easier to implement the [SingleTraceStep] trait directly without this trait.
379+
pub trait AdapterTraceStep<F, CTX> {
380+
/// Adapter row width
381+
const WIDTH: usize;
382+
type ReadData;
383+
type WriteData;
384+
/// The minimal amount of information needed to generate the sub-row of the trace matrix.
385+
/// This type has a lifetime so other context, such as references to other chips, can be
386+
/// provided.
387+
type TraceContext<'a>
388+
where
389+
Self: 'a;
390+
391+
fn start(pc: u32, memory: &TracingMemory, adapter_row: &mut [F]);
392+
393+
fn read(
394+
memory: &mut TracingMemory,
395+
instruction: &Instruction<F>,
396+
adapter_row: &mut [F],
397+
) -> Self::ReadData;
398+
399+
fn write(
400+
memory: &mut TracingMemory,
401+
instruction: &Instruction<F>,
402+
adapter_row: &mut [F],
403+
data: &Self::WriteData,
404+
);
405+
406+
// Note[jpw]: should we reuse TraceSubRowGenerator trait instead?
407+
/// Post-execution filling of rest of adapter row.
408+
fn fill_trace_row(
409+
mem_helper: &MemoryAuxColsFactory<F>,
410+
ctx: Self::TraceContext<'_>,
411+
adapter_row: &mut [F],
412+
);
413+
}
414+
374415
pub struct VmChipWrapper<F, A: VmAdapterChip<F>, C: VmCoreChip<F, A::Interface>> {
375416
pub adapter: A,
376417
pub core: C,
@@ -440,18 +481,18 @@ where
440481
}
441482
}
442483

443-
impl<Mem, Ctx, F, A, C> InsExecutorE1<Mem, Ctx, F> for NewVmChipWrapper<F, A, C>
484+
impl<Mem, Ctx, F, A, S> InsExecutorE1<Mem, Ctx, F> for NewVmChipWrapper<F, A, S>
444485
where
445486
Mem: GuestMemory,
446487
F: PrimeField32,
447-
C: InsExecutorE1<Mem, Ctx, F>,
488+
S: InsExecutorE1<Mem, Ctx, F>,
448489
{
449490
fn execute_e1(
450491
&mut self,
451492
state: &mut VmExecutionState<Mem, Ctx>,
452493
instruction: &Instruction<F>,
453494
) -> Result<()> {
454-
self.inner.execute_e1(state, instruction)
495+
self.step.execute_e1(state, instruction)
455496
}
456497
}
457498

crates/vm/src/system/memory/offline_checker/columns.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ impl<F: PrimeField32> MemoryReadAuxCols<F> {
8888
pub fn get_base(self) -> MemoryBaseAuxCols<F> {
8989
self.base
9090
}
91+
92+
/// Sets the previous timestamp **without** updating the less than auxiliary columns.
93+
pub fn set_prev(&mut self, timestamp: F) {
94+
self.base.prev_timestamp = timestamp;
95+
}
9196
}
9297

9398
#[repr(C)]
@@ -114,3 +119,9 @@ impl<T, const N: usize> AsMut<MemoryBaseAuxCols<T>> for MemoryWriteAuxCols<T, N>
114119
&mut self.base
115120
}
116121
}
122+
123+
impl<T> AsMut<MemoryBaseAuxCols<T>> for MemoryReadAuxCols<T> {
124+
fn as_mut(&mut self) -> &mut MemoryBaseAuxCols<T> {
125+
&mut self.base
126+
}
127+
}

0 commit comments

Comments
 (0)