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

chore: pull SSA parser from sync PR #9928

Merged
merged 4 commits into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 1 addition & 14 deletions noir/noir-repo/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions noir/noir-repo/compiler/noirc_evaluator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ fxhash.workspace = true
iter-extended.workspace = true
thiserror.workspace = true
num-bigint = "0.4"
num-traits.workspace = true
im.workspace = true
serde.workspace = true
serde_json.workspace = true
Expand All @@ -31,6 +32,7 @@ cfg-if.workspace = true

[dev-dependencies]
proptest.workspace = true
similar-asserts.workspace = true

[features]
bn254 = ["noirc_frontend/bn254"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,6 @@ pub(crate) fn directive_invert<F: AcirField>() -> GeneratedBrillig<F> {
return_data: HeapVector { pointer: zero_usize, size: one_usize },
},
],
error_types: Default::default(),
locations: Default::default(),
name: "directive_invert".to_string(),
..Default::default()
}
Expand Down Expand Up @@ -144,8 +142,6 @@ pub(crate) fn directive_quotient<F: AcirField>() -> GeneratedBrillig<F> {
},
},
],
error_types: Default::default(),
locations: Default::default(),
name: "directive_integer_quotient".to_string(),
..Default::default()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use acvm::{
AcirField,
};

use crate::ErrorType;
use crate::ssa::ir::instruction::ErrorType;

