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: thread generics through ACIR/brillig gen #5120

Merged
merged 10 commits into from
Jun 13, 2024
1 change: 1 addition & 0 deletions acvm-repo/acir_field/src/field_element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ impl<F: PrimeField> AcirField for FieldElement<F> {
(self.num_bits() <= 64).then(|| self.to_u128() as u64)
}


TomAFrench marked this conversation as resolved.
Show resolved Hide resolved
fn try_to_u32(&self) -> Option<u32> {
(self.num_bits() <= 32).then(|| self.to_u128() as u32)
}
Expand Down
7 changes: 6 additions & 1 deletion compiler/noirc_evaluator/src/brillig/brillig_gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,17 @@ pub(crate) mod brillig_fn;
pub(crate) mod brillig_slice_ops;
mod variable_liveness;

use acvm::FieldElement;

use self::{brillig_block::BrilligBlock, brillig_fn::FunctionContext};
use super::brillig_ir::{artifact::BrilligArtifact, BrilligContext};
use crate::ssa::ir::function::Function;

/// Converting an SSA function into Brillig bytecode.
pub(crate) fn convert_ssa_function(func: &Function, enable_debug_trace: bool) -> BrilligArtifact {
pub(crate) fn convert_ssa_function(
func: &Function,
enable_debug_trace: bool,
) -> BrilligArtifact<FieldElement> {
let mut brillig_context = BrilligContext::new(enable_debug_trace);

let mut function_context = FunctionContext::new(func);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
use acvm::{
acir::{brillig::BlackBoxOp, BlackBoxFunc},
FieldElement,
AcirField,
};

use crate::brillig::brillig_ir::{
brillig_variable::{BrilligVariable, BrilligVector, SingleAddrVariable},
debug_show::DebugToString,
BrilligBinaryOp, BrilligContext,
};

/// Transforms SSA's black box function calls into the corresponding brillig instructions
/// Extracting arguments and results from the SSA function call
/// And making any necessary type conversions to adapt noir's blackbox calls to brillig's
pub(crate) fn convert_black_box_call(
brillig_context: &mut BrilligContext,
pub(crate) fn convert_black_box_call<F: AcirField + DebugToString>(
TomAFrench marked this conversation as resolved.
Show resolved Hide resolved
brillig_context: &mut BrilligContext<F>,
bb_func: &BlackBoxFunc,
function_arguments: &[BrilligVariable],
function_results: &[BrilligVariable],
Expand Down Expand Up @@ -341,7 +342,7 @@ pub(crate) fn convert_black_box_call(
let inputs_vector = convert_array_or_vector(brillig_context, inputs, bb_func);
let modulus_vector = convert_array_or_vector(brillig_context, modulus, bb_func);
let output_id = brillig_context.get_new_bigint_id();
brillig_context.const_instruction(*output, FieldElement::from(output_id as u128));
brillig_context.const_instruction(*output, F::from(output_id as u128));
brillig_context.black_box_op_instruction(BlackBoxOp::BigIntFromLeBytes {
inputs: inputs_vector.to_heap_vector(),
modulus: modulus_vector.to_heap_vector(),
Expand Down Expand Up @@ -426,8 +427,8 @@ pub(crate) fn convert_black_box_call(
}
}

fn convert_array_or_vector(
brillig_context: &mut BrilligContext,
fn convert_array_or_vector<F: AcirField + DebugToString>(
brillig_context: &mut BrilligContext<F>,
array_or_vector: &BrilligVariable,
bb_func: &BlackBoxFunc,
) -> BrilligVector {
Expand All @@ -442,8 +443,8 @@ fn convert_array_or_vector(
}
}

fn prepare_bigint_output(
brillig_context: &mut BrilligContext,
fn prepare_bigint_output<F: AcirField + DebugToString>(
brillig_context: &mut BrilligContext<F>,
lhs_modulus: &SingleAddrVariable,
rhs_modulus: &SingleAddrVariable,
output: &SingleAddrVariable,
Expand All @@ -465,6 +466,6 @@ fn prepare_bigint_output(
brillig_context.deallocate_register(condition);
// Set output id
let output_id = brillig_context.get_new_bigint_id();
brillig_context.const_instruction(*output, FieldElement::from(output_id as u128));
brillig_context.const_instruction(*output, F::from(output_id as u128));
brillig_context.mov_instruction(modulus_id.address, lhs_modulus.address);
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub(crate) struct BrilligBlock<'block> {
/// The basic block that is being converted
pub(crate) block_id: BasicBlockId,
/// Context for creating brillig opcodes
pub(crate) brillig_context: &'block mut BrilligContext,
pub(crate) brillig_context: &'block mut BrilligContext<FieldElement>,
/// 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.
Expand All @@ -44,7 +44,7 @@ impl<'block> BrilligBlock<'block> {
/// 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,
brillig_context: &'block mut BrilligContext<FieldElement>,
block_id: BasicBlockId,
dfg: &DataFlowGraph,
) {
Expand Down Expand Up @@ -944,7 +944,7 @@ impl<'block> BrilligBlock<'block> {
}

pub(crate) fn store_variable_in_array_with_ctx(
ctx: &mut BrilligContext,
ctx: &mut BrilligContext<FieldElement>,
destination_pointer: MemoryAddress,
index_register: SingleAddrVariable,
value_variable: BrilligVariable,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use acvm::FieldElement;
use fxhash::{FxHashMap as HashMap, FxHashSet as HashSet};

use crate::{
Expand Down Expand Up @@ -50,7 +51,7 @@ impl BlockVariables {
pub(crate) fn define_variable(
&mut self,
function_context: &mut FunctionContext,
brillig_context: &mut BrilligContext,
brillig_context: &mut BrilligContext<FieldElement>,
value_id: ValueId,
dfg: &DataFlowGraph,
) -> BrilligVariable {
Expand All @@ -70,7 +71,7 @@ impl BlockVariables {
pub(crate) fn define_single_addr_variable(
&mut self,
function_context: &mut FunctionContext,
brillig_context: &mut BrilligContext,
brillig_context: &mut BrilligContext<FieldElement>,
value: ValueId,
dfg: &DataFlowGraph,
) -> SingleAddrVariable {
Expand All @@ -83,7 +84,7 @@ impl BlockVariables {
&mut self,
value_id: &ValueId,
function_context: &mut FunctionContext,
brillig_context: &mut BrilligContext,
brillig_context: &mut BrilligContext<FieldElement>,
) {
assert!(self.available_variables.remove(value_id), "ICE: Variable is not available");
let variable = function_context
Expand Down Expand Up @@ -122,7 +123,7 @@ impl BlockVariables {
/// We keep constants block-local.
pub(crate) fn allocate_constant(
&mut self,
brillig_context: &mut BrilligContext,
brillig_context: &mut BrilligContext<FieldElement>,
value_id: ValueId,
dfg: &DataFlowGraph,
) -> BrilligVariable {
Expand Down Expand Up @@ -154,9 +155,9 @@ pub(crate) fn compute_array_length(item_typ: &CompositeType, elem_count: usize)
}

/// For a given value_id, allocates the necessary registers to hold it.
pub(crate) fn allocate_value(
pub(crate) fn allocate_value<F>(
value_id: ValueId,
brillig_context: &mut BrilligContext,
brillig_context: &mut BrilligContext<F>,
dfg: &DataFlowGraph,
) -> BrilligVariable {
let typ = dfg.type_of_value(value_id);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
use acvm::{
acir::brillig::{BinaryFieldOp, BinaryIntOp, MemoryAddress, Opcode as BrilligOpcode},
acir::AcirField,
FieldElement,
};

use crate::brillig::brillig_ir::artifact::GeneratedBrillig;

/// Generates brillig bytecode which computes the inverse of its input if not null, and zero else.
pub(crate) fn directive_invert() -> GeneratedBrillig {
pub(crate) fn directive_invert<F: AcirField>() -> GeneratedBrillig<F> {
// We generate the following code:
// fn invert(x : Field) -> Field {
// 1/ x
Expand All @@ -28,8 +27,8 @@ pub(crate) fn directive_invert() -> GeneratedBrillig {
// Put value zero in register (2)
BrilligOpcode::Const {
destination: zero_const,
value: FieldElement::from(0_usize),
bit_size: FieldElement::max_num_bits(),
value: F::from(0_usize),
bit_size: F::max_num_bits(),
},
BrilligOpcode::BinaryFieldOp {
op: BinaryFieldOp::Equals,
Expand All @@ -42,8 +41,8 @@ pub(crate) fn directive_invert() -> GeneratedBrillig {
// Put value one in register (1)
BrilligOpcode::Const {
destination: one_const,
value: FieldElement::from(1_usize),
bit_size: FieldElement::max_num_bits(),
value: F::from(1_usize),
TomAFrench marked this conversation as resolved.
Show resolved Hide resolved
bit_size: F::max_num_bits(),
},
// Divide 1 by the input, and set the result of the division into register (0)
BrilligOpcode::BinaryFieldOp {
Expand All @@ -68,13 +67,13 @@ pub(crate) fn directive_invert() -> GeneratedBrillig {
/// (a/b, a-a/b*b)
/// }
/// ```
pub(crate) fn directive_quotient(bit_size: u32) -> GeneratedBrillig {
pub(crate) fn directive_quotient<F: AcirField>(bit_size: u32) -> GeneratedBrillig<F> {
// `a` is (0) (i.e register index 0)
// `b` is (1)

// TODO: The only difference between these implementations is the integer version will truncate the input to the `bit_size` via cast.
// Once we deduplicate brillig functions then we can modify this so that fields and integers share the same quotient function.
if bit_size >= FieldElement::max_num_bits() {
if bit_size >= F::max_num_bits() {
// Field version
GeneratedBrillig {
byte_code: vec![
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ pub(crate) struct FunctionContext {
}

impl FunctionContext {
/// Creates a new function context. It will compute the liveness of every variable.
/// 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 {
let id = function.id();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ mod tests {
use crate::ssa::ir::map::Id;
use crate::ssa::ssa_gen::Ssa;

fn create_test_environment() -> (Ssa, FunctionContext, BrilligContext) {
fn create_test_environment() -> (Ssa, FunctionContext, BrilligContext<FieldElement>) {
let mut builder = FunctionBuilder::new("main".to_string(), Id::test_new(0));
builder.set_runtime(RuntimeType::Brillig);

Expand All @@ -385,7 +385,7 @@ mod tests {

fn create_brillig_block<'a>(
function_context: &'a mut FunctionContext,
brillig_context: &'a mut BrilligContext,
brillig_context: &'a mut BrilligContext<FieldElement>,
) -> BrilligBlock<'a> {
let variables = BlockVariables::default();
BrilligBlock {
Expand Down
24 changes: 13 additions & 11 deletions compiler/noirc_evaluator/src/brillig/brillig_ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@ mod instructions;

pub(crate) use instructions::BrilligBinaryOp;

use self::{artifact::BrilligArtifact, registers::BrilligRegistersContext};
use self::{
artifact::BrilligArtifact, debug_show::DebugToString, registers::BrilligRegistersContext,
};
use crate::ssa::ir::dfg::CallStack;
use acvm::{
acir::brillig::{MemoryAddress, Opcode as BrilligOpcode},
FieldElement,
AcirField,
};
use debug_show::DebugShow;

Expand Down Expand Up @@ -76,8 +78,8 @@ impl ReservedRegisters {

/// Brillig context object that is used while constructing the
/// Brillig bytecode.
pub(crate) struct BrilligContext {
obj: BrilligArtifact,
pub(crate) struct BrilligContext<F> {
obj: BrilligArtifact<F>,
/// Tracks register allocations
registers: BrilligRegistersContext,
/// Context label, must be unique with respect to the function
Expand All @@ -93,9 +95,9 @@ pub(crate) struct BrilligContext {
bigint_new_id: u32,
}

impl BrilligContext {
impl<F: AcirField + DebugToString> BrilligContext<F> {
/// Initial context state
pub(crate) fn new(enable_debug_trace: bool) -> BrilligContext {
pub(crate) fn new(enable_debug_trace: bool) -> BrilligContext<F> {
BrilligContext {
obj: BrilligArtifact::default(),
registers: BrilligRegistersContext::new(),
Expand All @@ -113,12 +115,12 @@ impl BrilligContext {
result
}
/// Adds a brillig instruction to the brillig byte code
fn push_opcode(&mut self, opcode: BrilligOpcode<FieldElement>) {
fn push_opcode(&mut self, opcode: BrilligOpcode<F>) {
self.obj.push_opcode(opcode);
}

/// Returns the artifact
pub(crate) fn artifact(self) -> BrilligArtifact {
pub(crate) fn artifact(self) -> BrilligArtifact<F> {
self.obj
}

Expand Down Expand Up @@ -200,17 +202,17 @@ pub(crate) mod tests {
}
}

pub(crate) fn create_context() -> BrilligContext {
pub(crate) fn create_context() -> BrilligContext<FieldElement> {
let mut context = BrilligContext::new(true);
context.enter_context("test");
context
}

pub(crate) fn create_entry_point_bytecode(
context: BrilligContext,
context: BrilligContext<FieldElement>,
arguments: Vec<BrilligParameter>,
returns: Vec<BrilligParameter>,
) -> GeneratedBrillig {
) -> GeneratedBrillig<FieldElement> {
let artifact = context.artifact();
let mut entry_point_artifact =
BrilligContext::new_entry_point_artifact(arguments, returns, "test".to_string());
Expand Down
Loading
Loading