Skip to content

Commit 41c2b4b

Browse files
perf: remove step from Program (#1897)
We always use `DEFAULT_PC_STEP = 4` and this can lead to slightly better compiler optimizations. closes INT-4385 comparison: https://github.com/axiom-crypto/openvm-reth-benchmark/actions/runs/16510779617 (6% on E1)
1 parent 32ffd88 commit 41c2b4b

File tree

9 files changed

+33
-46
lines changed

9 files changed

+33
-46
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ All notable changes to OpenVM will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project follows a versioning principles documented in [VERSIONING.md](./VERSIONING.md).
77

8+
## [Unreleased]
9+
10+
### Changed
11+
- (Toolchain) Removed `step` from `Program` struct because `DEFAULT_PC_STEP = 4` is always used.
12+
813
## v1.3.0 (2025-07-15)
914

1015
No circuit constraints or verifying keys were changed in this release.

crates/toolchain/instructions/src/program.rs

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,52 +28,42 @@ pub struct Program<F> {
2828
deserialize_with = "deserialize_instructions_and_debug_infos"
2929
)]
3030
pub instructions_and_debug_infos: Vec<Option<(Instruction<F>, Option<DebugInfo>)>>,
31-
pub step: u32,
3231
pub pc_base: u32,
3332
}
3433

3534
#[derive(Clone, Debug, Default)]
3635
pub struct ProgramDebugInfo {
3736
inner: Arc<Vec<Option<DebugInfo>>>,
3837
pc_base: u32,
39-
step: u32,
4038
}
4139

