Skip to content

Commit

Permalink
Merge 9f83dd7 into a9acf5a
Browse files Browse the repository at this point in the history
  • Loading branch information
vezenovm authored Jan 13, 2025
2 parents a9acf5a + 9f83dd7 commit 4342173
Show file tree
Hide file tree
Showing 21 changed files with 351 additions and 87 deletions.
7 changes: 5 additions & 2 deletions compiler/noirc_evaluator/src/brillig/brillig_gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,21 @@ pub(crate) mod brillig_black_box;
pub(crate) mod brillig_block;
pub(crate) mod brillig_block_variables;
pub(crate) mod brillig_fn;
pub(crate) mod brillig_globals;
pub(crate) mod brillig_slice_ops;
mod constant_allocation;
mod variable_liveness;

use acvm::FieldElement;
use fxhash::FxHashMap as HashMap;

use self::{brillig_block::BrilligBlock, brillig_fn::FunctionContext};
use super::{
brillig_ir::{
artifact::{BrilligArtifact, BrilligParameter, GeneratedBrillig, Label},
BrilligContext,
},
Brillig,
Brillig, BrilligVariable, ValueId,
};
use crate::{
errors::InternalError,
Expand All @@ -25,10 +27,11 @@ use crate::{
pub(crate) fn convert_ssa_function(
func: &Function,
enable_debug_trace: bool,
globals: &HashMap<ValueId, BrilligVariable>,
) -> BrilligArtifact<FieldElement> {
let mut brillig_context = BrilligContext::new(enable_debug_trace);

let mut function_context = FunctionContext::new(func);
let mut function_context = FunctionContext::new(func, globals);

brillig_context.enter_context(Label::function(func.id()));

Expand Down
103 changes: 78 additions & 25 deletions compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::brillig::brillig_ir::brillig_variable::{
type_to_heap_value_type, BrilligArray, BrilligVariable, SingleAddrVariable,
};

use crate::brillig::brillig_ir::registers::Stack;
use crate::brillig::brillig_ir::registers::RegisterAllocator;
use crate::brillig::brillig_ir::{
BrilligBinaryOp, BrilligContext, ReservedRegisters, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE,
};
Expand Down Expand Up @@ -32,28 +32,38 @@ use super::brillig_fn::FunctionContext;
use super::constant_allocation::InstructionLocation;

/// Generate the compilation artifacts for compiling a function into brillig bytecode.
pub(crate) struct BrilligBlock<'block> {
pub(crate) function_context: &'block mut FunctionContext,
pub(crate) struct BrilligBlock<'block, 'global, Registers: RegisterAllocator> {
pub(crate) function_context: &'block mut FunctionContext<'global>,
/// The basic block that is being converted
pub(crate) block_id: BasicBlockId,
/// Context for creating brillig opcodes
pub(crate) brillig_context: &'block mut BrilligContext<FieldElement, Stack>,
pub(crate) brillig_context: &'block mut BrilligContext<FieldElement, Registers>,
/// Tracks the available variable during the codegen of the block
pub(crate) variables: BlockVariables,
/// For each instruction, the set of values that are not used anymore after it.
pub(crate) last_uses: HashMap<InstructionId, HashSet<ValueId>>,

pub(crate) building_globals: bool,
}

impl<'block> BrilligBlock<'block> {
impl<'block, 'global, Registers: RegisterAllocator> BrilligBlock<'block, 'global, Registers> {
/// Converts an SSA Basic block into a sequence of Brillig opcodes
pub(crate) fn compile(
function_context: &'block mut FunctionContext,
brillig_context: &'block mut BrilligContext<FieldElement, Stack>,
function_context: &'block mut FunctionContext<'global>,
brillig_context: &'block mut BrilligContext<FieldElement, Registers>,
block_id: BasicBlockId,
dfg: &DataFlowGraph,
) {
let live_in = function_context.liveness.get_live_in(&block_id);
let variables = BlockVariables::new(live_in.clone());

let mut live_in_no_globals = HashSet::default();
for value in live_in {
if !matches!(&dfg[*value], Value::Global(_)) {
live_in_no_globals.insert(*value);
}
}

let variables = BlockVariables::new(live_in_no_globals);

brillig_context.set_allocated_registers(
variables
Expand All @@ -64,12 +74,36 @@ impl<'block> BrilligBlock<'block> {
);
let last_uses = function_context.liveness.get_last_uses(&block_id).clone();

let mut brillig_block =
BrilligBlock { function_context, block_id, brillig_context, variables, last_uses };
let mut brillig_block = BrilligBlock {
function_context,
block_id,
brillig_context,
variables,
last_uses,
building_globals: false,
};

brillig_block.convert_block(dfg);
}

pub(crate) fn compile_globals(&mut self, globals: &DataFlowGraph) {
for (id, value) in globals.values_iter() {
match value {
Value::NumericConstant { .. } => {
self.convert_ssa_value(id, globals);
}
Value::Instruction { instruction, .. } => {
self.convert_ssa_instruction(*instruction, globals);
}
_ => {
panic!(
"Expected either an instruction or a numeric constant for a global value"
)
}
}
}
}

fn convert_block(&mut self, dfg: &DataFlowGraph) {
// Add a label for this block
let block_label = self.create_block_label_for_current_function(self.block_id);
Expand Down Expand Up @@ -199,7 +233,11 @@ impl<'block> BrilligBlock<'block> {
}

/// Converts an SSA instruction into a sequence of Brillig opcodes.
fn convert_ssa_instruction(&mut self, instruction_id: InstructionId, dfg: &DataFlowGraph) {
pub(crate) fn convert_ssa_instruction(
&mut self,
instruction_id: InstructionId,
dfg: &DataFlowGraph,
) {
let instruction = &dfg[instruction_id];
self.brillig_context.set_call_stack(dfg.get_instruction_call_stack(instruction_id));

Expand Down Expand Up @@ -843,18 +881,27 @@ impl<'block> BrilligBlock<'block> {
Instruction::Noop => (),
};

let dead_variables = self
.last_uses
.get(&instruction_id)
.expect("Last uses for instruction should have been computed");
if !self.building_globals {
let dead_variables = self
.last_uses
.get(&instruction_id)
.expect("Last uses for instruction should have been computed");

for dead_variable in dead_variables {
self.variables.remove_variable(
dead_variable,
self.function_context,
self.brillig_context,
);
for dead_variable in dead_variables {
match &dfg[*dead_variable] {
// Globals are reserved throughout the entirety of the program
Value::Global(_) => {}
_ => {
self.variables.remove_variable(
dead_variable,
self.function_context,
self.brillig_context,
);
}
}
}
}

self.brillig_context.set_call_stack(CallStack::new());
}

Expand Down Expand Up @@ -1555,14 +1602,20 @@ impl<'block> BrilligBlock<'block> {
}

/// Converts an SSA `ValueId` into a `RegisterOrMemory`. Initializes if necessary.
fn convert_ssa_value(&mut self, value_id: ValueId, dfg: &DataFlowGraph) -> BrilligVariable {
pub(crate) fn convert_ssa_value(
&mut self,
value_id: ValueId,
dfg: &DataFlowGraph,
) -> BrilligVariable {
let value_id = dfg.resolve(value_id);
let value = &dfg[value_id];

match value {
Value::Global(_) => {
unreachable!("ICE: All globals should have been inlined");
}
Value::Global(_) => *self
.function_context
.globals
.get(&value_id)
.unwrap_or_else(|| panic!("ICE: Global value not found in cache {value_id}")),
Value::Param { .. } | Value::Instruction { .. } => {
// All block parameters and instruction results should have already been
// converted to registers so we fetch from the cache.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
get_bit_size_from_ssa_type, BrilligArray, BrilligVariable, BrilligVector,
SingleAddrVariable,
},
registers::{RegisterAllocator, Stack},
registers::RegisterAllocator,
BrilligContext,
},
ssa::ir::{
Expand Down Expand Up @@ -48,10 +48,10 @@ impl BlockVariables {
}

/// For a given SSA value id, define the variable and return the corresponding cached allocation.
pub(crate) fn define_variable(
pub(crate) fn define_variable<Registers: RegisterAllocator>(
&mut self,
function_context: &mut FunctionContext,
brillig_context: &mut BrilligContext<FieldElement, Stack>,
brillig_context: &mut BrilligContext<FieldElement, Registers>,
value_id: ValueId,
dfg: &DataFlowGraph,
) -> BrilligVariable {
Expand All @@ -68,10 +68,10 @@ impl BlockVariables {
}

/// Defines a variable that fits in a single register and returns the allocated register.
pub(crate) fn define_single_addr_variable(
pub(crate) fn define_single_addr_variable<Registers: RegisterAllocator>(
&mut self,
function_context: &mut FunctionContext,
brillig_context: &mut BrilligContext<FieldElement, Stack>,
brillig_context: &mut BrilligContext<FieldElement, Registers>,
value: ValueId,
dfg: &DataFlowGraph,
) -> SingleAddrVariable {
Expand All @@ -80,11 +80,11 @@ impl BlockVariables {
}

/// Removes a variable so it's not used anymore within this block.
pub(crate) fn remove_variable(
pub(crate) fn remove_variable<Registers: RegisterAllocator>(
&mut self,
value_id: &ValueId,
function_context: &mut FunctionContext,
brillig_context: &mut BrilligContext<FieldElement, Stack>,
brillig_context: &mut BrilligContext<FieldElement, Registers>,
) {
assert!(self.available_variables.remove(value_id), "ICE: Variable is not available");
let variable = function_context
Expand Down Expand Up @@ -133,6 +133,14 @@ pub(crate) fn allocate_value<F, Registers: RegisterAllocator>(
) -> BrilligVariable {
let typ = dfg.type_of_value(value_id);

allocate_value_with_type(brillig_context, typ)
}

/// For a given value_id, allocates the necessary registers to hold it.
pub(crate) fn allocate_value_with_type<F, Registers: RegisterAllocator>(
brillig_context: &mut BrilligContext<F, Registers>,
typ: Type,
) -> BrilligVariable {
match typ {
Type::Numeric(_) | Type::Reference(_) | Type::Function => {
BrilligVariable::SingleAddr(SingleAddrVariable {
Expand Down
11 changes: 8 additions & 3 deletions compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use fxhash::FxHashMap as HashMap;

use super::{constant_allocation::ConstantAllocation, variable_liveness::VariableLiveness};

pub(crate) struct FunctionContext {
pub(crate) struct FunctionContext<'global> {
pub(crate) function_id: FunctionId,
/// Map from SSA values its allocation. Since values can be only defined once in SSA form, we insert them here on when we allocate them at their definition.
pub(crate) ssa_value_allocations: HashMap<ValueId, BrilligVariable>,
Expand All @@ -27,11 +27,15 @@ pub(crate) struct FunctionContext {
pub(crate) liveness: VariableLiveness,
/// Information on where to allocate constants
pub(crate) constant_allocation: ConstantAllocation,
pub(crate) globals: &'global HashMap<ValueId, BrilligVariable>,
}

impl FunctionContext {
impl<'global> FunctionContext<'global> {
/// Creates a new function context. It will allocate parameters for all blocks and compute the liveness of every variable.
pub(crate) fn new(function: &Function) -> Self {
pub(crate) fn new(
function: &Function,
globals: &'global HashMap<ValueId, BrilligVariable>,
) -> Self {
let id = function.id();

let mut reverse_post_order = Vec::new();
Expand All @@ -47,6 +51,7 @@ impl FunctionContext {
blocks: reverse_post_order,
liveness,
constant_allocation: constants,
globals,
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use acvm::FieldElement;
use fxhash::FxHashMap as HashMap;

use super::{
BrilligArtifact, BrilligBlock, BrilligVariable, Function, FunctionContext, Label, ValueId,
};
use crate::brillig::{brillig_ir::BrilligContext, DataFlowGraph};

pub(crate) fn convert_ssa_globals(
enable_debug_trace: bool,
globals: &Function,
) -> (BrilligArtifact<FieldElement>, HashMap<ValueId, BrilligVariable>) {
let mut brillig_context = BrilligContext::new_for_global_init(enable_debug_trace);
// The global space does not have globals itself
let empty_globals = HashMap::default();
// We can use any ID here as this context is only going to be used for globals which does not differentiate
// by functions and blocks. The only Label that should be used in the globals context is `Label::globals_init()`
let mut function_context = FunctionContext::new(globals, &empty_globals);
brillig_context.enter_context(Label::globals_init());

let block_id = DataFlowGraph::default().make_block();
let mut brillig_block = BrilligBlock {
function_context: &mut function_context,
block_id,
brillig_context: &mut brillig_context,
variables: Default::default(),
last_uses: HashMap::default(),
building_globals: true,
};

brillig_block.compile_globals(&globals.dfg);

brillig_context.return_instruction();

let artifact = brillig_context.artifact();
(artifact, function_context.ssa_value_allocations)
}
Loading

0 comments on commit 4342173

Please sign in to comment.