-
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 division for i8
Implement the following polyfills: - `__llvm_udiv_i8_i8` - `__llvm_sdiv_i8_i8` Signed-off-by: Wojciech Zmuda <zmuda.w@gmail.com>
- Loading branch information
Showing
5 changed files
with
688 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
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,72 @@ | ||
pub mod sdiv_i8; | ||
|
||
use crate::utils::assert_fits_in_type; | ||
use crate::alu::shl::shl; | ||
use core::num::traits::{BitSize, Bounded, WrappingAdd}; | ||
|
||
// Perform the `sdiv` operation. | ||
// | ||
// This is a generic implementation for every data type. Its specialized versions | ||
// are defined and tested in the sdiv/sdiv_<type>.cairo files. | ||
fn sdiv< | ||
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>, | ||
>( | ||
lhs: u128, rhs: u128, | ||
) -> u128 { | ||
// Make sure the value passed in the u128 arguments can fit in the concrete type. | ||
assert_fits_in_type::<T>(lhs); | ||
assert_fits_in_type::<T>(rhs); | ||
|
||
// Check if operands and result are negative | ||
let sign_mask = shl::<u128>(1, BitSize::<T>::bits().into() - 1); | ||
let is_dividend_negative = (lhs & sign_mask) != 0; | ||
let is_divisor_negative = (rhs & sign_mask) != 0; | ||
let is_result_negative = is_dividend_negative ^ is_divisor_negative; | ||
|
||
// A helper function to compute two's complement | ||
let twos_complement = |x: u128| -> u128 { | ||
(~x).wrapping_add(1) | ||
}; | ||
|
||
// Get absolute value of operands | ||
let abs_dividend = if is_dividend_negative { | ||
twos_complement(lhs) & Bounded::<T>::MAX.into() | ||
} else { | ||
lhs | ||
}; | ||
let abs_divisor = if is_divisor_negative { | ||
twos_complement(rhs) & Bounded::<T>::MAX.into() | ||
} else { | ||
rhs | ||
}; | ||
|
||
// Perform unsigned division and get quotient and remainder. | ||
// Adjust quotient for floor division if result is negative and there's a remainder. | ||
let quotient_unsigned = abs_dividend / abs_divisor; | ||
let remainder = abs_dividend % abs_divisor; | ||
let quotient_unsigned = if is_result_negative && remainder != 0 { | ||
quotient_unsigned.wrapping_add(1) | ||
} else { | ||
quotient_unsigned | ||
}; | ||
|
||
// Apply sign to the quotient | ||
if is_result_negative { | ||
twos_complement(quotient_unsigned) | ||
} else { | ||
quotient_unsigned | ||
} & Bounded::<T>::MAX.into() | ||
} |
Oops, something went wrong.