| 1 | use crate::int::udiv::*; | 
| 2 |  | 
|---|
| 3 | macro_rules! sdivmod { | 
|---|
| 4 | ( | 
|---|
| 5 | $unsigned_fn:ident, // name of the unsigned division function | 
|---|
| 6 | $signed_fn:ident, // name of the signed division function | 
|---|
| 7 | $uX:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name` | 
|---|
| 8 | $iX:ident, // signed integer type for the inputs and outputs of `$signed_name` | 
|---|
| 9 | $($attr:tt),* // attributes | 
|---|
| 10 | ) => { | 
|---|
| 11 | intrinsics! { | 
|---|
| 12 | $( | 
|---|
| 13 | #[$attr] | 
|---|
| 14 | )* | 
|---|
| 15 | /// Returns `n / d` and sets `*rem = n % d` | 
|---|
| 16 | pub extern "C"fn $signed_fn(a: $iX, b: $iX, rem: &mut $iX) -> $iX { | 
|---|
| 17 | let a_neg = a < 0; | 
|---|
| 18 | let b_neg = b < 0; | 
|---|
| 19 | let mut a = a; | 
|---|
| 20 | let mut b = b; | 
|---|
| 21 |  | 
|---|
| 22 | if a_neg { | 
|---|
| 23 | a = a.wrapping_neg(); | 
|---|
| 24 | } | 
|---|
| 25 | if b_neg { | 
|---|
| 26 | b = b.wrapping_neg(); | 
|---|
| 27 | } | 
|---|
| 28 |  | 
|---|
| 29 | let mut r = *rem as $uX; | 
|---|
| 30 | let t = $unsigned_fn(a as $uX, b as $uX, Some(&mut r)) as $iX; | 
|---|
| 31 | let mut r = r as $iX; | 
|---|
| 32 |  | 
|---|
| 33 | if a_neg { | 
|---|
| 34 | r = r.wrapping_neg(); | 
|---|
| 35 | } | 
|---|
| 36 | *rem = r; | 
|---|
| 37 | if a_neg != b_neg { | 
|---|
| 38 | t.wrapping_neg() | 
|---|
| 39 | } else { | 
|---|
| 40 | t | 
|---|
| 41 | } | 
|---|
| 42 | } | 
|---|
| 43 | } | 
|---|
| 44 | } | 
|---|
| 45 | } | 
|---|
| 46 |  | 
|---|
| 47 | macro_rules! sdiv { | 
|---|
| 48 | ( | 
|---|
| 49 | $unsigned_fn:ident, // name of the unsigned division function | 
|---|
| 50 | $signed_fn:ident, // name of the signed division function | 
|---|
| 51 | $uX:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name` | 
|---|
| 52 | $iX:ident, // signed integer type for the inputs and outputs of `$signed_name` | 
|---|
| 53 | $($attr:tt),* // attributes | 
|---|
| 54 | ) => { | 
|---|
| 55 | intrinsics! { | 
|---|
| 56 | $( | 
|---|
| 57 | #[$attr] | 
|---|
| 58 | )* | 
|---|
| 59 | /// Returns `n / d` | 
|---|
| 60 | pub extern "C"fn $signed_fn(a: $iX, b: $iX) -> $iX { | 
|---|
| 61 | let a_neg = a < 0; | 
|---|
| 62 | let b_neg = b < 0; | 
|---|
| 63 | let mut a = a; | 
|---|
| 64 | let mut b = b; | 
|---|
| 65 | if a_neg { | 
|---|
| 66 | a = a.wrapping_neg(); | 
|---|
| 67 | } | 
|---|
| 68 | if b_neg { | 
|---|
| 69 | b = b.wrapping_neg(); | 
|---|
| 70 | } | 
|---|
| 71 | let t = $unsigned_fn(a as $uX, b as $uX) as $iX; | 
|---|
| 72 | if a_neg != b_neg { | 
|---|
| 73 | t.wrapping_neg() | 
|---|
| 74 | } else { | 
|---|
| 75 | t | 
|---|
| 76 | } | 
|---|
| 77 | } | 
|---|
| 78 | } | 
|---|
| 79 | } | 
|---|
| 80 | } | 
|---|
| 81 |  | 
|---|
| 82 | macro_rules! smod { | 
|---|
| 83 | ( | 
|---|
| 84 | $unsigned_fn:ident, // name of the unsigned division function | 
|---|
| 85 | $signed_fn:ident, // name of the signed division function | 
|---|
| 86 | $uX:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name` | 
|---|
| 87 | $iX:ident, // signed integer type for the inputs and outputs of `$signed_name` | 
|---|
| 88 | $($attr:tt),* // attributes | 
|---|
| 89 | ) => { | 
|---|
| 90 | intrinsics! { | 
|---|
| 91 | $( | 
|---|
| 92 | #[$attr] | 
|---|
| 93 | )* | 
|---|
| 94 | /// Returns `n % d` | 
|---|
| 95 | pub extern "C"fn $signed_fn(a: $iX, b: $iX) -> $iX { | 
|---|
| 96 | let a_neg = a < 0; | 
|---|
| 97 | let b_neg = b < 0; | 
|---|
| 98 | let mut a = a; | 
|---|
| 99 | let mut b = b; | 
|---|
| 100 | if a_neg { | 
|---|
| 101 | a = a.wrapping_neg(); | 
|---|
| 102 | } | 
|---|
| 103 | if b_neg { | 
|---|
| 104 | b = b.wrapping_neg(); | 
|---|
| 105 | } | 
|---|
| 106 | let r = $unsigned_fn(a as $uX, b as $uX) as $iX; | 
|---|
| 107 | if a_neg { | 
|---|
| 108 | r.wrapping_neg() | 
|---|
| 109 | } else { | 
|---|
| 110 | r | 
|---|
| 111 | } | 
|---|
| 112 | } | 
|---|
| 113 | } | 
|---|
| 114 | } | 
|---|
| 115 | } | 
|---|
| 116 |  | 
|---|
| 117 | #[ cfg(not(target_arch = "avr"))] | 
|---|
| 118 | sdivmod!( | 
|---|
| 119 | __udivmodsi4, | 
|---|
| 120 | __divmodsi4, | 
|---|
| 121 | u32, | 
|---|
| 122 | i32, | 
|---|
| 123 | maybe_use_optimized_c_shim | 
|---|
| 124 | ); | 
|---|
| 125 |  | 
|---|
| 126 | #[ cfg(target_arch = "avr")] | 
|---|
| 127 | intrinsics! { | 
|---|
| 128 | /// Returns `a / b` and `a % b` packed together. | 
|---|
| 129 | /// | 
|---|
| 130 | /// Ideally we'd use `-> (u32, u32)` or some kind of a packed struct, but | 
|---|
| 131 | /// both force a stack allocation, while our result has to be in R18:R26. | 
|---|
| 132 | pub extern "C"fn __divmodsi4(a: i32, b: i32) -> u64 { | 
|---|
| 133 | let a_neg = a < 0; | 
|---|
| 134 | let b_neg = b < 0; | 
|---|
| 135 | let mut a = a; | 
|---|
| 136 | let mut b = b; | 
|---|
| 137 |  | 
|---|
| 138 | if a_neg { | 
|---|
| 139 | a = a.wrapping_neg(); | 
|---|
| 140 | } | 
|---|
| 141 | if b_neg { | 
|---|
| 142 | b = b.wrapping_neg(); | 
|---|
| 143 | } | 
|---|
| 144 |  | 
|---|
| 145 | let tr = __udivmodsi4(a as u32, b as u32); | 
|---|
| 146 | let mut t = tr as u32 as i32; | 
|---|
| 147 | let mut r = (tr >> 32) as u32 as i32; | 
|---|
| 148 |  | 
|---|
| 149 | if a_neg { | 
|---|
| 150 | r = r.wrapping_neg(); | 
|---|
| 151 | } | 
|---|
| 152 | if a_neg != b_neg { | 
|---|
| 153 | t = t.wrapping_neg(); | 
|---|
| 154 | } | 
|---|
| 155 |  | 
|---|
| 156 | ((r as u32 as u64) << 32) | (t as u32 as u64) | 
|---|
| 157 | } | 
|---|
| 158 | } | 
|---|
| 159 |  | 
|---|
| 160 | // The `#[arm_aeabi_alias = __aeabi_idiv]` attribute cannot be made to work with `intrinsics!` in macros | 
|---|
| 161 | intrinsics! { | 
|---|
| 162 | #[maybe_use_optimized_c_shim] | 
|---|
| 163 | #[arm_aeabi_alias = __aeabi_idiv] | 
|---|
| 164 | /// Returns `n / d` | 
|---|
| 165 | pub extern "C"fn __divsi3(a: i32, b: i32) -> i32 { | 
|---|
| 166 | let a_neg = a < 0; | 
|---|
| 167 | let b_neg = b < 0; | 
|---|
| 168 | let mut a = a; | 
|---|
| 169 | let mut b = b; | 
|---|
| 170 | if a_neg { | 
|---|
| 171 | a = a.wrapping_neg(); | 
|---|
| 172 | } | 
|---|
| 173 | if b_neg { | 
|---|
| 174 | b = b.wrapping_neg(); | 
|---|
| 175 | } | 
|---|
| 176 | let t = __udivsi3(a as u32, b as u32) as i32; | 
|---|
| 177 | if a_neg != b_neg { | 
|---|
| 178 | t.wrapping_neg() | 
|---|
| 179 | } else { | 
|---|
| 180 | t | 
|---|
| 181 | } | 
|---|
| 182 | } | 
|---|
| 183 | } | 
|---|
| 184 | smod!(__umodsi3, __modsi3, u32, i32, maybe_use_optimized_c_shim); | 
|---|
| 185 |  | 
|---|
| 186 | sdivmod!( | 
|---|
| 187 | __udivmoddi4, | 
|---|
| 188 | __divmoddi4, | 
|---|
| 189 | u64, | 
|---|
| 190 | i64, | 
|---|
| 191 | maybe_use_optimized_c_shim | 
|---|
| 192 | ); | 
|---|
| 193 | sdiv!(__udivdi3, __divdi3, u64, i64, maybe_use_optimized_c_shim); | 
|---|
| 194 | smod!(__umoddi3, __moddi3, u64, i64, maybe_use_optimized_c_shim); | 
|---|
| 195 |  | 
|---|
| 196 | // LLVM does not currently have a `__divmodti4` function, but GCC does | 
|---|
| 197 | sdivmod!( | 
|---|
| 198 | __udivmodti4, | 
|---|
| 199 | __divmodti4, | 
|---|
| 200 | u128, | 
|---|
| 201 | i128, | 
|---|
| 202 | maybe_use_optimized_c_shim | 
|---|
| 203 | ); | 
|---|
| 204 | sdiv!(__udivti3, __divti3, u128, i128,); | 
|---|
| 205 | smod!(__umodti3, __modti3, u128, i128,); | 
|---|
| 206 |  | 
|---|