Skip to content

Commit

Permalink
compiler-rt: refactor downcast possibility check to utility function
Browse files Browse the repository at this point in the history
Bitwise polyfills API uses only u128 as input and output types. The
actual bitwise operations happen on shorter types (e.g. i8 operations
are in fact done on u8 etc). For this reason we make sure that the value
passed in an u128 fits in the target type. This check happens so often,
it is now moved to an utility submodule to reduce code duplication.

Signed-off-by: Wojciech Zmuda <[email protected]>
  • Loading branch information
wzmuda committed Nov 21, 2024
1 parent 8d29138 commit 1e084f7
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 30 deletions.
13 changes: 3 additions & 10 deletions compiler-rt/src/alu/and.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub mod and_i32;
pub mod and_i64;
pub mod and_i128;

use crate::utils::assert_fits_in_type;
use core::num::traits::{BitSize, Bounded};
use core::integer::Bitwise;
extern fn bitwise(lhs: u128, rhs: u128) -> (u128, u128, u128) implicits(Bitwise) nopanic;
Expand Down Expand Up @@ -32,16 +33,8 @@ fn and<
lhs: u128, rhs: u128
) -> u128 {
// Make sure the value passed as u128 arguments can fit into the concrete type.
let bit_size = BitSize::<T>::bits();
let _: T = match lhs.try_into() {
Option::Some(value) => value,
Option::None => { panic!("lhs = {} does not fit in u{}", lhs, bit_size) },
};

let _: T = match rhs.try_into() {
Option::Some(value) => value,
Option::None => { panic!("rhs = {} does not fit in u{}", rhs, bit_size) },
};
assert_fits_in_type::<T>(lhs);
assert_fits_in_type::<T>(rhs);

// Use the `bitwise` built-in function. It returns the tuple of the `(and, xor, or)` results. We
// discard the uninteresting results.
Expand Down
13 changes: 3 additions & 10 deletions compiler-rt/src/alu/or.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub mod or_i32;
pub mod or_i64;
pub mod or_i128;

use crate::utils::assert_fits_in_type;
use core::num::traits::{BitSize, Bounded};
use core::integer::Bitwise;
extern fn bitwise(lhs: u128, rhs: u128) -> (u128, u128, u128) implicits(Bitwise) nopanic;
Expand Down Expand Up @@ -32,16 +33,8 @@ fn or<
lhs: u128, rhs: u128
) -> u128 {
// Make sure the value passed in the u128 arguments can still fit in the concrete type.
let bit_size = BitSize::<T>::bits();
let _: T = match lhs.try_into() {
Option::Some(value) => value,
Option::None => { panic!("lhs = {} does not fit in u{}", lhs, bit_size) },
};

let _: T = match rhs.try_into() {
Option::Some(value) => value,
Option::None => { panic!("rhs = {} does not fit in u{}", rhs, bit_size) },
};
assert_fits_in_type::<T>(lhs);
assert_fits_in_type::<T>(rhs);

// Use the `bitwise` built-in function. It returns the tuple of the `(and, xor, or)` results. We
// discard the uninteresting results.
Expand Down
13 changes: 3 additions & 10 deletions compiler-rt/src/alu/xor.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub mod xor_i32;
pub mod xor_i64;
pub mod xor_i128;

use crate::utils::assert_fits_in_type;
use core::num::traits::{BitSize, Bounded};
use core::integer::Bitwise;
extern fn bitwise(lhs: u128, rhs: u128) -> (u128, u128, u128) implicits(Bitwise) nopanic;
Expand Down Expand Up @@ -32,16 +33,8 @@ fn xor<
lhs: u128, rhs: u128
) -> u128 {
// Make sure the value passed in the u128 arguments can fit in the concrete type.
let bit_size = BitSize::<T>::bits();
let _: T = match lhs.try_into() {
Option::Some(value) => value,
Option::None => { panic!("lhs = {} does not fit in u{}", lhs, bit_size) },
};

let _: T = match rhs.try_into() {
Option::Some(value) => value,
Option::None => { panic!("rhs = {} does not fit in u{}", rhs, bit_size) },
};
assert_fits_in_type::<T>(lhs);
assert_fits_in_type::<T>(rhs);

// Use the `bitwise` built-in function. It returns the tuple of the `(and, xor, or)` results. We
// discard the uninteresting results.
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pub mod alu;
mod utils;
20 changes: 20 additions & 0 deletions compiler-rt/src/utils.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use core::num::traits::BitSize;

// Make sure the value `v` can be safely casted down into type `T` without doing the actual cast,
// panicking if this is not possible.
//
// This check is used multiple times throughout the project, so it is marked as #[inline] to hint
// to the compiler that, if possible, it should not emit a call to this function but instead
// insert its body directly into the caller.
#[inline]
pub fn assert_fits_in_type<
T, impl TBitSize: BitSize<T>, impl TTryInto: TryInto<u128, T>, impl TDestruct: Destruct<T>
>(
v: u128
) {
let bit_size = BitSize::<T>::bits();
let _: T = match v.try_into() {
Option::Some(value) => value,
Option::None => { panic!("value = {} does not fit in u{}", v, bit_size) },
};
}

0 comments on commit 1e084f7

Please sign in to comment.