Skip to content

Commit fd3377b

Browse files
asteritevezenovm
andauthored
feat: parse globals in SSA parser (#7112)
Co-authored-by: Maxim Vezenov <mvezenov@gmail.com>
1 parent 966d8a6 commit fd3377b

File tree

5 files changed

+271
-63
lines changed

5 files changed

+271
-63
lines changed

compiler/noirc_evaluator/src/ssa/opt/normalize_value_ids.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ impl Ssa {
2525
let mut context = Context::default();
2626
context.populate_functions(&self.functions);
2727
for function in self.functions.values_mut() {
28-
context.normalize_ids(function);
28+
context.normalize_ids(function, &self.globals);
2929
}
3030
self.functions = context.functions.into_btree();
3131
}
@@ -65,14 +65,14 @@ impl Context {
6565
}
6666
}
6767

68-
fn normalize_ids(&mut self, old_function: &mut Function) {
68+
fn normalize_ids(&mut self, old_function: &mut Function, globals: &Function) {
6969
self.new_ids.blocks.clear();
7070
self.new_ids.values.clear();
7171

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

75-
for (_, value) in old_function.dfg.globals.values_iter() {
75+
for (_, value) in globals.dfg.values_iter() {
7676
new_function.dfg.make_global(value.get_type().into_owned());
7777
}
7878

compiler/noirc_evaluator/src/ssa/parser/ast.rs

+26-1
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,28 @@ use crate::ssa::ir::{function::RuntimeType, instruction::BinaryOp, types::Type};
77

88
#[derive(Debug)]
99
pub(crate) struct ParsedSsa {
10+
pub(crate) globals: Vec<ParsedGlobal>,
1011
pub(crate) functions: Vec<ParsedFunction>,
1112
}
1213

14+
#[derive(Debug)]
15+
pub(crate) struct ParsedGlobal {
16+
pub(crate) name: Identifier,
17+
pub(crate) value: ParsedGlobalValue,
18+
}
19+
20+
#[derive(Debug)]
21+
pub(crate) enum ParsedGlobalValue {
22+
NumericConstant(ParsedNumericConstant),
23+
MakeArray(ParsedMakeArray),
24+
}
25+
26+
#[derive(Debug)]
27+
pub(crate) struct ParsedMakeArray {
28+
pub(crate) elements: Vec<ParsedValue>,
29+
pub(crate) typ: Type,
30+
}
31+
1332
#[derive(Debug)]
1433
pub(crate) struct ParsedFunction {
1534
pub(crate) runtime_type: RuntimeType,
@@ -145,6 +164,12 @@ pub(crate) enum ParsedTerminator {
145164

146165
#[derive(Debug, Clone)]
147166
pub(crate) enum ParsedValue {
148-
NumericConstant { constant: FieldElement, typ: Type },
167+
NumericConstant(ParsedNumericConstant),
149168
Variable(Identifier),
150169
}
170+
171+
#[derive(Debug, Clone)]
172+
pub(crate) struct ParsedNumericConstant {
173+
pub(crate) value: FieldElement,
174+
pub(crate) typ: Type,
175+
}

compiler/noirc_evaluator/src/ssa/parser/into_ssa.rs

+104-9
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
1-
use std::collections::HashMap;
1+
use std::{collections::HashMap, sync::Arc};
22

33
use acvm::acir::circuit::ErrorSelector;
44

55
use crate::ssa::{
66
function_builder::FunctionBuilder,
77
ir::{
88
basic_block::BasicBlockId,
9+
call_stack::CallStackId,
10+
dfg::GlobalsGraph,
911
function::{Function, FunctionId},
10-
instruction::ConstrainError,
12+
instruction::{ConstrainError, Instruction},
1113
value::ValueId,
1214
},
1315
};
1416

1517
use super::{
16-
ast::AssertMessage, Identifier, ParsedBlock, ParsedFunction, ParsedInstruction, ParsedSsa,
17-
ParsedTerminator, ParsedValue, RuntimeType, Ssa, SsaError,
18+
ast::AssertMessage, Identifier, ParsedBlock, ParsedFunction, ParsedGlobal, ParsedGlobalValue,
19+
ParsedInstruction, ParsedSsa, ParsedTerminator, ParsedValue, RuntimeType, Ssa, SsaError, Type,
1820
};
1921

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

44+
/// The function that will hold the actual SSA globals.
45+
globals_function: Function,
46+
47+
/// The types of globals in the parsed SSA, in the order they were defined.
48+
global_types: Vec<Type>,
49+
50+
/// Maps names (e.g. "g0") in the parsed SSA to global IDs.
51+
global_values: HashMap<String, ValueId>,
52+
53+
globals_graph: Arc<GlobalsGraph>,
54+
4255
error_selector_counter: u64,
4356
}
4457

@@ -74,13 +87,26 @@ impl Translator {
7487
functions.insert(function.internal_name.clone(), function_id);
7588
}
7689

90+
// Does not matter what ID we use here.
91+
let globals = Function::new("globals".to_owned(), main_id);
92+
7793
let mut translator = Self {
7894
builder,
7995
functions,
8096
variables: HashMap::new(),
8197
blocks: HashMap::new(),
98+
globals_function: globals,
99+
global_types: Vec::new(),
100+
global_values: HashMap::new(),
101+
globals_graph: Arc::new(GlobalsGraph::default()),
82102
error_selector_counter: 0,
83103
};
104+
105+
translator.translate_globals(std::mem::take(&mut parsed_ssa.globals))?;
106+
107+
translator.globals_graph =
108+
Arc::new(GlobalsGraph::from_dfg(translator.globals_function.dfg.clone()));
109+
84110
translator.translate_function_body(main_function)?;
85111

86112
Ok(translator)
@@ -103,6 +129,8 @@ impl Translator {
103129
}
104130

105131
fn translate_function_body(&mut self, function: ParsedFunction) -> Result<(), SsaError> {
132+
self.builder.set_globals(self.globals_graph.clone());
133+
106134
// First define all blocks so that they are known (a block might jump to a block that comes next)
107135
for (index, block) in function.blocks.iter().enumerate() {
108136
// The first block is the entry block and it was automatically created by the builder
@@ -297,8 +325,8 @@ impl Translator {
297325

298326
fn translate_value(&mut self, value: ParsedValue) -> Result<ValueId, SsaError> {
299327
match value {
300-
ParsedValue::NumericConstant { constant, typ } => {
301-
Ok(self.builder.numeric_constant(constant, typ.unwrap_numeric()))
328+
ParsedValue::NumericConstant(constant) => {
329+
Ok(self.builder.numeric_constant(constant.value, constant.typ.unwrap_numeric()))
302330
}
303331
ParsedValue::Variable(identifier) => self.lookup_variable(&identifier).or_else(|e| {
304332
self.lookup_function(&identifier)
@@ -311,6 +339,45 @@ impl Translator {
311339
}
312340
}
313341

342+
fn translate_globals(&mut self, globals: Vec<ParsedGlobal>) -> Result<(), SsaError> {
343+
for global in globals {
344+
self.translate_global(global)?;
345+
}
346+
Ok(())
347+
}
348+
349+
fn translate_global(&mut self, global: ParsedGlobal) -> Result<(), SsaError> {
350+
let value_id = match global.value {
351+
ParsedGlobalValue::NumericConstant(constant) => self
352+
.globals_function
353+
.dfg
354+
.make_constant(constant.value, constant.typ.unwrap_numeric()),
355+
ParsedGlobalValue::MakeArray(make_array) => {
356+
let mut elements = im::Vector::new();
357+
for element in make_array.elements {
358+
let element_id = match element {
359+
ParsedValue::NumericConstant(constant) => self
360+
.globals_function
361+
.dfg
362+
.make_constant(constant.value, constant.typ.unwrap_numeric()),
363+
ParsedValue::Variable(identifier) => self.lookup_global(identifier)?,
364+
};
365+
elements.push_back(element_id);
366+
}
367+
368+
let instruction = Instruction::MakeArray { elements, typ: make_array.typ.clone() };
369+
let block = self.globals_function.entry_block();
370+
let call_stack = CallStackId::root();
371+
self.globals_function
372+
.dfg
373+
.insert_instruction_and_results(instruction, block, None, call_stack)
374+
.first()
375+
}
376+
};
377+
378+
self.define_global(global.name, value_id)
379+
}
380+
314381
fn define_variable(
315382
&mut self,
316383
identifier: Identifier,
@@ -329,13 +396,40 @@ impl Translator {
329396
}
330397

331398
fn lookup_variable(&mut self, identifier: &Identifier) -> Result<ValueId, SsaError> {
332-
if let Some(value_id) = self.variables[&self.current_function_id()].get(&identifier.name) {
399+
if let Some(value_id) = self
400+
.variables
401+
.get(&self.current_function_id())
402+
.and_then(|hash| hash.get(&identifier.name))
403+
{
404+
Ok(*value_id)
405+
} else if let Some(value_id) = self.global_values.get(&identifier.name) {
333406
Ok(*value_id)
334407
} else {
335408
Err(SsaError::UnknownVariable(identifier.clone()))
336409
}
337410
}
338411

412+
fn define_global(&mut self, identifier: Identifier, value_id: ValueId) -> Result<(), SsaError> {
413+
if self.global_values.contains_key(&identifier.name) {
414+
return Err(SsaError::GlobalAlreadyDefined(identifier));
415+
}
416+
417+
self.global_values.insert(identifier.name, value_id);
418+
419+
let typ = self.globals_function.dfg.type_of_value(value_id);
420+
self.global_types.push(typ);
421+
422+
Ok(())
423+
}
424+
425+
fn lookup_global(&mut self, identifier: Identifier) -> Result<ValueId, SsaError> {
426+
if let Some(value_id) = self.global_values.get(&identifier.name) {
427+
Ok(*value_id)
428+
} else {
429+
Err(SsaError::UnknownGlobal(identifier))
430+
}
431+
}
432+
339433
fn lookup_block(&mut self, identifier: &Identifier) -> Result<BasicBlockId, SsaError> {
340434
if let Some(block_id) = self.blocks[&self.current_function_id()].get(&identifier.name) {
341435
Ok(*block_id)
@@ -354,13 +448,14 @@ impl Translator {
354448

355449
fn finish(self) -> Ssa {
356450
let mut ssa = self.builder.finish();
451+
ssa.globals = self.globals_function;
452+
357453
// Normalize the IDs so we have a better chance of matching the SSA we parsed
358454
// after the step-by-step reconstruction done during translation. This assumes
359455
// that the SSA we parsed was printed by the `SsaBuilder`, which normalizes
360456
// before each print.
361457
ssa.normalize_ids();
362-
// Does not matter what ID we use here.
363-
ssa.globals = Function::new("globals".to_owned(), ssa.main_id);
458+
364459
ssa
365460
}
366461

0 commit comments

Comments
 (0)