Skip to content

Commit

Permalink
feat: parse globals in SSA parser (#7112)
Browse files Browse the repository at this point in the history
Co-authored-by: Maxim Vezenov <[email protected]>
  • Loading branch information
asterite and vezenovm authored Jan 21, 2025
1 parent 966d8a6 commit fd3377b
Show file tree
Hide file tree
Showing 5 changed files with 271 additions and 63 deletions.
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,
}
113 changes: 104 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,8 @@ impl Translator {
}

fn translate_function_body(&mut self, function: ParsedFunction) -> Result<(), SsaError> {
self.builder.set_globals(self.globals_graph.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 +325,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 +339,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 +396,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 +448,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

0 comments on commit fd3377b

Please sign in to comment.