use super::{
artifact::BrilligParameter,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use noirc_errors::debug_info::ProcedureDebugId;
use prepare_vector_insert::compile_prepare_vector_insert_procedure;
use prepare_vector_push::compile_prepare_vector_push_procedure;
use revert_with_string::compile_revert_with_string_procedure;
use serde::{Deserialize, Serialize};
use vector_copy::compile_vector_copy_procedure;
use vector_pop_back::compile_vector_pop_back_procedure;
use vector_pop_front::compile_vector_pop_front_procedure;
Expand All @@ -34,7 +35,7 @@ use super::{
/// Procedures are a set of complex operations that are common in the noir language.
/// Extracting them to reusable procedures allows us to reduce the size of the generated Brillig.
/// Procedures receive their arguments on scratch space to avoid stack dumping&restoring.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord, Deserialize, Serialize)]
pub enum ProcedureId {
ArrayCopy,
ArrayReverse,
Expand Down
18 changes: 18 additions & 0 deletions noir/noir-repo/compiler/noirc_evaluator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,21 @@ pub mod brillig;
pub use ssa::create_program;

pub use ssa::ir::instruction::ErrorType;

/// Trims leading whitespace from each line of the input string, according to
/// how much leading whitespace there is on the first non-empty line.
#[cfg(test)]
pub(crate) fn trim_leading_whitespace_from_lines(src: &str) -> String {
let mut lines = src.trim_end().lines();
let mut first_line = lines.next().unwrap();
while first_line.is_empty() {
first_line = lines.next().unwrap();
}
let indent = first_line.len() - first_line.trim_start().len();
let mut result = first_line.trim_start().to_string();
for line in lines {
result.push('\n');
result.push_str(&line[indent..]);
}
result
}
1 change: 1 addition & 0 deletions noir/noir-repo/compiler/noirc_evaluator/src/ssa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ mod checks;
pub(super) mod function_builder;
pub mod ir;
mod opt;
mod parser;
pub mod ssa_gen;

pub struct SsaEvaluatorOptions {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1009,13 +1009,13 @@ impl<'a> Context<'a> {
};
entry_point.link_with(artifact);
// Insert the range of opcode locations occupied by a procedure
if let Some(procedure_id) = artifact.procedure.clone() {
if let Some(procedure_id) = &artifact.procedure {
let num_opcodes = entry_point.byte_code.len();
let previous_num_opcodes = entry_point.byte_code.len() - artifact.byte_code.len();
// We subtract one as to keep the range inclusive on both ends
entry_point
.procedure_locations
.insert(procedure_id, (previous_num_opcodes, num_opcodes - 1));
.insert(procedure_id.clone(), (previous_num_opcodes, num_opcodes - 1));
}
}
// Generate the final bytecode
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,16 @@ impl FunctionBuilder {
.first()
}

pub(crate) fn insert_mutable_array_set(
&mut self,
array: ValueId,
index: ValueId,
value: ValueId,
) -> ValueId {
self.insert_instruction(Instruction::ArraySet { array, index, value, mutable: true }, None)
.first()
}

/// Insert an instruction to increment an array's reference count. This only has an effect
/// in unconstrained code where arrays are reference counted and copy on write.
pub(crate) fn insert_inc_rc(&mut self, value: ValueId) {
Expand Down
5 changes: 3 additions & 2 deletions noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/dfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,9 @@ pub(crate) struct DataFlowGraph {
blocks: DenseMap<BasicBlock>,

/// Debugging information about which `ValueId`s have had their underlying `Value` substituted
/// for that of another. This information is purely used for printing the SSA, and has no
/// material effect on the SSA itself.
/// for that of another. In theory this information is purely used for printing the SSA,
/// and has no material effect on the SSA itself, however in practice the IDs can get out of
/// sync and may need this resolution before they can be compared.
#[serde(skip)]
replaced_value_ids: HashMap<ValueId, ValueId>,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,6 @@ impl Binary {
let zero = dfg.make_constant(FieldElement::zero(), operand_type);
return SimplifyResult::SimplifiedTo(zero);
}

// `two_pow_rhs` is limited to be at most `2 ^ {operand_bitsize - 1}` so it fits in `operand_type`.
let two_pow_rhs = FieldElement::from(2u128).pow(&rhs_const);
let two_pow_rhs = dfg.make_constant(two_pow_rhs, operand_type);
Expand Down
50 changes: 42 additions & 8 deletions noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/printer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,16 @@ fn value(function: &Function, id: ValueId) -> String {
}
Value::Function(id) => id.to_string(),
Value::Intrinsic(intrinsic) => intrinsic.to_string(),
Value::Array { array, .. } => {
Value::Array { array, typ } => {
let elements = vecmap(array, |element| value(function, *element));
format!("[{}]", elements.join(", "))
let element_types = &typ.clone().element_types();
let element_types_str =
element_types.iter().map(|typ| typ.to_string()).collect::<Vec<String>>().join(", ");
if element_types.len() == 1 {
format!("[{}] of {}", elements.join(", "), element_types_str)
} else {
format!("[{}] of ({})", elements.join(", "), element_types_str)
}
}
Value::Param { .. } | Value::Instruction { .. } | Value::ForeignFunction(_) => {
id.to_string()
Expand Down Expand Up @@ -119,7 +126,11 @@ pub(crate) fn display_terminator(
)
}
Some(TerminatorInstruction::Return { return_values, .. }) => {
writeln!(f, " return {}", value_list(function, return_values))
if return_values.is_empty() {
writeln!(f, " return")
} else {
writeln!(f, " return {}", value_list(function, return_values))
}
}
None => writeln!(f, " (no terminator instruction)"),
}
Expand All @@ -139,12 +150,13 @@ pub(crate) fn display_instruction(
write!(f, "{} = ", value_list(function, results))?;
}

display_instruction_inner(function, &function.dfg[instruction], f)
display_instruction_inner(function, &function.dfg[instruction], results, f)
}

fn display_instruction_inner(
function: &Function,
instruction: &Instruction,
results: &[ValueId],
f: &mut Formatter,
) -> Result {
let show = |id| value(function, id);
Expand All @@ -168,18 +180,29 @@ fn display_instruction_inner(
}
}
Instruction::Call { func, arguments } => {
writeln!(f, "call {}({})", show(*func), value_list(function, arguments))
let arguments = value_list(function, arguments);
writeln!(f, "call {}({}){}", show(*func), arguments, result_types(function, results))
}
Instruction::Allocate => {
writeln!(f, "allocate{}", result_types(function, results))
}
Instruction::Load { address } => {
writeln!(f, "load {}{}", show(*address), result_types(function, results))
}
Instruction::Allocate => writeln!(f, "allocate"),
Instruction::Load { address } => writeln!(f, "load {}", show(*address)),
Instruction::Store { address, value } => {
writeln!(f, "store {} at {}", show(*value), show(*address))
}
Instruction::EnableSideEffectsIf { condition } => {
writeln!(f, "enable_side_effects {}", show(*condition))
}
Instruction::ArrayGet { array, index } => {
writeln!(f, "array_get {}, index {}", show(*array), show(*index))
writeln!(
f,
"array_get {}, index {}{}",
show(*array),
show(*index),
result_types(function, results)
)
}
Instruction::ArraySet { array, index, value, mutable } => {
let array = show(*array);
Expand Down Expand Up @@ -210,6 +233,17 @@ fn display_instruction_inner(
}
}

fn result_types(function: &Function, results: &[ValueId]) -> String {
let types = vecmap(results, |result| function.dfg.type_of_value(*result).to_string());
if types.is_empty() {
String::new()
} else if types.len() == 1 {
format!(" -> {}", types[0])
} else {
format!(" -> ({})", types.join(", "))
}
}

/// Tries to extract a constant string from an error payload.
pub(crate) fn try_to_extract_string_from_error_payload(
is_string_type: bool,
Expand Down
6 changes: 5 additions & 1 deletion noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,11 @@ impl std::fmt::Display for Type {
Type::Reference(element) => write!(f, "&mut {element}"),
Type::Array(element, length) => {
let elements = vecmap(element.iter(), |element| element.to_string());
write!(f, "[{}; {length}]", elements.join(", "))
if elements.len() == 1 {
write!(f, "[{}; {length}]", elements.join(", "))
} else {
write!(f, "[({}); {length}]", elements.join(", "))
}
}
Type::Slice(element) => {
let elements = vecmap(element.iter(), |element| element.to_string());
Expand Down
Loading
Loading