-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
compiler-rt: alu: add bitwise
lshr
polyfills
Signed-off-by: Wojciech Zmuda <[email protected]>
- Loading branch information
Showing
8 changed files
with
874 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,5 +2,6 @@ pub mod and; | |
pub mod or; | ||
pub mod xor; | ||
pub mod shl; | ||
pub mod lshr; | ||
|
||
mod test_case; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
pub mod lshr_i1; | ||
pub mod lshr_i8; | ||
pub mod lshr_i16; | ||
pub mod lshr_i32; | ||
pub mod lshr_i64; | ||
pub mod lshr_i128; | ||
|
||
use crate::utils::assert_fits_in_type; | ||
use core::num::traits::{BitSize, Bounded}; | ||
|
||
// Perform logical shift right operation. | ||
// | ||
// This is a generic implementation for every data type. Its specialized versions | ||
// are defined and tested in lshr/lshr_<type>.cairo files. | ||
fn lshr< | ||
T, | ||
// The trait bounds are chosen so that: | ||
// - BitSize<T>: we can determine the length of the data type in bits, | ||
// - Bounded<T>: we can determine min and max value of the type, | ||
// - TryInto<u128, T>, Into<T, u128> - we can convert the type from/to u128, | ||
// - Destruct<T>: the type can be dropped as the result of the downcasting check. | ||
// Overall these trait bounds allow any unsigned integer to be used as the concrete type. | ||
impl TBitSize: BitSize<T>, | ||
impl TBounded: Bounded<T>, | ||
impl TTryInto: TryInto<u128, T>, | ||
impl TInto: Into<T, u128>, | ||
impl TDestruct: Destruct<T> | ||
>( | ||
n: u128, shift: u128 | ||
) -> u128 { | ||
// Make sure the value passed as u128 arguments can fit in the concrete type. | ||
assert_fits_in_type::<T>(n); | ||
assert_fits_in_type::<T>(shift); | ||
|
||
// Cairo does not have << or >> operators so we must implement the shift manually. | ||
let mut result = n; | ||
// Right logical shift by 1 bit is effectively division by 2, so just divide `shift` times | ||
for _ in 0..shift { | ||
result /= 2; | ||
}; | ||
|
||
// Make sure the result is limited only to the bit width of the concrete type. | ||
result & Bounded::<T>::MAX.into() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
use crate::alu::lshr::lshr; | ||
|
||
pub fn __llvm_lshr_i1_i1(n: u128, shift: u128) -> u128 { | ||
if n > 1 { | ||
panic!("n = {:?} does not fit in i1", n) | ||
} | ||
|
||
if shift > 1 { | ||
panic!("shift = {:?} does not fit in i1", shift) | ||
} | ||
|
||
// There is no dedicated 1-bit type so after making sure that lhs and rhs | ||
// fit in 1 bit, promote them to u8, do the job and return the LSB. | ||
lshr::<u8>(n, shift) & 0x1 | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::__llvm_lshr_i1_i1; | ||
use crate::alu::test_case::TestCase; | ||
#[cairofmt::skip] | ||
pub const test_cases: [TestCase; 4] = [ | ||
// All possible 1-bit cases | ||
TestCase { lhs: 0, rhs: 0, expected: 0 }, | ||
TestCase { lhs: 0, rhs: 1, expected: 0 }, | ||
TestCase { lhs: 1, rhs: 0, expected: 1 }, | ||
TestCase { lhs: 1, rhs: 1, expected: 0 }, | ||
]; | ||
|
||
#[test] | ||
fn test_i1() { | ||
for case in test_cases | ||
.span() { | ||
assert_eq!(__llvm_lshr_i1_i1(*case.lhs, *case.rhs), *case.expected); | ||
} | ||
} | ||
} | ||
|
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
use crate::alu::lshr::lshr; | ||
|
||
pub fn __llvm_lshr_i16_i16(n: u128, shift: u128) -> u128 { | ||
lshr::<u16>(n, shift) | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::__llvm_lshr_i16_i16; | ||
use crate::alu::test_case::TestCase; | ||
#[cairofmt::skip] | ||
pub const test_cases: [TestCase; 41] = [ | ||
// All possible shifts on all 1s from 0 throughout the whole input value length | ||
TestCase { lhs: 0b1111111111111111, rhs: 0, expected: 0b1111111111111111 }, | ||
TestCase { lhs: 0b1111111111111111, rhs: 1, expected: 0b0111111111111111 }, | ||
TestCase { lhs: 0b1111111111111111, rhs: 2, expected: 0b0011111111111111 }, | ||
TestCase { lhs: 0b1111111111111111, rhs: 3, expected: 0b0001111111111111 }, | ||
TestCase { lhs: 0b1111111111111111, rhs: 4, expected: 0b0000111111111111 }, | ||
TestCase { lhs: 0b1111111111111111, rhs: 5, expected: 0b0000011111111111 }, | ||
TestCase { lhs: 0b1111111111111111, rhs: 6, expected: 0b0000001111111111 }, | ||
TestCase { lhs: 0b1111111111111111, rhs: 7, expected: 0b0000000111111111 }, | ||
TestCase { lhs: 0b1111111111111111, rhs: 8, expected: 0b0000000011111111 }, | ||
TestCase { lhs: 0b1111111111111111, rhs: 9, expected: 0b0000000001111111 }, | ||
TestCase { lhs: 0b1111111111111111, rhs: 10, expected: 0b0000000000111111 }, | ||
TestCase { lhs: 0b1111111111111111, rhs: 11, expected: 0b0000000000011111 }, | ||
TestCase { lhs: 0b1111111111111111, rhs: 12, expected: 0b0000000000001111 }, | ||
TestCase { lhs: 0b1111111111111111, rhs: 13, expected: 0b0000000000000111 }, | ||
TestCase { lhs: 0b1111111111111111, rhs: 14, expected: 0b0000000000000011 }, | ||
TestCase { lhs: 0b1111111111111111, rhs: 15, expected: 0b0000000000000001 }, | ||
TestCase { lhs: 0b1111111111111111, rhs: 16, expected: 0b0000000000000000 }, | ||
|
||
// Shifts by more bits than the input value contains - overflow should cause loss of the excessive bits | ||
TestCase { lhs: 0b1111111111111111, rhs: 17, expected: 0b0000000000000000 }, | ||
TestCase { lhs: 0b1111111111111111, rhs: 90, expected: 0b0000000000000000 }, | ||
TestCase { lhs: 0b1111111111111111, rhs: 123, expected: 0b0000000000000000 }, | ||
|
||
// The same set of operations but on a zero bit pattern | ||
TestCase { lhs: 0b0000000000000000, rhs: 0, expected: 0b0000000000000000 }, | ||
TestCase { lhs: 0b0000000000000000, rhs: 1, expected: 0b0000000000000000 }, | ||
TestCase { lhs: 0b0000000000000000, rhs: 2, expected: 0b0000000000000000 }, | ||
TestCase { lhs: 0b0000000000000000, rhs: 3, expected: 0b0000000000000000 }, | ||
TestCase { lhs: 0b0000000000000000, rhs: 4, expected: 0b0000000000000000 }, | ||
TestCase { lhs: 0b0000000000000000, rhs: 5, expected: 0b0000000000000000 }, | ||
TestCase { lhs: 0b0000000000000000, rhs: 6, expected: 0b0000000000000000 }, | ||
TestCase { lhs: 0b0000000000000000, rhs: 7, expected: 0b0000000000000000 }, | ||
TestCase { lhs: 0b0000000000000000, rhs: 8, expected: 0b0000000000000000 }, | ||
TestCase { lhs: 0b0000000000000000, rhs: 9, expected: 0b0000000000000000 }, | ||
TestCase { lhs: 0b0000000000000000, rhs: 10, expected: 0b0000000000000000 }, | ||
TestCase { lhs: 0b0000000000000000, rhs: 11, expected: 0b0000000000000000 }, | ||
TestCase { lhs: 0b0000000000000000, rhs: 12, expected: 0b0000000000000000 }, | ||
TestCase { lhs: 0b0000000000000000, rhs: 13, expected: 0b0000000000000000 }, | ||
TestCase { lhs: 0b0000000000000000, rhs: 14, expected: 0b0000000000000000 }, | ||
TestCase { lhs: 0b0000000000000000, rhs: 15, expected: 0b0000000000000000 }, | ||
TestCase { lhs: 0b0000000000000000, rhs: 16, expected: 0b0000000000000000 }, | ||
TestCase { lhs: 0b0000000000000000, rhs: 17, expected: 0b0000000000000000 }, | ||
TestCase { lhs: 0b0000000000000000, rhs: 90, expected: 0b0000000000000000 }, | ||
TestCase { lhs: 0b0000000000000000, rhs: 123, expected: 0b0000000000000000 }, | ||
|
||
// Shift of a mixed 0/1 bit pattern | ||
TestCase { lhs: 0b1010101010101010, rhs: 8, expected: 0b10101010 }, | ||
]; | ||
|
||
|
||
#[test] | ||
fn test_i16() { | ||
for case in test_cases | ||
.span() { | ||
assert_eq!(__llvm_lshr_i16_i16(*case.lhs, *case.rhs), *case.expected); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
use crate::alu::lshr::lshr; | ||
|
||
pub fn __llvm_lshr_i32_i32(n: u128, shift: u128) -> u128 { | ||
lshr::<u32>(n, shift) | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::__llvm_lshr_i32_i32; | ||
use crate::alu::test_case::TestCase; | ||
#[cairofmt::skip] | ||
pub const test_cases: [TestCase; 73] = [ | ||
// All possible shifts on all 1s from 0 throughout the whole input value length | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 0, expected: 0b11111111111111111111111111111111 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 1, expected: 0b01111111111111111111111111111111 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 2, expected: 0b00111111111111111111111111111111 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 3, expected: 0b00011111111111111111111111111111 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 4, expected: 0b00001111111111111111111111111111 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 5, expected: 0b00000111111111111111111111111111 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 6, expected: 0b00000011111111111111111111111111 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 7, expected: 0b00000001111111111111111111111111 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 8, expected: 0b00000000111111111111111111111111 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 9, expected: 0b00000000011111111111111111111111 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 10, expected: 0b00000000001111111111111111111111 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 11, expected: 0b00000000000111111111111111111111 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 12, expected: 0b00000000000011111111111111111111 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 13, expected: 0b00000000000001111111111111111111 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 14, expected: 0b00000000000000111111111111111111 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 15, expected: 0b00000000000000011111111111111111 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 16, expected: 0b00000000000000001111111111111111 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 17, expected: 0b00000000000000000111111111111111 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 18, expected: 0b00000000000000000011111111111111 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 19, expected: 0b00000000000000000001111111111111 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 20, expected: 0b00000000000000000000111111111111 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 21, expected: 0b00000000000000000000011111111111 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 22, expected: 0b00000000000000000000001111111111 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 23, expected: 0b00000000000000000000000111111111 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 24, expected: 0b00000000000000000000000011111111 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 25, expected: 0b00000000000000000000000001111111 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 26, expected: 0b00000000000000000000000000111111 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 27, expected: 0b00000000000000000000000000011111 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 28, expected: 0b00000000000000000000000000001111 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 29, expected: 0b00000000000000000000000000000111 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 30, expected: 0b00000000000000000000000000000011 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 31, expected: 0b00000000000000000000000000000001 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 32, expected: 0b00000000000000000000000000000000 }, | ||
|
||
// Shifts by more bits than the input value contains - overflow should cause loss of the excessive bits | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 33, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 90, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b11111111111111111111111111111111, rhs: 123, expected: 0b00000000000000000000000000000000 }, | ||
|
||
// The same set of operations but on a zero bit pattern | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 0, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 1, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 2, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 3, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 4, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 5, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 6, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 7, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 8, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 9, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 10, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 11, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 12, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 13, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 14, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 15, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 16, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 17, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 18, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 19, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 20, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 21, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 22, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 23, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 24, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 25, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 26, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 27, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 28, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 29, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 30, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 31, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 32, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 33, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 90, expected: 0b00000000000000000000000000000000 }, | ||
TestCase { lhs: 0b00000000000000000000000000000000, rhs: 123, expected: 0b00000000000000000000000000000000 }, | ||
|
||
// Shift of a mixed 0/1 bit pattern | ||
TestCase { lhs: 0b10101010101010101010101010101010, rhs: 16, expected: 0b1010101010101010 }, | ||
]; | ||
|
||
#[test] | ||
fn test_i32() { | ||
for case in test_cases | ||
.span() { | ||
assert_eq!(__llvm_lshr_i32_i32(*case.lhs, *case.rhs), *case.expected); | ||
} | ||
} | ||
} | ||
|
Oops, something went wrong.