|
| 1 | +use core::num::Wrapping; |
| 2 | +use float::Float; |
| 3 | + |
| 4 | +macro_rules! add { |
| 5 | + ($intrinsic:ident: $ty:ty) => { |
| 6 | + /// Returns `a + b` |
| 7 | + #[allow(unused_parens)] |
| 8 | + #[cfg_attr(not(test), no_mangle)] |
| 9 | + pub extern fn $intrinsic(a: $ty, b: $ty) -> $ty { |
| 10 | + let one = Wrapping(1 as <$ty as Float>::Int); |
| 11 | + let zero = Wrapping(0 as <$ty as Float>::Int); |
| 12 | + |
| 13 | + let bits = Wrapping(<$ty>::bits() as <$ty as Float>::Int); |
| 14 | + let significand_bits = Wrapping(<$ty>::significand_bits() as <$ty as Float>::Int); |
| 15 | + let exponent_bits = bits - significand_bits - one; |
| 16 | + let max_exponent = (one << exponent_bits.0 as usize) - one; |
| 17 | + |
| 18 | + let implicit_bit = one << significand_bits.0 as usize; |
| 19 | + let significand_mask = implicit_bit - one; |
| 20 | + let sign_bit = one << (significand_bits + exponent_bits).0 as usize; |
| 21 | + let abs_mask = sign_bit - one; |
| 22 | + let exponent_mask = abs_mask ^ significand_mask; |
| 23 | + let inf_rep = exponent_mask; |
| 24 | + let quiet_bit = implicit_bit >> 1; |
| 25 | + let qnan_rep = exponent_mask | quiet_bit; |
| 26 | + |
| 27 | + let mut a_rep = Wrapping(a.repr()); |
| 28 | + let mut b_rep = Wrapping(b.repr()); |
| 29 | + let a_abs = a_rep & abs_mask; |
| 30 | + let b_abs = b_rep & abs_mask; |
| 31 | + |
| 32 | + // Detect if a or b is zero, infinity, or NaN. |
| 33 | + if a_abs - one >= inf_rep - one || |
| 34 | + b_abs - one >= inf_rep - one { |
| 35 | + // NaN + anything = qNaN |
| 36 | + if a_abs > inf_rep { |
| 37 | + return (<$ty as Float>::from_repr((a_abs | quiet_bit).0)); |
| 38 | + } |
| 39 | + // anything + NaN = qNaN |
| 40 | + if b_abs > inf_rep { |
| 41 | + return (<$ty as Float>::from_repr((b_abs | quiet_bit).0)); |
| 42 | + } |
| 43 | + |
| 44 | + if a_abs == inf_rep { |
| 45 | + // +/-infinity + -/+infinity = qNaN |
| 46 | + if (a.repr() ^ b.repr()) == sign_bit.0 { |
| 47 | + return (<$ty as Float>::from_repr(qnan_rep.0)); |
| 48 | + } else { |
| 49 | + // +/-infinity + anything remaining = +/- infinity |
| 50 | + return a; |
| 51 | + } |
| 52 | + } |
| 53 | + |
| 54 | + // anything remaining + +/-infinity = +/-infinity |
| 55 | + if b_abs == inf_rep { |
| 56 | + return b; |
| 57 | + } |
| 58 | + |
| 59 | + // zero + anything = anything |
| 60 | + if a_abs.0 == 0 { |
| 61 | + // but we need to get the sign right for zero + zero |
| 62 | + if b_abs.0 == 0 { |
| 63 | + return (<$ty as Float>::from_repr(a.repr() & b.repr())); |
| 64 | + } else { |
| 65 | + return b; |
| 66 | + } |
| 67 | + } |
| 68 | + |
| 69 | + // anything + zero = anything |
| 70 | + if b_abs.0 == 0 { |
| 71 | + return a; |
| 72 | + } |
| 73 | + } |
| 74 | + |
| 75 | + // Swap a and b if necessary so that a has the larger absolute value. |
| 76 | + if b_abs > a_abs { |
| 77 | + let temp = a_rep; |
| 78 | + a_rep = b_rep; |
| 79 | + b_rep = temp; |
| 80 | + } |
| 81 | + |
| 82 | + // Extract the exponent and significand from the (possibly swapped) a and b. |
| 83 | + let mut a_exponent = Wrapping((a_rep >> significand_bits.0 as usize & max_exponent).0 as i32); |
| 84 | + let mut b_exponent = Wrapping((b_rep >> significand_bits.0 as usize & max_exponent).0 as i32); |
| 85 | + let mut a_significand = a_rep & significand_mask; |
| 86 | + let mut b_significand = b_rep & significand_mask; |
| 87 | + |
| 88 | + // normalize any denormals, and adjust the exponent accordingly. |
| 89 | + if a_exponent.0 == 0 { |
| 90 | + let (exponent, significand) = <$ty>::normalize(a_significand.0); |
| 91 | + a_exponent = Wrapping(exponent); |
| 92 | + a_significand = Wrapping(significand); |
| 93 | + } |
| 94 | + if b_exponent.0 == 0 { |
| 95 | + let (exponent, significand) = <$ty>::normalize(b_significand.0); |
| 96 | + b_exponent = Wrapping(exponent); |
| 97 | + b_significand = Wrapping(significand); |
| 98 | + } |
| 99 | + |
| 100 | + // The sign of the result is the sign of the larger operand, a. If they |
| 101 | + // have opposite signs, we are performing a subtraction; otherwise addition. |
| 102 | + let result_sign = a_rep & sign_bit; |
| 103 | + let subtraction = ((a_rep ^ b_rep) & sign_bit) != zero; |
| 104 | + |
| 105 | + // Shift the significands to give us round, guard and sticky, and or in the |
| 106 | + // implicit significand bit. (If we fell through from the denormal path it |
| 107 | + // was already set by normalize(), but setting it twice won't hurt |
| 108 | + // anything.) |
| 109 | + a_significand = (a_significand | implicit_bit) << 3; |
| 110 | + b_significand = (b_significand | implicit_bit) << 3; |
| 111 | + |
| 112 | + // Shift the significand of b by the difference in exponents, with a sticky |
| 113 | + // bottom bit to get rounding correct. |
| 114 | + let align = Wrapping((a_exponent - b_exponent).0 as <$ty as Float>::Int); |
| 115 | + if align.0 != 0 { |
| 116 | + if align < bits { |
| 117 | + let sticky = ((b_significand << (bits - align).0 as usize).0 != 0) as <$ty as Float>::Int; |
| 118 | + b_significand = (b_significand >> align.0 as usize) | Wrapping(sticky); |
| 119 | + } else { |
| 120 | + b_significand = one; // sticky; b is known to be non-zero. |
| 121 | + } |
| 122 | + } |
| 123 | + if subtraction { |
| 124 | + a_significand -= b_significand; |
| 125 | + // If a == -b, return +zero. |
| 126 | + if a_significand.0 == 0 { |
| 127 | + return (<$ty as Float>::from_repr(0)); |
| 128 | + } |
| 129 | + |
| 130 | + // If partial cancellation occured, we need to left-shift the result |
| 131 | + // and adjust the exponent: |
| 132 | + if a_significand < implicit_bit << 3 { |
| 133 | + let shift = a_significand.0.leading_zeros() as i32 |
| 134 | + - (implicit_bit << 3).0.leading_zeros() as i32; |
| 135 | + a_significand <<= shift as usize; |
| 136 | + a_exponent -= Wrapping(shift); |
| 137 | + } |
| 138 | + } else /* addition */ { |
| 139 | + a_significand += b_significand; |
| 140 | + |
| 141 | + // If the addition carried up, we need to right-shift the result and |
| 142 | + // adjust the exponent: |
| 143 | + if (a_significand & implicit_bit << 4).0 != 0 { |
| 144 | + let sticky = ((a_significand & one).0 != 0) as <$ty as Float>::Int; |
| 145 | + a_significand = a_significand >> 1 | Wrapping(sticky); |
| 146 | + a_exponent += Wrapping(1); |
| 147 | + } |
| 148 | + } |
| 149 | + |
| 150 | + // If we have overflowed the type, return +/- infinity: |
| 151 | + if a_exponent >= Wrapping(max_exponent.0 as i32) { |
| 152 | + return (<$ty>::from_repr((inf_rep | result_sign).0)); |
| 153 | + } |
| 154 | + |
| 155 | + if a_exponent.0 <= 0 { |
| 156 | + // Result is denormal before rounding; the exponent is zero and we |
| 157 | + // need to shift the significand. |
| 158 | + let shift = Wrapping((Wrapping(1) - a_exponent).0 as <$ty as Float>::Int); |
| 159 | + let sticky = ((a_significand << (bits - shift).0 as usize).0 != 0) as <$ty as Float>::Int; |
| 160 | + a_significand = a_significand >> shift.0 as usize | Wrapping(sticky); |
| 161 | + a_exponent = Wrapping(0); |
| 162 | + } |
| 163 | + |
| 164 | + // Low three bits are round, guard, and sticky. |
| 165 | + let round_guard_sticky: i32 = (a_significand.0 & 0x7) as i32; |
| 166 | + |
| 167 | + // Shift the significand into place, and mask off the implicit bit. |
| 168 | + let mut result = a_significand >> 3 & significand_mask; |
| 169 | + |
| 170 | + // Insert the exponent and sign. |
| 171 | + result |= Wrapping(a_exponent.0 as <$ty as Float>::Int) << significand_bits.0 as usize; |
| 172 | + result |= result_sign; |
| 173 | + |
| 174 | + // Final rounding. The result may overflow to infinity, but that is the |
| 175 | + // correct result in that case. |
| 176 | + if round_guard_sticky > 0x4 { result += one; } |
| 177 | + if round_guard_sticky == 0x4 { result += result & one; } |
| 178 | + return (<$ty>::from_repr(result.0)); |
| 179 | + } |
| 180 | + } |
| 181 | +} |
| 182 | + |
| 183 | +add!(__addsf3: f32); |
| 184 | +add!(__adddf3: f64); |
| 185 | + |
| 186 | +// FIXME: Implement these using aliases |
| 187 | +#[cfg(target_arch = "arm")] |
| 188 | +#[cfg_attr(not(test), no_mangle)] |
| 189 | +pub extern fn __aeabi_dadd(a: f64, b: f64) -> f64 { |
| 190 | + __adddf3(a, b) |
| 191 | +} |
| 192 | + |
| 193 | +#[cfg(target_arch = "arm")] |
| 194 | +#[cfg_attr(not(test), no_mangle)] |
| 195 | +pub extern fn __aeabi_fadd(a: f32, b: f32) -> f32 { |
| 196 | + __addsf3(a, b) |
| 197 | +} |
| 198 | + |
| 199 | +#[cfg(test)] |
| 200 | +mod tests { |
| 201 | + use core::{f32, f64}; |
| 202 | + use qc::{U32, U64}; |
| 203 | + use float::Float; |
| 204 | + |
| 205 | + // NOTE The tests below have special handing for NaN values. |
| 206 | + // Because NaN != NaN, the floating-point representations must be used |
| 207 | + // Because there are many diffferent values of NaN, and the implementation |
| 208 | + // doesn't care about calculating the 'correct' one, if both values are NaN |
| 209 | + // the values are considered equivalent. |
| 210 | + |
| 211 | + // TODO: Add F32/F64 to qc so that they print the right values (at the very least) |
| 212 | + quickcheck! { |
| 213 | + fn addsf3(a: U32, b: U32) -> bool { |
| 214 | + let (a, b) = (f32::from_repr(a.0), f32::from_repr(b.0)); |
| 215 | + let x = super::__addsf3(a, b); |
| 216 | + let y = a + b; |
| 217 | + if !(x.is_nan() && y.is_nan()) { |
| 218 | + x.repr() == y.repr() |
| 219 | + } else { |
| 220 | + true |
| 221 | + } |
| 222 | + } |
| 223 | + |
| 224 | + fn adddf3(a: U64, b: U64) -> bool { |
| 225 | + let (a, b) = (f64::from_repr(a.0), f64::from_repr(b.0)); |
| 226 | + let x = super::__adddf3(a, b); |
| 227 | + let y = a + b; |
| 228 | + if !(x.is_nan() && y.is_nan()) { |
| 229 | + x.repr() == y.repr() |
| 230 | + } else { |
| 231 | + true |
| 232 | + } |
| 233 | + } |
| 234 | + } |
| 235 | + |
| 236 | + // More tests for special float values |
| 237 | + |
| 238 | + #[test] |
| 239 | + fn test_float_tiny_plus_tiny() { |
| 240 | + let tiny = f32::from_repr(1); |
| 241 | + let r = super::__addsf3(tiny, tiny); |
| 242 | + assert_eq!(r, tiny + tiny); |
| 243 | + } |
| 244 | + |
| 245 | + #[test] |
| 246 | + fn test_double_tiny_plus_tiny() { |
| 247 | + let tiny = f64::from_repr(1); |
| 248 | + let r = super::__adddf3(tiny, tiny); |
| 249 | + assert_eq!(r, tiny + tiny); |
| 250 | + } |
| 251 | + |
| 252 | + #[test] |
| 253 | + fn test_float_small_plus_small() { |
| 254 | + let a = f32::from_repr(327); |
| 255 | + let b = f32::from_repr(256); |
| 256 | + let r = super::__addsf3(a, b); |
| 257 | + assert_eq!(r, a + b); |
| 258 | + } |
| 259 | + |
| 260 | + #[test] |
| 261 | + fn test_double_small_plus_small() { |
| 262 | + let a = f64::from_repr(327); |
| 263 | + let b = f64::from_repr(256); |
| 264 | + let r = super::__adddf3(a, b); |
| 265 | + assert_eq!(r, a + b); |
| 266 | + } |
| 267 | + |
| 268 | + #[test] |
| 269 | + fn test_float_one_plus_one() { |
| 270 | + let r = super::__addsf3(1f32, 1f32); |
| 271 | + assert_eq!(r, 1f32 + 1f32); |
| 272 | + } |
| 273 | + |
| 274 | + #[test] |
| 275 | + fn test_double_one_plus_one() { |
| 276 | + let r = super::__adddf3(1f64, 1f64); |
| 277 | + assert_eq!(r, 1f64 + 1f64); |
| 278 | + } |
| 279 | + |
| 280 | + #[test] |
| 281 | + fn test_float_different_nan() { |
| 282 | + let a = f32::from_repr(1); |
| 283 | + let b = f32::from_repr(0b11111111100100010001001010101010); |
| 284 | + let x = super::__addsf3(a, b); |
| 285 | + let y = a + b; |
| 286 | + if !(x.is_nan() && y.is_nan()) { |
| 287 | + assert_eq!(x.repr(), y.repr()); |
| 288 | + } |
| 289 | + } |
| 290 | + |
| 291 | + #[test] |
| 292 | + fn test_double_different_nan() { |
| 293 | + let a = f64::from_repr(1); |
| 294 | + let b = f64::from_repr( |
| 295 | + 0b1111111111110010001000100101010101001000101010000110100011101011); |
| 296 | + let x = super::__adddf3(a, b); |
| 297 | + let y = a + b; |
| 298 | + if !(x.is_nan() && y.is_nan()) { |
| 299 | + assert_eq!(x.repr(), y.repr()); |
| 300 | + } |
| 301 | + } |
| 302 | + |
| 303 | + #[test] |
| 304 | + fn test_float_nan() { |
| 305 | + let r = super::__addsf3(f32::NAN, 1.23); |
| 306 | + assert_eq!(r.repr(), f32::NAN.repr()); |
| 307 | + } |
| 308 | + |
| 309 | + #[test] |
| 310 | + fn test_double_nan() { |
| 311 | + let r = super::__adddf3(f64::NAN, 1.23); |
| 312 | + assert_eq!(r.repr(), f64::NAN.repr()); |
| 313 | + } |
| 314 | + |
| 315 | + #[test] |
| 316 | + fn test_float_inf() { |
| 317 | + let r = super::__addsf3(f32::INFINITY, -123.4); |
| 318 | + assert_eq!(r, f32::INFINITY); |
| 319 | + } |
| 320 | + |
| 321 | + #[test] |
| 322 | + fn test_double_inf() { |
| 323 | + let r = super::__adddf3(f64::INFINITY, -123.4); |
| 324 | + assert_eq!(r, f64::INFINITY); |
| 325 | + } |
| 326 | +} |
0 commit comments