Skip to content

Commit e5575a0

Browse files
leonardoaltlvella
andauthored
const32 (#15)
* const32 * fix opcode * ignore Nones * Supporting other const types. * fix limbs of const32 * add const tests --------- Co-authored-by: Lucas Clemente Vella <lvella@powdrlabs.com>
1 parent 2d5b552 commit e5575a0

File tree

10 files changed

+529
-15
lines changed

10 files changed

+529
-15
lines changed
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
use std::{
2+
borrow::{Borrow, BorrowMut},
3+
marker::PhantomData,
4+
};
5+
6+
use openvm_circuit::{
7+
arch::{
8+
AdapterAirContext, BasicAdapterInterface, ExecutionBridge, ExecutionBus, ExecutionState,
9+
MinimalInstruction, Result, VmAdapterAir, VmAdapterInterface,
10+
},
11+
system::{
12+
memory::{
13+
offline_checker::{MemoryBridge, MemoryReadAuxCols, MemoryWriteAuxCols},
14+
MemoryController, OfflineMemory, RecordId,
15+
},
16+
program::ProgramBus,
17+
},
18+
};
19+
use openvm_circuit_primitives_derive::AlignedBorrow;
20+
use openvm_instructions::{instruction::Instruction, program::DEFAULT_PC_STEP};
21+
use openvm_stark_backend::{
22+
interaction::InteractionBuilder,
23+
p3_air::BaseAir,
24+
p3_field::{Field, PrimeField32},
25+
rap::ColumnsAir,
26+
};
27+
use serde::{Deserialize, Serialize};
28+
use struct_reflection::{StructReflection, StructReflectionHelper};
29+
30+
use crate::{AdapterRuntimeContextWom, FrameBus, FrameState, VmAdapterChipWom};
31+
32+
use super::{decompose, RV32_REGISTER_NUM_LIMBS};
33+
34+
#[derive(Debug)]
35+
pub struct ConstsAdapterChipWom<F: Field> {
36+
pub air: ConstsAdapterAirWom,
37+
_marker: PhantomData<F>,
38+
}
39+
40+
impl<F: PrimeField32> ConstsAdapterChipWom<F> {
41+
pub fn new(
42+
execution_bus: ExecutionBus,
43+
program_bus: ProgramBus,
44+
frame_bus: FrameBus,
45+
memory_bridge: MemoryBridge,
46+
) -> Self {
47+
Self {
48+
air: ConstsAdapterAirWom {
49+
_execution_bridge: ExecutionBridge::new(execution_bus, program_bus),
50+
_frame_bus: frame_bus,
51+
_memory_bridge: memory_bridge,
52+
},
53+
_marker: PhantomData,
54+
}
55+
}
56+
}
57+
58+
#[repr(C)]
59+
#[derive(Debug, Clone, Serialize, Deserialize)]
60+
pub struct ConstsWriteRecord {
61+
pub from_state: ExecutionState<u32>,
62+
pub from_frame: FrameState<u32>,
63+
pub rd: u32,
64+
pub rd_id: Option<RecordId>,
65+
}
66+
67+
#[repr(C)]
68+
#[derive(Debug, Clone, AlignedBorrow, StructReflection)]
69+
pub struct ConstsAdapterColsWom<T> {
70+
pub from_state: ExecutionState<T>,
71+
pub from_frame: FrameState<T>,
72+
pub offset_within_frame: T, // rd - the offset within the frame
73+
pub value_reg_ptr: T, // rs1 pointer (register containing value to copy)
74+
pub value_reg_aux_cols: MemoryReadAuxCols<T>,
75+
pub frame_ptr_reg_ptr: T, // rs2 pointer (register containing frame pointer)
76+
pub frame_ptr_reg_aux_cols: MemoryReadAuxCols<T>,
77+
pub destination_ptr: T, // Where we write: frame_pointer + offset
78+
pub destination_aux_cols: MemoryWriteAuxCols<T, RV32_REGISTER_NUM_LIMBS>,
79+
/// 1 if we need to write to destination
80+
pub needs_write: T,
81+
}
82+
83+
#[derive(Clone, Copy, Debug, derive_new::new)]
84+
pub struct ConstsAdapterAirWom {
85+
pub(super) _memory_bridge: MemoryBridge,
86+
pub(super) _execution_bridge: ExecutionBridge,
87+
pub(super) _frame_bus: FrameBus,
88+
}
89+
90+
impl<F: Field> BaseAir<F> for ConstsAdapterAirWom {
91+
fn width(&self) -> usize {
92+
ConstsAdapterColsWom::<F>::width()
93+
}
94+
}
95+
96+
impl<F: Field> ColumnsAir<F> for ConstsAdapterAirWom {
97+
fn columns(&self) -> Option<Vec<String>> {
98+
ConstsAdapterColsWom::<F>::struct_reflection()
99+
}
100+
}
101+
102+
impl<AB: InteractionBuilder> VmAdapterAir<AB> for ConstsAdapterAirWom {
103+
type Interface = BasicAdapterInterface<AB::Expr, MinimalInstruction<AB::Expr>, 0, 0, 0, 0>;
104+
105+
fn eval(
106+
&self,
107+
_builder: &mut AB,
108+
_local: &[AB::Var],
109+
_ctx: AdapterAirContext<AB::Expr, Self::Interface>,
110+
) {
111+
// Empty eval function as requested
112+
}
113+
114+
fn get_from_pc(&self, local: &[AB::Var]) -> AB::Var {
115+
let cols: &ConstsAdapterColsWom<_> = local.borrow();
116+
cols.from_state.pc
117+
}
118+
}
119+
120+
impl<F: PrimeField32> VmAdapterChipWom<F> for ConstsAdapterChipWom<F> {
121+
type ReadRecord = ();
122+
type WriteRecord = ConstsWriteRecord;
123+
type Air = ConstsAdapterAirWom;
124+
type Interface = BasicAdapterInterface<
125+
F,
126+
MinimalInstruction<F>,
127+
0,
128+
1,
129+
RV32_REGISTER_NUM_LIMBS,
130+
RV32_REGISTER_NUM_LIMBS,
131+
>;
132+
133+
fn preprocess(
134+
&mut self,
135+
_memory: &mut MemoryController<F>,
136+
_fp: u32,
137+
_instruction: &Instruction<F>,
138+
) -> Result<(
139+
<Self::Interface as VmAdapterInterface<F>>::Reads,
140+
Self::ReadRecord,
141+
)> {
142+
Ok(([], ()))
143+
}
144+
145+
fn postprocess(
146+
&mut self,
147+
memory: &mut MemoryController<F>,
148+
instruction: &Instruction<F>,
149+
from_state: ExecutionState<u32>,
150+
from_frame: FrameState<u32>,
151+
_output: AdapterRuntimeContextWom<F, Self::Interface>,
152+
_read_record: &Self::ReadRecord,
153+
) -> Result<(ExecutionState<u32>, u32, Self::WriteRecord)> {
154+
let Instruction {
155+
a,
156+
b,
157+
c,
158+
f: enabled,
159+
..
160+
} = *instruction;
161+
162+
let mut destination_id = None;
163+
164+
if enabled != F::ZERO {
165+
let imm_lo = b.as_canonical_u32();
166+
let imm_hi = c.as_canonical_u32();
167+
assert!(
168+
imm_lo < (1 << 16) && imm_hi < (1 << 16),
169+
"Immediate values out of range",
170+
);
171+
let imm = imm_hi << 16 | imm_lo;
172+
let fp_f = F::from_canonical_u32(from_frame.fp);
173+
let write_result = memory.write(F::ONE, a + fp_f, decompose(imm));
174+
destination_id = Some(write_result.0);
175+
}
176+
177+
Ok((
178+
ExecutionState {
179+
pc: from_state.pc + DEFAULT_PC_STEP,
180+
timestamp: memory.timestamp(),
181+
},
182+
from_frame.fp,
183+
Self::WriteRecord {
184+
from_state,
185+
from_frame,
186+
rd: a.as_canonical_u32(),
187+
rd_id: destination_id,
188+
},
189+
))
190+
}
191+
192+
fn generate_trace_row(
193+
&self,
194+
row_slice: &mut [F],
195+
_read_record: Self::ReadRecord,
196+
write_record: Self::WriteRecord,
197+
memory: &OfflineMemory<F>,
198+
) {
199+
let aux_cols_factory = memory.aux_cols_factory();
200+
let adapter_cols: &mut ConstsAdapterColsWom<_> = row_slice.borrow_mut();
201+
202+
adapter_cols.from_state = write_record.from_state.map(F::from_canonical_u32);
203+
adapter_cols.from_frame = write_record.from_frame.map(F::from_canonical_u32);
204+
adapter_cols.offset_within_frame = F::from_canonical_u32(write_record.rd);
205+
206+
// Handle destination write
207+
if let Some(dest_id) = write_record.rd_id {
208+
let dest_record = memory.record_by_id(dest_id);
209+
adapter_cols.destination_ptr = dest_record.pointer;
210+
adapter_cols.needs_write = F::ONE;
211+
aux_cols_factory
212+
.generate_write_aux(dest_record, &mut adapter_cols.destination_aux_cols);
213+
} else {
214+
adapter_cols.needs_write = F::ZERO;
215+
}
216+
}
217+
218+
fn air(&self) -> &Self::Air {
219+
&self.air
220+
}
221+
}

extensions/circuit/src/adapters/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use openvm_stark_backend::p3_field::{FieldAlgebra, PrimeField32};
66
mod allocate_frame;
77
mod alu;
88
mod branch;
9+
mod consts;
910
mod copy_into_frame;
1011
mod jaaf;
1112
mod jalr;
@@ -17,6 +18,7 @@ mod rdwrite;
1718
pub use allocate_frame::*;
1819
pub use alu::*;
1920
pub use branch::*;
21+
pub use consts::*;
2022
pub use copy_into_frame::*;
2123
pub use jaaf::*;
2224
pub use jalr::*;
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
use std::borrow::Borrow;
2+
3+
use openvm_circuit::arch::{
4+
AdapterAirContext, MinimalInstruction, Result, VmAdapterInterface, VmCoreAir,
5+
};
6+
use openvm_circuit_primitives_derive::AlignedBorrow;
7+
use openvm_instructions::{instruction::Instruction, LocalOpcode};
8+
use openvm_stark_backend::{
9+
interaction::InteractionBuilder,
10+
p3_air::BaseAir,
11+
p3_field::{Field, FieldAlgebra, PrimeField32},
12+
rap::{BaseAirWithPublicValues, ColumnsAir},
13+
};
14+
use openvm_womir_transpiler::ConstOpcodes;
15+
use struct_reflection::{StructReflection, StructReflectionHelper};
16+
17+
use crate::{AdapterRuntimeContextWom, VmCoreChipWom};
18+
19+
use crate::adapters::RV32_REGISTER_NUM_LIMBS;
20+
21+
#[repr(C)]
22+
#[derive(Debug, Clone, AlignedBorrow, StructReflection)]
23+
pub struct ConstsCoreCols<T> {
24+
pub is_valid: T,
25+
}
26+
27+
#[derive(Debug, Clone)]
28+
pub struct ConstsCoreAir {}
29+
30+
impl<F: Field> BaseAir<F> for ConstsCoreAir {
31+
fn width(&self) -> usize {
32+
ConstsCoreCols::<F>::width()
33+
}
34+
}
35+
36+
impl<F: Field> ColumnsAir<F> for ConstsCoreAir {
37+
fn columns(&self) -> Option<Vec<String>> {
38+
ConstsCoreCols::<F>::struct_reflection()
39+
}
40+
}
41+
42+
impl<F: Field> BaseAirWithPublicValues<F> for ConstsCoreAir {}
43+
44+
impl<AB, I> VmCoreAir<AB, I> for ConstsCoreAir
45+
where
46+
AB: InteractionBuilder,
47+
I: VmAdapterInterface<AB::Expr>,
48+
I::Reads: From<[[AB::Expr; 0]; 0]>,
49+
I::Writes: From<[[AB::Expr; 0]; 0]>,
50+
I::ProcessedInstruction: From<MinimalInstruction<AB::Expr>>,
51+
{
52+
fn eval(
53+
&self,
54+
_builder: &mut AB,
55+
local_core: &[AB::Var],
56+
_from_pc: AB::Var,
57+
) -> AdapterAirContext<AB::Expr, I> {
58+
let core_cols: &ConstsCoreCols<_> = local_core.borrow();
59+
60+
let opcode = VmCoreAir::<AB, I>::expr_to_global_expr(
61+
self,
62+
AB::Expr::from_canonical_usize(ConstOpcodes::CONST32 as usize),
63+
);
64+
65+
AdapterAirContext {
66+
to_pc: None,
67+
reads: [].into(),
68+
writes: [].into(),
69+
instruction: MinimalInstruction {
70+
is_valid: core_cols.is_valid.into(),
71+
opcode,
72+
}
73+
.into(),
74+
}
75+
}
76+
77+
fn start_offset(&self) -> usize {
78+
ConstOpcodes::CLASS_OFFSET
79+
}
80+
}
81+
82+
pub struct ConstsCoreChipWom {
83+
pub air: ConstsCoreAir,
84+
}
85+
86+
impl ConstsCoreChipWom {
87+
pub fn new() -> Self {
88+
Self {
89+
air: ConstsCoreAir {},
90+
}
91+
}
92+
}
93+
94+
impl Default for ConstsCoreChipWom {
95+
fn default() -> Self {
96+
Self::new()
97+
}
98+
}
99+
100+
impl<F: PrimeField32, I: VmAdapterInterface<F>> VmCoreChipWom<F, I> for ConstsCoreChipWom
101+
where
102+
I::Reads: Into<[[F; RV32_REGISTER_NUM_LIMBS]; 0]>,
103+
I::Writes: From<[[F; RV32_REGISTER_NUM_LIMBS]; 1]>,
104+
{
105+
type Record = ();
106+
type Air = ConstsCoreAir;
107+
108+
#[allow(clippy::type_complexity)]
109+
fn execute_instruction(
110+
&self,
111+
_instruction: &Instruction<F>,
112+
_from_pc: u32,
113+
_from_fp: u32,
114+
_reads: I::Reads,
115+
) -> Result<(AdapterRuntimeContextWom<F, I>, Self::Record)> {
116+
let output = AdapterRuntimeContextWom {
117+
to_pc: None,
118+
to_fp: None,
119+
writes: [[F::ZERO; 4]].into(),
120+
};
121+
122+
Ok((output, ()))
123+
}
124+
125+
fn get_opcode_name(&self, opcode: usize) -> String {
126+
format!("CONSTS_{}", opcode - ConstOpcodes::CLASS_OFFSET)
127+
}
128+
129+
fn generate_trace_row(&self, _row_slice: &mut [F], _record: Self::Record) {}
130+
131+
fn air(&self) -> &Self::Air {
132+
&self.air
133+
}
134+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
mod core;
2+
3+
use crate::adapters::ConstsAdapterChipWom;
4+
pub use core::ConstsCoreChipWom;
5+
6+
pub type ConstsChipWom<F> =
7+
crate::wom_traits::VmChipWrapperWom<F, ConstsAdapterChipWom<F>, ConstsCoreChipWom>;

0 commit comments

Comments
 (0)