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: remove the as_field and from_field built-ins #6845

Merged
merged 9 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 0 additions & 2 deletions compiler/noirc_evaluator/src/acir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2760,8 +2760,6 @@ impl<'a> Context<'a> {
unreachable!("Expected static_assert to be removed by this point")
}
Intrinsic::StrAsBytes => unreachable!("Expected as_bytes to be removed by this point"),
Intrinsic::FromField => unreachable!("Expected from_field to be removed by this point"),
Intrinsic::AsField => unreachable!("Expected as_field to be removed by this point"),
Intrinsic::IsUnconstrained => {
unreachable!("Expected is_unconstrained to be removed by this point")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -635,9 +635,7 @@ impl<'block> BrilligBlock<'block> {
let array = array.extract_register();
self.brillig_context.load_instruction(destination, array);
}
Intrinsic::FromField
| Intrinsic::AsField
| Intrinsic::IsUnconstrained
Intrinsic::IsUnconstrained
| Intrinsic::DerivePedersenGenerators
| Intrinsic::ApplyRangeConstraint
| Intrinsic::StrAsBytes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -294,11 +294,9 @@ impl DependencyContext {
Intrinsic::ArrayLen
| Intrinsic::ArrayRefCount
| Intrinsic::ArrayAsStrUnchecked
| Intrinsic::AsField
| Intrinsic::AsSlice
| Intrinsic::BlackBox(..)
| Intrinsic::DerivePedersenGenerators
| Intrinsic::FromField
| Intrinsic::Hint(..)
| Intrinsic::SlicePushBack
| Intrinsic::SlicePushFront
Expand Down Expand Up @@ -574,12 +572,10 @@ impl Context {
Intrinsic::ArrayLen
| Intrinsic::ArrayAsStrUnchecked
| Intrinsic::ArrayRefCount
| Intrinsic::AsField
| Intrinsic::AsSlice
| Intrinsic::BlackBox(..)
| Intrinsic::Hint(Hint::BlackBox)
| Intrinsic::DerivePedersenGenerators
| Intrinsic::FromField
| Intrinsic::SliceInsert
| Intrinsic::SlicePushBack
| Intrinsic::SlicePushFront
Expand Down
8 changes: 0 additions & 8 deletions compiler/noirc_evaluator/src/ssa/ir/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,6 @@
ToRadix(Endian),
BlackBox(BlackBoxFunc),
Hint(Hint),
FromField,
AsField,
AsWitness,
IsUnconstrained,
DerivePedersenGenerators,
Expand Down Expand Up @@ -97,8 +95,6 @@
Intrinsic::ToRadix(Endian::Little) => write!(f, "to_le_radix"),
Intrinsic::BlackBox(function) => write!(f, "{function}"),
Intrinsic::Hint(Hint::BlackBox) => write!(f, "black_box"),
Intrinsic::FromField => write!(f, "from_field"),
Intrinsic::AsField => write!(f, "as_field"),
Intrinsic::AsWitness => write!(f, "as_witness"),
Intrinsic::IsUnconstrained => write!(f, "is_unconstrained"),
Intrinsic::DerivePedersenGenerators => write!(f, "derive_pedersen_generators"),
Expand Down Expand Up @@ -140,8 +136,6 @@
| Intrinsic::SlicePushFront
| Intrinsic::SliceInsert
| Intrinsic::StrAsBytes
| Intrinsic::FromField
| Intrinsic::AsField
| Intrinsic::IsUnconstrained
| Intrinsic::DerivePedersenGenerators
| Intrinsic::FieldLessThan => false,
Expand Down Expand Up @@ -213,8 +207,6 @@
"to_be_radix" => Some(Intrinsic::ToRadix(Endian::Big)),
"to_le_bits" => Some(Intrinsic::ToBits(Endian::Little)),
"to_be_bits" => Some(Intrinsic::ToBits(Endian::Big)),
"from_field" => Some(Intrinsic::FromField),
"as_field" => Some(Intrinsic::AsField),
"as_witness" => Some(Intrinsic::AsWitness),
"is_unconstrained" => Some(Intrinsic::IsUnconstrained),
"derive_pedersen_generators" => Some(Intrinsic::DerivePedersenGenerators),
Expand Down Expand Up @@ -406,7 +398,7 @@
// These can fail.
Constrain(..) | RangeCheck { .. } => true,

// This should never be side-effectful

Check warning on line 401 in compiler/noirc_evaluator/src/ssa/ir/instruction.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (effectful)
MakeArray { .. } => false,

// Some binary math can overflow or underflow
Expand Down
25 changes: 0 additions & 25 deletions compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,31 +330,6 @@ pub(super) fn simplify_call(
Intrinsic::BlackBox(bb_func) => {
simplify_black_box_func(bb_func, arguments, dfg, block, call_stack)
}
Intrinsic::AsField => {
let instruction = Instruction::Cast(arguments[0], NumericType::NativeField);
SimplifyResult::SimplifiedToInstruction(instruction)
}
Intrinsic::FromField => {
let incoming_type = Type::field();
let target_type = return_type.clone().unwrap();

let truncate = Instruction::Truncate {
value: arguments[0],
bit_size: target_type.bit_size(),
max_bit_size: incoming_type.bit_size(),
};
let truncated_value = dfg
.insert_instruction_and_results(
truncate,
block,
Some(vec![incoming_type]),
call_stack,
)
.first();

let instruction = Instruction::Cast(truncated_value, target_type.unwrap_numeric());
SimplifyResult::SimplifiedToInstruction(instruction)
}
Intrinsic::AsWitness => SimplifyResult::None,
Intrinsic::IsUnconstrained => SimplifyResult::None,
Intrinsic::DerivePedersenGenerators => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,6 @@ impl Context {
| Intrinsic::ToRadix(_)
| Intrinsic::BlackBox(_)
| Intrinsic::Hint(Hint::BlackBox)
| Intrinsic::FromField
| Intrinsic::AsField
| Intrinsic::AsSlice
| Intrinsic::AsWitness
| Intrinsic::IsUnconstrained
Expand Down
2 changes: 0 additions & 2 deletions compiler/noirc_evaluator/src/ssa/opt/remove_if_else.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,6 @@ fn slice_capacity_change(
| Intrinsic::StrAsBytes
| Intrinsic::BlackBox(_)
| Intrinsic::Hint(Hint::BlackBox)
| Intrinsic::FromField
| Intrinsic::AsField
| Intrinsic::AsWitness
| Intrinsic::IsUnconstrained
| Intrinsic::DerivePedersenGenerators
Expand Down
23 changes: 0 additions & 23 deletions compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ impl<'local, 'context> Interpreter<'local, 'context> {
"array_len" => array_len(interner, arguments, location),
"array_refcount" => Ok(Value::U32(0)),
"assert_constant" => Ok(Value::Bool(true)),
"as_field" => as_field(interner, arguments, location),
"as_slice" => as_slice(interner, arguments, location),
"ctstring_eq" => ctstring_eq(arguments, location),
"ctstring_hash" => ctstring_hash(arguments, location),
Expand Down Expand Up @@ -117,7 +116,6 @@ impl<'local, 'context> Interpreter<'local, 'context> {
"field_less_than" => field_less_than(arguments, location),
"fmtstr_as_ctstring" => fmtstr_as_ctstring(interner, arguments, location),
"fmtstr_quoted_contents" => fmtstr_quoted_contents(interner, arguments, location),
"from_field" => from_field(interner, arguments, return_type, location),
"fresh_type_variable" => fresh_type_variable(interner),
"function_def_add_attribute" => function_def_add_attribute(self, arguments, location),
"function_def_body" => function_def_body(interner, arguments, location),
Expand Down Expand Up @@ -292,16 +290,6 @@ fn array_as_str_unchecked(
Ok(Value::String(Rc::new(string)))
}

// fn as_field<T>(x: T) -> Field {}
fn as_field(
interner: &NodeInterner,
arguments: Vec<(Value, Location)>,
location: Location,
) -> IResult<Value> {
let (value, value_location) = check_one_argument(arguments, location)?;
Interpreter::evaluate_cast_one_step(&Type::FieldElement, value_location, value, interner)
}

fn as_slice(
interner: &NodeInterner,
arguments: Vec<(Value, Location)>,
Expand Down Expand Up @@ -2236,17 +2224,6 @@ fn fmtstr_quoted_contents(
Ok(Value::Quoted(Rc::new(tokens)))
}

// fn from_field<T>(x: Field) -> T {}
fn from_field(
interner: &NodeInterner,
arguments: Vec<(Value, Location)>,
return_type: Type,
location: Location,
) -> IResult<Value> {
let (value, value_location) = check_one_argument(arguments, location)?;
Interpreter::evaluate_cast_one_step(&return_type, value_location, value, interner)
}

// fn fresh_type_variable() -> Type
fn fresh_type_variable(interner: &NodeInterner) -> IResult<Value> {
Ok(Value::Type(interner.next_type_variable_with_kind(Kind::Any)))
Expand Down
48 changes: 48 additions & 0 deletions noir_stdlib/src/convert.nr
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,51 @@ impl From<bool> for Field {
}
}
// docs:end:from-impls

/// A generic interface for casting between primitive types,
/// equivalent of using the `as` keyword between values.
///
/// # Example
///
/// ```
/// let x: Field = 1234567890;
/// let y: u8 = x as u8;
/// let z: u8 = x.as_();
/// assert_eq(y, z);
/// ```
pub trait AsPrimitive<T> {
/// The equivalent of doing `self as T`.
fn as_(self) -> T;
}

#[generate_as_primitive_impls]
comptime fn generate_as_primitive_impls(_: FunctionDefinition) -> Quoted {
let types = [
quote { bool },
quote { u8 },
quote { u16 },
quote { u32 },
quote { u64 },
quote { i8 },
quote { i16 },
quote { i32 },
quote { i64 },
quote { Field },
];

let mut impls = &[];
for type1 in types {
for type2 in types {
impls = impls.push_back(
quote {
impl AsPrimitive<$type1> for $type2 {
fn as_(self) -> $type1 {
self as $type1
}
}
},
);
}
}
impls.join(quote {})
}
37 changes: 20 additions & 17 deletions noir_stdlib/src/lib.nr
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ pub mod mem;
pub mod panic;
pub mod hint;

use convert::AsPrimitive;

// Oracle calls are required to be wrapped in an unconstrained function
// Thus, the only argument to the `println` oracle is expected to always be an ident
#[oracle(print)]
Expand Down Expand Up @@ -89,28 +91,29 @@ pub fn assert_constant<T>(x: T) {}
#[builtin(static_assert)]
pub fn static_assert<let N: u32>(predicate: bool, message: str<N>) {}

// from_field and as_field are private since they are not valid for every type.
// `as` should be the default for users to cast between primitive types, and in the future
// traits can be used to work with generic types.
#[builtin(from_field)]
fn from_field<T>(x: Field) -> T {}

#[builtin(as_field)]
fn as_field<T>(x: T) -> Field {}

pub fn wrapping_add<T>(x: T, y: T) -> T {
crate::from_field(crate::as_field(x) + crate::as_field(y))
pub fn wrapping_add<T>(x: T, y: T) -> T
where
T: AsPrimitive<Field>,
Field: AsPrimitive<T>,
{
AsPrimitive::as_(x.as_() + y.as_())
}

pub fn wrapping_sub<T>(x: T, y: T) -> T {
pub fn wrapping_sub<T>(x: T, y: T) -> T
where
T: AsPrimitive<Field>,
Field: AsPrimitive<T>,
{
//340282366920938463463374607431768211456 is 2^128, it is used to avoid underflow
crate::from_field(
crate::as_field(x) + 340282366920938463463374607431768211456 - crate::as_field(y),
)
AsPrimitive::as_(x.as_() + 340282366920938463463374607431768211456 - y.as_())
}

pub fn wrapping_mul<T>(x: T, y: T) -> T {
crate::from_field(crate::as_field(x) * crate::as_field(y))
pub fn wrapping_mul<T>(x: T, y: T) -> T
where
T: AsPrimitive<Field>,
Field: AsPrimitive<T>,
{
AsPrimitive::as_(x.as_() * y.as_())
}

#[builtin(as_witness)]
Expand Down
15 changes: 11 additions & 4 deletions noir_stdlib/src/uint128.nr
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::cmp::{Eq, Ord, Ordering};
use crate::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Not, Rem, Shl, Shr, Sub};
use super::convert::AsPrimitive;

global pow64: Field = 18446744073709551616; //2^64;
global pow63: Field = 9223372036854775808; // 2^63;
Expand Down Expand Up @@ -139,17 +140,23 @@ impl U128 {
}
}

pub fn from_integer<T>(i: T) -> U128 {
let f = crate::as_field(i);
pub fn from_integer<T>(i: T) -> U128
where
T: AsPrimitive<Field>,
{
let f = i.as_();
// Reject values which would overflow a u128
f.assert_max_bit_size::<128>();
let lo = f as u64 as Field;
let hi = (f - lo) / pow64;
U128 { lo, hi }
}

pub fn to_integer<T>(self) -> T {
crate::from_field(self.lo + self.hi * pow64)
pub fn to_integer<T>(self) -> T
where
Field: AsPrimitive<T>,
{
AsPrimitive::as_(self.lo + self.hi * pow64)
}

fn wrapping_mul(self: Self, b: U128) -> U128 {
Expand Down
Loading