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

feat(brillig): SSA globals code gen #7021

Draft
wants to merge 39 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
c7d8009
cleanup global generation with GlobalsBuilder
vezenovm Jan 8, 2025
4b19a7b
all tests paassing
vezenovm Jan 8, 2025
c8e08d3
cargo fmt
vezenovm Jan 8, 2025
8a24746
fmt and clippy
vezenovm Jan 8, 2025
e3358e3
some comments for context
vezenovm Jan 8, 2025
c3948fe
nargo fmt
vezenovm Jan 8, 2025
328004e
merge master and conflicts w/ printer
vezenovm Jan 8, 2025
40c50fc
remove type from Value::Global and cleanup
vezenovm Jan 8, 2025
7744179
bring back global type
vezenovm Jan 8, 2025
68ddd14
Update compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs
vezenovm Jan 8, 2025
6823019
only print globals when printing ssa if globals exist
vezenovm Jan 8, 2025
73ceea5
Merge remote-tracking branch 'origin/mv/ssa-globals-1' into mv/ssa-gl…
vezenovm Jan 8, 2025
cbe377e
make an eval method
vezenovm Jan 8, 2025
2d750fb
Update compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs
vezenovm Jan 8, 2025
faeb30f
Update compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs
vezenovm Jan 8, 2025
2322cb6
Update test_programs/execution_success/global_var_regression_simple/s…
vezenovm Jan 8, 2025
08a2aba
Merge branch 'master' into mv/ssa-globals-1
vezenovm Jan 8, 2025
fa6d9cf
cargo mft
vezenovm Jan 8, 2025
200964f
Merge branch 'master' into mv/ssa-globals-1
vezenovm Jan 8, 2025
5bbe0c9
working brillig implementation of globals
vezenovm Jan 9, 2025
f98c713
merge conflicts w/ master
vezenovm Jan 9, 2025
2bff6eb
Merge branch 'mv/ssa-globals-1' into mv/ssa-globals-brillig-gen
vezenovm Jan 9, 2025
ad19fc3
Merge branch 'master' into mv/ssa-globals-1
vezenovm Jan 9, 2025
bb5a9ea
Update compiler/noirc_frontend/src/hir/comptime/value.rs
vezenovm Jan 9, 2025
fa0122d
make separate BrilligsGlobal struct
vezenovm Jan 9, 2025
74a7358
do ot duplicate codegen
vezenovm Jan 9, 2025
df5eef0
Merge branch 'master' into mv/ssa-globals-1
vezenovm Jan 9, 2025
eaacac8
merge conflcits w/ mv/ssa-globals-1
vezenovm Jan 10, 2025
91c0c35
some fixes and fmt after merge
vezenovm Jan 10, 2025
94683e6
re-use codegen methods for BrilligBlock
vezenovm Jan 10, 2025
584cc92
Merge branch 'master' into mv/ssa-globals-1
vezenovm Jan 10, 2025
f5c5f25
cleanup and put brillig globals code gen into separate method
vezenovm Jan 10, 2025
8809385
remove pub(crate) on registers field from debugging
vezenovm Jan 10, 2025
713fc80
Merge branch 'mv/ssa-globals-1' into mv/ssa-globals-brillig-gen
vezenovm Jan 10, 2025
8ff2934
switch to Function from DataFlowGraph to represent globals
vezenovm Jan 10, 2025
00a9759
fixes post merge where globals are represented as a Function rather t…
vezenovm Jan 10, 2025
4c390c7
fmt and clippy
vezenovm Jan 10, 2025
c19adb0
Merge remote-tracking branch 'origin/mv/ssa-globals-brillig-gen' into…
vezenovm Jan 10, 2025
9f83dd7
merge conflicts w/ master
vezenovm Jan 13, 2025
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
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
Loading