Skip to content

Commit

Permalink
feat(comptime): Implement to_be_bits and to_le_bits in the interpreter (
Browse files Browse the repository at this point in the history
#7008)

Co-authored-by: jfecher <[email protected]>
  • Loading branch information
aakoshh and jfecher authored Jan 9, 2025
1 parent e0d6840 commit a7eea81
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 7 deletions.
2 changes: 1 addition & 1 deletion compiler/noirc_evaluator/src/acir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2169,7 +2169,7 @@ impl<'a> Context<'a> {

let Type::Array(result_type, array_length) = dfg.type_of_value(result_ids[0])
else {
unreachable!("ICE: ToRadix result must be an array");
unreachable!("ICE: ToBits result must be an array");
};

self.acir_context
Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_frontend/src/elaborator/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1526,7 +1526,7 @@ impl<'context> Elaborator<'context> {
) -> Option<HirMethodReference> {
let func_id = match self.current_item {
Some(DependencyId::Function(id)) => id,
_ => panic!("unexpected method outside a function"),
_ => panic!("unexpected method outside a function: {method_name}"),
};
let func_meta = self.interner.function_meta(&func_id);

Expand Down
22 changes: 22 additions & 0 deletions compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ impl<'local, 'context> Interpreter<'local, 'context> {
"struct_def_set_fields" => struct_def_set_fields(interner, arguments, location),
"to_be_radix" => to_be_radix(arguments, return_type, location),
"to_le_radix" => to_le_radix(arguments, return_type, location),
"to_be_bits" => to_be_bits(arguments, return_type, location),
"to_le_bits" => to_le_bits(arguments, return_type, location),
"trait_constraint_eq" => trait_constraint_eq(arguments, location),
"trait_constraint_hash" => trait_constraint_hash(arguments, location),
"trait_def_as_trait_constraint" => {
Expand Down Expand Up @@ -776,6 +778,26 @@ fn quoted_tokens(arguments: Vec<(Value, Location)>, location: Location) -> IResu
))
}

fn to_be_bits(
arguments: Vec<(Value, Location)>,
return_type: Type,
location: Location,
) -> IResult<Value> {
let value = check_one_argument(arguments, location)?;
let radix = (Value::U32(2), value.1);
to_be_radix(vec![value, radix], return_type, location)
}

fn to_le_bits(
arguments: Vec<(Value, Location)>,
return_type: Type,
location: Location,
) -> IResult<Value> {
let value = check_one_argument(arguments, location)?;
let radix = (Value::U32(2), value.1);
to_le_radix(vec![value, radix], return_type, location)
}

fn to_be_radix(
arguments: Vec<(Value, Location)>,
return_type: Type,
Expand Down
2 changes: 2 additions & 0 deletions compiler/noirc_frontend/src/hir/comptime/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ use crate::node_interner::FuncId;
use crate::parse_program;

/// Create an interpreter for a code snippet and pass it to a test function.
///
/// The stdlib is not made available as a dependency.
pub(crate) fn with_interpreter<T>(
src: &str,
f: impl FnOnce(&mut Interpreter, FuncId, &[(CompilationError, FileId)]) -> T,
Expand Down
13 changes: 8 additions & 5 deletions compiler/noirc_frontend/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ pub(crate) fn get_program(src: &str) -> (ParsedModule, Context, Vec<(Compilation
)
}

/// Compile a program.
///
/// The stdlib is not available for these snippets.
pub(crate) fn get_program_with_maybe_parser_errors(
src: &str,
allow_parser_errors: bool,
Expand Down Expand Up @@ -3894,10 +3897,10 @@ fn errors_on_cyclic_globals() {
#[test]
fn warns_on_unneeded_unsafe() {
let src = r#"
fn main() {
fn main() {
/// Safety: test
unsafe {
foo()
foo()
}
}
Expand All @@ -3914,12 +3917,12 @@ fn warns_on_unneeded_unsafe() {
#[test]
fn warns_on_nested_unsafe() {
let src = r#"
fn main() {
fn main() {
/// Safety: test
unsafe {
unsafe {
/// Safety: test
unsafe {
foo()
foo()
}
}
}
Expand Down
7 changes: 7 additions & 0 deletions test_programs/noir_test_success/global_eval/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "global_eval"
type = "bin"
authors = [""]
compiler_version = ">=0.27.0"

[dependencies]
20 changes: 20 additions & 0 deletions test_programs/noir_test_success/global_eval/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use std::uint128::U128;

// These definitions require `to_be_bits` and `to_le_bits` to be supported at comptime.
global BITS_BE_13: [u1; 4] = (13 as Field).to_be_bits();
global BITS_LE_13: [u1; 4] = (13 as Field).to_le_bits();

// Examples from #6691 which use the above behind the scenes.
global POW64_A: Field = 2.pow_32(64);
global POW64_B: Field = (U128::one() << 64).to_integer();

#[test]
fn test_be_and_le_bits() {
assert_eq(BITS_BE_13, [1,1,0,1]);
assert_eq(BITS_LE_13, [1,0,1,1]);
}

#[test]
fn test_pow64() {
assert_eq(POW64_A, POW64_B);
}

0 comments on commit a7eea81

Please sign in to comment.