| 1 | #[cfg (not(feature = "unstable-public-internals" ))] |
| 2 | pub(crate) use crate::int::specialized_div_rem::*; |
| 3 | #[cfg (feature = "unstable-public-internals" )] |
| 4 | pub use crate::int::specialized_div_rem::*; |
| 5 | |
| 6 | intrinsics! { |
| 7 | #[maybe_use_optimized_c_shim] |
| 8 | #[arm_aeabi_alias = __aeabi_uidiv] |
| 9 | /// Returns `n / d` |
| 10 | pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { |
| 11 | u32_div_rem(n, d).0 |
| 12 | } |
| 13 | |
| 14 | #[maybe_use_optimized_c_shim] |
| 15 | /// Returns `n % d` |
| 16 | pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 { |
| 17 | u32_div_rem(n, d).1 |
| 18 | } |
| 19 | } |
| 20 | |
| 21 | #[cfg (not(target_arch = "avr" ))] |
| 22 | intrinsics! { |
| 23 | #[maybe_use_optimized_c_shim] |
| 24 | /// Returns `n / d` and sets `*rem = n % d` |
| 25 | pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { |
| 26 | let quo_rem = u32_div_rem(n, d); |
| 27 | if let Some(rem) = rem { |
| 28 | *rem = quo_rem.1; |
| 29 | } |
| 30 | quo_rem.0 |
| 31 | } |
| 32 | } |
| 33 | |
| 34 | #[cfg (target_arch = "avr" )] |
| 35 | intrinsics! { |
| 36 | /// Returns `n / d` and `n % d` packed together. |
| 37 | /// |
| 38 | /// Ideally we'd use `-> (u32, u32)` or some kind of a packed struct, but |
| 39 | /// both force a stack allocation, while our result has to be in R18:R26. |
| 40 | pub extern "C" fn __udivmodsi4(n: u32, d: u32) -> u64 { |
| 41 | let (div, rem) = u32_div_rem(n, d); |
| 42 | |
| 43 | ((rem as u64) << 32) | (div as u64) |
| 44 | } |
| 45 | |
| 46 | #[unsafe(naked)] |
| 47 | pub unsafe extern "C" fn __udivmodqi4() { |
| 48 | // compute unsigned 8-bit `n / d` and `n % d`. |
| 49 | // |
| 50 | // Note: GCC implements a [non-standard calling convention](https://gcc.gnu.org/wiki/avr-gcc#Exceptions_to_the_Calling_Convention) for this function. |
| 51 | // Inputs: |
| 52 | // R24: dividend |
| 53 | // R22: divisor |
| 54 | // Outputs: |
| 55 | // R24: quotient (dividend / divisor) |
| 56 | // R25: remainder (dividend % divisor) |
| 57 | // Clobbers: |
| 58 | // R23: loop counter |
| 59 | core::arch::naked_asm!( |
| 60 | // This assembly routine implements the [long division](https://en.wikipedia.org/wiki/Division_algorithm#Long_division) algorithm. |
| 61 | // Bits shift out of the dividend and into the quotient, so R24 is used for both. |
| 62 | "clr R25" , // remainder = 0 |
| 63 | |
| 64 | "ldi R23, 8" , // for each bit |
| 65 | "1:" , |
| 66 | "lsl R24" , // shift the dividend MSb |
| 67 | "rol R25" , // into the remainder LSb |
| 68 | |
| 69 | "cp R25, R22" , // if remainder >= divisor |
| 70 | "brlo 2f" , |
| 71 | "sub R25, R22" , // remainder -= divisor |
| 72 | "sbr R24, 1" , // quotient |= 1 |
| 73 | "2:" , |
| 74 | |
| 75 | "dec R23" , // end loop |
| 76 | "brne 1b" , |
| 77 | "ret" , |
| 78 | ); |
| 79 | } |
| 80 | |
| 81 | #[unsafe(naked)] |
| 82 | pub unsafe extern "C" fn __udivmodhi4() { |
| 83 | // compute unsigned 16-bit `n / d` and `n % d`. |
| 84 | // |
| 85 | // Note: GCC implements a [non-standard calling convention](https://gcc.gnu.org/wiki/avr-gcc#Exceptions_to_the_Calling_Convention) for this function. |
| 86 | // Inputs: |
| 87 | // R24: dividend [low] |
| 88 | // R25: dividend [high] |
| 89 | // R22: divisor [low] |
| 90 | // R23: divisor [high] |
| 91 | // Outputs: |
| 92 | // R22: quotient [low] (dividend / divisor) |
| 93 | // R23: quotient [high] |
| 94 | // R24: remainder [low] (dividend % divisor) |
| 95 | // R25: remainder [high] |
| 96 | // Clobbers: |
| 97 | // R21: loop counter |
| 98 | // R26: divisor [low] |
| 99 | // R27: divisor [high] |
| 100 | core::arch::naked_asm!( |
| 101 | // This assembly routine implements the [long division](https://en.wikipedia.org/wiki/Division_algorithm#Long_division) algorithm. |
| 102 | // Bits shift out of the dividend and into the quotient, so R24+R25 are used for both. |
| 103 | "mov R26, R22" , // move divisor to make room for quotient |
| 104 | "mov R27, R23" , |
| 105 | "mov R22, R24" , // move dividend to output location (becomes quotient) |
| 106 | "mov R23, R25" , |
| 107 | "clr R24" , // remainder = 0 |
| 108 | "clr R25" , |
| 109 | |
| 110 | "ldi R21, 16" , // for each bit |
| 111 | "1:" , |
| 112 | "lsl R22" , // shift the dividend MSb |
| 113 | "rol R23" , |
| 114 | "rol R24" , // into the remainder LSb |
| 115 | "rol R25" , |
| 116 | |
| 117 | "cp R24, R26" , // if remainder >= divisor |
| 118 | "cpc R25, R27" , |
| 119 | "brlo 2f" , |
| 120 | "sub R24, R26" , // remainder -= divisor |
| 121 | "sbc R25, R27" , |
| 122 | "sbr R22, 1" , // quotient |= 1 |
| 123 | "2:" , |
| 124 | |
| 125 | "dec R21" , // end loop |
| 126 | "brne 1b" , |
| 127 | "ret" , |
| 128 | ); |
| 129 | } |
| 130 | |
| 131 | } |
| 132 | |
| 133 | intrinsics! { |
| 134 | #[maybe_use_optimized_c_shim] |
| 135 | /// Returns `n / d` |
| 136 | pub extern "C" fn __udivdi3(n: u64, d: u64) -> u64 { |
| 137 | u64_div_rem(n, d).0 |
| 138 | } |
| 139 | |
| 140 | #[maybe_use_optimized_c_shim] |
| 141 | /// Returns `n % d` |
| 142 | pub extern "C" fn __umoddi3(n: u64, d: u64) -> u64 { |
| 143 | u64_div_rem(n, d).1 |
| 144 | } |
| 145 | |
| 146 | #[maybe_use_optimized_c_shim] |
| 147 | /// Returns `n / d` and sets `*rem = n % d` |
| 148 | pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { |
| 149 | let quo_rem = u64_div_rem(n, d); |
| 150 | if let Some(rem) = rem { |
| 151 | *rem = quo_rem.1; |
| 152 | } |
| 153 | quo_rem.0 |
| 154 | } |
| 155 | |
| 156 | // Note: we use block configuration and not `if cfg!(...)`, because we need to entirely disable |
| 157 | // the existence of `u128_div_rem` to get 32-bit SPARC to compile, see `u128_divide_sparc` docs. |
| 158 | |
| 159 | /// Returns `n / d` |
| 160 | pub extern "C" fn __udivti3(n: u128, d: u128) -> u128 { |
| 161 | #[cfg (not(any(target_arch = "sparc" , target_arch = "sparc64" )))] { |
| 162 | u128_div_rem(n, d).0 |
| 163 | } |
| 164 | #[cfg (any(target_arch = "sparc" , target_arch = "sparc64" ))] { |
| 165 | u128_divide_sparc(n, d, &mut 0) |
| 166 | } |
| 167 | } |
| 168 | |
| 169 | /// Returns `n % d` |
| 170 | pub extern "C" fn __umodti3(n: u128, d: u128) -> u128 { |
| 171 | #[cfg (not(any(target_arch = "sparc" , target_arch = "sparc64" )))] { |
| 172 | u128_div_rem(n, d).1 |
| 173 | } |
| 174 | #[cfg (any(target_arch = "sparc" , target_arch = "sparc64" ))] { |
| 175 | let mut rem = 0; |
| 176 | u128_divide_sparc(n, d, &mut rem); |
| 177 | rem |
| 178 | } |
| 179 | } |
| 180 | |
| 181 | /// Returns `n / d` and sets `*rem = n % d` |
| 182 | pub extern "C" fn __udivmodti4(n: u128, d: u128, rem: Option<&mut u128>) -> u128 { |
| 183 | #[cfg (not(any(target_arch = "sparc" , target_arch = "sparc64" )))] { |
| 184 | let quo_rem = u128_div_rem(n, d); |
| 185 | if let Some(rem) = rem { |
| 186 | *rem = quo_rem.1; |
| 187 | } |
| 188 | quo_rem.0 |
| 189 | } |
| 190 | #[cfg (any(target_arch = "sparc" , target_arch = "sparc64" ))] { |
| 191 | let mut tmp = 0; |
| 192 | let quo = u128_divide_sparc(n, d, &mut tmp); |
| 193 | if let Some(rem) = rem { |
| 194 | *rem = tmp; |
| 195 | } |
| 196 | quo |
| 197 | } |
| 198 | } |
| 199 | } |
| 200 | |