4240
impl<F: Field> Program<F> {
43-
pub fn new_empty(step: u32, pc_base: u32) -> Self {
41+
pub fn new_empty(pc_base: u32) -> Self {
4442
Self {
4543
instructions_and_debug_infos: vec![],
46-
step,
4744
pc_base,
4845
}
4946
}
5047

51-
pub fn new_without_debug_infos(
52-
instructions: &[Instruction<F>],
53-
step: u32,
54-
pc_base: u32,
55-
) -> Self {
48+
pub fn new_without_debug_infos(instructions: &[Instruction<F>], pc_base: u32) -> Self {
5649
Self {
5750
instructions_and_debug_infos: instructions
5851
.iter()
5952
.map(|instruction| Some((instruction.clone(), None)))
6053
.collect(),
61-
step,
6254
pc_base,
6355
}
6456
}
6557

6658
pub fn new_without_debug_infos_with_option(
6759
instructions: &[Option<Instruction<F>>],
68-
step: u32,
6960
pc_base: u32,
7061
) -> Self {
7162
Self {
7263
instructions_and_debug_infos: instructions
7364
.iter()
7465
.map(|instruction| instruction.clone().map(|instruction| (instruction, None)))
7566
.collect(),
76-
step,
7767
pc_base,
7868
}
7969
}
@@ -90,7 +80,6 @@ impl<F: Field> Program<F> {
9080
.zip_eq(debug_infos.iter())
9181
.map(|(instruction, debug_info)| Some((instruction.clone(), debug_info.clone())))
9282
.collect(),
93-
step: DEFAULT_PC_STEP,
9483
pc_base: 0,
9584
}
9685
}
@@ -107,7 +96,7 @@ impl<F: Field> Program<F> {
10796
}
10897

10998
pub fn from_instructions(instructions: &[Instruction<F>]) -> Self {
110-
Self::new_without_debug_infos(instructions, DEFAULT_PC_STEP, 0)
99+
Self::new_without_debug_infos(instructions, 0)
111100
}
112101

113102
pub fn len(&self) -> usize {
@@ -138,7 +127,7 @@ impl<F: Field> Program<F> {
138127
.flat_map(|(index, option)| {
139128
option.clone().map(|(instruction, debug_info)| {
140129
(
141-
self.pc_base + (self.step * (index as u32)),
130+
self.pc_base + (DEFAULT_PC_STEP * (index as u32)),
142131
instruction,
143132
debug_info,
144133
)
@@ -186,7 +175,6 @@ impl<F> Program<F> {
186175
ProgramDebugInfo {
187176
inner: Arc::new(debug_infos),
188177
pc_base: self.pc_base,
189-
step: self.step,
190178
}
191179
}
192180
}
@@ -218,9 +206,8 @@ impl ProgramDebugInfo {
218206
/// ## Panics
219207
/// If `pc` is out of bounds.
220208
pub fn get(&self, pc: u32) -> &Option<DebugInfo> {
221-
let step = self.step;
222209
let pc_base = self.pc_base;
223-
let pc_idx = ((pc - pc_base) / step) as usize;
210+
let pc_idx = ((pc - pc_base) / DEFAULT_PC_STEP) as usize;
224211
&self.inner[pc_idx]
225212
}
226213
}
@@ -295,7 +282,7 @@ mod tests {
295282

296283
#[test]
297284
fn test_program_serde() {
298-
let mut program = Program::<F>::new_empty(4, 0);
285+
let mut program = Program::<F>::new_empty(0);
299286
program.instructions_and_debug_infos.push(Some((
300287
Instruction::from_isize(VmOpcode::from_usize(113), 1, 2, 3, 4, 5),
301288
None,

crates/toolchain/transpiler/src/lib.rs

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
//! A transpiler from custom RISC-V ELFs to OpenVM executable binaries.
22
33
use elf::Elf;
4-
use openvm_instructions::{
5-
exe::VmExe,
6-
program::{Program, DEFAULT_PC_STEP},
7-
};
4+
use openvm_instructions::{exe::VmExe, program::Program};
85
pub use openvm_platform;
96
use openvm_stark_backend::p3_field::PrimeField32;
107
use transpiler::{Transpiler, TranspilerError};
@@ -29,11 +26,7 @@ impl<F: PrimeField32> FromElf for VmExe<F> {
2926
type ElfContext = Transpiler<F>;
3027
fn from_elf(elf: Elf, transpiler: Self::ElfContext) -> Result<Self, TranspilerError> {
3128
let instructions = transpiler.transpile(&elf.instructions)?;
32-
let program = Program::new_without_debug_infos_with_option(
33-
&instructions,
34-
DEFAULT_PC_STEP,
35-
elf.pc_base,
36-
);
29+
let program = Program::new_without_debug_infos_with_option(&instructions, elf.pc_base);
3730
let init_memory = elf_memory_image_to_openvm_memory_image(elf.memory_image);
3831

3932
Ok(VmExe {

crates/vm/src/arch/execution.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,9 @@ pub type Result<T> = std::result::Result<T, ExecutionError>;
2828
pub enum ExecutionError {
2929
#[error("execution failed at pc {pc}")]
3030
Fail { pc: u32 },
31-
#[error("pc {pc} out of bounds for program of length {program_len}, with pc_base {pc_base} and step = {step}")]
31+
#[error("pc {pc} out of bounds for program of length {program_len}, with pc_base {pc_base}")]
3232
PcOutOfBounds {
3333
pc: u32,
34-
step: u32,
3534
pc_base: u32,
3635
program_len: usize,
3736
},

crates/vm/src/arch/interpreter.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ use std::{
77
use itertools::Itertools;
88
use openvm_circuit_primitives_derive::AlignedBytesBorrow;
99
use openvm_instructions::{
10-
exe::VmExe, instruction::Instruction, program::Program, LocalOpcode, SystemOpcode,
10+
exe::VmExe,
11+
instruction::Instruction,
12+
program::{Program, DEFAULT_PC_STEP},
13+
LocalOpcode, SystemOpcode,
1114
};
1215
use openvm_stark_backend::p3_field::{Field, PrimeField32};
1316
use rand::{rngs::StdRng, SeedableRng};
@@ -233,13 +236,11 @@ unsafe fn execute_impl<F: PrimeField32, Ctx: E1ExecutionCtx>(
233236
}
234237

235238
fn get_pc_index<F: Field>(program: &Program<F>, pc: u32) -> Result<usize, ExecutionError> {
236-
let step = program.step;
237239
let pc_base = program.pc_base;
238-
let pc_index = ((pc - pc_base) / step) as usize;
240+
let pc_index = ((pc - pc_base) / DEFAULT_PC_STEP) as usize;
239241
if !(0..program.len()).contains(&pc_index) {
240242
return Err(ExecutionError::PcOutOfBounds {
241243
pc,
242-
step,
243244
pc_base,
244245
program_len: program.len(),
245246
});
@@ -365,7 +366,7 @@ fn get_pre_compute_instructions<'a, F: PrimeField32, E: InsExecutorE1<F>, Ctx: E
365366
let buf: &mut [u8] = buf;
366367
let pre_inst = if let Some((inst, _)) = inst_opt {
367368
tracing::trace!("get_e2_pre_compute_instruction {inst:?}");
368-
let pc = program.pc_base + i as u32 * program.step;
369+
let pc = program.pc_base + i as u32 * DEFAULT_PC_STEP;
369370
if let Some(handler) = get_system_opcode_handler(inst, buf) {
370371
PreComputeInstruction {
371372
handler,
@@ -415,7 +416,7 @@ fn get_e2_pre_compute_instructions<
415416
let buf: &mut [u8] = buf;
416417
let pre_inst = if let Some((inst, _)) = inst_opt {
417418
tracing::trace!("get_e2_pre_compute_instruction {inst:?}");
418-
let pc = program.pc_base + i as u32 * program.step;
419+
let pc = program.pc_base + i as u32 * DEFAULT_PC_STEP;
419420
if let Some(handler) = get_system_opcode_handler(inst, buf) {
420421
PreComputeInstruction {
421422
handler,

crates/vm/src/system/program/mod.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use openvm_instructions::{
2-
instruction::Instruction, program::Program, LocalOpcode, SystemOpcode, VmOpcode,
2+
instruction::Instruction,
3+
program::{Program, DEFAULT_PC_STEP},
4+
LocalOpcode, SystemOpcode, VmOpcode,
35
};
46
use openvm_stark_backend::{
57
config::StarkGenericConfig,
@@ -58,7 +60,6 @@ pub struct ProgramHandler<F, E> {
5860
pc_handler: Vec<PcEntry<F>>,
5961
execution_frequencies: Vec<u32>,
6062
pc_base: u32,
61-
step: u32,
6263
}
6364

6465
impl<F: Field, E> ProgramHandler<F, E> {
@@ -110,15 +111,13 @@ impl<F: Field, E> ProgramHandler<F, E> {
110111
executors,
111112
pc_handler,
112113
pc_base: program.pc_base,
113-
step: program.step,
114114
})
115115
}
116116

117117
#[inline(always)]
118118
fn get_pc_index(&self, pc: u32) -> usize {
119-
let step = self.step;
120119
let pc_base = self.pc_base;
121-
((pc - pc_base) / step) as usize
120+
((pc - pc_base) / DEFAULT_PC_STEP) as usize
122121
}
123122

124123
/// Returns `(executor, pc_entry, pc_idx)`.
@@ -130,7 +129,6 @@ impl<F: Field, E> ProgramHandler<F, E> {
130129
.get(pc_idx)
131130
.ok_or_else(|| ExecutionError::PcOutOfBounds {
132131
pc,
133-
step: self.step,
134132
pc_base: self.pc_base,
135133
program_len: self.pc_handler.len(),
136134
})?;

crates/vm/src/system/program/tests/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ fn test_program_with_undefined_instructions() {
288288
)),
289289
];
290290

291-
let program = Program::new_without_debug_infos_with_option(&instructions, DEFAULT_PC_STEP, 0);
291+
let program = Program::new_without_debug_infos_with_option(&instructions, 0);
292292

293293
interaction_test(program, vec![0, 2, 5]);
294294
}

crates/vm/src/system/program/trace.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@ use std::{borrow::BorrowMut, sync::Arc};
33
use derivative::Derivative;
44
use itertools::Itertools;
55
use openvm_circuit::arch::hasher::poseidon2::Poseidon2Hasher;
6-
use openvm_instructions::{exe::VmExe, program::Program, LocalOpcode, SystemOpcode};
6+
use openvm_instructions::{
7+
exe::VmExe,
8+
program::{Program, DEFAULT_PC_STEP},
9+
LocalOpcode, SystemOpcode,
10+
};
711
use openvm_stark_backend::{
812
config::{Com, PcsProverData, StarkGenericConfig, Val},
913
p3_commit::Pcs,
@@ -169,7 +173,7 @@ pub(crate) fn generate_cached_trace<F: Field>(program: &Program<F>) -> RowMajorM
169173
let padding = padding_instruction();
170174
while !instructions.len().is_power_of_two() {
171175
instructions.push((
172-
program.pc_base + instructions.len() as u32 * program.step,
176+
program.pc_base + instructions.len() as u32 * DEFAULT_PC_STEP,
173177
padding.clone(),
174178
));
175179
}

extensions/native/compiler/src/conversion/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -565,7 +565,7 @@ pub fn convert_program<F: PrimeField32, EF: ExtensionField<F>>(
565565
}
566566
}
567567

568-
let mut result = Program::new_empty(DEFAULT_PC_STEP, 0);
568+
let mut result = Program::new_empty(0);
569569
result.push_instruction_and_debug_info(init_register_0, init_debug_info);
570570
for block in program.blocks.iter() {
571571
for (instruction, debug_info) in block.0.iter().zip(block.1.iter()) {

0 commit comments

Comments
 (0)