diff --git a/crates/noirc_evaluator/src/lib.rs b/crates/noirc_evaluator/src/lib.rs index 166c2d58239..8b3cbb009a9 100644 --- a/crates/noirc_evaluator/src/lib.rs +++ b/crates/noirc_evaluator/src/lib.rs @@ -304,7 +304,7 @@ impl Evaluator { // u8 and arrays are assumed to be private // This is not a short-coming of the ABI, but of the grammar // The new grammar has been conceived, and will be implemented. - let main = ir_gen.program.main(); + let main = ir_gen.program.main_mut(); let main_params = std::mem::take(&mut main.parameters); let abi_params = std::mem::take(&mut ir_gen.program.main_function_signature.0); diff --git a/crates/noirc_evaluator/src/ssa_refactor.rs b/crates/noirc_evaluator/src/ssa_refactor.rs index 073b54cbf10..37f1ead2b07 100644 --- a/crates/noirc_evaluator/src/ssa_refactor.rs +++ b/crates/noirc_evaluator/src/ssa_refactor.rs @@ -5,9 +5,8 @@ //! elimination and constant folding. //! //! This module heavily borrows from Cranelift -#[allow(dead_code)] -mod basic_block; -#[allow(dead_code)] -mod dfg; -#[allow(dead_code)] +#![allow(dead_code)] + mod ir; +mod ssa_builder; +mod ssa_gen; diff --git a/crates/noirc_evaluator/src/ssa_refactor/ir.rs b/crates/noirc_evaluator/src/ssa_refactor/ir.rs index bdb722cd456..ce63bdc7238 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/ir.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/ir.rs @@ -1,5 +1,6 @@ -pub(crate) mod extfunc; -mod function; +pub(crate) mod basic_block; +pub(crate) mod dfg; +pub(crate) mod function; pub(crate) mod instruction; pub(crate) mod map; pub(crate) mod types; diff --git a/crates/noirc_evaluator/src/ssa_refactor/basic_block.rs b/crates/noirc_evaluator/src/ssa_refactor/ir/basic_block.rs similarity index 55% rename from crates/noirc_evaluator/src/ssa_refactor/basic_block.rs rename to crates/noirc_evaluator/src/ssa_refactor/ir/basic_block.rs index d6c2198b4a0..b11c4dc3f1c 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/basic_block.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/ir/basic_block.rs @@ -1,4 +1,8 @@ -use super::ir::instruction::{Instruction, TerminatorInstruction}; +use super::{ + instruction::{InstructionId, TerminatorInstruction}, + map::Id, + value::ValueId, +}; /// A Basic block is a maximal collection of instructions /// such that there are only jumps at the end of block @@ -8,10 +12,11 @@ use super::ir::instruction::{Instruction, TerminatorInstruction}; /// block, then all instructions are executed. ie single-entry single-exit. #[derive(Debug, PartialEq, Eq, Hash, Clone)] pub(crate) struct BasicBlock { - /// Arguments to the basic block. - phi_nodes: Vec, + /// Parameters to the basic block. + parameters: Vec, + /// Instructions in the basic block. - instructions: Vec, + instructions: Vec, /// A basic block is considered sealed /// if no further predecessors will be added to it. @@ -21,17 +26,16 @@ pub(crate) struct BasicBlock { /// The terminating instruction for the basic block. /// - /// This will be a control flow instruction. - terminator: TerminatorInstruction, + /// This will be a control flow instruction. This is only + /// None if the block is still being constructed. + terminator: Option, } -#[derive(Debug, PartialEq, Eq, Hash, Clone)] /// An identifier for a Basic Block. -pub(crate) struct BasicBlockId; +pub(crate) type BasicBlockId = Id; -#[derive(Debug, PartialEq, Eq, Hash, Clone)] -/// Arguments to the basic block. -/// We use the modern Crane-lift strategy -/// of representing phi nodes as basic block -/// arguments. -pub(crate) struct BlockArguments; +impl BasicBlock { + pub(super) fn new(parameters: Vec) -> Self { + Self { parameters, instructions: Vec::new(), is_sealed: false, terminator: None } + } +} diff --git a/crates/noirc_evaluator/src/ssa_refactor/dfg.rs b/crates/noirc_evaluator/src/ssa_refactor/ir/dfg.rs similarity index 88% rename from crates/noirc_evaluator/src/ssa_refactor/dfg.rs rename to crates/noirc_evaluator/src/ssa_refactor/ir/dfg.rs index 6dcee5212e2..ad6d614fec0 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/dfg.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/ir/dfg.rs @@ -1,14 +1,11 @@ use super::{ basic_block::{BasicBlock, BasicBlockId}, - ir::{ - extfunc::Signature, - instruction::{Instruction, InstructionId, Instructions}, - map::{Id, SparseMap}, - types::Type, - value::{Value, ValueId}, - }, + function::Signature, + instruction::{Instruction, InstructionId}, + map::{DenseMap, Id, SecondaryMap}, + types::Type, + value::{Value, ValueId}, }; -use std::collections::HashMap; #[derive(Debug, Default)] /// A convenience wrapper to store `Value`s. @@ -39,7 +36,7 @@ impl ValueList { #[derive(Debug, Default)] pub(crate) struct DataFlowGraph { /// All of the instructions in a function - instructions: Instructions, + instructions: DenseMap, /// Stores the results for a particular instruction. /// @@ -50,17 +47,17 @@ pub(crate) struct DataFlowGraph { /// Currently, we need to define them in a better way /// Call instructions require the func signature, but /// other instructions may need some more reading on my part - results: HashMap, + results: SecondaryMap, /// Storage for all of the values defined in this /// function. - values: SparseMap, + values: DenseMap, /// Function signatures of external methods - signatures: SparseMap, + signatures: DenseMap, /// All blocks in a function - blocks: SparseMap, + blocks: DenseMap, } impl DataFlowGraph { @@ -71,13 +68,17 @@ impl DataFlowGraph { /// Inserts a new instruction into the DFG. pub(crate) fn make_instruction(&mut self, instruction_data: Instruction) -> InstructionId { - let id = self.instructions.push(instruction_data); + let id = self.instructions.insert(instruction_data); // Create a new vector to store the potential results for the instruction. self.results.insert(id, Default::default()); id } + pub(crate) fn make_value(&mut self, value: Value) -> ValueId { + self.values.insert(value) + } + /// Attaches results to the instruction. /// /// Returns the number of results that this instruction @@ -126,9 +127,9 @@ impl DataFlowGraph { let results = self.results.get_mut(&instruction_id).unwrap(); let expected_res_position = results.len(); - let value_id = self.values.push(Value::Instruction { + let value_id = self.values.insert(Value::Instruction { typ, - position: expected_res_position as u16, + position: expected_res_position, instruction: instruction_id, }); diff --git a/crates/noirc_evaluator/src/ssa_refactor/ir/extfunc.rs b/crates/noirc_evaluator/src/ssa_refactor/ir/extfunc.rs deleted file mode 100644 index 0ec7d6f5fc0..00000000000 --- a/crates/noirc_evaluator/src/ssa_refactor/ir/extfunc.rs +++ /dev/null @@ -1,20 +0,0 @@ -//! Like Crane-lift all functions outside of the current function is seen as -//! external. -//! To reference external functions, one must first import the function signature -//! into the current function's context. - -use super::types::Type; - -#[derive(Debug, Default, Clone)] -pub(crate) struct Signature { - pub(crate) params: Vec, - pub(crate) returns: Vec, -} - -#[test] -fn sign_smoke() { - let mut signature = Signature::default(); - - signature.params.push(Type::Numeric(super::types::NumericType::NativeField)); - signature.returns.push(Type::Numeric(super::types::NumericType::Unsigned { bit_size: 32 })); -} diff --git a/crates/noirc_evaluator/src/ssa_refactor/ir/function.rs b/crates/noirc_evaluator/src/ssa_refactor/ir/function.rs index 331c0d656d6..2509a85f435 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/ir/function.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/ir/function.rs @@ -1,25 +1,70 @@ -use crate::ssa_refactor::basic_block::{BasicBlock, BasicBlockId}; - +use super::basic_block::{BasicBlock, BasicBlockId}; +use super::dfg::DataFlowGraph; use super::instruction::Instruction; +use super::map::{DenseMap, Id, SecondaryMap}; +use super::types::Type; +use super::value::Value; +use iter_extended::vecmap; use noirc_errors::Location; -use std::collections::HashMap; /// A function holds a list of instructions. -/// These instructions are further grouped into -/// Basic blocks +/// These instructions are further grouped into Basic blocks +/// +/// Like Crane-lift all functions outside of the current function is seen as external. +/// To reference external functions, one must first import the function signature +/// into the current function's context. #[derive(Debug)] pub(crate) struct Function { /// Basic blocks associated to this particular function - basic_blocks: HashMap, + basic_blocks: DenseMap, /// Maps instructions to source locations - source_locations: HashMap, + source_locations: SecondaryMap, /// The first basic block in the function entry_block: BasicBlockId, + + dfg: DataFlowGraph, +} + +impl Function { + pub(crate) fn new(parameter_count: usize) -> Self { + let mut dfg = DataFlowGraph::default(); + let mut basic_blocks = DenseMap::default(); + + // The parameters for each function are stored as the block parameters + // of the function's entry block + let entry_block = basic_blocks.insert_with_id(|entry_block| { + // TODO: Give each parameter its correct type + let parameters = vecmap(0..parameter_count, |i| { + dfg.make_value(Value::Param { block: entry_block, position: i, typ: Type::Unit }) + }); + + BasicBlock::new(parameters) + }); + + Self { basic_blocks, source_locations: SecondaryMap::new(), entry_block, dfg } + } + + pub(crate) fn entry_block(&self) -> BasicBlockId { + self.entry_block + } } /// FunctionId is a reference for a function -#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] -pub(crate) struct FunctionId(pub(crate) u32); +pub(crate) type FunctionId = Id; + +#[derive(Debug, Default, Clone)] +pub(crate) struct Signature { + pub(crate) params: Vec, + pub(crate) returns: Vec, +} + +#[test] +fn sign_smoke() { + let mut signature = Signature::default(); + + signature.params.push(Type::Numeric(super::types::NumericType::NativeField)); + signature.returns.push(Type::Numeric(super::types::NumericType::Unsigned { bit_size: 32 })); +} diff --git a/crates/noirc_evaluator/src/ssa_refactor/ir/instruction.rs b/crates/noirc_evaluator/src/ssa_refactor/ir/instruction.rs index e3298532ce0..1d5089179d5 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/ir/instruction.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/ir/instruction.rs @@ -1,15 +1,8 @@ use acvm::FieldElement; use super::{ - function::FunctionId, - map::{Id, SparseMap}, - types::Type, - value::ValueId, + basic_block::BasicBlockId, function::FunctionId, map::Id, types::Type, value::ValueId, }; -use crate::ssa_refactor::basic_block::{BasicBlockId, BlockArguments}; - -// Container for all Instructions, per-function -pub(crate) type Instructions = SparseMap; /// Reference to an instruction pub(crate) type InstructionId = Id; @@ -134,12 +127,12 @@ pub(crate) enum TerminatorInstruction { condition: ValueId, then_destination: BasicBlockId, else_destination: BasicBlockId, - arguments: BlockArguments, + arguments: Vec, }, /// Unconditional Jump /// /// Jumps to specified `destination` with `arguments` - Jmp { destination: BasicBlockId, arguments: BlockArguments }, + Jmp { destination: BasicBlockId, arguments: Vec }, } /// A binary instruction in the IR. @@ -181,34 +174,3 @@ pub(crate) enum BinaryOp { /// false otherwise. Ne, } - -#[test] -fn smoke_instructions_map_duplicate() { - let id = Id::test_new(0); - - let ins = Instruction::Not(id); - let same_ins = Instruction::Not(id); - - let mut ins_map = Instructions::default(); - - // Document what happens when we insert the same instruction twice - let id = ins_map.push(ins); - let id_same_ins = ins_map.push(same_ins); - - // The map is quite naive and does not check if the instruction has ben inserted - // before. We simply assign a different Id. - assert_ne!(id, id_same_ins) -} - -#[test] -fn num_instructions_smoke() { - let n = 100; - - let mut ins_map = Instructions::default(); - for i in 0..n { - let ins = Instruction::Not(Id::test_new(i)); - ins_map.push(ins); - } - - assert_eq!(n, ins_map.len()) -} diff --git a/crates/noirc_evaluator/src/ssa_refactor/ir/map.rs b/crates/noirc_evaluator/src/ssa_refactor/ir/map.rs index 6c7511b5bdd..53a7db3a5d5 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/ir/map.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/ir/map.rs @@ -1,4 +1,7 @@ -use std::collections::HashMap; +use std::{ + collections::HashMap, + sync::atomic::{AtomicUsize, Ordering}, +}; /// A unique ID corresponding to a value of type T. /// This type can be used to retrieve a value of type T from @@ -80,13 +83,22 @@ impl DenseMap { pub(crate) fn len(&self) -> usize { self.storage.len() } + /// Adds an element to the map. /// Returns the identifier/reference to that element. - pub(crate) fn push(&mut self, element: T) -> Id { + pub(crate) fn insert(&mut self, element: T) -> Id { let id = Id::new(self.storage.len()); self.storage.push(element); id } + + /// Given the Id of the element being created, adds the element + /// returned by the given function to the map + pub(crate) fn insert_with_id(&mut self, f: impl FnOnce(Id) -> T) -> Id { + let id = Id::new(self.storage.len()); + self.storage.push(f(id)); + id + } } impl Default for DenseMap { @@ -132,12 +144,20 @@ impl SparseMap { /// Adds an element to the map. /// Returns the identifier/reference to that element. - pub(crate) fn push(&mut self, element: T) -> Id { + pub(crate) fn insert(&mut self, element: T) -> Id { let id = Id::new(self.storage.len()); self.storage.insert(id, element); id } + /// Given the Id of the element being created, adds the element + /// returned by the given function to the map + pub(crate) fn insert_with_id(&mut self, f: impl FnOnce(Id) -> T) -> Id { + let id = Id::new(self.storage.len()); + self.storage.insert(id, f(id)); + id + } + /// Remove an element from the map and return it. /// This may return None if the element was already /// previously removed from the map. @@ -165,3 +185,41 @@ impl std::ops::IndexMut> for SparseMap { self.storage.get_mut(&id).expect("Invalid id used in SparseMap::index_mut") } } + +/// A SecondaryMap is for storing secondary data for a given key. Since this +/// map is for secondary data, it will not return fresh Ids for data, instead +/// it expects users to provide these ids in order to associate existing ids with +/// additional data. +/// +/// Unlike SecondaryMap in cranelift, this version is sparse and thus +/// does not require inserting default elements for each key in between +/// the desired key and the previous length of the map. +/// +/// There is no expectation that there is always secondary data for all relevant +/// Ids of a given type, so unlike the other Map types, it is possible for +/// a call to .get(id) to return None. +pub(crate) type SecondaryMap = HashMap, V>; + +/// A simple counter to create fresh Ids without any storage. +/// Useful for assigning ids before the storage is created or assigning ids +/// for types that have no single owner. +/// +/// This type wraps an AtomicUsize so it can safely be used across threads. +#[derive(Debug)] +pub(crate) struct AtomicCounter { + next: AtomicUsize, + _marker: std::marker::PhantomData, +} + +impl AtomicCounter { + /// Return the next fresh id + pub(crate) fn next(&self) -> Id { + Id::new(self.next.fetch_add(1, Ordering::Relaxed)) + } +} + +impl Default for AtomicCounter { + fn default() -> Self { + Self { next: Default::default(), _marker: Default::default() } + } +} diff --git a/crates/noirc_evaluator/src/ssa_refactor/ir/value.rs b/crates/noirc_evaluator/src/ssa_refactor/ir/value.rs index ddd00efb38f..38ca8b12c40 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/ir/value.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/ir/value.rs @@ -1,3 +1,5 @@ +use crate::ssa_refactor::ir::basic_block::BasicBlockId; + use super::{instruction::InstructionId, map::Id, types::Type}; pub(crate) type ValueId = Id; @@ -15,5 +17,11 @@ pub(crate) enum Value { /// Example, if you add two numbers together, then the resulting /// value would have position `0`, the typ would be the type /// of the operands, and the instruction would map to an add instruction. - Instruction { typ: Type, position: u16, instruction: InstructionId }, + Instruction { instruction: InstructionId, position: usize, typ: Type }, + + /// This Value originates from a block parameter. Since function parameters + /// are also represented as block parameters, this includes function parameters as well. + /// + /// position -- the index of this Value in the block parameters list + Param { block: BasicBlockId, position: usize, typ: Type }, } diff --git a/crates/noirc_evaluator/src/ssa_refactor/ssa_builder/function_builder.rs b/crates/noirc_evaluator/src/ssa_refactor/ssa_builder/function_builder.rs new file mode 100644 index 00000000000..8d90a95332e --- /dev/null +++ b/crates/noirc_evaluator/src/ssa_refactor/ssa_builder/function_builder.rs @@ -0,0 +1,54 @@ +use crate::ssa_refactor::ir::{ + basic_block::BasicBlockId, + function::{Function, FunctionId}, +}; + +use super::SharedBuilderContext; + +/// The per-function context for each ssa function being generated. +/// +/// This is split from the global SsaBuilder context to allow each function +/// to be potentially built concurrently. +/// +/// Contrary to the name, this struct has the capacity to build as many +/// functions as needed, although it is limited to one function at a time. +pub(crate) struct FunctionBuilder<'ssa> { + global_context: &'ssa SharedBuilderContext, + + current_function: Function, + current_function_id: FunctionId, + + current_block: BasicBlockId, + + finished_functions: Vec<(FunctionId, Function)>, +} + +impl<'ssa> FunctionBuilder<'ssa> { + pub(crate) fn new(parameters: usize, context: &'ssa SharedBuilderContext) -> Self { + let new_function = Function::new(parameters); + let current_block = new_function.entry_block(); + + Self { + global_context: context, + current_function: new_function, + current_function_id: context.next_function(), + current_block, + finished_functions: Vec::new(), + } + } + + /// Finish the current function and create a new function + pub(crate) fn new_function(&mut self, parameters: usize) { + let new_function = Function::new(parameters); + let old_function = std::mem::replace(&mut self.current_function, new_function); + + self.finished_functions.push((self.current_function_id, old_function)); + + self.current_function_id = self.global_context.next_function(); + } + + pub(crate) fn finish(mut self) -> Vec<(FunctionId, Function)> { + self.finished_functions.push((self.current_function_id, self.current_function)); + self.finished_functions + } +} diff --git a/crates/noirc_evaluator/src/ssa_refactor/ssa_builder/mod.rs b/crates/noirc_evaluator/src/ssa_refactor/ssa_builder/mod.rs new file mode 100644 index 00000000000..8f9ceed800e --- /dev/null +++ b/crates/noirc_evaluator/src/ssa_refactor/ssa_builder/mod.rs @@ -0,0 +1,19 @@ +pub(crate) mod function_builder; + +use crate::ssa_refactor::ir::{ + function::{Function, FunctionId}, + map::AtomicCounter, +}; + +/// The global context while building the ssa representation. +/// Because this may be shared across threads, it is synchronized internally as necessary. +#[derive(Default)] +pub(crate) struct SharedBuilderContext { + function_count: AtomicCounter, +} + +impl SharedBuilderContext { + pub(super) fn next_function(&self) -> FunctionId { + self.function_count.next() + } +} diff --git a/crates/noirc_evaluator/src/ssa_refactor/ssa_gen/context.rs b/crates/noirc_evaluator/src/ssa_refactor/ssa_gen/context.rs new file mode 100644 index 00000000000..94fedb7b4cf --- /dev/null +++ b/crates/noirc_evaluator/src/ssa_refactor/ssa_gen/context.rs @@ -0,0 +1,60 @@ +use std::collections::HashMap; +use std::sync::{Mutex, RwLock}; + +use noirc_frontend::monomorphization::ast::{self, LocalId}; +use noirc_frontend::monomorphization::ast::{FuncId, Program}; + +use crate::ssa_refactor::ssa_builder::SharedBuilderContext; +use crate::ssa_refactor::{ + ir::function::FunctionId as IrFunctionId, ssa_builder::function_builder::FunctionBuilder, +}; + +use super::value::Value; + +// TODO: Make this a threadsafe queue so we can compile functions in parallel +type FunctionQueue = Vec<(ast::FuncId, IrFunctionId)>; + +pub(super) struct FunctionContext<'a> { + definitions: HashMap, + function_builder: FunctionBuilder<'a>, + shared_context: &'a SharedContext, +} + +/// Shared context for all functions during ssa codegen +pub(super) struct SharedContext { + functions: RwLock>, + function_queue: Mutex, + pub(super) program: Program, +} + +impl<'a> FunctionContext<'a> { + pub(super) fn new( + parameter_count: usize, + shared_context: &'a SharedContext, + shared_builder_context: &'a SharedBuilderContext, + ) -> Self { + Self { + definitions: HashMap::new(), + function_builder: FunctionBuilder::new(parameter_count, shared_builder_context), + shared_context, + } + } + + pub(super) fn new_function(&mut self, parameters: impl ExactSizeIterator) { + self.function_builder.new_function(parameters.len()); + + for (_i, _parameter) in parameters.enumerate() { + todo!("Add block param to definitions") + } + } +} + +impl SharedContext { + pub(super) fn new(program: Program) -> Self { + Self { functions: Default::default(), function_queue: Default::default(), program } + } + + pub(super) fn pop_next_function_in_queue(&self) -> Option<(ast::FuncId, IrFunctionId)> { + self.function_queue.lock().expect("Failed to lock function_queue").pop() + } +} diff --git a/crates/noirc_evaluator/src/ssa_refactor/ssa_gen/mod.rs b/crates/noirc_evaluator/src/ssa_refactor/ssa_gen/mod.rs new file mode 100644 index 00000000000..1da65fafd48 --- /dev/null +++ b/crates/noirc_evaluator/src/ssa_refactor/ssa_gen/mod.rs @@ -0,0 +1,120 @@ +mod context; +mod value; + +use context::SharedContext; +use noirc_errors::Location; +use noirc_frontend::monomorphization::ast::{self, Expression, Program}; + +use self::{context::FunctionContext, value::Value}; + +use super::ssa_builder::SharedBuilderContext; + +pub(crate) fn generate_ssa(program: Program) { + let context = SharedContext::new(program); + let builder_context = SharedBuilderContext::default(); + + let main = context.program.main(); + // TODO struct parameter counting + let parameter_count = main.parameters.len(); + + let mut function_context = FunctionContext::new(parameter_count, &context, &builder_context); + function_context.codegen_expression(&main.body); + + while let Some((src_function_id, _new_id)) = context.pop_next_function_in_queue() { + let function = &context.program[src_function_id]; + // TODO: Need to ensure/assert the new function's id == new_id + function_context.new_function(function.parameters.iter().map(|(id, ..)| *id)); + function_context.codegen_expression(&function.body); + } +} + +impl<'a> FunctionContext<'a> { + fn codegen_expression(&mut self, expr: &Expression) -> Value { + match expr { + Expression::Ident(ident) => self.codegen_ident(ident), + Expression::Literal(literal) => self.codegen_literal(literal), + Expression::Block(block) => self.codegen_block(block), + Expression::Unary(unary) => self.codegen_unary(unary), + Expression::Binary(binary) => self.codegen_binary(binary), + Expression::Index(index) => self.codegen_index(index), + Expression::Cast(cast) => self.codegen_cast(cast), + Expression::For(for_expr) => self.codegen_for(for_expr), + Expression::If(if_expr) => self.codegen_if(if_expr), + Expression::Tuple(tuple) => self.codegen_tuple(tuple), + Expression::ExtractTupleField(tuple, index) => { + self.codegen_extract_tuple_field(tuple, *index) + } + Expression::Call(call) => self.codegen_call(call), + Expression::Let(let_expr) => self.codegen_let(let_expr), + Expression::Constrain(constrain, location) => { + self.codegen_constrain(constrain, *location) + } + Expression::Assign(assign) => self.codegen_assign(assign), + Expression::Semi(semi) => self.codegen_semi(semi), + } + } + + fn codegen_ident(&mut self, _ident: &ast::Ident) -> Value { + todo!() + } + + fn codegen_literal(&mut self, _literal: &ast::Literal) -> Value { + todo!() + } + + fn codegen_block(&mut self, _block: &[Expression]) -> Value { + todo!() + } + + fn codegen_unary(&mut self, _unary: &ast::Unary) -> Value { + todo!() + } + + fn codegen_binary(&mut self, _binary: &ast::Binary) -> Value { + todo!() + } + + fn codegen_index(&mut self, _index: &ast::Index) -> Value { + todo!() + } + + fn codegen_cast(&mut self, _cast: &ast::Cast) -> Value { + todo!() + } + + fn codegen_for(&mut self, _for_expr: &ast::For) -> Value { + todo!() + } + + fn codegen_if(&mut self, _if_expr: &ast::If) -> Value { + todo!() + } + + fn codegen_tuple(&mut self, _tuple: &[Expression]) -> Value { + todo!() + } + + fn codegen_extract_tuple_field(&mut self, _tuple: &Expression, _index: usize) -> Value { + todo!() + } + + fn codegen_call(&mut self, _call: &ast::Call) -> Value { + todo!() + } + + fn codegen_let(&mut self, _let_expr: &ast::Let) -> Value { + todo!() + } + + fn codegen_constrain(&mut self, _constrain: &Expression, _location: Location) -> Value { + todo!() + } + + fn codegen_assign(&mut self, _assign: &ast::Assign) -> Value { + todo!() + } + + fn codegen_semi(&mut self, _semi: &Expression) -> Value { + todo!() + } +} diff --git a/crates/noirc_evaluator/src/ssa_refactor/ssa_gen/value.rs b/crates/noirc_evaluator/src/ssa_refactor/ssa_gen/value.rs new file mode 100644 index 00000000000..785ae3cd8f7 --- /dev/null +++ b/crates/noirc_evaluator/src/ssa_refactor/ssa_gen/value.rs @@ -0,0 +1,13 @@ +use crate::ssa_refactor::ir::function::FunctionId as IrFunctionId; +use crate::ssa_refactor::ir::value::ValueId; + +#[derive(Debug, Clone)] +pub(super) enum Value { + Normal(ValueId), + Function(IrFunctionId), + Tuple(Vec), + + /// Lazily inserting unit values helps prevent cluttering the IR with too many + /// unit literals. + Unit, +} diff --git a/crates/noirc_frontend/src/monomorphization/ast.rs b/crates/noirc_frontend/src/monomorphization/ast.rs index 938a937405c..6a2b97ae19d 100644 --- a/crates/noirc_frontend/src/monomorphization/ast.rs +++ b/crates/noirc_frontend/src/monomorphization/ast.rs @@ -226,8 +226,12 @@ impl Program { Program { functions, main_function_signature } } - pub fn main(&mut self) -> &mut Function { - &mut self.functions[0] + pub fn main(&self) -> &Function { + &self[Self::main_id()] + } + + pub fn main_mut(&mut self) -> &mut Function { + &mut self[Self::main_id()] } pub fn main_id() -> FuncId {