mirror of
https://github.com/powdr-labs/powdr.git
synced 2026-05-13 03:00:26 -04:00
pass arguments by value in asm compiler
This commit is contained in:
@@ -46,7 +46,7 @@ impl ASMPILConverter {
|
||||
fn convert(&mut self, input: ASMFile) -> PILFile {
|
||||
self.set_degree(1024);
|
||||
|
||||
let mut statements = input.0.iter().peekable();
|
||||
let mut statements = input.0.into_iter().peekable();
|
||||
|
||||
if let Some(ASMStatement::Degree(_, degree)) = statements.peek() {
|
||||
self.set_degree(crate::number::abstract_to_degree(degree));
|
||||
@@ -72,27 +72,25 @@ impl ASMPILConverter {
|
||||
panic!("The degree statement is only supported at the start of the asm source");
|
||||
}
|
||||
ASMStatement::RegisterDeclaration(start, name, flags) => {
|
||||
self.handle_register_declaration(flags, name, start);
|
||||
self.handle_register_declaration(flags, &name, start);
|
||||
}
|
||||
ASMStatement::InstructionDeclaration(start, name, params, body) => {
|
||||
self.handle_instruction_def(start, body, name, params);
|
||||
}
|
||||
ASMStatement::InlinePil(_start, statements) => self.pil.extend(statements.clone()),
|
||||
ASMStatement::Assignment(start, write_regs, assign_reg, value) => {
|
||||
match value.as_ref() {
|
||||
Expression::FunctionCall(function_name, args) => {
|
||||
self.handle_functional_instruction(
|
||||
write_regs,
|
||||
assign_reg,
|
||||
function_name,
|
||||
args,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
self.handle_assignment(*start, write_regs, assign_reg, value.as_ref());
|
||||
}
|
||||
ASMStatement::Assignment(start, write_regs, assign_reg, value) => match *value {
|
||||
Expression::FunctionCall(function_name, args) => {
|
||||
self.handle_functional_instruction(
|
||||
write_regs,
|
||||
assign_reg,
|
||||
function_name,
|
||||
args,
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
self.handle_assignment(start, write_regs, assign_reg, *value);
|
||||
}
|
||||
},
|
||||
ASMStatement::Instruction(_start, instr_name, args) => {
|
||||
self.handle_instruction(instr_name, args)
|
||||
}
|
||||
@@ -104,7 +102,7 @@ impl ASMPILConverter {
|
||||
}
|
||||
let assignment_registers = self.assignment_registers().cloned().collect::<Vec<_>>();
|
||||
for reg in assignment_registers {
|
||||
self.create_constraints_for_assignment_reg(®);
|
||||
self.create_constraints_for_assignment_reg(reg);
|
||||
}
|
||||
|
||||
self.pil.extend(
|
||||
@@ -143,9 +141,9 @@ impl ASMPILConverter {
|
||||
|
||||
fn handle_register_declaration(
|
||||
&mut self,
|
||||
flags: &Option<RegisterFlag>,
|
||||
flags: Option<RegisterFlag>,
|
||||
name: &str,
|
||||
start: &usize,
|
||||
start: usize,
|
||||
) {
|
||||
let mut conditioned_updates = vec![];
|
||||
let mut default_update = None;
|
||||
@@ -158,7 +156,7 @@ impl ASMPILConverter {
|
||||
// This might be superfluous but makes it easier to determine that the PC needs to
|
||||
// be zero in the first row.
|
||||
self.pil.push(Statement::PolynomialIdentity(
|
||||
*start,
|
||||
start,
|
||||
build_mul(direct_reference("first_step"), direct_reference(name)),
|
||||
));
|
||||
// The value here is actually irrelevant, it is only important
|
||||
@@ -173,7 +171,7 @@ impl ASMPILConverter {
|
||||
// This might be superfluous but makes it easier to determine that the register needs to
|
||||
// be zero in the first row.
|
||||
self.pil.push(Statement::PolynomialIdentity(
|
||||
*start,
|
||||
start,
|
||||
build_mul(direct_reference("first_step"), direct_reference(name)),
|
||||
));
|
||||
conditioned_updates = vec![
|
||||
@@ -185,7 +183,7 @@ impl ASMPILConverter {
|
||||
// TODO do this at the same place where we set up the read flags.
|
||||
for reg in assignment_regs {
|
||||
let write_flag = format!("reg_write_{reg}_{name}");
|
||||
self.create_witness_fixed_pair(*start, &write_flag);
|
||||
self.create_witness_fixed_pair(start, &write_flag);
|
||||
conditioned_updates
|
||||
.push((direct_reference(&write_flag), direct_reference(®)));
|
||||
}
|
||||
@@ -197,30 +195,30 @@ impl ASMPILConverter {
|
||||
Register {
|
||||
conditioned_updates,
|
||||
default_update,
|
||||
is_assignment: *flags == Some(RegisterFlag::IsAssignment),
|
||||
is_assignment: flags == Some(RegisterFlag::IsAssignment),
|
||||
},
|
||||
);
|
||||
self.pil.push(witness_column(*start, name, None));
|
||||
self.pil.push(witness_column(start, name, None));
|
||||
}
|
||||
|
||||
fn handle_instruction_def(
|
||||
&mut self,
|
||||
start: &usize,
|
||||
body: &Vec<InstructionBodyElement>,
|
||||
name: &str,
|
||||
params: &Vec<InstructionParam>,
|
||||
start: usize,
|
||||
body: Vec<InstructionBodyElement>,
|
||||
name: String,
|
||||
params: Vec<InstructionParam>,
|
||||
) {
|
||||
let instruction_flag = format!("instr_{name}");
|
||||
self.create_witness_fixed_pair(*start, &instruction_flag);
|
||||
self.create_witness_fixed_pair(start, &instruction_flag);
|
||||
// it's part of the lookup!
|
||||
//self.pil.push(constrain_zero_one(&col_name));
|
||||
|
||||
let mut substitutions = HashMap::new();
|
||||
for p in params {
|
||||
for p in ¶ms {
|
||||
if p.assignment_reg.0.is_none() && p.assignment_reg.1.is_none() {
|
||||
// literal argument
|
||||
let param_col_name = format!("instr_{name}_param_{}", p.name);
|
||||
self.create_witness_fixed_pair(*start, ¶m_col_name);
|
||||
self.create_witness_fixed_pair(start, ¶m_col_name);
|
||||
substitutions.insert(p.name.clone(), param_col_name);
|
||||
}
|
||||
}
|
||||
@@ -247,40 +245,36 @@ impl ASMPILConverter {
|
||||
assert!(left.selector.is_none(), "LHS selector not supported, could and-combine with instruction flag later.");
|
||||
let left = SelectedExpressions {
|
||||
selector: Some(direct_reference(&instruction_flag)),
|
||||
expressions: substitute_vec(&left.expressions, &substitutions),
|
||||
expressions: substitute_vec(left.expressions, &substitutions),
|
||||
};
|
||||
let right = substitute_selected_exprs(right, &substitutions);
|
||||
self.pil.push(match op {
|
||||
PlookupOperator::In => Statement::PlookupIdentity(*start, left, right),
|
||||
PlookupOperator::Is => Statement::PermutationIdentity(*start, left, right),
|
||||
PlookupOperator::In => Statement::PlookupIdentity(start, left, right),
|
||||
PlookupOperator::Is => Statement::PermutationIdentity(start, left, right),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
let instr = Instruction {
|
||||
params: params.clone(),
|
||||
};
|
||||
self.instructions.insert(name.to_string(), instr);
|
||||
let instr = Instruction { params };
|
||||
self.instructions.insert(name, instr);
|
||||
}
|
||||
|
||||
fn handle_assignment(
|
||||
&mut self,
|
||||
_start: usize,
|
||||
write_regs: &Vec<String>,
|
||||
assign_reg: &Option<String>,
|
||||
value: &Expression,
|
||||
write_regs: Vec<String>,
|
||||
assign_reg: Option<String>,
|
||||
value: Expression,
|
||||
) {
|
||||
assert!(write_regs.len() <= 1);
|
||||
assert!(
|
||||
assign_reg.is_some(),
|
||||
"Implicit assign register not yet supported."
|
||||
);
|
||||
let assign_reg = assign_reg.clone().unwrap();
|
||||
let assign_reg = assign_reg.unwrap();
|
||||
let value = self.process_assignment_value(value);
|
||||
self.code_lines.push(CodeLine {
|
||||
write_regs: [(assign_reg.clone(), write_regs.clone())]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
write_regs: [(assign_reg.clone(), write_regs)].into_iter().collect(),
|
||||
value: [(assign_reg, value)].into(),
|
||||
..Default::default()
|
||||
})
|
||||
@@ -288,27 +282,27 @@ impl ASMPILConverter {
|
||||
|
||||
fn handle_functional_instruction(
|
||||
&mut self,
|
||||
write_regs: &Vec<String>,
|
||||
assign_reg: &Option<String>,
|
||||
instr_name: &str,
|
||||
args: &Vec<Expression>,
|
||||
write_regs: Vec<String>,
|
||||
assign_reg: Option<String>,
|
||||
instr_name: String,
|
||||
args: Vec<Expression>,
|
||||
) {
|
||||
assert!(write_regs.len() == 1);
|
||||
assert!(assign_reg.is_some());
|
||||
let instr = &self.instructions[instr_name];
|
||||
let instr = &self.instructions[&instr_name];
|
||||
assert_eq!(instr.params.len(), args.len() + 1);
|
||||
let last_param = instr.params.last().unwrap();
|
||||
assert!(last_param.param_type.is_none());
|
||||
assert!(last_param.assignment_reg.0.is_none());
|
||||
assert!(last_param.assignment_reg.1 == Some(assign_reg.clone()));
|
||||
assert!(last_param.assignment_reg.1 == Some(assign_reg));
|
||||
|
||||
let mut args = args.clone();
|
||||
args.push(direct_reference(write_regs.first().unwrap()));
|
||||
self.handle_instruction(instr_name, &args);
|
||||
let mut args = args;
|
||||
args.push(direct_reference(write_regs.first().unwrap().clone()));
|
||||
self.handle_instruction(instr_name, args);
|
||||
}
|
||||
|
||||
fn handle_instruction(&mut self, instr_name: &str, args: &Vec<Expression>) {
|
||||
let instr = &self.instructions[instr_name];
|
||||
fn handle_instruction(&mut self, instr_name: String, args: Vec<Expression>) {
|
||||
let instr = &self.instructions[&instr_name];
|
||||
assert_eq!(instr.params.len(), args.len());
|
||||
let mut value = BTreeMap::new();
|
||||
let mut instruction_literal_args = vec![];
|
||||
@@ -357,7 +351,7 @@ impl ASMPILConverter {
|
||||
|
||||
fn process_assignment_value(
|
||||
&self,
|
||||
value: &Expression,
|
||||
value: Expression,
|
||||
) -> Vec<(AbstractNumberType, AffineExpressionComponent)> {
|
||||
match value {
|
||||
Expression::Constant(_) => panic!(),
|
||||
@@ -370,31 +364,28 @@ impl ASMPILConverter {
|
||||
// TODO check it actually is a register
|
||||
vec![(
|
||||
1.into(),
|
||||
AffineExpressionComponent::Register(reference.name.clone()),
|
||||
AffineExpressionComponent::Register(reference.name),
|
||||
)]
|
||||
}
|
||||
Expression::Number(value) => vec![(value.clone(), AffineExpressionComponent::Constant)],
|
||||
Expression::Number(value) => vec![(value, AffineExpressionComponent::Constant)],
|
||||
Expression::String(_) => panic!(),
|
||||
Expression::Tuple(_) => panic!(),
|
||||
Expression::MatchExpression(_, _) => panic!(),
|
||||
Expression::FreeInput(expr) => {
|
||||
vec![(
|
||||
1.into(),
|
||||
AffineExpressionComponent::FreeInput(*expr.clone()),
|
||||
)]
|
||||
vec![(1.into(), AffineExpressionComponent::FreeInput(*expr))]
|
||||
}
|
||||
Expression::BinaryOperation(left, op, right) => match op {
|
||||
BinaryOperator::Add => self.add_assignment_value(
|
||||
self.process_assignment_value(left),
|
||||
self.process_assignment_value(right),
|
||||
self.process_assignment_value(*left),
|
||||
self.process_assignment_value(*right),
|
||||
),
|
||||
BinaryOperator::Sub => self.add_assignment_value(
|
||||
self.process_assignment_value(left),
|
||||
self.negate_assignment_value(self.process_assignment_value(right)),
|
||||
self.process_assignment_value(*left),
|
||||
self.negate_assignment_value(self.process_assignment_value(*right)),
|
||||
),
|
||||
BinaryOperator::Mul => {
|
||||
let left = self.process_assignment_value(left);
|
||||
let right = self.process_assignment_value(right);
|
||||
let left = self.process_assignment_value(*left);
|
||||
let right = self.process_assignment_value(*right);
|
||||
if let [(f, AffineExpressionComponent::Constant)] = &left[..] {
|
||||
// TODO overflow?
|
||||
right
|
||||
@@ -420,8 +411,8 @@ impl ASMPILConverter {
|
||||
| BinaryOperator::ShiftRight => panic!(),
|
||||
},
|
||||
Expression::UnaryOperation(op, expr) => {
|
||||
assert!(*op == UnaryOperator::Minus);
|
||||
self.negate_assignment_value(self.process_assignment_value(expr))
|
||||
assert!(op == UnaryOperator::Minus);
|
||||
self.negate_assignment_value(self.process_assignment_value(*expr))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -443,7 +434,7 @@ impl ASMPILConverter {
|
||||
expr.into_iter().map(|(v, c)| (-v, c)).collect()
|
||||
}
|
||||
|
||||
fn create_constraints_for_assignment_reg(&mut self, register: &str) {
|
||||
fn create_constraints_for_assignment_reg(&mut self, register: String) {
|
||||
let assign_const = format!("{register}_const");
|
||||
self.create_witness_fixed_pair(0, &assign_const);
|
||||
let read_free = format!("{register}_read_free");
|
||||
@@ -455,11 +446,14 @@ impl ASMPILConverter {
|
||||
.map(|name| {
|
||||
let read_coefficient = format!("read_{register}_{name}");
|
||||
self.create_witness_fixed_pair(0, &read_coefficient);
|
||||
build_mul(direct_reference(&read_coefficient), direct_reference(name))
|
||||
build_mul(
|
||||
direct_reference(read_coefficient),
|
||||
direct_reference(name.clone()),
|
||||
)
|
||||
})
|
||||
.chain([
|
||||
direct_reference(&assign_const),
|
||||
build_mul(direct_reference(&read_free), direct_reference(&free_value)),
|
||||
direct_reference(assign_const),
|
||||
build_mul(direct_reference(read_free), direct_reference(free_value)),
|
||||
])
|
||||
.reduce(build_add);
|
||||
self.pil.push(Statement::PolynomialIdentity(
|
||||
@@ -573,7 +567,7 @@ impl ASMPILConverter {
|
||||
let free_value = format!("{reg}_free_value");
|
||||
witness_column(
|
||||
0,
|
||||
&free_value,
|
||||
free_value,
|
||||
Some(FunctionDefinition::Query(
|
||||
vec!["i".to_string()],
|
||||
Expression::Tuple(free_value_queries[reg].clone()),
|
||||
@@ -692,21 +686,25 @@ enum AffineExpressionComponent {
|
||||
FreeInput(Expression),
|
||||
}
|
||||
|
||||
fn witness_column(start: usize, name: &str, def: Option<FunctionDefinition>) -> Statement {
|
||||
fn witness_column<S: Into<String>>(
|
||||
start: usize,
|
||||
name: S,
|
||||
def: Option<FunctionDefinition>,
|
||||
) -> Statement {
|
||||
Statement::PolynomialCommitDeclaration(
|
||||
start,
|
||||
vec![PolynomialName {
|
||||
name: name.to_string(),
|
||||
name: name.into(),
|
||||
array_size: None,
|
||||
}],
|
||||
def,
|
||||
)
|
||||
}
|
||||
|
||||
fn direct_reference(name: &str) -> Expression {
|
||||
fn direct_reference<S: Into<String>>(name: S) -> Expression {
|
||||
Expression::PolynomialReference(PolynomialReference {
|
||||
namespace: None,
|
||||
name: name.to_owned(),
|
||||
name: name.into(),
|
||||
index: None,
|
||||
next: false,
|
||||
})
|
||||
@@ -766,7 +764,7 @@ fn extract_update(expr: Expression) -> (Option<String>, Expression) {
|
||||
}
|
||||
}
|
||||
|
||||
fn substitute(input: &Expression, substitution: &HashMap<String, String>) -> Expression {
|
||||
fn substitute(input: Expression, substitution: &HashMap<String, String>) -> Expression {
|
||||
match input {
|
||||
// TODO namespace
|
||||
Expression::PolynomialReference(r) => {
|
||||
@@ -776,44 +774,55 @@ fn substitute(input: &Expression, substitution: &HashMap<String, String>) -> Exp
|
||||
})
|
||||
}
|
||||
Expression::BinaryOperation(left, op, right) => build_binary_expr(
|
||||
substitute(left, substitution),
|
||||
*op,
|
||||
substitute(right, substitution),
|
||||
substitute(*left, substitution),
|
||||
op,
|
||||
substitute(*right, substitution),
|
||||
),
|
||||
Expression::UnaryOperation(op, exp) => build_unary_expr(*op, substitute(exp, substitution)),
|
||||
Expression::UnaryOperation(op, exp) => build_unary_expr(op, substitute(*exp, substitution)),
|
||||
Expression::FunctionCall(name, args) => Expression::FunctionCall(
|
||||
name.clone(),
|
||||
args.iter().map(|e| substitute(e, substitution)).collect(),
|
||||
name,
|
||||
args.into_iter()
|
||||
.map(|e| substitute(e, substitution))
|
||||
.collect(),
|
||||
),
|
||||
Expression::Tuple(items) => Expression::Tuple(
|
||||
items
|
||||
.into_iter()
|
||||
.map(|e| substitute(e, substitution))
|
||||
.collect(),
|
||||
),
|
||||
Expression::Tuple(items) => {
|
||||
Expression::Tuple(items.iter().map(|e| substitute(e, substitution)).collect())
|
||||
}
|
||||
Expression::Constant(_)
|
||||
| Expression::PublicReference(_)
|
||||
| Expression::Number(_)
|
||||
| Expression::String(_)
|
||||
| Expression::FreeInput(_) => input.clone(),
|
||||
Expression::MatchExpression(scrutinee, arms) => Expression::MatchExpression(
|
||||
Box::new(substitute(scrutinee, substitution)),
|
||||
arms.iter()
|
||||
.map(|(n, e)| (n.clone(), substitute(e, substitution)))
|
||||
Box::new(substitute(*scrutinee, substitution)),
|
||||
arms.into_iter()
|
||||
.map(|(n, e)| (n, substitute(e, substitution)))
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn substitute_selected_exprs(
|
||||
input: &SelectedExpressions,
|
||||
input: SelectedExpressions,
|
||||
substitution: &HashMap<String, String>,
|
||||
) -> SelectedExpressions {
|
||||
SelectedExpressions {
|
||||
selector: input.selector.as_ref().map(|s| substitute(s, substitution)),
|
||||
expressions: substitute_vec(&input.expressions, substitution),
|
||||
selector: input.selector.map(|s| substitute(s, substitution)),
|
||||
expressions: substitute_vec(input.expressions, substitution),
|
||||
}
|
||||
}
|
||||
|
||||
fn substitute_vec(input: &[Expression], substitution: &HashMap<String, String>) -> Vec<Expression> {
|
||||
input.iter().map(|e| substitute(e, substitution)).collect()
|
||||
fn substitute_vec(
|
||||
input: Vec<Expression>,
|
||||
substitution: &HashMap<String, String>,
|
||||
) -> Vec<Expression> {
|
||||
input
|
||||
.into_iter()
|
||||
.map(|e| substitute(e, substitution))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn substitute_string(input: &str, substitution: &HashMap<String, String>) -> String {
|
||||
|
||||
Reference in New Issue
Block a user