From bb80742952f2ff9a869c657a9d70d40f24170ce6 Mon Sep 17 00:00:00 2001 From: Wojciech Zmuda Date: Tue, 19 Nov 2024 23:37:19 +0100 Subject: [PATCH] compiler-rt: refactor downcast possibility check to utility function 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 --- compiler-rt/src/alu/and.cairo | 13 +++---------- compiler-rt/src/alu/or.cairo | 13 +++---------- compiler-rt/src/alu/xor.cairo | 13 +++---------- compiler-rt/src/lib.cairo | 1 + compiler-rt/src/utils.cairo | 16 ++++++++++++++++ 5 files changed, 26 insertions(+), 30 deletions(-) create mode 100644 compiler-rt/src/utils.cairo diff --git a/compiler-rt/src/alu/and.cairo b/compiler-rt/src/alu/and.cairo index bd9aa09..50ddc54 100644 --- a/compiler-rt/src/alu/and.cairo +++ b/compiler-rt/src/alu/and.cairo @@ -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; @@ -19,16 +20,8 @@ fn and< >( lhs: u128, rhs: u128 ) -> u128 { - let bit_size = BitSize::::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::(lhs); + assert_fits_in_type::(rhs); let (and_result, _, _) = bitwise(lhs, rhs); and_result & Bounded::::MAX.into() diff --git a/compiler-rt/src/alu/or.cairo b/compiler-rt/src/alu/or.cairo index 909e902..613f4d6 100644 --- a/compiler-rt/src/alu/or.cairo +++ b/compiler-rt/src/alu/or.cairo @@ -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; @@ -19,16 +20,8 @@ fn or< >( lhs: u128, rhs: u128 ) -> u128 { - let bit_size = BitSize::::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::(lhs); + assert_fits_in_type::(rhs); let (_, _, or_result) = bitwise(lhs, rhs); or_result & Bounded::::MAX.into() diff --git a/compiler-rt/src/alu/xor.cairo b/compiler-rt/src/alu/xor.cairo index 9974eb6..76e3f58 100644 --- a/compiler-rt/src/alu/xor.cairo +++ b/compiler-rt/src/alu/xor.cairo @@ -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; @@ -19,16 +20,8 @@ fn xor< >( lhs: u128, rhs: u128 ) -> u128 { - let bit_size = BitSize::::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::(lhs); + assert_fits_in_type::(rhs); let (_, xor_result, _) = bitwise(lhs, rhs); xor_result & Bounded::::MAX.into() diff --git a/compiler-rt/src/lib.cairo b/compiler-rt/src/lib.cairo index 0040cfb..f7a4fec 100644 --- a/compiler-rt/src/lib.cairo +++ b/compiler-rt/src/lib.cairo @@ -1 +1,2 @@ pub mod alu; +mod utils; diff --git a/compiler-rt/src/utils.cairo b/compiler-rt/src/utils.cairo new file mode 100644 index 0000000..92be576 --- /dev/null +++ b/compiler-rt/src/utils.cairo @@ -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, impl TTryInto: TryInto, impl TDestruct: Destruct +>( + v: u128 +) { + let bit_size = BitSize::::bits(); + let _: T = match v.try_into() { + Option::Some(value) => value, + Option::None => { panic!("value = {} does not fit in u{}", v, bit_size) }, + }; +}