Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement "can process" for block machine. #2372

Draft
wants to merge 13 commits into
base: main
Choose a base branch
from
2 changes: 1 addition & 1 deletion executor/src/witgen/data_structures/mutable_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ impl<'a, T: FieldElement, Q: QueryCallback<T>> MutableState<'a, T, Q> {
// unique machine responsible for handling a bus send), so just answer "false" if the identity
// has no responsible machine.
let mut machine = self.responsible_machine(identity_id).ok()?;
machine.can_process_call_fully(identity_id, known_inputs, range_constraints)
machine.can_process_call_fully(self, identity_id, known_inputs, range_constraints)
}

/// Call the machine responsible for the right-hand-side of an identity given its ID
Expand Down
33 changes: 19 additions & 14 deletions executor/src/witgen/jit/block_machine_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use powdr_number::FieldElement;
use crate::witgen::{jit::processor::Processor, machines::MachineParts, FixedData};

use super::{
effect::Effect,
processor::ProcessorResult,
variable::Variable,
witgen_inference::{CanProcessCall, FixedEvaluator, WitgenInference},
};
Expand Down Expand Up @@ -41,12 +41,12 @@ impl<'a, T: FieldElement> BlockMachineProcessor<'a, T> {

/// Generates the JIT code for a given combination of connection and known arguments.
/// Fails if it cannot solve for the outputs, or if any sub-machine calls cannot be completed.
pub fn generate_code<CanProcess: CanProcessCall<T> + Clone>(
pub fn generate_code(
&self,
can_process: CanProcess,
can_process: impl CanProcessCall<T>,
identity_id: u64,
known_args: &BitVec,
) -> Result<Vec<Effect<T, Variable>>, String> {
) -> Result<ProcessorResult<T>, String> {
let connection = self.machine_parts.connections[&identity_id];
assert_eq!(connection.right.expressions.len(), known_args.len());

Expand Down Expand Up @@ -92,12 +92,13 @@ impl<'a, T: FieldElement> BlockMachineProcessor<'a, T> {
self.block_size,
true,
requested_known,
(0..known_args.len()).map(Variable::Param),
BLOCK_MACHINE_MAX_BRANCH_DEPTH,
)
.generate_code(can_process, witgen)
.map_err(|e| {
let err_str = e.to_string_with_variable_formatter(|var| match var {
Variable::Param(i) => format!("{}", &connection.right.expressions[*i]),
Variable::Param(i) => format!("{} (connection param)", &connection.right.expressions[*i]),
_ => var.to_string(),
});
log::trace!("\nCode generation failed for connection:\n {connection}");
Expand Down Expand Up @@ -158,11 +159,9 @@ mod test {
use crate::witgen::{
data_structures::mutable_state::MutableState,
global_constraints,
jit::{
effect::{format_code, Effect},
test_util::read_pil,
},
jit::{effect::format_code, test_util::read_pil},
machines::{machine_extractor::MachineExtractor, KnownMachine, Machine},
range_constraints::RangeConstraint,
FixedData,
};

Expand All @@ -173,7 +172,7 @@ mod test {
machine_name: &str,
num_inputs: usize,
num_outputs: usize,
) -> Result<Vec<Effect<GoldilocksField, Variable>>, String> {
) -> Result<ProcessorResult<GoldilocksField>, String> {
let (analyzed, fixed_col_vals) = read_pil(input_pil);

let fixed_data = FixedData::new(&analyzed, &fixed_col_vals, &[], Default::default(), 0);
Expand Down Expand Up @@ -221,9 +220,9 @@ mod test {
col witness sel, a, b, c;
c = a + b;
";
let code = generate_for_block_machine(input, "Add", 2, 1);
let code = generate_for_block_machine(input, "Add", 2, 1).unwrap().code;
assert_eq!(
format_code(&code.unwrap()),
format_code(&code),
"Add::sel[0] = 1;
Add::a[0] = params[0];
Add::b[0] = params[1];
Expand Down Expand Up @@ -266,9 +265,15 @@ params[2] = Add::c[0];"
#[test]
fn binary() {
let input = read_to_string("../test_data/pil/binary.pil").unwrap();
let code = generate_for_block_machine(&input, "main_binary", 3, 1).unwrap();
let result = generate_for_block_machine(&input, "main_binary", 3, 1).unwrap();
let [op_rc, a_rc, b_rc, c_rc] = &result.range_constraints.try_into().unwrap();
assert_eq!(op_rc, &RangeConstraint::from_range(0.into(), 2.into()));
// TODO why are they not constrained to four bytes?
assert_eq!(a_rc, &RangeConstraint::default());
assert_eq!(b_rc, &RangeConstraint::default());
assert_eq!(c_rc, &RangeConstraint::from_mask(0xffffffffu64));
assert_eq!(
format_code(&code),
format_code(&result.code),
"main_binary::sel[0][3] = 1;
main_binary::operation_id[3] = params[0];
main_binary::A[3] = params[1];
Expand Down
Loading