Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: parse globals in SSA parser #7112

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
6 changes: 3 additions & 3 deletions compiler/noirc_evaluator/src/ssa/opt/normalize_value_ids.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ impl Ssa {
let mut context = Context::default();
context.populate_functions(&self.functions);
for function in self.functions.values_mut() {
context.normalize_ids(function);
context.normalize_ids(function, &self.globals);
}
self.functions = context.functions.into_btree();
}
Expand Down Expand Up @@ -65,14 +65,14 @@ impl Context {
}
}

fn normalize_ids(&mut self, old_function: &mut Function) {
fn normalize_ids(&mut self, old_function: &mut Function, globals: &Function) {
self.new_ids.blocks.clear();
self.new_ids.values.clear();

let new_function_id = self.new_ids.function_ids[&old_function.id()];
let new_function = &mut self.functions[new_function_id];

for (_, value) in old_function.dfg.globals.values_iter() {
for (_, value) in globals.dfg.values_iter() {
new_function.dfg.make_global(value.get_type().into_owned());
}

Expand Down
27 changes: 26 additions & 1 deletion compiler/noirc_evaluator/src/ssa/parser/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,28 @@ use crate::ssa::ir::{function::RuntimeType, instruction::BinaryOp, types::Type};

#[derive(Debug)]
pub(crate) struct ParsedSsa {
pub(crate) globals: Vec<ParsedGlobal>,
pub(crate) functions: Vec<ParsedFunction>,
}

#[derive(Debug)]
pub(crate) struct ParsedGlobal {
pub(crate) name: Identifier,
pub(crate) value: ParsedGlobalValue,
}

#[derive(Debug)]
pub(crate) enum ParsedGlobalValue {
NumericConstant(ParsedNumericConstant),
MakeArray(ParsedMakeArray),
}

#[derive(Debug)]
pub(crate) struct ParsedMakeArray {
pub(crate) elements: Vec<ParsedValue>,
pub(crate) typ: Type,
}

#[derive(Debug)]
pub(crate) struct ParsedFunction {
pub(crate) runtime_type: RuntimeType,
Expand Down Expand Up @@ -145,6 +164,12 @@ pub(crate) enum ParsedTerminator {

#[derive(Debug, Clone)]
pub(crate) enum ParsedValue {
NumericConstant { constant: FieldElement, typ: Type },
NumericConstant(ParsedNumericConstant),
Variable(Identifier),
}

#[derive(Debug, Clone)]
pub(crate) struct ParsedNumericConstant {
pub(crate) value: FieldElement,
pub(crate) typ: Type,
}
117 changes: 108 additions & 9 deletions compiler/noirc_evaluator/src/ssa/parser/into_ssa.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
use std::collections::HashMap;
use std::{collections::HashMap, sync::Arc};

use acvm::acir::circuit::ErrorSelector;

use crate::ssa::{
function_builder::FunctionBuilder,
ir::{
basic_block::BasicBlockId,
call_stack::CallStackId,
dfg::GlobalsGraph,
function::{Function, FunctionId},
instruction::ConstrainError,
instruction::{ConstrainError, Instruction},
value::ValueId,
},
};

use super::{
ast::AssertMessage, Identifier, ParsedBlock, ParsedFunction, ParsedInstruction, ParsedSsa,
ParsedTerminator, ParsedValue, RuntimeType, Ssa, SsaError,
ast::AssertMessage, Identifier, ParsedBlock, ParsedFunction, ParsedGlobal, ParsedGlobalValue,
ParsedInstruction, ParsedSsa, ParsedTerminator, ParsedValue, RuntimeType, Ssa, SsaError, Type,
};

impl ParsedSsa {
Expand All @@ -39,6 +41,17 @@ struct Translator {
/// will recreate the SSA step by step, which can result in a new ID layout.
variables: HashMap<FunctionId, HashMap<String, ValueId>>,

/// The function that will hold the actual SSA globals.
globals_function: Function,

/// The types of globals in the parsed SSA, in the order they were defined.
global_types: Vec<Type>,

/// Maps names (e.g. "g0") in the parsed SSA to global IDs.
global_values: HashMap<String, ValueId>,

globals_graph: Arc<GlobalsGraph>,

error_selector_counter: u64,
}

Expand Down Expand Up @@ -74,13 +87,26 @@ impl Translator {
functions.insert(function.internal_name.clone(), function_id);
}

// Does not matter what ID we use here.
let globals = Function::new("globals".to_owned(), main_id);

let mut translator = Self {
builder,
functions,
variables: HashMap::new(),
blocks: HashMap::new(),
globals_function: globals,
global_types: Vec::new(),
global_values: HashMap::new(),
globals_graph: Arc::new(GlobalsGraph::default()),
error_selector_counter: 0,
};

translator.translate_globals(std::mem::take(&mut parsed_ssa.globals))?;

translator.globals_graph =
Arc::new(GlobalsGraph::from_dfg(translator.globals_function.dfg.clone()));

translator.translate_function_body(main_function)?;

Ok(translator)
Expand All @@ -103,6 +129,12 @@ impl Translator {
}

fn translate_function_body(&mut self, function: ParsedFunction) -> Result<(), SsaError> {
self.builder.current_function.set_globals(self.globals_graph.clone());

for typ in &self.global_types {
self.builder.current_function.dfg.make_global(typ.clone());
}

// First define all blocks so that they are known (a block might jump to a block that comes next)
for (index, block) in function.blocks.iter().enumerate() {
// The first block is the entry block and it was automatically created by the builder
Expand Down Expand Up @@ -297,8 +329,8 @@ impl Translator {

fn translate_value(&mut self, value: ParsedValue) -> Result<ValueId, SsaError> {
match value {
ParsedValue::NumericConstant { constant, typ } => {
Ok(self.builder.numeric_constant(constant, typ.unwrap_numeric()))
ParsedValue::NumericConstant(constant) => {
Ok(self.builder.numeric_constant(constant.value, constant.typ.unwrap_numeric()))
}
ParsedValue::Variable(identifier) => self.lookup_variable(&identifier).or_else(|e| {
self.lookup_function(&identifier)
Expand All @@ -311,6 +343,45 @@ impl Translator {
}
}

fn translate_globals(&mut self, globals: Vec<ParsedGlobal>) -> Result<(), SsaError> {
for global in globals {
self.translate_global(global)?;
}
Ok(())
}

fn translate_global(&mut self, global: ParsedGlobal) -> Result<(), SsaError> {
let value_id = match global.value {
ParsedGlobalValue::NumericConstant(constant) => self
.globals_function
.dfg
.make_constant(constant.value, constant.typ.unwrap_numeric()),
ParsedGlobalValue::MakeArray(make_array) => {
let mut elements = im::Vector::new();
for element in make_array.elements {
let element_id = match element {
ParsedValue::NumericConstant(constant) => self
.globals_function
.dfg
.make_constant(constant.value, constant.typ.unwrap_numeric()),
ParsedValue::Variable(identifier) => self.lookup_global(identifier)?,
};
elements.push_back(element_id);
}

let instruction = Instruction::MakeArray { elements, typ: make_array.typ.clone() };
let block = self.globals_function.entry_block();
let call_stack = CallStackId::root();
self.globals_function
.dfg
.insert_instruction_and_results(instruction, block, None, call_stack)
.first()
}
};

self.define_global(global.name, value_id)
}

fn define_variable(
&mut self,
identifier: Identifier,
Expand All @@ -329,13 +400,40 @@ impl Translator {
}

fn lookup_variable(&mut self, identifier: &Identifier) -> Result<ValueId, SsaError> {
if let Some(value_id) = self.variables[&self.current_function_id()].get(&identifier.name) {
if let Some(value_id) = self
.variables
.get(&self.current_function_id())
.and_then(|hash| hash.get(&identifier.name))
{
Ok(*value_id)
} else if let Some(value_id) = self.global_values.get(&identifier.name) {
Ok(*value_id)
} else {
Err(SsaError::UnknownVariable(identifier.clone()))
}
}

fn define_global(&mut self, identifier: Identifier, value_id: ValueId) -> Result<(), SsaError> {
if self.global_values.contains_key(&identifier.name) {
return Err(SsaError::GlobalAlreadyDefined(identifier));
}

self.global_values.insert(identifier.name, value_id);

let typ = self.globals_function.dfg.type_of_value(value_id);
self.global_types.push(typ);

Ok(())
}

fn lookup_global(&mut self, identifier: Identifier) -> Result<ValueId, SsaError> {
if let Some(value_id) = self.global_values.get(&identifier.name) {
Ok(*value_id)
} else {
Err(SsaError::UnknownGlobal(identifier))
}
}

fn lookup_block(&mut self, identifier: &Identifier) -> Result<BasicBlockId, SsaError> {
if let Some(block_id) = self.blocks[&self.current_function_id()].get(&identifier.name) {
Ok(*block_id)
Expand All @@ -354,13 +452,14 @@ impl Translator {

fn finish(self) -> Ssa {
let mut ssa = self.builder.finish();
ssa.globals = self.globals_function;

// Normalize the IDs so we have a better chance of matching the SSA we parsed
// after the step-by-step reconstruction done during translation. This assumes
// that the SSA we parsed was printed by the `SsaBuilder`, which normalizes
// before each print.
ssa.normalize_ids();
// Does not matter what ID we use here.
ssa.globals = Function::new("globals".to_owned(), ssa.main_id);

ssa
}

Expand Down
Loading
Loading