| 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 |  | 
|---|