Skip to content

Commit 5ccef50

Browse files
authored
Extract program (#3462)
This PR extracts a `program` module. For the most part, it moves code related to the OpenVM program. It enables us to more easily accesses the program's basic blocks in #3461.
1 parent 11d7933 commit 5ccef50

File tree

4 files changed

+209
-266
lines changed

4 files changed

+209
-266
lines changed

cli-openvm/src/main.rs

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use metrics_util::{debugging::DebuggingRecorder, layers::Layer};
44
use openvm_sdk::StdIn;
55
use openvm_stark_sdk::bench::serialize_metric_snapshot;
66
use powdr_autoprecompiles::pgo::{pgo_config, PgoType};
7-
use powdr_openvm::{default_powdr_openvm_config, CompiledProgram, GuestOptions};
7+
use powdr_openvm::{compile_openvm, default_powdr_openvm_config, CompiledProgram, GuestOptions};
88

99
#[cfg(feature = "metrics")]
1010
use openvm_stark_sdk::metrics_tracing::TimingMetricsLayer;
@@ -140,14 +140,13 @@ fn run_command(command: Commands) {
140140
if let Some(apc_candidates_dir) = apc_candidates_dir {
141141
powdr_config = powdr_config.with_apc_candidates_dir(apc_candidates_dir);
142142
}
143-
let execution_profile = powdr_openvm::execution_profile_from_guest(
144-
&guest,
145-
guest_opts.clone(),
146-
stdin_from(input),
147-
);
143+
let guest_program = compile_openvm(&guest, guest_opts.clone()).unwrap();
144+
let execution_profile =
145+
powdr_openvm::execution_profile_from_guest(&guest_program, stdin_from(input));
146+
148147
let pgo_config = pgo_config(pgo, max_columns, execution_profile);
149148
let program =
150-
powdr_openvm::compile_guest(&guest, guest_opts, powdr_config, pgo_config).unwrap();
149+
powdr_openvm::compile_exe(guest_program, powdr_config, pgo_config).unwrap();
151150
write_program_to_file(program, &format!("{guest}_compiled.cbor")).unwrap();
152151
}
153152

@@ -165,16 +164,13 @@ fn run_command(command: Commands) {
165164
if let Some(apc_candidates_dir) = apc_candidates_dir {
166165
powdr_config = powdr_config.with_apc_candidates_dir(apc_candidates_dir);
167166
}
168-
let execution_profile = powdr_openvm::execution_profile_from_guest(
169-
&guest,
170-
guest_opts.clone(),
171-
stdin_from(input),
172-
);
167+
let guest_program = compile_openvm(&guest, guest_opts.clone()).unwrap();
168+
let execution_profile =
169+
powdr_openvm::execution_profile_from_guest(&guest_program, stdin_from(input));
173170
let pgo_config = pgo_config(pgo, max_columns, execution_profile);
174171
let compile_and_exec = || {
175172
let program =
176-
powdr_openvm::compile_guest(&guest, guest_opts, powdr_config, pgo_config)
177-
.unwrap();
173+
powdr_openvm::compile_exe(guest_program, powdr_config, pgo_config).unwrap();
178174
powdr_openvm::execute(program, stdin_from(input)).unwrap();
179175
};
180176
if let Some(metrics_path) = metrics {
@@ -203,16 +199,14 @@ fn run_command(command: Commands) {
203199
if let Some(apc_candidates_dir) = apc_candidates_dir {
204200
powdr_config = powdr_config.with_apc_candidates_dir(apc_candidates_dir);
205201
}
206-
let execution_profile = powdr_openvm::execution_profile_from_guest(
207-
&guest,
208-
guest_opts.clone(),
209-
stdin_from(input),
210-
);
202+
let guest_program = compile_openvm(&guest, guest_opts).unwrap();
203+
204+
let execution_profile =
205+
powdr_openvm::execution_profile_from_guest(&guest_program, stdin_from(input));
211206
let pgo_config = pgo_config(pgo, max_columns, execution_profile);
212207
let compile_and_prove = || {
213208
let program =
214-
powdr_openvm::compile_guest(&guest, guest_opts, powdr_config, pgo_config)
215-
.unwrap();
209+
powdr_openvm::compile_exe(guest_program, powdr_config, pgo_config).unwrap();
216210
powdr_openvm::prove(&program, mock, recursion, stdin_from(input), None).unwrap()
217211
};
218212
if let Some(metrics_path) = metrics {

openvm/src/customize_exe.rs

Lines changed: 15 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::collections::{BTreeSet, HashMap};
1+
use std::collections::HashMap;
22

33
use std::fmt::Display;
44
use std::hash::Hash;
@@ -10,14 +10,14 @@ use crate::bus_map::OpenVmBusType;
1010
use crate::extraction_utils::{get_air_metrics, AirWidthsDiff, OriginalAirs, OriginalVmConfig};
1111
use crate::instruction_formatter::openvm_instruction_formatter;
1212
use crate::memory_bus_interaction::OpenVmMemoryBusInteraction;
13-
use crate::opcode::branch_opcodes_bigint_set;
1413
use crate::powdr_extension::chip::PowdrAir;
14+
use crate::program::Prog;
1515
use crate::utils::UnsupportedOpenVmReferenceError;
1616
use crate::OriginalCompiledProgram;
1717
use crate::{CompiledProgram, SpecializedConfig};
1818
use itertools::Itertools;
1919
use openvm_instructions::instruction::Instruction as OpenVmInstruction;
20-
use openvm_instructions::program::{Program as OpenVmProgram, DEFAULT_PC_STEP};
20+
use openvm_instructions::program::DEFAULT_PC_STEP;
2121
use openvm_instructions::VmOpcode;
2222
use openvm_stark_backend::{
2323
interaction::SymbolicInteraction,
@@ -27,7 +27,7 @@ use openvm_stark_sdk::p3_baby_bear::BabyBear;
2727
use powdr_autoprecompiles::adapter::{
2828
Adapter, AdapterApc, AdapterApcWithStats, AdapterVmConfig, ApcWithStats, PgoAdapter,
2929
};
30-
use powdr_autoprecompiles::blocks::{collect_basic_blocks, BasicBlock, Instruction, Program};
30+
use powdr_autoprecompiles::blocks::{BasicBlock, Instruction};
3131
use powdr_autoprecompiles::evaluation::{evaluate_apc, EvaluationResult};
3232
use powdr_autoprecompiles::expression::try_convert;
3333
use powdr_autoprecompiles::pgo::{ApcCandidateJsonExport, Candidate, KnapsackItem};
@@ -76,16 +76,6 @@ impl<'a> Adapter for BabyBearOpenVmApcAdapter<'a> {
7676
}
7777
}
7878

79-
/// A newtype wrapper around `OpenVmProgram` to implement the `Program` trait.
80-
/// This is necessary because we cannot implement a foreign trait for a foreign type.
81-
pub struct Prog<'a, F>(&'a OpenVmProgram<F>);
82-
83-
impl<'a, F> From<&'a OpenVmProgram<F>> for Prog<'a, F> {
84-
fn from(program: &'a OpenVmProgram<F>) -> Self {
85-
Prog(program)
86-
}
87-
}
88-
8979
/// A newtype wrapper around `OpenVmInstruction` to implement the `Instruction` trait.
9080
/// This is necessary because we cannot implement a foreign trait for a foreign type.
9181
#[derive(Clone, Serialize, Deserialize)]
@@ -116,54 +106,21 @@ impl<F: PrimeField32> Instruction<F> for Instr<F> {
116106
}
117107
}
118108

119-
impl<'a, F: PrimeField32> Program<Instr<F>> for Prog<'a, F> {
120-
fn base_pc(&self) -> u64 {
121-
self.0.pc_base as u64
122-
}
123-
124-
fn pc_step(&self) -> u32 {
125-
DEFAULT_PC_STEP
126-
}
127-
128-
fn instructions(&self) -> Box<dyn Iterator<Item = Instr<F>> + '_> {
129-
Box::new(
130-
self.0
131-
.instructions_and_debug_infos
132-
.iter()
133-
.filter_map(|x| x.as_ref().map(|i| Instr(i.0.clone()))),
134-
)
135-
}
136-
137-
fn length(&self) -> u32 {
138-
self.0.instructions_and_debug_infos.len() as u32
139-
}
140-
}
141-
142109
pub fn customize<'a, P: PgoAdapter<Adapter = BabyBearOpenVmApcAdapter<'a>>>(
143-
OriginalCompiledProgram {
144-
exe,
145-
vm_config,
146-
elf,
147-
}: OriginalCompiledProgram,
110+
original_program: OriginalCompiledProgram,
148111
config: PowdrConfig,
149112
pgo: P,
150113
) -> CompiledProgram {
151-
let labels = elf.text_labels();
152-
let debug_info = elf.debug_info();
153-
let original_config = OriginalVmConfig::new(vm_config.clone());
114+
let original_config = OriginalVmConfig::new(original_program.vm_config.clone());
154115
let airs = original_config.airs(config.degree_bound.identities).expect("Failed to convert the AIR of an OpenVM instruction, even after filtering by the blacklist!");
155116
let bus_map = original_config.bus_map();
156117

157-
let jumpdest_set = add_extra_targets(
158-
&exe.program,
159-
labels.clone(),
160-
exe.program.pc_base,
161-
DEFAULT_PC_STEP,
162-
);
163-
164-
let program = Prog(&exe.program);
165-
166-
let range_tuple_checker_sizes = vm_config.sdk.rv32m.unwrap().range_tuple_checker_sizes;
118+
let range_tuple_checker_sizes = original_program
119+
.vm_config
120+
.sdk
121+
.rv32m
122+
.unwrap()
123+
.range_tuple_checker_sizes;
167124
let vm_config = VmConfig {
168125
instruction_handler: &airs,
169126
bus_interaction_handler: OpenVmBusInteractionHandler::new(
@@ -173,13 +130,9 @@ pub fn customize<'a, P: PgoAdapter<Adapter = BabyBearOpenVmApcAdapter<'a>>>(
173130
bus_map: bus_map.clone(),
174131
};
175132

176-
// Convert the jump destinations to u64 for compatibility with the `collect_basic_blocks` function.
177-
let jumpdest_set = jumpdest_set
178-
.iter()
179-
.map(|&x| x as u64)
180-
.collect::<BTreeSet<_>>();
181-
182-
let blocks = collect_basic_blocks::<BabyBearOpenVmApcAdapter>(&program, &jumpdest_set, &airs);
133+
let blocks = original_program.collect_basic_blocks(config.degree_bound.identities);
134+
let exe = original_program.exe;
135+
let debug_info = original_program.elf.debug_info();
183136
tracing::info!(
184137
"Got {} basic blocks from `collect_basic_blocks`",
185138
blocks.len()
@@ -264,36 +217,6 @@ pub fn customize<'a, P: PgoAdapter<Adapter = BabyBearOpenVmApcAdapter<'a>>>(
264217
}
265218
}
266219

267-
/// Besides the base RISCV-V branching instructions, the bigint extension adds two more branching
268-
/// instruction classes over BranchEqual and BranchLessThan.
269-
/// Those instructions have the form <INSTR rs0 rs1 target_offset ...>, where target_offset is the
270-
/// relative jump we're interested in.
271-
/// This means that for a given program address A containing the instruction above,
272-
/// we add A + target_offset as a target as well.
273-
fn add_extra_targets<F: PrimeField32>(
274-
program: &OpenVmProgram<F>,
275-
mut labels: BTreeSet<u32>,
276-
base_pc: u32,
277-
pc_step: u32,
278-
) -> BTreeSet<u32> {
279-
let branch_opcodes_bigint = branch_opcodes_bigint_set();
280-
let new_labels = program
281-
.instructions_and_debug_infos
282-
.iter()
283-
.enumerate()
284-
.filter_map(|(i, instr)| {
285-
let instr = instr.as_ref().unwrap().0.clone();
286-
let adjusted_pc = base_pc + (i as u32) * pc_step;
287-
let op = instr.opcode;
288-
branch_opcodes_bigint
289-
.contains(&op)
290-
.then_some(adjusted_pc + instr.c.as_canonical_u32())
291-
});
292-
labels.extend(new_labels);
293-
294-
labels
295-
}
296-
297220
pub fn openvm_bus_interaction_to_powdr<F: PrimeField32>(
298221
interaction: &SymbolicInteraction<F>,
299222
columns: &[Arc<String>],

0 commit comments

Comments
 (0)