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 19, 2024
1 parent fe21ec3 commit bb80742
Show file tree
Hide file tree
Showing 5 changed files with 26 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 All @@ -19,16 +20,8 @@ fn and<
>(
lhs: u128, rhs: u128
) -> u128 {
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);

let (and_result, _, _) = bitwise(lhs, rhs);
and_result & Bounded::<T>::MAX.into()
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 All @@ -19,16 +20,8 @@ fn or<
>(
lhs: u128, rhs: u128
) -> u128 {
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);

let (_, _, or_result) = bitwise(lhs, rhs);
or_result & Bounded::<T>::MAX.into()
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 All @@ -19,16 +20,8 @@ fn xor<
>(
lhs: u128, rhs: u128
) -> u128 {
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);

let (_, xor_result, _) = bitwise(lhs, rhs);
xor_result & Bounded::<T>::MAX.into()
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;
16 changes: 16 additions & 0 deletions compiler-rt/src/utils.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use core::num::traits::BitSize;

#[inline]
// Make sure the value v can be safely casted down into type T without doing the actual cast. Panic
// if this is not possible.
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 bb80742

Please sign in to comment.