Skip to content

Commit 83d63ea

Browse files
committed
Convert float intrinsics to the intrinsics! macro
1 parent 93fed26 commit 83d63ea

File tree

6 files changed

+349
-356
lines changed

6 files changed

+349
-356
lines changed

src/float/add.rs

Lines changed: 161 additions & 163 deletions
Original file line numberDiff line numberDiff line change
@@ -3,192 +3,190 @@ use core::num::Wrapping;
33

44
use float::Float;
55

6+
/// Returns `a + b`
67
macro_rules! add {
7-
($abi:tt, $intrinsic:ident: $ty:ty) => {
8-
/// Returns `a + b`
9-
#[allow(unused_parens)]
10-
#[cfg_attr(not(test), no_mangle)]
11-
pub extern $abi fn $intrinsic(a: $ty, b: $ty) -> $ty {
12-
let one = Wrapping(1 as <$ty as Float>::Int);
13-
let zero = Wrapping(0 as <$ty as Float>::Int);
14-
15-
let bits = Wrapping(<$ty>::bits() as <$ty as Float>::Int);
16-
let significand_bits = Wrapping(<$ty>::significand_bits() as <$ty as Float>::Int);
17-
let exponent_bits = bits - significand_bits - one;
18-
let max_exponent = (one << exponent_bits.0 as usize) - one;
19-
20-
let implicit_bit = one << significand_bits.0 as usize;
21-
let significand_mask = implicit_bit - one;
22-
let sign_bit = one << (significand_bits + exponent_bits).0 as usize;
23-
let abs_mask = sign_bit - one;
24-
let exponent_mask = abs_mask ^ significand_mask;
25-
let inf_rep = exponent_mask;
26-
let quiet_bit = implicit_bit >> 1;
27-
let qnan_rep = exponent_mask | quiet_bit;
28-
29-
let mut a_rep = Wrapping(a.repr());
30-
let mut b_rep = Wrapping(b.repr());
31-
let a_abs = a_rep & abs_mask;
32-
let b_abs = b_rep & abs_mask;
33-
34-
// Detect if a or b is zero, infinity, or NaN.
35-
if a_abs - one >= inf_rep - one ||
36-
b_abs - one >= inf_rep - one {
37-
// NaN + anything = qNaN
38-
if a_abs > inf_rep {
39-
return (<$ty as Float>::from_repr((a_abs | quiet_bit).0));
40-
}
41-
// anything + NaN = qNaN
42-
if b_abs > inf_rep {
43-
return (<$ty as Float>::from_repr((b_abs | quiet_bit).0));
44-
}
45-
46-
if a_abs == inf_rep {
47-
// +/-infinity + -/+infinity = qNaN
48-
if (a.repr() ^ b.repr()) == sign_bit.0 {
49-
return (<$ty as Float>::from_repr(qnan_rep.0));
50-
} else {
51-
// +/-infinity + anything remaining = +/- infinity
52-
return a;
53-
}
54-
}
8+
($a:expr, $b:expr, $ty:ty) => ({
9+
let a = $a;
10+
let b = $b;
11+
let one = Wrapping(1 as <$ty as Float>::Int);
12+
let zero = Wrapping(0 as <$ty as Float>::Int);
13+
14+
let bits = Wrapping(<$ty>::bits() as <$ty as Float>::Int);
15+
let significand_bits = Wrapping(<$ty>::significand_bits() as <$ty as Float>::Int);
16+
let exponent_bits = bits - significand_bits - one;
17+
let max_exponent = (one << exponent_bits.0 as usize) - one;
18+
19+
let implicit_bit = one << significand_bits.0 as usize;
20+
let significand_mask = implicit_bit - one;
21+
let sign_bit = one << (significand_bits + exponent_bits).0 as usize;
22+
let abs_mask = sign_bit - one;
23+
let exponent_mask = abs_mask ^ significand_mask;
24+
let inf_rep = exponent_mask;
25+
let quiet_bit = implicit_bit >> 1;
26+
let qnan_rep = exponent_mask | quiet_bit;
27+
28+
let mut a_rep = Wrapping(a.repr());
29+
let mut b_rep = Wrapping(b.repr());
30+
let a_abs = a_rep & abs_mask;
31+
let b_abs = b_rep & abs_mask;
32+
33+
// Detect if a or b is zero, infinity, or NaN.
34+
if a_abs - one >= inf_rep - one ||
35+
b_abs - one >= inf_rep - one {
36+
// NaN + anything = qNaN
37+
if a_abs > inf_rep {
38+
return <$ty as Float>::from_repr((a_abs | quiet_bit).0);
39+
}
40+
// anything + NaN = qNaN
41+
if b_abs > inf_rep {
42+
return <$ty as Float>::from_repr((b_abs | quiet_bit).0);
43+
}
5544

56-
// anything remaining + +/-infinity = +/-infinity
57-
if b_abs == inf_rep {
58-
return b;
45+
if a_abs == inf_rep {
46+
// +/-infinity + -/+infinity = qNaN
47+
if (a.repr() ^ b.repr()) == sign_bit.0 {
48+
return <$ty as Float>::from_repr(qnan_rep.0);
49+
} else {
50+
// +/-infinity + anything remaining = +/- infinity
51+
return a;
5952
}
53+
}
6054

61-
// zero + anything = anything
62-
if a_abs.0 == 0 {
63-
// but we need to get the sign right for zero + zero
64-
if b_abs.0 == 0 {
65-
return (<$ty as Float>::from_repr(a.repr() & b.repr()));
66-
} else {
67-
return b;
68-
}
69-
}
55+
// anything remaining + +/-infinity = +/-infinity
56+
if b_abs == inf_rep {
57+
return b;
58+
}
7059

71-
// anything + zero = anything
60+
// zero + anything = anything
61+
if a_abs.0 == 0 {
62+
// but we need to get the sign right for zero + zero
7263
if b_abs.0 == 0 {
73-
return a;
64+
return <$ty as Float>::from_repr(a.repr() & b.repr());
65+
} else {
66+
return b;
7467
}
7568
}
7669

77-
// Swap a and b if necessary so that a has the larger absolute value.
78-
if b_abs > a_abs {
79-
mem::swap(&mut a_rep, &mut b_rep);
70+
// anything + zero = anything
71+
if b_abs.0 == 0 {
72+
return a;
8073
}
74+
}
8175

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-
}
76+
// Swap a and b if necessary so that a has the larger absolute value.
77+
if b_abs > a_abs {
78+
mem::swap(&mut a_rep, &mut b_rep);
79+
}
9980

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-
}
81+
// Extract the exponent and significand from the (possibly swapped) a and b.
82+
let mut a_exponent = Wrapping((a_rep >> significand_bits.0 as usize & max_exponent).0 as i32);
83+
let mut b_exponent = Wrapping((b_rep >> significand_bits.0 as usize & max_exponent).0 as i32);
84+
let mut a_significand = a_rep & significand_mask;
85+
let mut b_significand = b_rep & significand_mask;
86+
87+
// normalize any denormals, and adjust the exponent accordingly.
88+
if a_exponent.0 == 0 {
89+
let (exponent, significand) = <$ty>::normalize(a_significand.0);
90+
a_exponent = Wrapping(exponent);
91+
a_significand = Wrapping(significand);
92+
}
93+
if b_exponent.0 == 0 {
94+
let (exponent, significand) = <$ty>::normalize(b_significand.0);
95+
b_exponent = Wrapping(exponent);
96+
b_significand = Wrapping(significand);
97+
}
12998

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-
}
99+
// The sign of the result is the sign of the larger operand, a. If they
100+
// have opposite signs, we are performing a subtraction; otherwise addition.
101+
let result_sign = a_rep & sign_bit;
102+
let subtraction = ((a_rep ^ b_rep) & sign_bit) != zero;
103+
104+
// Shift the significands to give us round, guard and sticky, and or in the
105+
// implicit significand bit. (If we fell through from the denormal path it
106+
// was already set by normalize(), but setting it twice won't hurt
107+
// anything.)
108+
a_significand = (a_significand | implicit_bit) << 3;
109+
b_significand = (b_significand | implicit_bit) << 3;
110+
111+
// Shift the significand of b by the difference in exponents, with a sticky
112+
// bottom bit to get rounding correct.
113+
let align = Wrapping((a_exponent - b_exponent).0 as <$ty as Float>::Int);
114+
if align.0 != 0 {
115+
if align < bits {
116+
let sticky = ((b_significand << (bits - align).0 as usize).0 != 0) as <$ty as Float>::Int;
117+
b_significand = (b_significand >> align.0 as usize) | Wrapping(sticky);
118+
} else {
119+
b_significand = one; // sticky; b is known to be non-zero.
148120
}
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));
121+
}
122+
if subtraction {
123+
a_significand -= b_significand;
124+
// If a == -b, return +zero.
125+
if a_significand.0 == 0 {
126+
return <$ty as Float>::from_repr(0);
153127
}
154128

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);
129+
// If partial cancellation occured, we need to left-shift the result
130+
// and adjust the exponent:
131+
if a_significand < implicit_bit << 3 {
132+
let shift = a_significand.0.leading_zeros() as i32
133+
- (implicit_bit << 3).0.leading_zeros() as i32;
134+
a_significand <<= shift as usize;
135+
a_exponent -= Wrapping(shift);
162136
}
137+
} else /* addition */ {
138+
a_significand += b_significand;
139+
140+
// If the addition carried up, we need to right-shift the result and
141+
// adjust the exponent:
142+
if (a_significand & implicit_bit << 4).0 != 0 {
143+
let sticky = ((a_significand & one).0 != 0) as <$ty as Float>::Int;
144+
a_significand = a_significand >> 1 | Wrapping(sticky);
145+
a_exponent += Wrapping(1);
146+
}
147+
}
163148

164-
// Low three bits are round, guard, and sticky.
165-
let round_guard_sticky: i32 = (a_significand.0 & 0x7) as i32;
149+
// If we have overflowed the type, return +/- infinity:
150+
if a_exponent >= Wrapping(max_exponent.0 as i32) {
151+
return <$ty>::from_repr((inf_rep | result_sign).0);
152+
}
166153

167-
// Shift the significand into place, and mask off the implicit bit.
168-
let mut result = a_significand >> 3 & significand_mask;
154+
if a_exponent.0 <= 0 {
155+
// Result is denormal before rounding; the exponent is zero and we
156+
// need to shift the significand.
157+
let shift = Wrapping((Wrapping(1) - a_exponent).0 as <$ty as Float>::Int);
158+
let sticky = ((a_significand << (bits - shift).0 as usize).0 != 0) as <$ty as Float>::Int;
159+
a_significand = a_significand >> shift.0 as usize | Wrapping(sticky);
160+
a_exponent = Wrapping(0);
161+
}
169162

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;
163+
// Low three bits are round, guard, and sticky.
164+
let round_guard_sticky: i32 = (a_significand.0 & 0x7) as i32;
173165

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; }
166+
// Shift the significand into place, and mask off the implicit bit.
167+
let mut result = a_significand >> 3 & significand_mask;
178168

179-
<$ty>::from_repr(result.0)
180-
}
181-
}
182-
}
169+
// Insert the exponent and sign.
170+
result |= Wrapping(a_exponent.0 as <$ty as Float>::Int) << significand_bits.0 as usize;
171+
result |= result_sign;
183172

184-
#[cfg(target_arch = "arm")]
185-
add!("aapcs", __addsf3: f32);
173+
// Final rounding. The result may overflow to infinity, but that is the
174+
// correct result in that case.
175+
if round_guard_sticky > 0x4 { result += one; }
176+
if round_guard_sticky == 0x4 { result += result & one; }
186177

187-
#[cfg(not(target_arch = "arm"))]
188-
add!("C", __addsf3: f32);
178+
<$ty>::from_repr(result.0)
179+
})
180+
}
189181

190-
#[cfg(target_arch = "arm")]
191-
add!("aapcs", __adddf3: f64);
182+
intrinsics! {
183+
#[aapcs_on_arm]
184+
pub extern "C" fn __addsf3(a: f32, b: f32) -> f32 {
185+
add!(a, b, f32)
186+
}
192187

193-
#[cfg(not(target_arch = "arm"))]
194-
add!("C", __adddf3: f64);
188+
#[aapcs_on_arm]
189+
pub extern "C" fn __adddf3(a: f64, b: f64) -> f64 {
190+
add!(a, b, f64)
191+
}
192+
}

0 commit comments

Comments
 (0)