Skip to content

Commit 5d9fe6f

Browse files
committed
Rollup merge of rust-lang#46926 - varkor:contrib-9, r=joshtriplett
Add LLVM `minnum`/`maxnum` intrinsics LLVM’s intrinsics `minnum` and `maxnum` are now used for `min` and `max` on `f32` and `f64`. This resolves rust-lang#18384.
2 parents f196e9b + a060814 commit 5d9fe6f

File tree

6 files changed

+71
-36
lines changed

6 files changed

+71
-36
lines changed

src/libcore/intrinsics.rs

+54
Original file line numberDiff line numberDiff line change
@@ -1142,6 +1142,19 @@ extern "rust-intrinsic" {
11421142
/// Returns the absolute value of an `f64`.
11431143
pub fn fabsf64(x: f64) -> f64;
11441144

1145+
/// Returns the minimum of two `f32` values.
1146+
#[cfg(not(stage0))]
1147+
pub fn minnumf32(x: f32, y: f32) -> f32;
1148+
/// Returns the minimum of two `f64` values.
1149+
#[cfg(not(stage0))]
1150+
pub fn minnumf64(x: f64, y: f64) -> f64;
1151+
/// Returns the maximum of two `f32` values.
1152+
#[cfg(not(stage0))]
1153+
pub fn maxnumf32(x: f32, y: f32) -> f32;
1154+
/// Returns the maximum of two `f64` values.
1155+
#[cfg(not(stage0))]
1156+
pub fn maxnumf64(x: f64, y: f64) -> f64;
1157+
11451158
/// Copies the sign from `y` to `x` for `f32` values.
11461159
pub fn copysignf32(x: f32, y: f32) -> f32;
11471160
/// Copies the sign from `y` to `x` for `f64` values.
@@ -1393,3 +1406,44 @@ extern "rust-intrinsic" {
13931406
#[cfg(not(stage0))]
13941407
pub fn nontemporal_store<T>(ptr: *mut T, val: T);
13951408
}
1409+
1410+
// Simple bootstrap implementations for stage0 compilation
1411+
1412+
/// Returns the minimum of two `f32` values.
1413+
#[cfg(stage0)]
1414+
pub unsafe fn minnumf32(x: f32, y: f32) -> f32 {
1415+
// IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the
1416+
// canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it
1417+
// is either x or y, canonicalized (this means results might differ among implementations).
1418+
// When either x or y is a signalingNaN, then the result is according to 6.2.
1419+
//
1420+
// Since we do not support sNaN in Rust yet, we do not need to handle them.
1421+
// FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by
1422+
// multiplying by 1.0. Should switch to the `canonicalize` when it works.
1423+
(if x < y || y != y { x } else { y }) * 1.0
1424+
}
1425+
/// Returns the minimum of two `f64` values.
1426+
#[cfg(stage0)]
1427+
pub unsafe fn minnumf64(x: f64, y: f64) -> f64 {
1428+
// Identical to the `f32` case.
1429+
(if x < y || y != y { x } else { y }) * 1.0
1430+
}
1431+
/// Returns the maximum of two `f32` values.
1432+
#[cfg(stage0)]
1433+
pub unsafe fn maxnumf32(x: f32, y: f32) -> f32 {
1434+
// IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the
1435+
// canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it
1436+
// is either x or y, canonicalized (this means results might differ among implementations).
1437+
// When either x or y is a signalingNaN, then the result is according to 6.2.
1438+
//
1439+
// Since we do not support sNaN in Rust yet, we do not need to handle them.
1440+
// FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by
1441+
// multiplying by 1.0. Should switch to the `canonicalize` when it works.
1442+
(if x < y || x != x { y } else { x }) * 1.0
1443+
}
1444+
/// Returns the maximum of two `f64` values.
1445+
#[cfg(stage0)]
1446+
pub unsafe fn maxnumf64(x: f64, y: f64) -> f64 {
1447+
// Identical to the `f32` case.
1448+
(if x < y || x != x { y } else { x }) * 1.0
1449+
}

src/libcore/num/f32.rs

+2-18
Original file line numberDiff line numberDiff line change
@@ -250,28 +250,12 @@ impl Float for f32 {
250250
/// Returns the maximum of the two numbers.
251251
#[inline]
252252
fn max(self, other: f32) -> f32 {
253-
// IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the
254-
// canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it
255-
// is either x or y, canonicalized (this means results might differ among implementations).
256-
// When either x or y is a signalingNaN, then the result is according to 6.2.
257-
//
258-
// Since we do not support sNaN in Rust yet, we do not need to handle them.
259-
// FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by
260-
// multiplying by 1.0. Should switch to the `canonicalize` when it works.
261-
(if self < other || self.is_nan() { other } else { self }) * 1.0
253+
unsafe { intrinsics::maxnumf32(self, other) }
262254
}
263255

264256
/// Returns the minimum of the two numbers.
265257
#[inline]
266258
fn min(self, other: f32) -> f32 {
267-
// IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the
268-
// canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it
269-
// is either x or y, canonicalized (this means results might differ among implementations).
270-
// When either x or y is a signalingNaN, then the result is according to 6.2.
271-
//
272-
// Since we do not support sNaN in Rust yet, we do not need to handle them.
273-
// FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by
274-
// multiplying by 1.0. Should switch to the `canonicalize` when it works.
275-
(if self < other || other.is_nan() { self } else { other }) * 1.0
259+
unsafe { intrinsics::minnumf32(self, other) }
276260
}
277261
}

src/libcore/num/f64.rs

+2-18
Original file line numberDiff line numberDiff line change
@@ -248,28 +248,12 @@ impl Float for f64 {
248248
/// Returns the maximum of the two numbers.
249249
#[inline]
250250
fn max(self, other: f64) -> f64 {
251-
// IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the
252-
// canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it
253-
// is either x or y, canonicalized (this means results might differ among implementations).
254-
// When either x or y is a signalingNaN, then the result is according to 6.2.
255-
//
256-
// Since we do not support sNaN in Rust yet, we do not need to handle them.
257-
// FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by
258-
// multiplying by 1.0. Should switch to the `canonicalize` when it works.
259-
(if self < other || self.is_nan() { other } else { self }) * 1.0
251+
unsafe { intrinsics::maxnumf64(self, other) }
260252
}
261253

262254
/// Returns the minimum of the two numbers.
263255
#[inline]
264256
fn min(self, other: f64) -> f64 {
265-
// IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the
266-
// canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it
267-
// is either x or y, canonicalized (this means results might differ among implementations).
268-
// When either x or y is a signalingNaN, then the result is according to 6.2.
269-
//
270-
// Since we do not support sNaN in Rust yet, we do not need to handle them.
271-
// FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by
272-
// multiplying by 1.0. Should switch to the `canonicalize` when it works.
273-
(if self < other || other.is_nan() { self } else { other }) * 1.0
257+
unsafe { intrinsics::minnumf64(self, other) }
274258
}
275259
}

src/librustc_trans/context.rs

+5
Original file line numberDiff line numberDiff line change
@@ -782,6 +782,11 @@ fn declare_intrinsic(ccx: &CrateContext, key: &str) -> Option<ValueRef> {
782782
ifn!("llvm.fabs.f32", fn(t_f32) -> t_f32);
783783
ifn!("llvm.fabs.f64", fn(t_f64) -> t_f64);
784784

785+
ifn!("llvm.minnum.f32", fn(t_f32, t_f32) -> t_f32);
786+
ifn!("llvm.minnum.f64", fn(t_f64, t_f64) -> t_f64);
787+
ifn!("llvm.maxnum.f32", fn(t_f32, t_f32) -> t_f32);
788+
ifn!("llvm.maxnum.f64", fn(t_f64, t_f64) -> t_f64);
789+
785790
ifn!("llvm.floor.f32", fn(t_f32) -> t_f32);
786791
ifn!("llvm.floor.f64", fn(t_f64) -> t_f64);
787792
ifn!("llvm.ceil.f32", fn(t_f32) -> t_f32);

src/librustc_trans/intrinsic.rs

+4
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ fn get_simple_intrinsic(ccx: &CrateContext, name: &str) -> Option<ValueRef> {
6161
"fmaf64" => "llvm.fma.f64",
6262
"fabsf32" => "llvm.fabs.f32",
6363
"fabsf64" => "llvm.fabs.f64",
64+
"minnumf32" => "llvm.minnum.f32",
65+
"minnumf64" => "llvm.minnum.f64",
66+
"maxnumf32" => "llvm.maxnum.f32",
67+
"maxnumf64" => "llvm.maxnum.f64",
6468
"copysignf32" => "llvm.copysign.f32",
6569
"copysignf64" => "llvm.copysign.f64",
6670
"floorf32" => "llvm.floor.f32",

src/librustc_typeck/check/intrinsic.rs

+4
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,10 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
255255
}
256256
"fabsf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32),
257257
"fabsf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64),
258+
"minnumf32" => (0, vec![ tcx.types.f32, tcx.types.f32 ], tcx.types.f32),
259+
"minnumf64" => (0, vec![ tcx.types.f64, tcx.types.f64 ], tcx.types.f64),
260+
"maxnumf32" => (0, vec![ tcx.types.f32, tcx.types.f32 ], tcx.types.f32),
261+
"maxnumf64" => (0, vec![ tcx.types.f64, tcx.types.f64 ], tcx.types.f64),
258262
"copysignf32" => (0, vec![ tcx.types.f32, tcx.types.f32 ], tcx.types.f32),
259263
"copysignf64" => (0, vec![ tcx.types.f64, tcx.types.f64 ], tcx.types.f64),
260264
"floorf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32),

0 commit comments

Comments
 (0)