From 39f1d5cc6272c9793d86b0255f63c9fb6594609c Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Wed, 17 Jul 2024 01:31:09 +0000 Subject: [PATCH 01/10] test to differentiate local var --- .../rom_table_local_var/Nargo.toml | 7 + .../rom_table_local_var/src/main.nr | 146 ++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 test_programs/execution_success/rom_table_local_var/Nargo.toml create mode 100644 test_programs/execution_success/rom_table_local_var/src/main.nr diff --git a/test_programs/execution_success/rom_table_local_var/Nargo.toml b/test_programs/execution_success/rom_table_local_var/Nargo.toml new file mode 100644 index 0000000000..790c0b81b0 --- /dev/null +++ b/test_programs/execution_success/rom_table_local_var/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "rom_table_local_var" +type = "bin" +authors = [""] +compiler_version = ">=0.31.0" + +[dependencies] \ No newline at end of file diff --git a/test_programs/execution_success/rom_table_local_var/src/main.nr b/test_programs/execution_success/rom_table_local_var/src/main.nr new file mode 100644 index 0000000000..cb98286edf --- /dev/null +++ b/test_programs/execution_success/rom_table_local_var/src/main.nr @@ -0,0 +1,146 @@ +fn main(x: [u8; 2]) { + for i in 0..1 { + let r: [u8; 32] = base64_decode_without_struct(x); + // let r: [u8; 32] = base64_decode_with_struct(x); + println(f"{r}"); + } +} + +fn base64_decode_without_struct(input: [u8; InputElements]) -> [u8; OutputBytes] { + let BASE64_DECODE_BE: [Field; 128] = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0-9 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 10-19 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 20-29 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 30-39 + 0, 0, 0,// 40-42 + 62,// 43 + 0, 0, 0,// 44-46 + 63,// 47 + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,// 48-57 + 0, 0, 0, 0, 0, 0, 0,// 58-64 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,// 65-90 (A-Z) + 0, 0, 0, 0, 0, 0,// 91-96 + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,// 97-122 (a-z) + 0, 0, 0, 0, 0// 123-127 + ]; + + // 240 bits fits 40 6-bit chunks and 30 8-bit chunks + // we pack 40 base64 values into a field element and convert into 30 bytes + // TODO: once we support arithmetic ops on generics, derive OutputBytes from InputBytes + let mut result: [u8; OutputBytes] = [0; OutputBytes]; + let BASE64_ELEMENTS_PER_CHUNK: u64 = 40; + let BYTES_PER_CHUNK: u64 = 30; + let num_chunks = (InputElements / BASE64_ELEMENTS_PER_CHUNK) + + (InputElements % BASE64_ELEMENTS_PER_CHUNK != 0) as u64; + + for i in 0..num_chunks - 1 { + let mut slice: Field = 0; + for j in 0..BASE64_ELEMENTS_PER_CHUNK { + slice *= 64; + let idx = input[i * BASE64_ELEMENTS_PER_CHUNK + j] as Field; + slice += BASE64_DECODE_BE[idx]; + } + let slice_bytes: [u8; 30] = slice.to_be_bytes(30).as_array(); + for j in 0..BYTES_PER_CHUNK { + result[i * BYTES_PER_CHUNK + j] = slice_bytes[j]; + } + } + + let base64_elements_in_final_chunk = InputElements - ((num_chunks - 1) * BASE64_ELEMENTS_PER_CHUNK); + + let mut slice: Field = 0; + for j in 0..base64_elements_in_final_chunk { + slice *= 64; + slice += BASE64_DECODE_BE[input[(num_chunks - 1) * BASE64_ELEMENTS_PER_CHUNK + j] as Field]; + } + for _ in base64_elements_in_final_chunk..BASE64_ELEMENTS_PER_CHUNK { + slice *= 64; + } + + // TODO: check is it cheaper to use a constant value in `to_be_bytes` or can we use `bytes_in_final_chunk`? + let slice_bytes: [u8; 30] = slice.to_be_bytes(30).as_array(); + let num_bytes_in_final_chunk = OutputBytes - ((num_chunks - 1) * BYTES_PER_CHUNK); + for i in 0..num_bytes_in_final_chunk { + result[(num_chunks - 1) * BYTES_PER_CHUNK + i] = slice_bytes[i]; + } + result +} + +// #### METHOD 2. When lookup table is in a struct, lookups are much cheaper and ROM table is used in backend +struct Lookup { + table: [Field; 128] +} +impl Lookup { + fn new() -> Self { + Lookup { + table: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0-9 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 10-19 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 20-29 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 30-39 + 0, 0, 0,// 40-42 + 62,// 43 + 0, 0, 0,// 44-46 + 63,// 47 + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,// 48-57 + 0, 0, 0, 0, 0, 0, 0,// 58-64 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,// 65-90 (A-Z) + 0, 0, 0, 0, 0, 0,// 91-96 + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,// 97-122 (a-z) + 0, 0, 0, 0, 0// 123-127 + ] + } + } + + fn get(self, idx: Field) -> Field { + self.table[idx] + } +} + +fn base64_decode_with_struct(input: [u8; InputElements]) -> [u8; OutputBytes] { + // 240 bits fits 40 6-bit chunks and 30 8-bit chunks + // we pack 40 base64 values into a field element and convert into 30 bytes + // TODO: once we support arithmetic ops on generics, derive OutputBytes from InputBytes + let mut BASE64_DECODE_BE = Lookup::new(); + + // 240 bits fits 40 6-bit chunks and 30 8-bit chunks + // we pack 40 base64 values into a field element and convert into 30 bytes + // TODO: once we support arithmetic ops on generics, derive OutputBytes from InputBytes + let mut result: [u8; OutputBytes] = [0; OutputBytes]; + let BASE64_ELEMENTS_PER_CHUNK: u64 = 40; + let BYTES_PER_CHUNK: u64 = 30; + let num_chunks = (InputElements / BASE64_ELEMENTS_PER_CHUNK) + + (InputElements % BASE64_ELEMENTS_PER_CHUNK != 0) as u64; + + for i in 0..num_chunks - 1 { + let mut slice: Field = 0; + for j in 0..BASE64_ELEMENTS_PER_CHUNK { + slice *= 64; + let idx = input[i * BASE64_ELEMENTS_PER_CHUNK + j] as Field; + slice += BASE64_DECODE_BE.get(idx); + } + let slice_bytes: [u8; 30] = slice.to_be_bytes(30).as_array(); + for j in 0..BYTES_PER_CHUNK { + result[i * BYTES_PER_CHUNK + j] = slice_bytes[j]; + } + } + + let base64_elements_in_final_chunk = InputElements - ((num_chunks - 1) * BASE64_ELEMENTS_PER_CHUNK); + + let mut slice: Field = 0; + for j in 0..base64_elements_in_final_chunk { + slice *= 64; + slice += BASE64_DECODE_BE.get(input[(num_chunks - 1) * BASE64_ELEMENTS_PER_CHUNK + j] as Field); + } + for _ in base64_elements_in_final_chunk..BASE64_ELEMENTS_PER_CHUNK { + slice *= 64; + } + + // TODO: check is it cheaper to use a constant value in `to_be_bytes` or can we use `bytes_in_final_chunk`? + let slice_bytes: [u8; 30] = slice.to_be_bytes(30).as_array(); + let num_bytes_in_final_chunk = OutputBytes - ((num_chunks - 1) * BYTES_PER_CHUNK); + for i in 0..num_bytes_in_final_chunk { + result[(num_chunks - 1) * BYTES_PER_CHUNK + i] = slice_bytes[i]; + } + result +} From 0117bb9fd0bdb0a681ecc6ca6b0e6d2bf6aaf8ed Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Wed, 17 Jul 2024 14:52:16 +0000 Subject: [PATCH 02/10] some more debug, nailed down where the blow-up is occurring --- .../noirc_evaluator/src/ssa/acir_gen/mod.rs | 3 +- .../rom_table_local_var/src/main.nr | 101 ++++++++++-------- 2 files changed, 61 insertions(+), 43 deletions(-) diff --git a/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs b/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs index 1bdc9aaf4e..8884e4f759 100644 --- a/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs @@ -431,7 +431,8 @@ impl<'a> Context<'a> { } warnings.extend(return_warnings); - + dbg!(self.memory_blocks.clone()); + dbg!(self.memory_blocks.len()); // Add the warnings from the alter Ssa passes Ok(self.acir_context.finish(input_witness, return_witnesses, warnings)) } diff --git a/test_programs/execution_success/rom_table_local_var/src/main.nr b/test_programs/execution_success/rom_table_local_var/src/main.nr index cb98286edf..300fcd9038 100644 --- a/test_programs/execution_success/rom_table_local_var/src/main.nr +++ b/test_programs/execution_success/rom_table_local_var/src/main.nr @@ -1,11 +1,28 @@ -fn main(x: [u8; 2]) { - for i in 0..1 { +fn main(x: [u8; 15]) { + for _ in 0..1 { let r: [u8; 32] = base64_decode_without_struct(x); // let r: [u8; 32] = base64_decode_with_struct(x); println(f"{r}"); } } +// global BASE64_DECODE_BE: [Field; 128] = [ +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0-9 +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 10-19 +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 20-29 +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 30-39 +// 0, 0, 0,// 40-42 +// 62,// 43 +// 0, 0, 0,// 44-46 +// 63,// 47 +// 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,// 48-57 +// 0, 0, 0, 0, 0, 0, 0,// 58-64 +// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,// 65-90 (A-Z) +// 0, 0, 0, 0, 0, 0,// 91-96 +// 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,// 97-122 (a-z) +// 0, 0, 0, 0, 0// 123-127 +// ]; + fn base64_decode_without_struct(input: [u8; InputElements]) -> [u8; OutputBytes] { let BASE64_DECODE_BE: [Field; 128] = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0-9 @@ -33,18 +50,18 @@ fn base64_decode_without_struct(in let num_chunks = (InputElements / BASE64_ELEMENTS_PER_CHUNK) + (InputElements % BASE64_ELEMENTS_PER_CHUNK != 0) as u64; - for i in 0..num_chunks - 1 { - let mut slice: Field = 0; - for j in 0..BASE64_ELEMENTS_PER_CHUNK { - slice *= 64; - let idx = input[i * BASE64_ELEMENTS_PER_CHUNK + j] as Field; - slice += BASE64_DECODE_BE[idx]; - } - let slice_bytes: [u8; 30] = slice.to_be_bytes(30).as_array(); - for j in 0..BYTES_PER_CHUNK { - result[i * BYTES_PER_CHUNK + j] = slice_bytes[j]; - } - } + // for i in 0..num_chunks - 1 { + // let mut slice: Field = 0; + // for j in 0..BASE64_ELEMENTS_PER_CHUNK { + // slice *= 64; + // let idx = input[i * BASE64_ELEMENTS_PER_CHUNK + j] as Field; + // slice += BASE64_DECODE_BE[idx]; + // } + // let slice_bytes: [u8; 30] = slice.to_be_bytes(30).as_array(); + // for j in 0..BYTES_PER_CHUNK { + // result[i * BYTES_PER_CHUNK + j] = slice_bytes[j]; + // } + // } let base64_elements_in_final_chunk = InputElements - ((num_chunks - 1) * BASE64_ELEMENTS_PER_CHUNK); @@ -53,16 +70,16 @@ fn base64_decode_without_struct(in slice *= 64; slice += BASE64_DECODE_BE[input[(num_chunks - 1) * BASE64_ELEMENTS_PER_CHUNK + j] as Field]; } - for _ in base64_elements_in_final_chunk..BASE64_ELEMENTS_PER_CHUNK { - slice *= 64; - } + // for _ in base64_elements_in_final_chunk..BASE64_ELEMENTS_PER_CHUNK { + // slice *= 64; + // } // TODO: check is it cheaper to use a constant value in `to_be_bytes` or can we use `bytes_in_final_chunk`? - let slice_bytes: [u8; 30] = slice.to_be_bytes(30).as_array(); - let num_bytes_in_final_chunk = OutputBytes - ((num_chunks - 1) * BYTES_PER_CHUNK); - for i in 0..num_bytes_in_final_chunk { - result[(num_chunks - 1) * BYTES_PER_CHUNK + i] = slice_bytes[i]; - } + let _: [u8; 30] = slice.to_be_bytes(30).as_array(); + // let num_bytes_in_final_chunk = OutputBytes - ((num_chunks - 1) * BYTES_PER_CHUNK); + // for i in 0..num_bytes_in_final_chunk { + // result[(num_chunks - 1) * BYTES_PER_CHUNK + i] = slice_bytes[i]; + // } result } @@ -112,18 +129,18 @@ fn base64_decode_with_struct(input let num_chunks = (InputElements / BASE64_ELEMENTS_PER_CHUNK) + (InputElements % BASE64_ELEMENTS_PER_CHUNK != 0) as u64; - for i in 0..num_chunks - 1 { - let mut slice: Field = 0; - for j in 0..BASE64_ELEMENTS_PER_CHUNK { - slice *= 64; - let idx = input[i * BASE64_ELEMENTS_PER_CHUNK + j] as Field; - slice += BASE64_DECODE_BE.get(idx); - } - let slice_bytes: [u8; 30] = slice.to_be_bytes(30).as_array(); - for j in 0..BYTES_PER_CHUNK { - result[i * BYTES_PER_CHUNK + j] = slice_bytes[j]; - } - } + // for i in 0..num_chunks - 1 { + // let mut slice: Field = 0; + // for j in 0..BASE64_ELEMENTS_PER_CHUNK { + // slice *= 64; + // let idx = input[i * BASE64_ELEMENTS_PER_CHUNK + j] as Field; + // slice += BASE64_DECODE_BE.get(idx); + // } + // let slice_bytes: [u8; 30] = slice.to_be_bytes(30).as_array(); + // for j in 0..BYTES_PER_CHUNK { + // result[i * BYTES_PER_CHUNK + j] = slice_bytes[j]; + // } + // } let base64_elements_in_final_chunk = InputElements - ((num_chunks - 1) * BASE64_ELEMENTS_PER_CHUNK); @@ -132,15 +149,15 @@ fn base64_decode_with_struct(input slice *= 64; slice += BASE64_DECODE_BE.get(input[(num_chunks - 1) * BASE64_ELEMENTS_PER_CHUNK + j] as Field); } - for _ in base64_elements_in_final_chunk..BASE64_ELEMENTS_PER_CHUNK { - slice *= 64; - } + // for _ in base64_elements_in_final_chunk..BASE64_ELEMENTS_PER_CHUNK { + // slice *= 64; + // } // TODO: check is it cheaper to use a constant value in `to_be_bytes` or can we use `bytes_in_final_chunk`? - let slice_bytes: [u8; 30] = slice.to_be_bytes(30).as_array(); - let num_bytes_in_final_chunk = OutputBytes - ((num_chunks - 1) * BYTES_PER_CHUNK); - for i in 0..num_bytes_in_final_chunk { - result[(num_chunks - 1) * BYTES_PER_CHUNK + i] = slice_bytes[i]; - } + let _: [u8; 30] = slice.to_be_bytes(30).as_array(); + // let num_bytes_in_final_chunk = OutputBytes - ((num_chunks - 1) * BYTES_PER_CHUNK); + // for i in 0..num_bytes_in_final_chunk { + // result[(num_chunks - 1) * BYTES_PER_CHUNK + i] = slice_bytes[i]; + // } result } From 5374d9e6c754e4322731b236186d906447fb4239 Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Wed, 17 Jul 2024 23:48:04 +0000 Subject: [PATCH 03/10] working array constant fix --- .../noirc_evaluator/src/ssa/acir_gen/mod.rs | 11 +- .../src/ssa/function_builder/mod.rs | 2 +- compiler/noirc_evaluator/src/ssa/ir/dfg.rs | 13 +- .../src/ssa/ir/function_inserter.rs | 24 +++- .../noirc_evaluator/src/ssa/ir/instruction.rs | 4 +- .../noirc_evaluator/src/ssa/opt/unrolling.rs | 2 + .../rom_table_local_var/src/main.nr | 127 +++++------------- 7 files changed, 81 insertions(+), 102 deletions(-) diff --git a/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs b/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs index 8884e4f759..673e5c6549 100644 --- a/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs @@ -431,8 +431,6 @@ impl<'a> Context<'a> { } warnings.extend(return_warnings); - dbg!(self.memory_blocks.clone()); - dbg!(self.memory_blocks.len()); // Add the warnings from the alter Ssa passes Ok(self.acir_context.finish(input_witness, return_witnesses, warnings)) } @@ -979,6 +977,15 @@ impl<'a> Context<'a> { // Ensure that array id is fully resolved. let array = dfg.resolve(array); + // dbg!(array); + // match &dfg[array] { + // Value::Array { array, typ } => { + // dbg!(typ.clone()); + // // dbg!(array.clone()); + // } + // _ => {} + // }; + let array_id = dfg.resolve(array); let array_typ = dfg.type_of_value(array_id); // Compiler sanity checks diff --git a/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs b/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs index b24c5632b2..be494467f4 100644 --- a/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs @@ -19,7 +19,7 @@ use super::{ basic_block::BasicBlock, dfg::{CallStack, InsertInstructionResult}, function::RuntimeType, - instruction::{ConstrainError, ErrorType, InstructionId, Intrinsic}, + instruction::{ConstrainError, ErrorType, InstructionId, Intrinsic}, types::NumericType, }, ssa_gen::Ssa, }; diff --git a/compiler/noirc_evaluator/src/ssa/ir/dfg.rs b/compiler/noirc_evaluator/src/ssa/ir/dfg.rs index 994386f819..8f8851f274 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/dfg.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/dfg.rs @@ -46,6 +46,8 @@ pub(crate) struct DataFlowGraph { /// twice will return the same ValueId. constants: HashMap<(FieldElement, Type), ValueId>, + constant_arrays: HashMap, ValueId>, + /// Contains each function that has been imported into the current function. /// A unique `ValueId` for each function's [`Value::Function`] is stored so any given FunctionId /// will always have the same ValueId within this function. @@ -255,7 +257,16 @@ impl DataFlowGraph { /// Create a new constant array value from the given elements pub(crate) fn make_array(&mut self, array: im::Vector, typ: Type) -> ValueId { assert!(matches!(typ, Type::Array(..) | Type::Slice(_))); - self.make_value(Value::Array { array, typ }) + + // if let Some(id) = self.constant_arrays.get(&array) { + // return *id; + // } + + let id = self.make_value(Value::Array { array: array.clone(), typ }); + // if array.iter().all(|value| self.is_constant(*value)) { + // self.constant_arrays.insert(array, id); + // } + id } /// Gets or creates a ValueId for the given FunctionId. diff --git a/compiler/noirc_evaluator/src/ssa/ir/function_inserter.rs b/compiler/noirc_evaluator/src/ssa/ir/function_inserter.rs index a063a7ff26..c0af26d9e1 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/function_inserter.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/function_inserter.rs @@ -1,9 +1,11 @@ use iter_extended::vecmap; +use crate::ssa::ir::types::{NumericType, Type}; + use super::{ basic_block::BasicBlockId, dfg::{CallStack, InsertInstructionResult}, - function::Function, + function::{Function, RuntimeType}, instruction::{Instruction, InstructionId}, value::ValueId, }; @@ -16,7 +18,11 @@ pub(crate) struct FunctionInserter<'f> { pub(crate) function: &'f mut Function, values: HashMap, - const_arrays: HashMap, ValueId>, + /// Map containing repeat array constant so that we do not initialize a new + /// array unnecessarily. An extra bool is included as part of the key to + /// distinguish between Type::Array and Type::Slice, as both are valid + /// types for a Value::Array + const_arrays: HashMap<(im::Vector, bool), ValueId>, } impl<'f> FunctionInserter<'f> { @@ -37,13 +43,23 @@ impl<'f> FunctionInserter<'f> { let typ = typ.clone(); let new_array: im::Vector = array.iter().map(|id| self.resolve(*id)).collect(); - if self.const_arrays.get(&new_array) == Some(&value) { + + // Flag to determine the type of the array value list + let is_array = matches!(typ, Type::Array { .. }); + + if matches!(self.function.runtime(), RuntimeType::Acir(_)) { + if let Some(value) = self.const_arrays.get(&(new_array.clone(), is_array)) { + return *value; + } + } + + if self.const_arrays.get(&(new_array.clone(), is_array)) == Some(&value) { value } else { let new_array_clone = new_array.clone(); let new_id = self.function.dfg.make_array(new_array, typ); self.values.insert(value, new_id); - self.const_arrays.insert(new_array_clone, new_id); + self.const_arrays.insert((new_array_clone, is_array), new_id); new_id } } diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction.rs index 9146fe9483..bba4546df7 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction.rs @@ -613,10 +613,10 @@ impl Instruction { } } } - + let array_id = array; let array = dfg.get_array_constant(*array); let index = dfg.get_numeric_constant(*index); - if let (Some((array, _)), Some(index)) = (array, index) { + if let (Some((array, _)), Some(index)) = (array.clone(), index) { let index = index.try_to_u32().expect("Expected array index to fit in u32") as usize; if index < array.len() { diff --git a/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs b/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs index 5f58be4142..af65d19999 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs @@ -64,6 +64,8 @@ impl Ssa { return Err(unroll_errors.swap_remove(0)); } } + + // println!("{}", ssa); Ok(ssa) } diff --git a/test_programs/execution_success/rom_table_local_var/src/main.nr b/test_programs/execution_success/rom_table_local_var/src/main.nr index 300fcd9038..a1eac6db35 100644 --- a/test_programs/execution_success/rom_table_local_var/src/main.nr +++ b/test_programs/execution_success/rom_table_local_var/src/main.nr @@ -1,30 +1,16 @@ -fn main(x: [u8; 15]) { - for _ in 0..1 { - let r: [u8; 32] = base64_decode_without_struct(x); - // let r: [u8; 32] = base64_decode_with_struct(x); - println(f"{r}"); - } -} +fn main(x: [u8; 44]) { + // for _ in 0..1 { + // let r: [u8; 32] = base64_decode_without_struct(x); + // // let r: [u8; 32] = base64_decode_with_struct(x); + // println(f"{r}"); + // } -// global BASE64_DECODE_BE: [Field; 128] = [ -// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0-9 -// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 10-19 -// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 20-29 -// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 30-39 -// 0, 0, 0,// 40-42 -// 62,// 43 -// 0, 0, 0,// 44-46 -// 63,// 47 -// 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,// 48-57 -// 0, 0, 0, 0, 0, 0, 0,// 58-64 -// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,// 65-90 (A-Z) -// 0, 0, 0, 0, 0, 0,// 91-96 -// 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,// 97-122 (a-z) -// 0, 0, 0, 0, 0// 123-127 -// ]; + let _: [u8; 2] = base64_decode_without_struct(x); + // let _: [u8; 2] = base64_decode_with_struct(x); + // println(f"{r}"); +} -fn base64_decode_without_struct(input: [u8; InputElements]) -> [u8; OutputBytes] { - let BASE64_DECODE_BE: [Field; 128] = [ +global BASE64_DECODE_BE: [Field; 128] = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0-9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 10-19 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 20-29 @@ -41,45 +27,37 @@ fn base64_decode_without_struct(in 0, 0, 0, 0, 0// 123-127 ]; +fn base64_decode_without_struct(input: [u8; InputElements]) -> [u8; OutputBytes] { + // let BASE64_DECODE_BE: [Field; 128] = [ + // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0-9 + // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 10-19 + // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 20-29 + // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 30-39 + // 0, 0, 0,// 40-42 + // 62,// 43 + // 0, 0, 0,// 44-46 + // 63,// 47 + // 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,// 48-57 + // 0, 0, 0, 0, 0, 0, 0,// 58-64 + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,// 65-90 (A-Z) + // 0, 0, 0, 0, 0, 0,// 91-96 + // 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,// 97-122 (a-z) + // 0, 0, 0, 0, 0// 123-127 + // ]; + // 240 bits fits 40 6-bit chunks and 30 8-bit chunks // we pack 40 base64 values into a field element and convert into 30 bytes // TODO: once we support arithmetic ops on generics, derive OutputBytes from InputBytes let mut result: [u8; OutputBytes] = [0; OutputBytes]; - let BASE64_ELEMENTS_PER_CHUNK: u64 = 40; - let BYTES_PER_CHUNK: u64 = 30; - let num_chunks = (InputElements / BASE64_ELEMENTS_PER_CHUNK) - + (InputElements % BASE64_ELEMENTS_PER_CHUNK != 0) as u64; - - // for i in 0..num_chunks - 1 { - // let mut slice: Field = 0; - // for j in 0..BASE64_ELEMENTS_PER_CHUNK { - // slice *= 64; - // let idx = input[i * BASE64_ELEMENTS_PER_CHUNK + j] as Field; - // slice += BASE64_DECODE_BE[idx]; - // } - // let slice_bytes: [u8; 30] = slice.to_be_bytes(30).as_array(); - // for j in 0..BYTES_PER_CHUNK { - // result[i * BYTES_PER_CHUNK + j] = slice_bytes[j]; - // } - // } - let base64_elements_in_final_chunk = InputElements - ((num_chunks - 1) * BASE64_ELEMENTS_PER_CHUNK); let mut slice: Field = 0; - for j in 0..base64_elements_in_final_chunk { - slice *= 64; - slice += BASE64_DECODE_BE[input[(num_chunks - 1) * BASE64_ELEMENTS_PER_CHUNK + j] as Field]; + for j in 0..InputElements { + slice += BASE64_DECODE_BE[input[j]]; } - // for _ in base64_elements_in_final_chunk..BASE64_ELEMENTS_PER_CHUNK { - // slice *= 64; - // } - // TODO: check is it cheaper to use a constant value in `to_be_bytes` or can we use `bytes_in_final_chunk`? let _: [u8; 30] = slice.to_be_bytes(30).as_array(); - // let num_bytes_in_final_chunk = OutputBytes - ((num_chunks - 1) * BYTES_PER_CHUNK); - // for i in 0..num_bytes_in_final_chunk { - // result[(num_chunks - 1) * BYTES_PER_CHUNK + i] = slice_bytes[i]; - // } + result } @@ -90,22 +68,7 @@ struct Lookup { impl Lookup { fn new() -> Self { Lookup { - table: [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0-9 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 10-19 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 20-29 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 30-39 - 0, 0, 0,// 40-42 - 62,// 43 - 0, 0, 0,// 44-46 - 63,// 47 - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,// 48-57 - 0, 0, 0, 0, 0, 0, 0,// 58-64 - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,// 65-90 (A-Z) - 0, 0, 0, 0, 0, 0,// 91-96 - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,// 97-122 (a-z) - 0, 0, 0, 0, 0// 123-127 - ] + table: BASE64_DECODE_BE } } @@ -124,30 +87,10 @@ fn base64_decode_with_struct(input // we pack 40 base64 values into a field element and convert into 30 bytes // TODO: once we support arithmetic ops on generics, derive OutputBytes from InputBytes let mut result: [u8; OutputBytes] = [0; OutputBytes]; - let BASE64_ELEMENTS_PER_CHUNK: u64 = 40; - let BYTES_PER_CHUNK: u64 = 30; - let num_chunks = (InputElements / BASE64_ELEMENTS_PER_CHUNK) - + (InputElements % BASE64_ELEMENTS_PER_CHUNK != 0) as u64; - - // for i in 0..num_chunks - 1 { - // let mut slice: Field = 0; - // for j in 0..BASE64_ELEMENTS_PER_CHUNK { - // slice *= 64; - // let idx = input[i * BASE64_ELEMENTS_PER_CHUNK + j] as Field; - // slice += BASE64_DECODE_BE.get(idx); - // } - // let slice_bytes: [u8; 30] = slice.to_be_bytes(30).as_array(); - // for j in 0..BYTES_PER_CHUNK { - // result[i * BYTES_PER_CHUNK + j] = slice_bytes[j]; - // } - // } - - let base64_elements_in_final_chunk = InputElements - ((num_chunks - 1) * BASE64_ELEMENTS_PER_CHUNK); let mut slice: Field = 0; - for j in 0..base64_elements_in_final_chunk { - slice *= 64; - slice += BASE64_DECODE_BE.get(input[(num_chunks - 1) * BASE64_ELEMENTS_PER_CHUNK + j] as Field); + for j in 0..InputElements { + slice += BASE64_DECODE_BE.get(input[j] as Field); } // for _ in base64_elements_in_final_chunk..BASE64_ELEMENTS_PER_CHUNK { // slice *= 64; From 808c35e22bd60a50b206909767534a0a554ccaa4 Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Thu, 18 Jul 2024 00:04:43 +0000 Subject: [PATCH 04/10] cleanup --- .../src/ssa/function_builder/mod.rs | 2 +- compiler/noirc_evaluator/src/ssa/ir/dfg.rs | 11 +---- .../src/ssa/ir/function_inserter.rs | 44 ++++++++++--------- .../noirc_evaluator/src/ssa/ir/instruction.rs | 1 - 4 files changed, 25 insertions(+), 33 deletions(-) diff --git a/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs b/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs index be494467f4..b24c5632b2 100644 --- a/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs @@ -19,7 +19,7 @@ use super::{ basic_block::BasicBlock, dfg::{CallStack, InsertInstructionResult}, function::RuntimeType, - instruction::{ConstrainError, ErrorType, InstructionId, Intrinsic}, types::NumericType, + instruction::{ConstrainError, ErrorType, InstructionId, Intrinsic}, }, ssa_gen::Ssa, }; diff --git a/compiler/noirc_evaluator/src/ssa/ir/dfg.rs b/compiler/noirc_evaluator/src/ssa/ir/dfg.rs index 8f8851f274..debf5aa61d 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/dfg.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/dfg.rs @@ -257,16 +257,7 @@ impl DataFlowGraph { /// Create a new constant array value from the given elements pub(crate) fn make_array(&mut self, array: im::Vector, typ: Type) -> ValueId { assert!(matches!(typ, Type::Array(..) | Type::Slice(_))); - - // if let Some(id) = self.constant_arrays.get(&array) { - // return *id; - // } - - let id = self.make_value(Value::Array { array: array.clone(), typ }); - // if array.iter().all(|value| self.is_constant(*value)) { - // self.constant_arrays.insert(array, id); - // } - id + self.make_value(Value::Array { array: array.clone(), typ }) } /// Gets or creates a ValueId for the given FunctionId. diff --git a/compiler/noirc_evaluator/src/ssa/ir/function_inserter.rs b/compiler/noirc_evaluator/src/ssa/ir/function_inserter.rs index c0af26d9e1..9baeb19206 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/function_inserter.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/function_inserter.rs @@ -1,6 +1,6 @@ use iter_extended::vecmap; -use crate::ssa::ir::types::{NumericType, Type}; +use crate::ssa::ir::types::Type; use super::{ basic_block::BasicBlockId, @@ -18,9 +18,9 @@ pub(crate) struct FunctionInserter<'f> { pub(crate) function: &'f mut Function, values: HashMap, - /// Map containing repeat array constant so that we do not initialize a new + /// Map containing repeat array constant so that we do not initialize a new /// array unnecessarily. An extra bool is included as part of the key to - /// distinguish between Type::Array and Type::Slice, as both are valid + /// distinguish between Type::Array and Type::Slice, as both are valid /// types for a Value::Array const_arrays: HashMap<(im::Vector, bool), ValueId>, } @@ -43,25 +43,27 @@ impl<'f> FunctionInserter<'f> { let typ = typ.clone(); let new_array: im::Vector = array.iter().map(|id| self.resolve(*id)).collect(); - - // Flag to determine the type of the array value list + + // Flag to determine the type of the value's array list let is_array = matches!(typ, Type::Array { .. }); - - if matches!(self.function.runtime(), RuntimeType::Acir(_)) { - if let Some(value) = self.const_arrays.get(&(new_array.clone(), is_array)) { - return *value; - } - } - - if self.const_arrays.get(&(new_array.clone(), is_array)) == Some(&value) { - value - } else { - let new_array_clone = new_array.clone(); - let new_id = self.function.dfg.make_array(new_array, typ); - self.values.insert(value, new_id); - self.const_arrays.insert((new_array_clone, is_array), new_id); - new_id - } + if let Some(fetched_value) = + self.const_arrays.get(&(new_array.clone(), is_array)) + { + // Arrays in ACIR are immutable, but in Brillig arrays are copy-on-write + // so for function's with a Brillig runtime we make sure to check that value + // in our constants array map matches the resolved array value id. + if matches!(self.function.runtime(), RuntimeType::Acir(_)) { + return *fetched_value; + } else if *fetched_value == value { + return value; + } + }; + + let new_array_clone = new_array.clone(); + let new_id = self.function.dfg.make_array(new_array, typ); + self.values.insert(value, new_id); + self.const_arrays.insert((new_array_clone, is_array), new_id); + new_id } _ => value, }, diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction.rs index bba4546df7..22eb28ef75 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction.rs @@ -613,7 +613,6 @@ impl Instruction { } } } - let array_id = array; let array = dfg.get_array_constant(*array); let index = dfg.get_numeric_constant(*index); if let (Some((array, _)), Some(index)) = (array.clone(), index) { From ada14b67d26b55f1eeecd39ebea54b7e572ec4ec Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Thu, 18 Jul 2024 00:07:05 +0000 Subject: [PATCH 05/10] restore acir gen file --- compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs b/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs index 673e5c6549..eeb2c6d1e3 100644 --- a/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs @@ -431,6 +431,7 @@ impl<'a> Context<'a> { } warnings.extend(return_warnings); + // Add the warnings from the alter Ssa passes Ok(self.acir_context.finish(input_witness, return_witnesses, warnings)) } @@ -977,15 +978,6 @@ impl<'a> Context<'a> { // Ensure that array id is fully resolved. let array = dfg.resolve(array); - // dbg!(array); - // match &dfg[array] { - // Value::Array { array, typ } => { - // dbg!(typ.clone()); - // // dbg!(array.clone()); - // } - // _ => {} - // }; - let array_id = dfg.resolve(array); let array_typ = dfg.type_of_value(array_id); // Compiler sanity checks From e1f7bd3f63ba25b260745c94ce00b45fdfe0d64c Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Thu, 18 Jul 2024 00:07:36 +0000 Subject: [PATCH 06/10] restore dfg file --- compiler/noirc_evaluator/src/ssa/ir/dfg.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/noirc_evaluator/src/ssa/ir/dfg.rs b/compiler/noirc_evaluator/src/ssa/ir/dfg.rs index debf5aa61d..217719d6cb 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/dfg.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/dfg.rs @@ -45,9 +45,7 @@ pub(crate) struct DataFlowGraph { /// Each constant is unique, attempting to insert the same constant /// twice will return the same ValueId. constants: HashMap<(FieldElement, Type), ValueId>, - - constant_arrays: HashMap, ValueId>, - + /// Contains each function that has been imported into the current function. /// A unique `ValueId` for each function's [`Value::Function`] is stored so any given FunctionId /// will always have the same ValueId within this function. @@ -257,7 +255,7 @@ impl DataFlowGraph { /// Create a new constant array value from the given elements pub(crate) fn make_array(&mut self, array: im::Vector, typ: Type) -> ValueId { assert!(matches!(typ, Type::Array(..) | Type::Slice(_))); - self.make_value(Value::Array { array: array.clone(), typ }) + self.make_value(Value::Array { array, typ }) } /// Gets or creates a ValueId for the given FunctionId. From 368a7ca960b0d3cab281de9130f1b742f90381d7 Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Thu, 18 Jul 2024 00:09:16 +0000 Subject: [PATCH 07/10] cleanup and remove old test --- .../noirc_evaluator/src/ssa/acir_gen/mod.rs | 2 +- compiler/noirc_evaluator/src/ssa/ir/dfg.rs | 2 +- .../noirc_evaluator/src/ssa/ir/instruction.rs | 2 +- .../noirc_evaluator/src/ssa/opt/unrolling.rs | 2 - .../rom_table_local_var/Nargo.toml | 7 -- .../rom_table_local_var/src/main.nr | 106 ------------------ 6 files changed, 3 insertions(+), 118 deletions(-) delete mode 100644 test_programs/execution_success/rom_table_local_var/Nargo.toml delete mode 100644 test_programs/execution_success/rom_table_local_var/src/main.nr diff --git a/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs b/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs index eeb2c6d1e3..1bdc9aaf4e 100644 --- a/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs @@ -431,7 +431,7 @@ impl<'a> Context<'a> { } warnings.extend(return_warnings); - + // Add the warnings from the alter Ssa passes Ok(self.acir_context.finish(input_witness, return_witnesses, warnings)) } diff --git a/compiler/noirc_evaluator/src/ssa/ir/dfg.rs b/compiler/noirc_evaluator/src/ssa/ir/dfg.rs index 217719d6cb..994386f819 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/dfg.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/dfg.rs @@ -45,7 +45,7 @@ pub(crate) struct DataFlowGraph { /// Each constant is unique, attempting to insert the same constant /// twice will return the same ValueId. constants: HashMap<(FieldElement, Type), ValueId>, - + /// Contains each function that has been imported into the current function. /// A unique `ValueId` for each function's [`Value::Function`] is stored so any given FunctionId /// will always have the same ValueId within this function. diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction.rs index 22eb28ef75..3456949710 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction.rs @@ -615,7 +615,7 @@ impl Instruction { } let array = dfg.get_array_constant(*array); let index = dfg.get_numeric_constant(*index); - if let (Some((array, _)), Some(index)) = (array.clone(), index) { + if let (Some((array, _)), Some(index)) = (array, index) { let index = index.try_to_u32().expect("Expected array index to fit in u32") as usize; if index < array.len() { diff --git a/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs b/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs index af65d19999..5f58be4142 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs @@ -64,8 +64,6 @@ impl Ssa { return Err(unroll_errors.swap_remove(0)); } } - - // println!("{}", ssa); Ok(ssa) } diff --git a/test_programs/execution_success/rom_table_local_var/Nargo.toml b/test_programs/execution_success/rom_table_local_var/Nargo.toml deleted file mode 100644 index 790c0b81b0..0000000000 --- a/test_programs/execution_success/rom_table_local_var/Nargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "rom_table_local_var" -type = "bin" -authors = [""] -compiler_version = ">=0.31.0" - -[dependencies] \ No newline at end of file diff --git a/test_programs/execution_success/rom_table_local_var/src/main.nr b/test_programs/execution_success/rom_table_local_var/src/main.nr deleted file mode 100644 index a1eac6db35..0000000000 --- a/test_programs/execution_success/rom_table_local_var/src/main.nr +++ /dev/null @@ -1,106 +0,0 @@ -fn main(x: [u8; 44]) { - // for _ in 0..1 { - // let r: [u8; 32] = base64_decode_without_struct(x); - // // let r: [u8; 32] = base64_decode_with_struct(x); - // println(f"{r}"); - // } - - let _: [u8; 2] = base64_decode_without_struct(x); - // let _: [u8; 2] = base64_decode_with_struct(x); - // println(f"{r}"); -} - -global BASE64_DECODE_BE: [Field; 128] = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0-9 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 10-19 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 20-29 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 30-39 - 0, 0, 0,// 40-42 - 62,// 43 - 0, 0, 0,// 44-46 - 63,// 47 - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,// 48-57 - 0, 0, 0, 0, 0, 0, 0,// 58-64 - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,// 65-90 (A-Z) - 0, 0, 0, 0, 0, 0,// 91-96 - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,// 97-122 (a-z) - 0, 0, 0, 0, 0// 123-127 - ]; - -fn base64_decode_without_struct(input: [u8; InputElements]) -> [u8; OutputBytes] { - // let BASE64_DECODE_BE: [Field; 128] = [ - // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0-9 - // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 10-19 - // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 20-29 - // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 30-39 - // 0, 0, 0,// 40-42 - // 62,// 43 - // 0, 0, 0,// 44-46 - // 63,// 47 - // 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,// 48-57 - // 0, 0, 0, 0, 0, 0, 0,// 58-64 - // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,// 65-90 (A-Z) - // 0, 0, 0, 0, 0, 0,// 91-96 - // 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,// 97-122 (a-z) - // 0, 0, 0, 0, 0// 123-127 - // ]; - - // 240 bits fits 40 6-bit chunks and 30 8-bit chunks - // we pack 40 base64 values into a field element and convert into 30 bytes - // TODO: once we support arithmetic ops on generics, derive OutputBytes from InputBytes - let mut result: [u8; OutputBytes] = [0; OutputBytes]; - - - let mut slice: Field = 0; - for j in 0..InputElements { - slice += BASE64_DECODE_BE[input[j]]; - } - - let _: [u8; 30] = slice.to_be_bytes(30).as_array(); - - result -} - -// #### METHOD 2. When lookup table is in a struct, lookups are much cheaper and ROM table is used in backend -struct Lookup { - table: [Field; 128] -} -impl Lookup { - fn new() -> Self { - Lookup { - table: BASE64_DECODE_BE - } - } - - fn get(self, idx: Field) -> Field { - self.table[idx] - } -} - -fn base64_decode_with_struct(input: [u8; InputElements]) -> [u8; OutputBytes] { - // 240 bits fits 40 6-bit chunks and 30 8-bit chunks - // we pack 40 base64 values into a field element and convert into 30 bytes - // TODO: once we support arithmetic ops on generics, derive OutputBytes from InputBytes - let mut BASE64_DECODE_BE = Lookup::new(); - - // 240 bits fits 40 6-bit chunks and 30 8-bit chunks - // we pack 40 base64 values into a field element and convert into 30 bytes - // TODO: once we support arithmetic ops on generics, derive OutputBytes from InputBytes - let mut result: [u8; OutputBytes] = [0; OutputBytes]; - - let mut slice: Field = 0; - for j in 0..InputElements { - slice += BASE64_DECODE_BE.get(input[j] as Field); - } - // for _ in base64_elements_in_final_chunk..BASE64_ELEMENTS_PER_CHUNK { - // slice *= 64; - // } - - // TODO: check is it cheaper to use a constant value in `to_be_bytes` or can we use `bytes_in_final_chunk`? - let _: [u8; 30] = slice.to_be_bytes(30).as_array(); - // let num_bytes_in_final_chunk = OutputBytes - ((num_chunks - 1) * BYTES_PER_CHUNK); - // for i in 0..num_bytes_in_final_chunk { - // result[(num_chunks - 1) * BYTES_PER_CHUNK + i] = slice_bytes[i]; - // } - result -} From 497d7a08d9d870b0e7ba73ac45c5529f11fe2aa9 Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Thu, 18 Jul 2024 02:49:29 +0000 Subject: [PATCH 08/10] reduce diff --- compiler/noirc_evaluator/src/ssa/ir/instruction.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction.rs index 3456949710..d6aba60c02 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction.rs @@ -613,6 +613,7 @@ impl Instruction { } } } + let array = dfg.get_array_constant(*array); let index = dfg.get_numeric_constant(*index); if let (Some((array, _)), Some(index)) = (array, index) { From 7d424e5491608f2ce9eae03001c0bb4095ef4d86 Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Thu, 18 Jul 2024 02:54:21 +0000 Subject: [PATCH 09/10] cargo fmt --- compiler/noirc_evaluator/src/ssa/ir/instruction.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction.rs index d6aba60c02..9146fe9483 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction.rs @@ -613,7 +613,7 @@ impl Instruction { } } } - + let array = dfg.get_array_constant(*array); let index = dfg.get_numeric_constant(*index); if let (Some((array, _)), Some(index)) = (array, index) { From ca8155af3d4d4612fd59dbe6930961bad7a88312 Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Thu, 18 Jul 2024 13:52:09 +0000 Subject: [PATCH 10/10] move optimized teststo compile_success_empty --- .../trait_method_mut_self/Nargo.toml | 0 .../trait_method_mut_self/Prover.toml | 0 .../trait_method_mut_self/src/main.nr | 0 .../turbofish_call_func_diff_types/Nargo.toml | 0 .../turbofish_call_func_diff_types/Prover.toml | 0 .../turbofish_call_func_diff_types/src/main.nr | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename test_programs/{execution_success => compile_success_empty}/trait_method_mut_self/Nargo.toml (100%) rename test_programs/{execution_success => compile_success_empty}/trait_method_mut_self/Prover.toml (100%) rename test_programs/{execution_success => compile_success_empty}/trait_method_mut_self/src/main.nr (100%) rename test_programs/{execution_success => compile_success_empty}/turbofish_call_func_diff_types/Nargo.toml (100%) rename test_programs/{execution_success => compile_success_empty}/turbofish_call_func_diff_types/Prover.toml (100%) rename test_programs/{execution_success => compile_success_empty}/turbofish_call_func_diff_types/src/main.nr (100%) diff --git a/test_programs/execution_success/trait_method_mut_self/Nargo.toml b/test_programs/compile_success_empty/trait_method_mut_self/Nargo.toml similarity index 100% rename from test_programs/execution_success/trait_method_mut_self/Nargo.toml rename to test_programs/compile_success_empty/trait_method_mut_self/Nargo.toml diff --git a/test_programs/execution_success/trait_method_mut_self/Prover.toml b/test_programs/compile_success_empty/trait_method_mut_self/Prover.toml similarity index 100% rename from test_programs/execution_success/trait_method_mut_self/Prover.toml rename to test_programs/compile_success_empty/trait_method_mut_self/Prover.toml diff --git a/test_programs/execution_success/trait_method_mut_self/src/main.nr b/test_programs/compile_success_empty/trait_method_mut_self/src/main.nr similarity index 100% rename from test_programs/execution_success/trait_method_mut_self/src/main.nr rename to test_programs/compile_success_empty/trait_method_mut_self/src/main.nr diff --git a/test_programs/execution_success/turbofish_call_func_diff_types/Nargo.toml b/test_programs/compile_success_empty/turbofish_call_func_diff_types/Nargo.toml similarity index 100% rename from test_programs/execution_success/turbofish_call_func_diff_types/Nargo.toml rename to test_programs/compile_success_empty/turbofish_call_func_diff_types/Nargo.toml diff --git a/test_programs/execution_success/turbofish_call_func_diff_types/Prover.toml b/test_programs/compile_success_empty/turbofish_call_func_diff_types/Prover.toml similarity index 100% rename from test_programs/execution_success/turbofish_call_func_diff_types/Prover.toml rename to test_programs/compile_success_empty/turbofish_call_func_diff_types/Prover.toml diff --git a/test_programs/execution_success/turbofish_call_func_diff_types/src/main.nr b/test_programs/compile_success_empty/turbofish_call_func_diff_types/src/main.nr similarity index 100% rename from test_programs/execution_success/turbofish_call_func_diff_types/src/main.nr rename to test_programs/compile_success_empty/turbofish_call_func_diff_types/src/main.nr