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(ssa refactor): Handle codegen for literals #1209

Merged
merged 13 commits into from
Apr 24, 2023
2 changes: 2 additions & 0 deletions crates/noirc_evaluator/src/ssa_refactor/ir.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
pub(crate) mod basic_block;
pub(crate) mod constant;
pub(crate) mod dfg;
pub(crate) mod function;
pub(crate) mod instruction;
pub(crate) mod map;
pub(crate) mod printer;
pub(crate) mod types;
pub(crate) mod value;
22 changes: 22 additions & 0 deletions crates/noirc_evaluator/src/ssa_refactor/ir/basic_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,29 @@ impl BasicBlock {
self.instructions.push(instruction);
}

pub(crate) fn instructions(&self) -> &[InstructionId] {
&self.instructions
}

pub(crate) fn set_terminator(&mut self, terminator: TerminatorInstruction) {
self.terminator = Some(terminator);
}

pub(crate) fn terminator(&self) -> Option<&TerminatorInstruction> {
self.terminator.as_ref()
}

/// Iterate over all the successors of the currently block, as determined by
/// the blocks jumped to in the terminator instruction. If there is no terminator
/// instruction yet, this will iterate 0 times.
pub(crate) fn successors(&self) -> impl ExactSizeIterator<Item = BasicBlockId> {
match &self.terminator {
Some(TerminatorInstruction::Jmp { destination, .. }) => vec![*destination].into_iter(),
Some(TerminatorInstruction::JmpIf { then_destination, else_destination, .. }) => {
vec![*then_destination, *else_destination].into_iter()
}
Some(TerminatorInstruction::Return { .. }) => vec![].into_iter(),
None => vec![].into_iter(),
}
}
}
56 changes: 56 additions & 0 deletions crates/noirc_evaluator/src/ssa_refactor/ir/constant.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use acvm::FieldElement;

use super::map::Id;

/// Represents a numeric constant in Ssa. Constants themselves are
/// uniqued in the DataFlowGraph and immutable.
///
/// This is just a thin wrapper around FieldElement so that
/// we can use Id<NumericConstant> without it getting confused
/// with a possible future use of Id<FieldElement>.
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub(crate) struct NumericConstant(FieldElement);

impl NumericConstant {
pub(crate) fn new(value: FieldElement) -> Self {
Self(value)
}

pub(crate) fn value(&self) -> &FieldElement {
&self.0
}
}

pub(crate) type NumericConstantId = Id<NumericConstant>;

impl std::ops::Add for NumericConstant {
type Output = NumericConstant;

fn add(self, rhs: Self) -> Self::Output {
Self::new(self.0 + rhs.0)
}
}

impl std::ops::Sub for NumericConstant {
type Output = NumericConstant;

fn sub(self, rhs: Self) -> Self::Output {
Self::new(self.0 - rhs.0)
}
}

impl std::ops::Mul for NumericConstant {
type Output = NumericConstant;

fn mul(self, rhs: Self) -> Self::Output {
Self::new(self.0 * rhs.0)
}
}

impl std::ops::Div for NumericConstant {
type Output = NumericConstant;

fn div(self, rhs: Self) -> Self::Output {
Self::new(self.0 / rhs.0)
}
}
76 changes: 64 additions & 12 deletions crates/noirc_evaluator/src/ssa_refactor/ir/dfg.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use super::{
basic_block::{BasicBlock, BasicBlockId},
constant::{NumericConstant, NumericConstantId},
function::Signature,
instruction::{Instruction, InstructionId},
map::{DenseMap, Id, SecondaryMap},
map::{DenseMap, Id, SecondaryMap, TwoWayMap},
types::Type,
value::{Value, ValueId},
};

use acvm::FieldElement;
use iter_extended::vecmap;

#[derive(Debug, Default)]
Expand All @@ -20,6 +22,7 @@ impl ValueList {
self.0.push(value);
self.len() - 1
}

