adapt inliner, remove String from function name, add stack to typed identifier
This commit is contained in:
parent
2a7b33f8c1
commit
addf79f20e
7 changed files with 327 additions and 311 deletions
|
@ -47,7 +47,7 @@ impl<'ast> Flattener<'ast> {
|
|||
|
||||
// Load IfElse helper
|
||||
let ie = TypedFunction {
|
||||
id: "_if_else_field".to_string(),
|
||||
id: "_if_else_field",
|
||||
arguments: vec![
|
||||
Parameter {
|
||||
id: Variable {
|
||||
|
@ -1230,7 +1230,7 @@ impl<'ast> Flattener<'ast> {
|
|||
}
|
||||
|
||||
FlatFunction {
|
||||
id: funct.id.clone(),
|
||||
id: funct.id.to_string(),
|
||||
arguments: arguments_flattened,
|
||||
statements: statements_flattened,
|
||||
signature: funct.signature,
|
||||
|
@ -1272,7 +1272,7 @@ impl<'ast> Flattener<'ast> {
|
|||
Type::FieldElementArray(size) => self.issue_new_variables(size),
|
||||
};
|
||||
|
||||
self.layout.insert(variable.id, vars.clone());
|
||||
self.layout.insert(variable.id.clone(), vars.clone());
|
||||
vars
|
||||
}
|
||||
|
||||
|
@ -1398,7 +1398,7 @@ mod tests {
|
|||
);
|
||||
|
||||
let fun = TypedFunction {
|
||||
id: String::from("main"),
|
||||
id: "main",
|
||||
arguments: vec![],
|
||||
statements: vec![statement],
|
||||
signature: Signature {
|
||||
|
@ -1473,7 +1473,7 @@ mod tests {
|
|||
let mut functions_flattened = vec![];
|
||||
|
||||
let funct = TypedFunction {
|
||||
id: "foo".to_string(),
|
||||
id: "foo",
|
||||
signature: Signature::new()
|
||||
.inputs(vec![Type::FieldElement])
|
||||
.outputs(vec![Type::FieldElement]),
|
||||
|
@ -1523,7 +1523,7 @@ mod tests {
|
|||
// return foo()
|
||||
|
||||
let foo = TypedFunction {
|
||||
id: String::from("foo"),
|
||||
id: "foo",
|
||||
arguments: vec![],
|
||||
statements: vec![
|
||||
TypedStatement::Definition(
|
||||
|
@ -1539,7 +1539,7 @@ mod tests {
|
|||
};
|
||||
|
||||
let main = TypedFunction {
|
||||
id: String::from("main"),
|
||||
id: "main",
|
||||
arguments: vec![],
|
||||
statements: vec![TypedStatement::Return(vec![
|
||||
FieldElementExpression::FunctionCall(String::from("foo"), vec![]).into(),
|
||||
|
@ -1589,7 +1589,7 @@ mod tests {
|
|||
// return _3
|
||||
|
||||
let function = TypedFunction {
|
||||
id: String::from("main"),
|
||||
id: "main",
|
||||
arguments: vec![],
|
||||
statements: vec![
|
||||
TypedStatement::Definition(
|
||||
|
@ -1672,7 +1672,7 @@ mod tests {
|
|||
let mut flattener = Flattener::new();
|
||||
let functions = vec![
|
||||
TypedFunction {
|
||||
id: "foo".to_string(),
|
||||
id: "foo",
|
||||
arguments: vec![],
|
||||
statements: vec![TypedStatement::Return(vec![TypedExpression::FieldElement(
|
||||
FieldElementExpression::Number(FieldPrime::from(1)),
|
||||
|
@ -1682,7 +1682,7 @@ mod tests {
|
|||
.outputs(vec![Type::FieldElement]),
|
||||
},
|
||||
TypedFunction {
|
||||
id: "foo".to_string(),
|
||||
id: "foo",
|
||||
arguments: vec![],
|
||||
statements: vec![TypedStatement::Return(vec![
|
||||
TypedExpression::FieldElement(FieldElementExpression::Number(
|
||||
|
@ -1697,7 +1697,7 @@ mod tests {
|
|||
.outputs(vec![Type::FieldElement, Type::FieldElement]),
|
||||
},
|
||||
TypedFunction {
|
||||
id: "main".to_string(),
|
||||
id: "main",
|
||||
arguments: vec![],
|
||||
statements: vec![
|
||||
TypedStatement::Definition(
|
||||
|
|
|
@ -279,7 +279,7 @@ impl<'ast> Checker<'ast> {
|
|||
}
|
||||
|
||||
Ok(TypedFunction {
|
||||
id: funct.id.to_string(),
|
||||
id: funct.id,
|
||||
arguments: funct
|
||||
.arguments
|
||||
.iter()
|
||||
|
|
|
@ -1,326 +1,322 @@
|
|||
// use crate::typed_absy::folder::*;
|
||||
// use crate::typed_absy::Folder;
|
||||
// use crate::typed_absy::*;
|
||||
// use crate::types::{Signature, Type};
|
||||
// use std::collections::HashMap;
|
||||
// use zokrates_field::field::Field;
|
||||
use crate::typed_absy::folder::*;
|
||||
use crate::typed_absy::Folder;
|
||||
use crate::typed_absy::*;
|
||||
use crate::types::{Signature, Type};
|
||||
use std::collections::HashMap;
|
||||
use zokrates_field::field::Field;
|
||||
|
||||
// pub struct Inliner<'ast, T: Field> {
|
||||
// functions: Vec<TypedFunction<'ast, T>>,
|
||||
// statements_buffer: Vec<TypedStatement<'ast, T>>,
|
||||
// context: Vec<(String, usize)>,
|
||||
// call_count: HashMap<String, usize>,
|
||||
// }
|
||||
pub struct Inliner<'ast, T: Field> {
|
||||
functions: Vec<TypedFunction<'ast, T>>,
|
||||
statements_buffer: Vec<TypedStatement<'ast, T>>,
|
||||
context: Vec<(&'ast str, Signature, usize)>,
|
||||
call_count: HashMap<String, usize>,
|
||||
}
|
||||
|
||||
// impl<'ast, T: Field> Inliner<'ast, T> {
|
||||
// pub fn new() -> Self {
|
||||
// Inliner {
|
||||
// functions: vec![],
|
||||
// statements_buffer: vec![],
|
||||
// context: vec![],
|
||||
// call_count: HashMap::new(),
|
||||
// }
|
||||
// }
|
||||
impl<'ast, T: Field> Inliner<'ast, T> {
|
||||
pub fn new() -> Self {
|
||||
Inliner {
|
||||
functions: vec![],
|
||||
statements_buffer: vec![],
|
||||
context: vec![],
|
||||
call_count: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
// fn should_inline(
|
||||
// &self,
|
||||
// function: &Option<TypedFunction<T>>,
|
||||
// arguments: &Vec<TypedExpression<T>>,
|
||||
// ) -> bool {
|
||||
// // we should define a heuristic here
|
||||
// // currently it doesn't seem like there's a tradeoff as everything gets inlined in flattening anyway (apart from compiling performance, as inlining
|
||||
// // in flattening should be faster and less memory intensive)
|
||||
// // however, using backends such as bellman, we could avoid flattening and "stream" the computation
|
||||
// // at proving time, the tradeoff becomes code size (not inlining keeps only one copy of each function) vs optimisation
|
||||
// // (inlining enables constant propagation through function calls, which cannot be achieved by our final optimiser in some cases)
|
||||
// // for now, we inline functions whose non-array parameters are constant, as this covers our main use case for inlining: propagation of
|
||||
// // constant array indices
|
||||
// match function {
|
||||
// Some(..) => {
|
||||
// // check whether non-array arguments are constant
|
||||
// arguments.iter().all(|e| match e {
|
||||
// TypedExpression::FieldElementArray(..) => true,
|
||||
// TypedExpression::FieldElement(FieldElementExpression::Number(..)) => true,
|
||||
// TypedExpression::Boolean(BooleanExpression::Value(..)) => true,
|
||||
// _ => false,
|
||||
// })
|
||||
// }
|
||||
// None => false,
|
||||
// }
|
||||
// }
|
||||
fn should_inline(
|
||||
&self,
|
||||
function: &Option<TypedFunction<T>>,
|
||||
arguments: &Vec<TypedExpression<T>>,
|
||||
) -> bool {
|
||||
// we should define a heuristic here
|
||||
// currently it doesn't seem like there's a tradeoff as everything gets inlined in flattening anyway (apart from compiling performance, as inlining
|
||||
// in flattening should be faster and less memory intensive)
|
||||
// however, using backends such as bellman, we could avoid flattening and "stream" the computation
|
||||
// at proving time, the tradeoff becomes code size (not inlining keeps only one copy of each function) vs optimisation
|
||||
// (inlining enables constant propagation through function calls, which cannot be achieved by our final optimiser in some cases)
|
||||
// for now, we inline functions whose non-array parameters are constant, as this covers our main use case for inlining: propagation of
|
||||
// constant array indices
|
||||
match function {
|
||||
Some(..) => {
|
||||
// check whether non-array arguments are constant
|
||||
arguments.iter().all(|e| match e {
|
||||
TypedExpression::FieldElementArray(..) => true,
|
||||
TypedExpression::FieldElement(FieldElementExpression::Number(..)) => true,
|
||||
TypedExpression::Boolean(BooleanExpression::Value(..)) => true,
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
// // inline a call to `function` taking `expressions` as inputs
|
||||
// // this function mutates `self.call` by incrementing the counter for `function`, and mutates `self.context`
|
||||
// fn inline_call(
|
||||
// &mut self,
|
||||
// function: &TypedFunction<T>,
|
||||
// expressions: Vec<TypedExpression<T>>,
|
||||
// ) -> Vec<TypedExpression<T>> {
|
||||
// self.call_count
|
||||
// .entry(function.to_slug())
|
||||
// .and_modify(|i| *i += 1)
|
||||
// .or_insert(1);
|
||||
// self.context.push((
|
||||
// function.to_slug(),
|
||||
// *self.call_count.get(&function.to_slug()).unwrap(),
|
||||
// ));
|
||||
// inline a call to `function` taking `expressions` as inputs
|
||||
// this function mutates `self.call` by incrementing the counter for `function`, and mutates `self.context`
|
||||
fn inline_call(
|
||||
&mut self,
|
||||
function: TypedFunction<'ast, T>,
|
||||
expressions: Vec<TypedExpression<'ast, T>>,
|
||||
) -> Vec<TypedExpression<'ast, T>> {
|
||||
self.call_count
|
||||
.entry(function.to_slug())
|
||||
.and_modify(|i| *i += 1)
|
||||
.or_insert(1);
|
||||
self.context.push((
|
||||
function.id.clone(),
|
||||
function.signature.clone(),
|
||||
*self.call_count.get(&function.to_slug()).unwrap(),
|
||||
));
|
||||
|
||||
// // add definitions for the inputs
|
||||
// let mut inputs_bindings = function
|
||||
// .arguments
|
||||
// .iter()
|
||||
// .zip(expressions)
|
||||
// .map(|(a, e)| {
|
||||
// TypedStatement::Definition(
|
||||
// TypedAssignee::Identifier(self.fold_variable(a.id.clone())),
|
||||
// e,
|
||||
// )
|
||||
// })
|
||||
// .collect();
|
||||
// self.statements_buffer.append(&mut inputs_bindings);
|
||||
// add definitions for the inputs
|
||||
let mut inputs_bindings = function
|
||||
.arguments
|
||||
.iter()
|
||||
.zip(expressions)
|
||||
.map(|(a, e)| {
|
||||
TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(self.fold_variable(a.id.clone())),
|
||||
e,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
self.statements_buffer.append(&mut inputs_bindings);
|
||||
|
||||
// // filter out the return statement and keep it aside
|
||||
// let (mut statements, ret): (Vec<_>, Vec<_>) = function
|
||||
// .statements
|
||||
// .clone()
|
||||
// .into_iter()
|
||||
// .flat_map(|s| self.fold_statement(s))
|
||||
// .partition(|s| match s {
|
||||
// TypedStatement::Return(..) => false,
|
||||
// _ => true,
|
||||
// });
|
||||
// filter out the return statement and keep it aside
|
||||
let (mut statements, ret): (Vec<_>, Vec<_>) = function
|
||||
.statements
|
||||
.clone()
|
||||
.into_iter()
|
||||
.flat_map(|s| self.fold_statement(s))
|
||||
.partition(|s| match s {
|
||||
TypedStatement::Return(..) => false,
|
||||
_ => true,
|
||||
});
|
||||
|
||||
// // add all statements to the buffer
|
||||
// self.statements_buffer.append(&mut statements);
|
||||
// add all statements to the buffer
|
||||
self.statements_buffer.append(&mut statements);
|
||||
|
||||
// // remove this call from the context
|
||||
// self.context.pop();
|
||||
// remove this call from the context
|
||||
self.context.pop();
|
||||
|
||||
// match ret[0].clone() {
|
||||
// TypedStatement::Return(exprs) => exprs,
|
||||
// _ => panic!(""),
|
||||
// }
|
||||
// }
|
||||
match ret[0].clone() {
|
||||
TypedStatement::Return(exprs) => exprs,
|
||||
_ => panic!(""),
|
||||
}
|
||||
}
|
||||
|
||||
// pub fn inline(prog: TypedProg<T>) -> TypedProg<T> {
|
||||
// Inliner::new().fold_program(prog)
|
||||
// }
|
||||
// }
|
||||
pub fn inline(prog: TypedProg<T>) -> TypedProg<T> {
|
||||
Inliner::new().fold_program(prog)
|
||||
}
|
||||
}
|
||||
|
||||
// impl<T: Field> Folder<T> for Inliner<T> {
|
||||
// // store the list of functions
|
||||
// fn fold_program(&mut self, p: TypedProg<T>) -> TypedProg<T> {
|
||||
// self.functions = p.functions.clone();
|
||||
// fold_program(self, p)
|
||||
// }
|
||||
impl<'ast, T: Field> Folder<'ast, T> for Inliner<'ast, T> {
|
||||
// store the list of functions
|
||||
fn fold_program(&mut self, p: TypedProg<'ast, T>) -> TypedProg<'ast, T> {
|
||||
self.functions = p.functions.clone();
|
||||
fold_program(self, p)
|
||||
}
|
||||
|
||||
// // add extra statements before the modified statement
|
||||
// fn fold_statement(&mut self, s: TypedStatement<T>) -> Vec<TypedStatement<T>> {
|
||||
// let mut statements = match s {
|
||||
// TypedStatement::MultipleDefinition(variables, elist) => {
|
||||
// match elist {
|
||||
// TypedExpressionList::FunctionCall(id, exps, types) => {
|
||||
// let variables: Vec<_> = variables
|
||||
// .into_iter()
|
||||
// .map(|a| self.fold_variable(a))
|
||||
// .collect();
|
||||
// let exps: Vec<_> =
|
||||
// exps.into_iter().map(|e| self.fold_expression(e)).collect();
|
||||
// add extra statements before the modified statement
|
||||
fn fold_statement(&mut self, s: TypedStatement<'ast, T>) -> Vec<TypedStatement<'ast, T>> {
|
||||
let mut statements = match s {
|
||||
TypedStatement::MultipleDefinition(variables, elist) => {
|
||||
match elist {
|
||||
TypedExpressionList::FunctionCall(id, exps, types) => {
|
||||
let variables: Vec<_> = variables
|
||||
.into_iter()
|
||||
.map(|a| self.fold_variable(a))
|
||||
.collect();
|
||||
let exps: Vec<_> =
|
||||
exps.into_iter().map(|e| self.fold_expression(e)).collect();
|
||||
|
||||
// let passed_signature = Signature::new()
|
||||
// .inputs(exps.iter().map(|e| e.get_type()).collect())
|
||||
// .outputs(types.clone());
|
||||
let passed_signature = Signature::new()
|
||||
.inputs(exps.iter().map(|e| e.get_type()).collect())
|
||||
.outputs(types.clone());
|
||||
|
||||
// // find the function
|
||||
// let function = self
|
||||
// .functions
|
||||
// .iter()
|
||||
// .find(|f| f.id == id && f.signature == passed_signature)
|
||||
// .cloned();
|
||||
// find the function
|
||||
let function = self
|
||||
.functions
|
||||
.iter()
|
||||
.find(|f| f.id == id && f.signature == passed_signature)
|
||||
.cloned();
|
||||
|
||||
// match self.should_inline(&function, &exps) {
|
||||
// true => {
|
||||
// let ret = self.inline_call(&function.unwrap(), exps);
|
||||
// variables
|
||||
// .into_iter()
|
||||
// .zip(ret.into_iter())
|
||||
// .map(|(v, e)| {
|
||||
// TypedStatement::Definition(TypedAssignee::Identifier(v), e)
|
||||
// })
|
||||
// .collect()
|
||||
// }
|
||||
// false => vec![TypedStatement::MultipleDefinition(
|
||||
// variables,
|
||||
// TypedExpressionList::FunctionCall(id, exps, types),
|
||||
// )],
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// s => fold_statement(self, s),
|
||||
// };
|
||||
match self.should_inline(&function, &exps) {
|
||||
true => {
|
||||
let ret = self.inline_call(function.unwrap(), exps);
|
||||
variables
|
||||
.into_iter()
|
||||
.zip(ret.into_iter())
|
||||
.map(|(v, e)| {
|
||||
TypedStatement::Definition(TypedAssignee::Identifier(v), e)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
false => vec![TypedStatement::MultipleDefinition(
|
||||
variables,
|
||||
TypedExpressionList::FunctionCall(id, exps, types),
|
||||
)],
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
s => fold_statement(self, s),
|
||||
};
|
||||
|
||||
// // add the result of folding to the buffer
|
||||
// self.statements_buffer.append(&mut statements);
|
||||
// // return the whole buffer
|
||||
// self.statements_buffer.drain(..).collect()
|
||||
// }
|
||||
// add the result of folding to the buffer
|
||||
self.statements_buffer.append(&mut statements);
|
||||
// return the whole buffer
|
||||
self.statements_buffer.drain(..).collect()
|
||||
}
|
||||
|
||||
// // prefix all names with the context
|
||||
// fn fold_name(&mut self, n: String) -> String {
|
||||
// match self.context.len() {
|
||||
// 0 => n,
|
||||
// _ => format!(
|
||||
// "{}_{}",
|
||||
// self.context
|
||||
// .iter()
|
||||
// .map(|(s, i)| format!("{}_{}", s, i))
|
||||
// .collect::<Vec<_>>()
|
||||
// .join("_"),
|
||||
// n
|
||||
// ),
|
||||
// }
|
||||
// }
|
||||
// prefix all names with the context
|
||||
fn fold_name(&mut self, n: Identifier<'ast>) -> Identifier<'ast> {
|
||||
Identifier {
|
||||
stack: self.context.clone(),
|
||||
..n
|
||||
}
|
||||
}
|
||||
|
||||
// // inline calls which return a field element
|
||||
// fn fold_field_expression(&mut self, e: FieldElementExpression<T>) -> FieldElementExpression<T> {
|
||||
// match e {
|
||||
// FieldElementExpression::FunctionCall(id, exps) => {
|
||||
// let exps: Vec<_> = exps.into_iter().map(|e| self.fold_expression(e)).collect();
|
||||
// inline calls which return a field element
|
||||
fn fold_field_expression(
|
||||
&mut self,
|
||||
e: FieldElementExpression<'ast, T>,
|
||||
) -> FieldElementExpression<'ast, T> {
|
||||
match e {
|
||||
FieldElementExpression::FunctionCall(id, exps) => {
|
||||
let exps: Vec<_> = exps.into_iter().map(|e| self.fold_expression(e)).collect();
|
||||
|
||||
// let passed_signature = Signature::new()
|
||||
// .inputs(exps.iter().map(|e| e.get_type()).collect())
|
||||
// .outputs(vec![Type::FieldElement]);
|
||||
let passed_signature = Signature::new()
|
||||
.inputs(exps.iter().map(|e| e.get_type()).collect())
|
||||
.outputs(vec![Type::FieldElement]);
|
||||
|
||||
// // find the function
|
||||
// let function = self
|
||||
// .functions
|
||||
// .iter()
|
||||
// .find(|f| f.id == id && f.signature == passed_signature)
|
||||
// .cloned();
|
||||
// find the function
|
||||
let function = self
|
||||
.functions
|
||||
.iter()
|
||||
.find(|f| f.id == id && f.signature == passed_signature)
|
||||
.cloned();
|
||||
|
||||
// match self.should_inline(&function, &exps) {
|
||||
// true => {
|
||||
// let ret = self.inline_call(&function.unwrap(), exps);
|
||||
// // unwrap the result to return a field element
|
||||
// match ret[0].clone() {
|
||||
// TypedExpression::FieldElement(e) => e,
|
||||
// _ => panic!(""),
|
||||
// }
|
||||
// }
|
||||
// false => FieldElementExpression::FunctionCall(id, exps),
|
||||
// }
|
||||
// }
|
||||
// // default
|
||||
// e => fold_field_expression(self, e),
|
||||
// }
|
||||
// }
|
||||
match self.should_inline(&function, &exps) {
|
||||
true => {
|
||||
let ret = self.inline_call(function.unwrap(), exps);
|
||||
// unwrap the result to return a field element
|
||||
match ret[0].clone() {
|
||||
TypedExpression::FieldElement(e) => e,
|
||||
_ => panic!(""),
|
||||
}
|
||||
}
|
||||
false => FieldElementExpression::FunctionCall(id, exps),
|
||||
}
|
||||
}
|
||||
// default
|
||||
e => fold_field_expression(self, e),
|
||||
}
|
||||
}
|
||||
|
||||
// // inline calls which return a field element array
|
||||
// fn fold_field_array_expression(
|
||||
// &mut self,
|
||||
// e: FieldElementArrayExpression<T>,
|
||||
// ) -> FieldElementArrayExpression<T> {
|
||||
// match e {
|
||||
// FieldElementArrayExpression::FunctionCall(size, id, exps) => {
|
||||
// let exps: Vec<_> = exps.into_iter().map(|e| self.fold_expression(e)).collect();
|
||||
// inline calls which return a field element array
|
||||
fn fold_field_array_expression(
|
||||
&mut self,
|
||||
e: FieldElementArrayExpression<'ast, T>,
|
||||
) -> FieldElementArrayExpression<'ast, T> {
|
||||
match e {
|
||||
FieldElementArrayExpression::FunctionCall(size, id, exps) => {
|
||||
let exps: Vec<_> = exps.into_iter().map(|e| self.fold_expression(e)).collect();
|
||||
|
||||
// let passed_signature = Signature::new()
|
||||
// .inputs(exps.iter().map(|e| e.get_type()).collect())
|
||||
// .outputs(vec![Type::FieldElementArray(size)]);
|
||||
let passed_signature = Signature::new()
|
||||
.inputs(exps.iter().map(|e| e.get_type()).collect())
|
||||
.outputs(vec![Type::FieldElementArray(size)]);
|
||||
|
||||
// // find the function
|
||||
// let function = self
|
||||
// .functions
|
||||
// .iter()
|
||||
// .find(|f| f.id == id && f.signature == passed_signature)
|
||||
// .cloned();
|
||||
// find the function
|
||||
let function = self
|
||||
.functions
|
||||
.iter()
|
||||
.find(|f| f.id == id && f.signature == passed_signature)
|
||||
.cloned();
|
||||
|
||||
// match self.should_inline(&function, &exps) {
|
||||
// true => {
|
||||
// let ret = self.inline_call(&function.unwrap(), exps);
|
||||
// // unwrap the result to return a field element
|
||||
// match ret[0].clone() {
|
||||
// TypedExpression::FieldElementArray(e) => e,
|
||||
// _ => panic!(""),
|
||||
// }
|
||||
// }
|
||||
// false => FieldElementArrayExpression::FunctionCall(size, id, exps),
|
||||
// }
|
||||
// }
|
||||
// // default
|
||||
// e => fold_field_array_expression(self, e),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
match self.should_inline(&function, &exps) {
|
||||
true => {
|
||||
let ret = self.inline_call(function.unwrap(), exps);
|
||||
// unwrap the result to return a field element
|
||||
match ret[0].clone() {
|
||||
TypedExpression::FieldElementArray(e) => e,
|
||||
_ => panic!(""),
|
||||
}
|
||||
}
|
||||
false => FieldElementArrayExpression::FunctionCall(size, id, exps),
|
||||
}
|
||||
}
|
||||
// default
|
||||
e => fold_field_array_expression(self, e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// #[cfg(test)]
|
||||
// mod tests {
|
||||
// use super::*;
|
||||
// use zokrates_field::field::FieldPrime;
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use zokrates_field::field::FieldPrime;
|
||||
|
||||
// #[cfg(test)]
|
||||
// mod heuristics {
|
||||
// use super::*;
|
||||
#[cfg(test)]
|
||||
mod heuristics {
|
||||
use super::*;
|
||||
|
||||
// #[test]
|
||||
// fn inline_constant_field() {
|
||||
// let f: TypedFunction<FieldPrime> = TypedFunction {
|
||||
// id: String::from("foo"),
|
||||
// arguments: vec![
|
||||
// Parameter::private(Variable::field_element("a")),
|
||||
// Parameter::private(Variable::field_array("b", 3)),
|
||||
// ],
|
||||
// statements: vec![TypedStatement::Return(vec![
|
||||
// FieldElementExpression::Select(
|
||||
// box FieldElementArrayExpression::Identifier(3, String::from("b")),
|
||||
// box FieldElementExpression::Identifier(String::from("a")),
|
||||
// )
|
||||
// .into(),
|
||||
// ])],
|
||||
// signature: Signature::new()
|
||||
// .inputs(vec![Type::FieldElement, Type::FieldElementArray(3)])
|
||||
// .outputs(vec![Type::FieldElement]),
|
||||
// };
|
||||
#[test]
|
||||
fn inline_constant_field() {
|
||||
let f: TypedFunction<FieldPrime> = TypedFunction {
|
||||
id: "foo",
|
||||
arguments: vec![
|
||||
Parameter::private(Variable::field_element("a".into())),
|
||||
Parameter::private(Variable::field_array("b".into(), 3)),
|
||||
],
|
||||
statements: vec![TypedStatement::Return(vec![
|
||||
FieldElementExpression::Select(
|
||||
box FieldElementArrayExpression::Identifier(3, Identifier::from("b")),
|
||||
box FieldElementExpression::Identifier(Identifier::from("a")),
|
||||
)
|
||||
.into(),
|
||||
])],
|
||||
signature: Signature::new()
|
||||
.inputs(vec![Type::FieldElement, Type::FieldElementArray(3)])
|
||||
.outputs(vec![Type::FieldElement]),
|
||||
};
|
||||
|
||||
// let arguments = vec![
|
||||
// FieldElementExpression::Number(FieldPrime::from(0)).into(),
|
||||
// FieldElementArrayExpression::Identifier(3, String::from("random")).into(),
|
||||
// ];
|
||||
let arguments = vec![
|
||||
FieldElementExpression::Number(FieldPrime::from(0)).into(),
|
||||
FieldElementArrayExpression::Identifier(3, Identifier::from("random")).into(),
|
||||
];
|
||||
|
||||
// let i = Inliner::new();
|
||||
let i = Inliner::new();
|
||||
|
||||
// assert!(i.should_inline(&Some(f), &arguments));
|
||||
// }
|
||||
assert!(i.should_inline(&Some(f), &arguments));
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn no_inline_non_constant_field() {
|
||||
// let f: TypedFunction<FieldPrime> = TypedFunction {
|
||||
// id: String::from("foo"),
|
||||
// arguments: vec![
|
||||
// Parameter::private(Variable::field_element("a")),
|
||||
// Parameter::private(Variable::field_array("b", 3)),
|
||||
// ],
|
||||
// statements: vec![TypedStatement::Return(vec![
|
||||
// FieldElementExpression::Select(
|
||||
// box FieldElementArrayExpression::Identifier(3, String::from("b")),
|
||||
// box FieldElementExpression::Identifier(String::from("a")),
|
||||
// )
|
||||
// .into(),
|
||||
// ])],
|
||||
// signature: Signature::new()
|
||||
// .inputs(vec![Type::FieldElement, Type::FieldElementArray(3)])
|
||||
// .outputs(vec![Type::FieldElement]),
|
||||
// };
|
||||
#[test]
|
||||
fn no_inline_non_constant_field() {
|
||||
let f: TypedFunction<FieldPrime> = TypedFunction {
|
||||
id: "foo",
|
||||
arguments: vec![
|
||||
Parameter::private(Variable::field_element("a".into())),
|
||||
Parameter::private(Variable::field_array("b".into(), 3)),
|
||||
],
|
||||
statements: vec![TypedStatement::Return(vec![
|
||||
FieldElementExpression::Select(
|
||||
box FieldElementArrayExpression::Identifier(3, Identifier::from("b")),
|
||||
box FieldElementExpression::Identifier(Identifier::from("a")),
|
||||
)
|
||||
.into(),
|
||||
])],
|
||||
signature: Signature::new()
|
||||
.inputs(vec![Type::FieldElement, Type::FieldElementArray(3)])
|
||||
.outputs(vec![Type::FieldElement]),
|
||||
};
|
||||
|
||||
// let arguments = vec![
|
||||
// FieldElementExpression::Identifier(String::from("notconstant")).into(),
|
||||
// FieldElementArrayExpression::Identifier(3, String::from("random")).into(),
|
||||
// ];
|
||||
let arguments = vec![
|
||||
FieldElementExpression::Identifier(Identifier::from("notconstant")).into(),
|
||||
FieldElementArrayExpression::Identifier(3, Identifier::from("random")).into(),
|
||||
];
|
||||
|
||||
// let i = Inliner::new();
|
||||
let i = Inliner::new();
|
||||
|
||||
// assert!(!i.should_inline(&Some(f), &arguments));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
assert!(!i.should_inline(&Some(f), &arguments));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,13 +6,13 @@
|
|||
|
||||
mod dead_code;
|
||||
mod flat_propagation;
|
||||
//mod inline;
|
||||
mod inline;
|
||||
mod power_check;
|
||||
mod propagation;
|
||||
mod unroll;
|
||||
|
||||
use self::dead_code::DeadCode;
|
||||
//use self::inline::Inliner;
|
||||
use self::inline::Inliner;
|
||||
use self::power_check::PowerChecker;
|
||||
use self::propagation::Propagator;
|
||||
use self::unroll::Unroller;
|
||||
|
@ -32,7 +32,8 @@ impl<'ast, T: Field> Analyse for TypedProg<'ast, T> {
|
|||
//propagate a first time for constants to reach function calls
|
||||
let r = Propagator::propagate(r);
|
||||
// apply inlining strategy
|
||||
//let r = Inliner::inline(r);
|
||||
let r = Inliner::inline(r);
|
||||
println!("{}", r);
|
||||
// Propagate again
|
||||
let r = Propagator::propagate(r);
|
||||
// remove unused functions
|
||||
|
|
|
@ -27,10 +27,11 @@ impl<'ast> Unroller<'ast> {
|
|||
id: Identifier {
|
||||
id: v.id.id,
|
||||
version: i + 1,
|
||||
stack: vec![],
|
||||
},
|
||||
..v
|
||||
},
|
||||
None => Variable { ..v },
|
||||
None => Variable { ..v.clone() },
|
||||
};
|
||||
self.substitution
|
||||
.entry(v.id)
|
||||
|
|
|
@ -21,21 +21,38 @@ use zokrates_field::field::Field;
|
|||
|
||||
pub use self::folder::Folder;
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Hash, Eq, Copy)]
|
||||
#[derive(Debug, PartialEq, Clone, Hash, Eq)]
|
||||
pub struct Identifier<'ast> {
|
||||
pub id: &'ast str,
|
||||
pub version: usize,
|
||||
pub stack: Vec<(&'ast str, Signature, usize)>,
|
||||
}
|
||||
|
||||
pub type FunctionIdentifier<'ast> = &'ast str;
|
||||
|
||||
impl<'ast> fmt::Display for Identifier<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}_{}", self.id, self.version)
|
||||
write!(
|
||||
f,
|
||||
"{}_{}_{}",
|
||||
self.stack
|
||||
.iter()
|
||||
.map(|(name, sig, count)| format!("{}_{}_{}", name, sig.to_slug(), count))
|
||||
.collect::<Vec<_>>()
|
||||
.join("_"),
|
||||
self.id,
|
||||
self.version
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> From<&'ast str> for Identifier<'ast> {
|
||||
fn from(id: &'ast str) -> Identifier<'ast> {
|
||||
Identifier { id, version: 0 }
|
||||
Identifier {
|
||||
id,
|
||||
version: 0,
|
||||
stack: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,7 +124,7 @@ impl<'ast, T: Field> fmt::Debug for TypedProg<'ast, T> {
|
|||
#[derive(Clone, PartialEq)]
|
||||
pub struct TypedFunction<'ast, T: Field> {
|
||||
/// Name of the program
|
||||
pub id: String,
|
||||
pub id: FunctionIdentifier<'ast>,
|
||||
/// Arguments of the function
|
||||
pub arguments: Vec<Parameter<'ast>>,
|
||||
/// Vector of statements that are executed when running the function
|
||||
|
|
|
@ -49,6 +49,7 @@ impl<'ast> From<absy::Variable<'ast>> for Variable<'ast> {
|
|||
Identifier {
|
||||
id: v.id,
|
||||
version: 0,
|
||||
stack: vec![],
|
||||
},
|
||||
v._type,
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue