From 9be5f770cbc60901e663fbb29ea512f841e33e6e Mon Sep 17 00:00:00 2001 From: ControlCplusControlV <44706811+ControlCplusControlV@users.noreply.github.com> Date: Mon, 16 Jan 2023 18:17:38 -0700 Subject: [PATCH 1/3] more progress on opts --- Cargo.toml | 1 + crates/miden-integration-tests/Cargo.toml | 2 +- crates/miden-integration-tests/src/lib.rs | 4 +- crates/miden-integration-tests/tests/lib.rs | 3 +- .../tests/optimization.rs | 89 +++++++++ .../tests/quickcheck_tests.rs | 2 +- crates/miden-integration-tests/tests/utils.rs | 40 ++-- crates/papyrus/src/ast_optimization.rs | 181 +++++++++++------- 8 files changed, 225 insertions(+), 97 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b32b031..59002e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] members = [ "crates/papyrus", + "crates/miden-integration-tests", "bin/scribe", "bin/repl", ] \ No newline at end of file diff --git a/crates/miden-integration-tests/Cargo.toml b/crates/miden-integration-tests/Cargo.toml index 6ec3cab..adc1d71 100644 --- a/crates/miden-integration-tests/Cargo.toml +++ b/crates/miden-integration-tests/Cargo.toml @@ -17,7 +17,7 @@ harness = true [dependencies] -scribe = {path = "../transpiler/"} +papyrus = { path = "../papyrus" } miden-assembly = { git = "http://github.com/maticnetwork/miden", branch = "next" } miden-processor = { git = "http://github.com/maticnetwork/miden", branch = "next" } miden-core = { git = "http://github.com/maticnetwork/miden", branch = "next" } diff --git a/crates/miden-integration-tests/src/lib.rs b/crates/miden-integration-tests/src/lib.rs index 8b13789..7a4432c 100644 --- a/crates/miden-integration-tests/src/lib.rs +++ b/crates/miden-integration-tests/src/lib.rs @@ -1 +1,3 @@ - +pub fn test() { + println!("Hello, world!"); +} \ No newline at end of file diff --git a/crates/miden-integration-tests/tests/lib.rs b/crates/miden-integration-tests/tests/lib.rs index 77e14a4..6179a5a 100644 --- a/crates/miden-integration-tests/tests/lib.rs +++ b/crates/miden-integration-tests/tests/lib.rs @@ -1,8 +1,7 @@ #[macro_use] extern crate quickcheck; mod future; -mod milestone_1; -mod milestone_2; mod quickcheck_tests; mod test; mod utils; +mod optimization; \ No newline at end of file diff --git a/crates/miden-integration-tests/tests/optimization.rs b/crates/miden-integration-tests/tests/optimization.rs index 9f2830b..247af08 100644 --- a/crates/miden-integration-tests/tests/optimization.rs +++ b/crates/miden-integration-tests/tests/optimization.rs @@ -1,5 +1,6 @@ use crate::utils::compile_example; use indoc::indoc; +use papyrus::ast_optimization::optimize_ast; #[test] fn optimization_basic_constant_replacement() { @@ -143,3 +144,91 @@ fn optimization_let_old_vars_die_v2() { "}, ); } + + +#[test] +fn test_for_loop_to_repeat_statement_optimization() { + //Conditional is lt + let source_code = " + let result := 0 + + for { let i := 0 } lt(i, 100) { i := add(i, 1) } + { + result := mul(result, 2) + } + "; + + let parsed = papyrus::parser::parse_yul_syntax(source_code); + let ast = optimize_ast(parsed); + + println!("{:#?}", ast); + + + + // insta::assert_debug_snapshot!(ast); + + + // //Conditional is lt, mul + // let source_code = " + // let result := 0 + + // for { let i := 0 } lt(i, 100) { i := mul(i, 2) } + // { + // result := mul(result, 2) + // } + // " + + // let parsed = parser::parse_yul_syntax(source_code); + // let ast = optimize_ast(parsed); + // insta::assert_debug_snapshot!(ast); + + + // //Conditional is gt, div + // let source_code = " + // let result := 0 + + // for { let i := 100 } gt(i, 0) { i := div(i, 2) } + // { + // result := mul(result, 2) + // } + // " + + // let parsed = parser::parse_yul_syntax(source_code); + // let ast = optimize_ast(parsed); + // insta::assert_debug_snapshot!(ast); + + + + // //Conditional is slt + // let source_code = " + // let result := 0 + + // for { let i := 100 } gt(i, 0) { i := sub(i, 1) } + // { + // result := mul(result, 2) + // } + // " + + // let parsed = parser::parse_yul_syntax(source_code); + // let ast = optimize_ast(parsed); + // insta::assert_debug_snapshot!(ast); + + + + // //Conditional is sgt + // let source_code = " + // let result := 0 + + // for { let i := 100 } gt(i, 0) { i := sub(i, 1) } + // { + // result := mul(result, 2) + // } + // " + + // let parsed = parser::parse_yul_syntax(source_code); + // let ast = optimize_ast(parsed); + // insta::assert_debug_snapshot!(ast); + + + +} \ No newline at end of file diff --git a/crates/miden-integration-tests/tests/quickcheck_tests.rs b/crates/miden-integration-tests/tests/quickcheck_tests.rs index 1f83502..7537a92 100644 --- a/crates/miden-integration-tests/tests/quickcheck_tests.rs +++ b/crates/miden-integration-tests/tests/quickcheck_tests.rs @@ -2,7 +2,7 @@ use crate::utils::{miden_to_u256, MidenResult}; use miden_core::StarkField; use quickcheck::{Arbitrary, Gen, TestResult}; use quickcheck_macros::quickcheck; -use scribe::{ +use papyrus::{ executor::execute, utils::{convert_u256_to_pushes, join_u32s_to_u256, load_all_procs, split_u256_to_u32s}, }; diff --git a/crates/miden-integration-tests/tests/utils.rs b/crates/miden-integration-tests/tests/utils.rs index cfbe178..905adc9 100644 --- a/crates/miden-integration-tests/tests/utils.rs +++ b/crates/miden-integration-tests/tests/utils.rs @@ -1,28 +1,31 @@ use colored::*; use miden_core::StarkField; use primitive_types::U256; -use scribe::ast_optimization::optimize_ast; -use scribe::executor; -use scribe::miden_generator; -use scribe::miden_generator::CompileOptions; -use scribe::parser; -use scribe::type_inference::infer_types; -use scribe::types::expressions_to_tree; -use scribe::types::YulFile; +use papyrus::ast_optimization::optimize_ast; +use papyrus::executor; +use papyrus::miden_generator; +use papyrus::miden_generator::CompileOptions; +use papyrus::parser; +use papyrus::type_inference::infer_types; +use papyrus::types::expressions_to_tree; +use papyrus::types::YulFile; use std::fs; pub enum MidenResult { U256(primitive_types::U256), U32(u32), } + +fn print_title(s: &str) { + let s1 = format!("=== {} ===", s).blue().bold(); + println!("{}", s1); + println!(" "); +} + //Function to display transpile Yul code and display each step of the transpilation process in the terminal. //This function is only used to demonstrate what Scribe does in a easy to read format. pub fn run_example(yul_code: &str, expected_output: MidenResult) { - fn print_title(s: &str) { - let s1 = format!("=== {} ===", s).blue().bold(); - println!("{}", s1); - println!(" "); - } + println!(); println!(); print_title("Input Yul"); @@ -38,7 +41,7 @@ pub fn run_example(yul_code: &str, expected_output: MidenResult) { println!("{}", expressions_to_tree(&ast)); println!(); - let (transpiler, miden_code) = miden_generator::transpile_program(ast, Default::default()); + let miden_code = miden_generator::transpile_program(ast, Default::default()); let mut trimmed_miden_code = miden_code .split('\n') // .skip_while(|line| *line != "# end std lib #") @@ -49,7 +52,7 @@ pub fn run_example(yul_code: &str, expected_output: MidenResult) { print_title("Generated Miden Assembly"); println!("{}", trimmed_miden_code); println!(); - println!("Estimated cost: {}", transpiler.cost); + // println!("Estimated cost: {}", transpiler.cost); println!(); fs::write(format!("./test_output.masm",), trimmed_miden_code) .expect("Unable to write Miden to file."); @@ -81,11 +84,6 @@ pub fn run_example(yul_code: &str, expected_output: MidenResult) { } pub fn compile_example(yul_code: &str, expected_output: &str) { - fn print_title(s: &str) { - let s1 = format!("=== {} ===", s).blue().bold(); - println!("{}", s1); - println!(" "); - } let parsed = parser::parse_yul_syntax(yul_code); @@ -93,7 +91,7 @@ pub fn compile_example(yul_code: &str, expected_output: &str) { let ast = infer_types(&ast); - let (_, miden_code) = miden_generator::transpile_program( + let miden_code = miden_generator::transpile_program( ast, CompileOptions { comments: false, diff --git a/crates/papyrus/src/ast_optimization.rs b/crates/papyrus/src/ast_optimization.rs index c94d7ba..5cab95e 100644 --- a/crates/papyrus/src/ast_optimization.rs +++ b/crates/papyrus/src/ast_optimization.rs @@ -8,9 +8,14 @@ use crate::types::*; pub fn optimize_ast(ast: Vec) -> Vec { // let mut assignment_visitor = VariableAssignmentVisitor::default(); // let ast = walk_ast(ast, &mut assignment_visitor); + + // let const_variables = assignment_visitor.get_const_variables(); // let ast = walk_ast(ast, &mut ConstVariableVisitor { const_variables }); + + + // walk_ast(ast, &mut ForLoopToRepeatVisitor {}) // TODO: fix optimizations ast @@ -73,77 +78,111 @@ impl VariableAssignmentVisitor { // add(i, 1) to i := add(1, i) will break this optimization. In the future we should support gt, // subtracting, etc. impl ExpressionVisitor for ForLoopToRepeatVisitor { - fn visit_expr(&mut self, _expr: Expr) -> Option { - todo!(); - // match &expr { - // Expr::ForLoop(ExprForLoop { - // init_block, - // conditional, - // after_block, - // interior_block, - // }) => { - // let start: Option; - // let iterator_identifier: Option; - // if let Some(first_expr) = (*init_block.exprs).first() { - // if let Expr::DeclareVariable(ExprDeclareVariable { identifier, rhs }) = - // first_expr - // { - // if let Some(Expr::Literal(value)) = rhs.clone().map(|e| *e) { - // start = Some(todo!("Need to get literal value here")); - // iterator_identifier = Some(identifier.to_string()); - // } else { - // return Some(expr); - // } - // } else { - // return Some(expr); - // } - // } else { - // return Some(expr); - // } - // - // if let Some(Expr::Assignment(assignment)) = (*after_block.exprs).first() { - // if *assignment - // == (ExprAssignment { - // typed_identifier: iterator_identifier.clone().unwrap(), - // rhs: Box::new(Expr::FunctionCall(ExprFunctionCall { - // function_name: "add".to_string(), - // exprs: Box::new(vec![ - // Expr::Variable(ExprVariableReference { - // identifier: iterator_identifier.clone().unwrap(), - // }), - // Expr::Literal(todo!("Need to get literal value here")), - // ]), - // })), - // }) - // {} - // } else { - // return Some(expr); - // } - // if let Expr::FunctionCall(ExprFunctionCall { - // function_name, - // exprs, - // }) = &**conditional - // { - // if function_name == "lt" - // && exprs[0] - // == Expr::Variable(ExprVariableReference { - // identifier: iterator_identifier.unwrap(), - // }) - // { - // if let Expr::Literal(value) = exprs[1] { - // return Some(Expr::Repeat(ExprRepeat { - // interior_block: interior_block.clone(), - // iterations: todo!("Get end value from literal"), - // })); - // } - // } - // } else { - // return Some(expr); - // } - // } - // _ => {} - // } - // Some(expr) + fn visit_expr(&mut self, expr: Expr) -> Option { + let preserve_value = Some(expr.clone()); + + if let Expr::ForLoop(ExprForLoop { + init_block, + conditional, + after_block, + interior_block, + }) = expr.clone() { + let mut i = 0; // Variable to keep track of where repeat begins + let init_value_name: String; + + + // Start out with the init block, and determine where iteration will start + /// This optimization will only be applied when the init block uses a number literal for the rhs + if init_block.exprs.len() != 1 { + return preserve_value; + } + + + + for expr in init_block.exprs { + if let Expr::Assignment(value) = expr.clone() { + if let Expr::Literal(value) = *value.rhs { + match value { + ExprLiteral::Number(n)=> { + i = n.value.0[3]; // TODO: make sure this is within u32 constraints + } + _ => { + return preserve_value; + } + } + } + } + } + + + let mut end_val = primitive_types::U256::zero(); + // With `i` now indicating where our iteration will start, we can check the conditional + if let Expr::FunctionCall(ExprFunctionCall{function_name, exprs, inferred_return_types, inferred_param_types }) = *conditional { + + if function_name == "lt"{ + if let Expr::Literal(ExprLiteral::Number(expr_literal_num)) = exprs.last().unwrap() { + end_val = expr_literal_num.value; + }; + + } else if function_name == "gt"{ + if let Expr::Literal(ExprLiteral::Number(expr_literal_num)) = exprs.last().unwrap() { + end_val = expr_literal_num.value; + }; + }else{ + return preserve_value; + } + + } + + // Determine iterator size + if after_block.exprs.len() != 1 { + return preserve_value; + } + let mut step = 0; + + for expr in after_block.exprs { + match expr { + Expr::Assignment(value) => { + if let Expr::FunctionCall(ExprFunctionCall { function_name, exprs, .. }) = *value.rhs { + if function_name == "add" { + + + + + for args in *exprs { + match args { + Expr::Literal(ExprLiteral::Number(expr_literal_num)) => { + step = expr_literal_num.value.0[3]; // TODO: make sure this is within u32 constraints + } + Expr::Variable(ExprVariableReference { identifier , ..}) => { + if identifier != "i" { // Should check identifier is the same as the one which appaered earlier + return preserve_value; + } + } + _ => return preserve_value + } + } + } + } + } + _ => return Some(expr) + } + } + + //TODO: + + // for { let i := 29 } lt(i, exponent) { i := add(i, 1) } + // { + // result := mul(result, base) + // } + + return Some(Expr::Repeat(ExprRepeat { + iterations: 53, + interior_block, + })); + }; + + Some(expr) } } From a5364d89b377460aa095ec168d7701d99daa88dc Mon Sep 17 00:00:00 2001 From: ControlCplusControlV <44706811+ControlCplusControlV@users.noreply.github.com> Date: Mon, 16 Jan 2023 19:04:56 -0700 Subject: [PATCH 2/3] changes --- crates/papyrus/src/ast_optimization.rs | 64 +++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 6 deletions(-) diff --git a/crates/papyrus/src/ast_optimization.rs b/crates/papyrus/src/ast_optimization.rs index 5cab95e..f7a6c90 100644 --- a/crates/papyrus/src/ast_optimization.rs +++ b/crates/papyrus/src/ast_optimization.rs @@ -88,8 +88,13 @@ impl ExpressionVisitor for ForLoopToRepeatVisitor { interior_block, }) = expr.clone() { let mut i = 0; // Variable to keep track of where repeat begins - let init_value_name: String; + let mut init_value_variable_name: String = "".to_string(); + //get the init value name, + + //Get the end value + + // Get the step and see if it is mul, add etc, and get the repeat amount // Start out with the init block, and determine where iteration will start /// This optimization will only be applied when the init block uses a number literal for the rhs @@ -97,7 +102,13 @@ impl ExpressionVisitor for ForLoopToRepeatVisitor { return preserve_value; } - + if let Some(Expr::DeclareVariable(ExprDeclareVariable{typed_identifiers, rhs: _}))= init_block.exprs.first(){ + if let Some(TypedIdentifier{identifier, yul_type}) = typed_identifiers.first(){ + init_value_variable_name = identifier.to_owned(); + } + }else{ + return preserve_value; + }; for expr in init_block.exprs { if let Expr::Assignment(value) = expr.clone() { @@ -138,30 +149,71 @@ impl ExpressionVisitor for ForLoopToRepeatVisitor { if after_block.exprs.len() != 1 { return preserve_value; } - let mut step = 0; + let mut iterations = 0; // Final value for repeat statement for expr in after_block.exprs { match expr { Expr::Assignment(value) => { if let Expr::FunctionCall(ExprFunctionCall { function_name, exprs, .. }) = *value.rhs { - if function_name == "add" { - + match function_name.to_string().as_str() { + "add" => { + let mut step = 1; + for args in *exprs { + match args { + Expr::Literal(ExprLiteral::Number(expr_literal_num)) => { + step = expr_literal_num.value.0[3]; // TODO: make sure this is within u32 constraints + } + Expr::Variable(ExprVariableReference { identifier , ..}) => { + if identifier != init_value_variable_name { // Should check identifier is the same as the one which appaered earlier + return preserve_value; + } + } + _ => return preserve_value + } + iterations = ((end_val - i) / step).0[3]; // TODO: make sure this is within u32 constraints + } + } + "sub" => { + let mut step = 1; + let args = *exprs; + if let Some(Expr::Variable( ExprVariableReference { identifier , ..})) = args.first() { + if *identifier != init_value_variable_name { + return preserve_value; + } + } + if let Some(Expr::Literal( ExprLiteral::Number())) = args.first() { + if *identifier != init_value_variable_name { + return preserve_value; + } + } + + + } + "mul" => { + let step = 1; + let args = *exprs; for args in *exprs { match args { Expr::Literal(ExprLiteral::Number(expr_literal_num)) => { step = expr_literal_num.value.0[3]; // TODO: make sure this is within u32 constraints } Expr::Variable(ExprVariableReference { identifier , ..}) => { - if identifier != "i" { // Should check identifier is the same as the one which appaered earlier + if identifier != init_value_variable_name { // Should check identifier is the same as the one which appaered earlier return preserve_value; } } _ => return preserve_value } + } + } + "div" => { + let step = 1; + let args = *exprs; } + _ => return preserve_value, } } } From 4982282eb19ad731754cb117ba8a0c821b0fde25 Mon Sep 17 00:00:00 2001 From: ControlCplusControlV <44706811+ControlCplusControlV@users.noreply.github.com> Date: Fri, 20 Jan 2023 21:14:52 -0700 Subject: [PATCH 3/3] finalized everything --- crates/miden-integration-tests/src/lib.rs | 2 +- .../miden-integration-tests/test_output.masm | 12 +- .../miden-integration-tests/tests/future.rs | 2 +- crates/miden-integration-tests/tests/lib.rs | 2 +- .../tests/optimization.rs | 34 +- .../tests/quickcheck_tests.rs | 4 +- crates/miden-integration-tests/tests/test.rs | 2 +- crates/miden-integration-tests/tests/utils.rs | 7 +- crates/papyrus/src/ast_optimization.rs | 310 +++++++++++------- 9 files changed, 209 insertions(+), 166 deletions(-) diff --git a/crates/miden-integration-tests/src/lib.rs b/crates/miden-integration-tests/src/lib.rs index 7a4432c..9815d27 100644 --- a/crates/miden-integration-tests/src/lib.rs +++ b/crates/miden-integration-tests/src/lib.rs @@ -1,3 +1,3 @@ pub fn test() { println!("Hello, world!"); -} \ No newline at end of file +} diff --git a/crates/miden-integration-tests/test_output.masm b/crates/miden-integration-tests/test_output.masm index 7b1384b..38cd87d 100644 --- a/crates/miden-integration-tests/test_output.masm +++ b/crates/miden-integration-tests/test_output.masm @@ -2,12 +2,12 @@ use.std::math::u256 begin - # and() # - # u256 literal: 0 # - push.0 push.0 push.0 push.0 push.0 push.0 push.0 push.0 + # eq() # + # u256 literal: 2 # + push.2 push.0 push.0 push.0 push.0 push.0 push.0 push.0 - # u256 literal: 0 # - push.0 push.0 push.0 push.0 push.0 push.0 push.0 push.0 + # u256 literal: 2 # + push.2 push.0 push.0 push.0 push.0 push.0 push.0 push.0 - exec.u256::and + exec.u256::eq_unsafe end \ No newline at end of file diff --git a/crates/miden-integration-tests/tests/future.rs b/crates/miden-integration-tests/tests/future.rs index 20f861f..c834ee7 100644 --- a/crates/miden-integration-tests/tests/future.rs +++ b/crates/miden-integration-tests/tests/future.rs @@ -1,5 +1,5 @@ -use primitive_types::U256; use crate::utils::{run_example, MidenResult}; +use primitive_types::U256; #[ignore] #[test] diff --git a/crates/miden-integration-tests/tests/lib.rs b/crates/miden-integration-tests/tests/lib.rs index 6179a5a..9406445 100644 --- a/crates/miden-integration-tests/tests/lib.rs +++ b/crates/miden-integration-tests/tests/lib.rs @@ -1,7 +1,7 @@ #[macro_use] extern crate quickcheck; mod future; +mod optimization; mod quickcheck_tests; mod test; mod utils; -mod optimization; \ No newline at end of file diff --git a/crates/miden-integration-tests/tests/optimization.rs b/crates/miden-integration-tests/tests/optimization.rs index 247af08..ed4c6f2 100644 --- a/crates/miden-integration-tests/tests/optimization.rs +++ b/crates/miden-integration-tests/tests/optimization.rs @@ -145,7 +145,6 @@ fn optimization_let_old_vars_die_v2() { ); } - #[test] fn test_for_loop_to_repeat_statement_optimization() { //Conditional is lt @@ -158,18 +157,15 @@ fn test_for_loop_to_repeat_statement_optimization() { } "; - let parsed = papyrus::parser::parse_yul_syntax(source_code); + let parsed = papyrus::parser::parse_yul_syntax(source_code); let ast = optimize_ast(parsed); println!("{:#?}", ast); - - // insta::assert_debug_snapshot!(ast); - // //Conditional is lt, mul - // let source_code = " + // let source_code = " // let result := 0 // for { let i := 0 } lt(i, 100) { i := mul(i, 2) } @@ -178,13 +174,12 @@ fn test_for_loop_to_repeat_statement_optimization() { // } // " - // let parsed = parser::parse_yul_syntax(source_code); + // let parsed = parser::parse_yul_syntax(source_code); // let ast = optimize_ast(parsed); // insta::assert_debug_snapshot!(ast); - // //Conditional is gt, div - // let source_code = " + // let source_code = " // let result := 0 // for { let i := 100 } gt(i, 0) { i := div(i, 2) } @@ -193,14 +188,12 @@ fn test_for_loop_to_repeat_statement_optimization() { // } // " - // let parsed = parser::parse_yul_syntax(source_code); + // let parsed = parser::parse_yul_syntax(source_code); // let ast = optimize_ast(parsed); // insta::assert_debug_snapshot!(ast); - - // //Conditional is slt - // let source_code = " + // let source_code = " // let result := 0 // for { let i := 100 } gt(i, 0) { i := sub(i, 1) } @@ -208,15 +201,13 @@ fn test_for_loop_to_repeat_statement_optimization() { // result := mul(result, 2) // } // " - - // let parsed = parser::parse_yul_syntax(source_code); + + // let parsed = parser::parse_yul_syntax(source_code); // let ast = optimize_ast(parsed); // insta::assert_debug_snapshot!(ast); - - // //Conditional is sgt - // let source_code = " + // let source_code = " // let result := 0 // for { let i := 100 } gt(i, 0) { i := sub(i, 1) } @@ -225,10 +216,7 @@ fn test_for_loop_to_repeat_statement_optimization() { // } // " - // let parsed = parser::parse_yul_syntax(source_code); + // let parsed = parser::parse_yul_syntax(source_code); // let ast = optimize_ast(parsed); // insta::assert_debug_snapshot!(ast); - - - -} \ No newline at end of file +} diff --git a/crates/miden-integration-tests/tests/quickcheck_tests.rs b/crates/miden-integration-tests/tests/quickcheck_tests.rs index 7537a92..899ee12 100644 --- a/crates/miden-integration-tests/tests/quickcheck_tests.rs +++ b/crates/miden-integration-tests/tests/quickcheck_tests.rs @@ -1,11 +1,11 @@ use crate::utils::{miden_to_u256, MidenResult}; use miden_core::StarkField; -use quickcheck::{Arbitrary, Gen, TestResult}; -use quickcheck_macros::quickcheck; use papyrus::{ executor::execute, utils::{convert_u256_to_pushes, join_u32s_to_u256, load_all_procs, split_u256_to_u32s}, }; +use quickcheck::{Arbitrary, Gen, TestResult}; +use quickcheck_macros::quickcheck; #[derive(Clone, Debug)] struct U256(primitive_types::U256); diff --git a/crates/miden-integration-tests/tests/test.rs b/crates/miden-integration-tests/tests/test.rs index 815e64d..38033c2 100644 --- a/crates/miden-integration-tests/tests/test.rs +++ b/crates/miden-integration-tests/tests/test.rs @@ -1,5 +1,5 @@ -use primitive_types::U256; use crate::utils::{run_example, MidenResult}; +use primitive_types::U256; #[test] fn integration_math() { diff --git a/crates/miden-integration-tests/tests/utils.rs b/crates/miden-integration-tests/tests/utils.rs index 905adc9..6e17acd 100644 --- a/crates/miden-integration-tests/tests/utils.rs +++ b/crates/miden-integration-tests/tests/utils.rs @@ -1,6 +1,5 @@ use colored::*; use miden_core::StarkField; -use primitive_types::U256; use papyrus::ast_optimization::optimize_ast; use papyrus::executor; use papyrus::miden_generator; @@ -9,13 +8,13 @@ use papyrus::parser; use papyrus::type_inference::infer_types; use papyrus::types::expressions_to_tree; use papyrus::types::YulFile; +use primitive_types::U256; use std::fs; pub enum MidenResult { U256(primitive_types::U256), U32(u32), } - fn print_title(s: &str) { let s1 = format!("=== {} ===", s).blue().bold(); println!("{}", s1); @@ -25,7 +24,6 @@ fn print_title(s: &str) { //Function to display transpile Yul code and display each step of the transpilation process in the terminal. //This function is only used to demonstrate what Scribe does in a easy to read format. pub fn run_example(yul_code: &str, expected_output: MidenResult) { - println!(); println!(); print_title("Input Yul"); @@ -41,7 +39,7 @@ pub fn run_example(yul_code: &str, expected_output: MidenResult) { println!("{}", expressions_to_tree(&ast)); println!(); - let miden_code = miden_generator::transpile_program(ast, Default::default()); + let miden_code = miden_generator::transpile_program(ast, Default::default()); let mut trimmed_miden_code = miden_code .split('\n') // .skip_while(|line| *line != "# end std lib #") @@ -84,7 +82,6 @@ pub fn run_example(yul_code: &str, expected_output: MidenResult) { } pub fn compile_example(yul_code: &str, expected_output: &str) { - let parsed = parser::parse_yul_syntax(yul_code); let ast = optimize_ast(parsed); diff --git a/crates/papyrus/src/ast_optimization.rs b/crates/papyrus/src/ast_optimization.rs index f7a6c90..cdaf8e0 100644 --- a/crates/papyrus/src/ast_optimization.rs +++ b/crates/papyrus/src/ast_optimization.rs @@ -9,13 +9,9 @@ pub fn optimize_ast(ast: Vec) -> Vec { // let mut assignment_visitor = VariableAssignmentVisitor::default(); // let ast = walk_ast(ast, &mut assignment_visitor); - // let const_variables = assignment_visitor.get_const_variables(); // let ast = walk_ast(ast, &mut ConstVariableVisitor { const_variables }); - - - // walk_ast(ast, &mut ForLoopToRepeatVisitor {}) // TODO: fix optimizations ast @@ -81,158 +77,220 @@ impl ExpressionVisitor for ForLoopToRepeatVisitor { fn visit_expr(&mut self, expr: Expr) -> Option { let preserve_value = Some(expr.clone()); - if let Expr::ForLoop(ExprForLoop { - init_block, - conditional, - after_block, - interior_block, - }) = expr.clone() { - let mut i = 0; // Variable to keep track of where repeat begins - let mut init_value_variable_name: String = "".to_string(); - - //get the init value name, - - //Get the end value - - // Get the step and see if it is mul, add etc, and get the repeat amount + if let Expr::ForLoop(ExprForLoop { + init_block, + conditional, + after_block, + interior_block, + }) = expr.clone() + { + let mut i = 0; // Variable to keep track of where repeat begins + let mut init_value_variable_name: String = "".to_string(); + + // Get the step and see if it is mul, add etc, and get the repeat amount + + // Start out with the init block, and determine where iteration will start + /// This optimization will only be applied when the init block uses a number literal for the rhs + if init_block.exprs.len() != 1 { + return preserve_value; + } - // Start out with the init block, and determine where iteration will start - /// This optimization will only be applied when the init block uses a number literal for the rhs - if init_block.exprs.len() != 1 { - return preserve_value; + //get the init value name, + if let Some(Expr::DeclareVariable(ExprDeclareVariable { + typed_identifiers, + rhs: _, + })) = init_block.exprs.first() + { + if let Some(TypedIdentifier { + identifier, + yul_type, + }) = typed_identifiers.first() + { + init_value_variable_name = identifier.to_owned(); } - - if let Some(Expr::DeclareVariable(ExprDeclareVariable{typed_identifiers, rhs: _}))= init_block.exprs.first(){ - if let Some(TypedIdentifier{identifier, yul_type}) = typed_identifiers.first(){ - init_value_variable_name = identifier.to_owned(); - } - }else{ + } else { return preserve_value; - }; - - for expr in init_block.exprs { - if let Expr::Assignment(value) = expr.clone() { - if let Expr::Literal(value) = *value.rhs { - match value { - ExprLiteral::Number(n)=> { - i = n.value.0[3]; // TODO: make sure this is within u32 constraints - } - _ => { - return preserve_value; - } + }; + + for expr in init_block.exprs { + if let Expr::Assignment(value) = expr.clone() { + if let Expr::Literal(value) = *value.rhs { + match value { + ExprLiteral::Number(n) => { + i = n.value.0[3]; // TODO: make sure this is within u32 constraints + } + _ => { + return preserve_value; } } } } + } + //Get the end value - let mut end_val = primitive_types::U256::zero(); - // With `i` now indicating where our iteration will start, we can check the conditional - if let Expr::FunctionCall(ExprFunctionCall{function_name, exprs, inferred_return_types, inferred_param_types }) = *conditional { - - if function_name == "lt"{ - if let Expr::Literal(ExprLiteral::Number(expr_literal_num)) = exprs.last().unwrap() { - end_val = expr_literal_num.value; - }; - - } else if function_name == "gt"{ - if let Expr::Literal(ExprLiteral::Number(expr_literal_num)) = exprs.last().unwrap() { - end_val = expr_literal_num.value; - }; - }else{ - return preserve_value; - } - - } - - // Determine iterator size - if after_block.exprs.len() != 1 { + let mut end_val = 0; + // With `i` now indicating where our iteration will start, we can check the conditional + if let Expr::FunctionCall(ExprFunctionCall { + function_name, + exprs, + inferred_return_types, + inferred_param_types, + }) = *conditional + { + if function_name == "lt" { + if let Expr::Literal(ExprLiteral::Number(expr_literal_num)) = + exprs.last().unwrap() + { + end_val = expr_literal_num.value.0[3]; + }; + } else if function_name == "gt" { + if let Expr::Literal(ExprLiteral::Number(expr_literal_num)) = + exprs.last().unwrap() + { + end_val = expr_literal_num.value.0[3]; + }; + } else { return preserve_value; } - let mut iterations = 0; // Final value for repeat statement - - for expr in after_block.exprs { - match expr { - Expr::Assignment(value) => { - if let Expr::FunctionCall(ExprFunctionCall { function_name, exprs, .. }) = *value.rhs { - match function_name.to_string().as_str() { - "add" => { - let mut step = 1; - for args in *exprs { - match args { - Expr::Literal(ExprLiteral::Number(expr_literal_num)) => { - step = expr_literal_num.value.0[3]; // TODO: make sure this is within u32 constraints - } - Expr::Variable(ExprVariableReference { identifier , ..}) => { - if identifier != init_value_variable_name { // Should check identifier is the same as the one which appaered earlier - return preserve_value; - } + } + + // Determine iterator size + if after_block.exprs.len() != 1 { + return preserve_value; + } + let mut iterations: u32 = 0; // Final value for repeat statement + + for expr in after_block.exprs { + match expr { + Expr::Assignment(value) => { + if let Expr::FunctionCall(ExprFunctionCall { + function_name, + exprs, + .. + }) = *value.rhs + { + match function_name.to_string().as_str() { + "add" => { + let mut step = 1; + for args in *exprs { + match args { + Expr::Literal(ExprLiteral::Number( + expr_literal_num, + )) => { + step = expr_literal_num.value.0[3]; + // TODO: make sure this is within u32 constraints + } + Expr::Variable(ExprVariableReference { + identifier, + .. + }) => { + if identifier != init_value_variable_name { + // Should check identifier is the same as the one which appaered earlier + return preserve_value; } - _ => return preserve_value } - iterations = ((end_val - i) / step).0[3]; // TODO: make sure this is within u32 constraints - } + _ => return preserve_value, + } + iterations = ((end_val - i) / step).try_into().unwrap(); + // TODO: make sure this is within u32 constraints } - "sub" => { - let mut step = 1; - let args = *exprs; - if let Some(Expr::Variable( ExprVariableReference { identifier , ..})) = args.first() { - if *identifier != init_value_variable_name { - return preserve_value; - } + } + "sub" => { + let mut step = 1; + let args = *exprs; + if let Some(Expr::Variable(ExprVariableReference { + identifier, + .. + })) = args.first() + { + if *identifier != init_value_variable_name { + return preserve_value; } + } + if let Some(Expr::Literal(ExprLiteral::Number(num))) = + args.last() + { + step = num.value.0[3]; + } else { + return preserve_value; + } - if let Some(Expr::Literal( ExprLiteral::Number())) = args.first() { - if *identifier != init_value_variable_name { - return preserve_value; + iterations = ((i - end_val) / step).try_into().unwrap(); + // Assumes no overflow + } + "mul" => { + let mut step = 1; + for args in *exprs { + match args { + Expr::Literal(ExprLiteral::Number( + expr_literal_num, + )) => { + step = expr_literal_num.value.0[3]; + // TODO: make sure this is within u32 constraints + } + Expr::Variable(ExprVariableReference { + identifier, + .. + }) => { + if identifier != init_value_variable_name { + // Should check identifier is the same as the one which appaered earlier + return preserve_value; + } } + _ => return preserve_value, } - - - + let mut j = i.clone(); + while j < end_val { + j *= step; + iterations += 1; + } } - "mul" => { - let step = 1; - let args = *exprs; - for args in *exprs { - match args { - Expr::Literal(ExprLiteral::Number(expr_literal_num)) => { - step = expr_literal_num.value.0[3]; // TODO: make sure this is within u32 constraints - } - Expr::Variable(ExprVariableReference { identifier , ..}) => { - if identifier != init_value_variable_name { // Should check identifier is the same as the one which appaered earlier - return preserve_value; - } + } + "div" => { + let mut step = 1; + for args in *exprs { + match args { + Expr::Literal(ExprLiteral::Number( + expr_literal_num, + )) => { + step = expr_literal_num.value.0[3]; + // TODO: make sure this is within u32 constraints + } + Expr::Variable(ExprVariableReference { + identifier, + .. + }) => { + if identifier != init_value_variable_name { + // Should check identifier is the same as the one which appaered earlier + return preserve_value; } - _ => return preserve_value } + _ => return preserve_value, + } + + let mut j = i.clone(); + while j > end_val { + j /= step; + iterations += 1; } } - "div" => { - let step = 1; - let args = *exprs; - } - _ => return preserve_value, } + + _ =>{} } } - _ => return Some(expr) } + _ => return Some(expr), } + } - //TODO: - - // for { let i := 29 } lt(i, exponent) { i := add(i, 1) } - // { - // result := mul(result, base) - // } - - return Some(Expr::Repeat(ExprRepeat { - iterations: 53, - interior_block, - })); - }; + return Some(Expr::Repeat(ExprRepeat { + iterations, + interior_block, + })); + }; Some(expr) }