/// Returns the number of values in the list.
fn len(&self) -> usize {
self.0.len()
Expand All @@ -29,6 +32,7 @@ impl ValueList {
fn clear(&mut self) {
self.0.clear();
}

/// Returns the ValueId's as a slice.
pub(crate) fn as_slice(&self) -> &[ValueId] {
&self.0
Expand All @@ -55,6 +59,11 @@ pub(crate) struct DataFlowGraph {
/// function.
values: DenseMap<Value>,

/// Storage for all constants used within a function.
/// Each constant is unique, attempting to insert the same constant
/// twice will return the same ConstantId.
constants: TwoWayMap<NumericConstant>,

/// Function signatures of external methods
signatures: DenseMap<Signature>,

Expand Down Expand Up @@ -91,41 +100,50 @@ impl DataFlowGraph {
}

/// Inserts a new instruction into the DFG.
/// This does not add the instruction to the block or populate the instruction's result list
pub(crate) fn make_instruction(&mut self, instruction_data: Instruction) -> InstructionId {
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
}

jfecher marked this conversation as resolved.
Show resolved Hide resolved
/// Insert a value into the dfg's storage and return an id to reference it.
/// Until the value is used in an instruction it is unreachable.
pub(crate) fn make_value(&mut self, value: Value) -> ValueId {
self.values.insert(value)
}

/// Attaches results to the instruction.
/// Creates a new constant value, or returns the Id to an existing one if
/// one already exists.
pub(crate) fn make_constant(&mut self, value: FieldElement, typ: Type) -> ValueId {
let constant = self.constants.insert(NumericConstant::new(value));
self.values.insert(Value::NumericConstant { constant, typ })
}

/// Attaches results to the instruction, clearing any previous results.
///
/// Returns the number of results that this instruction
/// produces.
/// Returns the results of the instruction
pub(crate) fn make_instruction_results(
&mut self,
instruction_id: InstructionId,
ctrl_typevar: Type,
) -> usize {
) -> &[ValueId] {
// Clear all of the results instructions associated with this
// instruction.
self.results.get_mut(&instruction_id).expect("all instructions should have a `result` allocation when instruction was added to the DFG").clear();

// Get all of the types that this instruction produces
// and append them as results.
let typs = self.instruction_result_types(instruction_id, ctrl_typevar);
let num_typs = typs.len();

for typ in typs {
self.append_result(instruction_id, typ);
}

num_typs
self.results.get_mut(&instruction_id)
.expect("all instructions should have a `result` allocation when instruction was added to the DFG")
.as_slice()
}

/// Return the result types of this instruction.
Expand Down Expand Up @@ -181,6 +199,42 @@ impl DataFlowGraph {
block.add_parameter(parameter);
parameter
}

pub(crate) fn insert_instruction_in_block(
&mut self,
block: BasicBlockId,
instruction: InstructionId,
) {
self.blocks[block].insert_instruction(instruction);
}
}

impl std::ops::Index<InstructionId> for DataFlowGraph {
type Output = Instruction;
fn index(&self, id: InstructionId) -> &Self::Output {
&self.instructions[id]
}
}

impl std::ops::Index<ValueId> for DataFlowGraph {
type Output = Value;
fn index(&self, id: ValueId) -> &Self::Output {
&self.values[id]
}
}

impl std::ops::Index<NumericConstantId> for DataFlowGraph {
type Output = NumericConstant;
fn index(&self, id: NumericConstantId) -> &Self::Output {
&self.constants[id]
}
}

impl std::ops::Index<BasicBlockId> for DataFlowGraph {
type Output = BasicBlock;
fn index(&self, id: BasicBlockId) -> &Self::Output {
&self.blocks[id]
}
}

#[cfg(test)]
Expand All @@ -190,19 +244,17 @@ mod tests {
instruction::Instruction,
types::{NumericType, Type},
};
use acvm::FieldElement;

#[test]
fn make_instruction() {
let mut dfg = DataFlowGraph::default();
let ins = Instruction::Immediate { value: FieldElement::from(0u128) };
let ins = Instruction::Allocate { size: 20 };
let ins_id = dfg.make_instruction(ins);

let num_results =
dfg.make_instruction_results(ins_id, Type::Numeric(NumericType::NativeField));
dfg.make_instruction_results(ins_id, Type::Numeric(NumericType::NativeField)).len();

let results = dfg.instruction_results(ins_id);

assert_eq!(results.len(), num_results);
}
}
15 changes: 12 additions & 3 deletions crates/noirc_evaluator/src/ssa_refactor/ir/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ pub(crate) struct Function {
source_locations: SecondaryMap<Instruction, Location>,

/// The first basic block in the function
entry_block: BasicBlockId,
pub(super) entry_block: BasicBlockId,

/// Name of the function for debugging only
pub(super) name: String,

pub(crate) dfg: DataFlowGraph,
}
Expand All @@ -27,10 +30,10 @@ impl Function {
/// Creates a new function with an automatically inserted entry block.
///
/// Note that any parameters to the function must be manually added later.
pub(crate) fn new() -> Self {
pub(crate) fn new(name: String) -> Self {
let mut dfg = DataFlowGraph::default();
let entry_block = dfg.new_block();
Self { source_locations: SecondaryMap::new(), entry_block, dfg }
Self { name, source_locations: SecondaryMap::new(), entry_block, dfg }
}

pub(crate) fn entry_block(&self) -> BasicBlockId {
Expand All @@ -47,6 +50,12 @@ pub(crate) struct Signature {
pub(crate) returns: Vec<Type>,
}

impl std::fmt::Display for Function {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
super::printer::display_function(self, f)
}
}

#[test]
fn sign_smoke() {
let mut signature = Signature::default();
Expand Down
Loading