openvm_rv32im_circuit/auipc/
execution.rs

1use std::{
2    borrow::{Borrow, BorrowMut},
3    mem::size_of,
4};
5
6use openvm_circuit::{arch::*, system::memory::online::GuestMemory};
7use openvm_circuit_primitives_derive::AlignedBytesBorrow;
8use openvm_instructions::{
9    instruction::Instruction, program::DEFAULT_PC_STEP, riscv::RV32_REGISTER_AS,
10};
11use openvm_stark_backend::p3_field::PrimeField32;
12
13use super::{run_auipc, Rv32AuipcExecutor};
14
15#[derive(AlignedBytesBorrow, Clone)]
16#[repr(C)]
17struct AuiPcPreCompute {
18    imm: u32,
19    a: u8,
20}
21
22impl<A> Rv32AuipcExecutor<A> {
23    fn pre_compute_impl<F: PrimeField32>(
24        &self,
25        pc: u32,
26        inst: &Instruction<F>,
27        data: &mut AuiPcPreCompute,
28    ) -> Result<(), StaticProgramError> {
29        let Instruction { a, c: imm, d, .. } = inst;
30        if d.as_canonical_u32() != RV32_REGISTER_AS {
31            return Err(StaticProgramError::InvalidInstruction(pc));
32        }
33        let imm = imm.as_canonical_u32();
34        let data: &mut AuiPcPreCompute = data.borrow_mut();
35        *data = AuiPcPreCompute {
36            imm,
37            a: a.as_canonical_u32() as u8,
38        };
39        Ok(())
40    }
41}
42
43impl<F, A> Executor<F> for Rv32AuipcExecutor<A>
44where
45    F: PrimeField32,
46{
47    #[inline(always)]
48    fn pre_compute_size(&self) -> usize {
49        size_of::<AuiPcPreCompute>()
50    }
51
52    #[cfg(not(feature = "tco"))]
53    #[inline(always)]
54    fn pre_compute<Ctx: ExecutionCtxTrait>(
55        &self,
56        pc: u32,
57        inst: &Instruction<F>,
58        data: &mut [u8],
59    ) -> Result<ExecuteFunc<F, Ctx>, StaticProgramError> {
60        let data: &mut AuiPcPreCompute = data.borrow_mut();
61        self.pre_compute_impl(pc, inst, data)?;
62        Ok(execute_e1_impl)
63    }
64
65    #[cfg(feature = "tco")]
66    fn handler<Ctx>(
67        &self,
68        pc: u32,
69        inst: &Instruction<F>,
70        data: &mut [u8],
71    ) -> Result<Handler<F, Ctx>, StaticProgramError>
72    where
73        Ctx: ExecutionCtxTrait,
74    {
75        let data: &mut AuiPcPreCompute = data.borrow_mut();
76        self.pre_compute_impl(pc, inst, data)?;
77        Ok(execute_e1_handler)
78    }
79}
80
81impl<F, A> MeteredExecutor<F> for Rv32AuipcExecutor<A>
82where
83    F: PrimeField32,
84{
85    fn metered_pre_compute_size(&self) -> usize {
86        size_of::<E2PreCompute<AuiPcPreCompute>>()
87    }
88
89    #[cfg(not(feature = "tco"))]
90    fn metered_pre_compute<Ctx>(
91        &self,
92        chip_idx: usize,
93        pc: u32,
94        inst: &Instruction<F>,
95        data: &mut [u8],
96    ) -> Result<ExecuteFunc<F, Ctx>, StaticProgramError>
97    where
98        Ctx: MeteredExecutionCtxTrait,
99    {
100        let data: &mut E2PreCompute<AuiPcPreCompute> = data.borrow_mut();
101        data.chip_idx = chip_idx as u32;
102        self.pre_compute_impl(pc, inst, &mut data.data)?;
103        Ok(execute_e2_impl)
104    }
105
106    #[cfg(feature = "tco")]
107    fn metered_handler<Ctx>(
108        &self,
109        chip_idx: usize,
110        pc: u32,
111        inst: &Instruction<F>,
112        data: &mut [u8],
113    ) -> Result<Handler<F, Ctx>, StaticProgramError>
114    where
115        Ctx: MeteredExecutionCtxTrait,
116    {
117        let data: &mut E2PreCompute<AuiPcPreCompute> = data.borrow_mut();
118        data.chip_idx = chip_idx as u32;
119        self.pre_compute_impl(pc, inst, &mut data.data)?;
120        Ok(execute_e2_handler)
121    }
122}
123
124#[inline(always)]
125unsafe fn execute_e12_impl<F: PrimeField32, CTX: ExecutionCtxTrait>(
126    pre_compute: &AuiPcPreCompute,
127    instret: &mut u64,
128    pc: &mut u32,
129    exec_state: &mut VmExecState<F, GuestMemory, CTX>,
130) {
131    let rd = run_auipc(*pc, pre_compute.imm);
132    exec_state.vm_write(RV32_REGISTER_AS, pre_compute.a as u32, &rd);
133
134    *pc = pc.wrapping_add(DEFAULT_PC_STEP);
135    *instret += 1;
136}
137
138#[create_handler]
139#[inline(always)]
140unsafe fn execute_e1_impl<F: PrimeField32, CTX: ExecutionCtxTrait>(
141    pre_compute: &[u8],
142    instret: &mut u64,
143    pc: &mut u32,
144    _instret_end: u64,
145    exec_state: &mut VmExecState<F, GuestMemory, CTX>,
146) {
147    let pre_compute: &AuiPcPreCompute = pre_compute.borrow();
148    execute_e12_impl(pre_compute, instret, pc, exec_state);
149}
150
151#[create_handler]
152#[inline(always)]
153unsafe fn execute_e2_impl<F: PrimeField32, CTX: MeteredExecutionCtxTrait>(
154    pre_compute: &[u8],
155    instret: &mut u64,
156    pc: &mut u32,
157    _arg: u64,
158    exec_state: &mut VmExecState<F, GuestMemory, CTX>,
159) {
160    let pre_compute: &E2PreCompute<AuiPcPreCompute> = pre_compute.borrow();
161    exec_state
162        .ctx
163        .on_height_change(pre_compute.chip_idx as usize, 1);
164    execute_e12_impl(&pre_compute.data, instret, pc, exec_state);
165}