Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,24 +33,24 @@ fn main() {
let n = f32x4([nan, nan, nan, nan]);

unsafe {
let min0 = simd_fmin(x, y);
let min1 = simd_fmin(y, x);
let min0 = simd_minimum_number_nsz(x, y);
let min1 = simd_minimum_number_nsz(y, x);
assert_eq!(min0.into_array(), min1.into_array());
let e = f32x4([1.0, 1.0, 3.0, 3.0]);
assert_eq!(min0.into_array(), e.into_array());
let minn = simd_fmin(x, n);
let minn = simd_minimum_number_nsz(x, n);
assert_eq!(minn.into_array(), x.into_array());
let minn = simd_fmin(y, n);
let minn = simd_minimum_number_nsz(y, n);
assert_eq!(minn.into_array(), y.into_array());

let max0 = simd_fmax(x, y);
let max1 = simd_fmax(y, x);
let max0 = simd_maximum_number_nsz(x, y);
let max1 = simd_maximum_number_nsz(y, x);
assert_eq!(max0.into_array(), max1.into_array());
let e = f32x4([2.0, 2.0, 4.0, 4.0]);
assert_eq!(max0.into_array(), e.into_array());
let maxn = simd_fmax(x, n);
let maxn = simd_maximum_number_nsz(x, n);
assert_eq!(maxn.into_array(), x.into_array());
let maxn = simd_fmax(y, n);
let maxn = simd_maximum_number_nsz(y, n);
assert_eq!(maxn.into_array(), y.into_array());
}
}
10 changes: 7 additions & 3 deletions compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
}
}

sym::simd_fmin | sym::simd_fmax => {
sym::simd_minimum_number_nsz | sym::simd_maximum_number_nsz => {
intrinsic_args!(fx, args => (x, y); intrinsic);

if !x.layout().ty.is_simd() {
Expand All @@ -508,8 +508,12 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
_ => unreachable!("{:?}", lane_ty),
}
match intrinsic {
sym::simd_fmin => crate::num::codegen_float_min(fx, x_lane, y_lane),
sym::simd_fmax => crate::num::codegen_float_max(fx, x_lane, y_lane),
sym::simd_minimum_number_nsz => {
crate::num::codegen_float_min(fx, x_lane, y_lane)
}
sym::simd_maximum_number_nsz => {
crate::num::codegen_float_max(fx, x_lane, y_lane)
}
_ => unreachable!(),
}
});
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_cranelift/src/num.rs
Original file line number Diff line number Diff line change
Expand Up @@ -500,8 +500,8 @@ fn codegen_ptr_binop<'tcx>(

// In Rust floating point min and max don't propagate NaN (not even SNaN). In Cranelift they do
// however. For this reason it is necessary to use `a.is_nan() ? b : (a >= b ? b : a)` for
// `minnumf*` and `a.is_nan() ? b : (a <= b ? b : a)` for `maxnumf*`. NaN checks are done by
// comparing a float against itself. Only in case of NaN is it not equal to itself.
// `minimum_number_nsz` and `a.is_nan() ? b : (a <= b ? b : a)` for `maximum_number_nsz`. NaN checks
// are done by comparing a float against itself. Only in case of NaN is it not equal to itself.
pub(crate) fn codegen_float_min(fx: &mut FunctionCx<'_, '_, '_>, a: Value, b: Value) -> Value {
// FIXME(bytecodealliance/wasmtime#8312): Replace with Cranelift `fcmp` once
// `f16`/`f128` backend lowerings have been added to Cranelift.
Expand Down
11 changes: 7 additions & 4 deletions compiler/rustc_codegen_gcc/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2278,6 +2278,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
})
}

/// Emits a SIMD min/max operation for floats. The semantics for each lane are: if one
/// side is NaN (QNaN or SNaN), the other side is returned.
fn vector_extremum(
&mut self,
a: RValue<'gcc>,
Expand All @@ -2286,8 +2288,9 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
) -> RValue<'gcc> {
let vector_type = a.get_type();

// mask out the NaNs in b and replace them with the corresponding lane in a, so when a and
// b get compared & spliced together, we get the numeric values instead of NaNs.
// Mask out the NaNs (both QNaN and SNaN) in b and replace them with the corresponding lane
// in a, so when a and b get compared & spliced together, we get the numeric values instead
// of NaNs.
let b_nan_mask = self.context.new_comparison(self.location, ComparisonOp::NotEquals, b, b);
let mask_type = b_nan_mask.get_type();
let b_nan_mask_inverted =
Expand All @@ -2309,7 +2312,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
self.context.new_bitcast(self.location, res, vector_type)
}

pub fn vector_fmin(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
pub fn vector_minimum_number_nsz(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
self.vector_extremum(a, b, ExtremumOperation::Min)
}

Expand Down Expand Up @@ -2341,7 +2344,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
unimplemented!();
}

pub fn vector_fmax(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
pub fn vector_maximum_number_nsz(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
self.vector_extremum(a, b, ExtremumOperation::Max)
}

Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1222,8 +1222,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
simd_and: Uint, Int => and;
simd_or: Uint, Int => or; // FIXME(antoyo): calling `or` might not work on vectors.
simd_xor: Uint, Int => xor;
simd_fmin: Float => vector_fmin;
simd_fmax: Float => vector_fmax;
simd_minimum_number_nsz: Float => vector_minimum_number_nsz;
simd_maximum_number_nsz: Float => vector_maximum_number_nsz;
}

macro_rules! arith_unary {
Expand Down
12 changes: 8 additions & 4 deletions compiler/rustc_codegen_llvm/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1605,12 +1605,16 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
*self = Self::build(self.cx, next_bb);
}

pub(crate) fn minnum(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.call_intrinsic("llvm.minnum", &[self.val_ty(lhs)], &[lhs, rhs])
pub(crate) fn minimum_number_nsz(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
let call = self.call_intrinsic("llvm.minimumnum", &[self.val_ty(lhs)], &[lhs, rhs]);
unsafe { llvm::LLVMRustSetNoSignedZeros(call) };
call
}

pub(crate) fn maxnum(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.call_intrinsic("llvm.maxnum", &[self.val_ty(lhs)], &[lhs, rhs])
pub(crate) fn maximum_number_nsz(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
let call = self.call_intrinsic("llvm.maximumnum", &[self.val_ty(lhs)], &[lhs, rhs]);
unsafe { llvm::LLVMRustSetNoSignedZeros(call) };
call
}

pub(crate) fn insert_element(
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_llvm/src/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2770,8 +2770,8 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
simd_and: Uint, Int => and;
simd_or: Uint, Int => or;
simd_xor: Uint, Int => xor;
simd_fmax: Float => maxnum;
simd_fmin: Float => minnum;
simd_maximum_number_nsz: Float => maximum_number_nsz;
simd_minimum_number_nsz: Float => minimum_number_nsz;

}
macro_rules! arith_unary {
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
| sym::simd_le
| sym::simd_gt
| sym::simd_ge
| sym::simd_fmax
| sym::simd_fmin
| sym::simd_maximum_number_nsz
| sym::simd_minimum_number_nsz
| sym::simd_saturating_add
| sym::simd_saturating_sub
| sym::simd_arith_offset => {
Expand Down Expand Up @@ -211,8 +211,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
sym::simd_le => Op::MirOp(BinOp::Le),
sym::simd_gt => Op::MirOp(BinOp::Gt),
sym::simd_ge => Op::MirOp(BinOp::Ge),
sym::simd_fmax => Op::FMinMax(MinMax::MaximumNumberNsz),
sym::simd_fmin => Op::FMinMax(MinMax::MinimumNumberNsz),
sym::simd_maximum_number_nsz => Op::FMinMax(MinMax::MaximumNumberNsz),
sym::simd_minimum_number_nsz => Op::FMinMax(MinMax::MinimumNumberNsz),
sym::simd_saturating_add => Op::SaturatingOp(BinOp::Add),
sym::simd_saturating_sub => Op::SaturatingOp(BinOp::Sub),
sym::simd_arith_offset => Op::WrappingOffset,
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_analysis/src/check/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -726,8 +726,8 @@ pub(crate) fn check_intrinsic_type(
| sym::simd_and
| sym::simd_or
| sym::simd_xor
| sym::simd_fmin
| sym::simd_fmax
| sym::simd_minimum_number_nsz
| sym::simd_maximum_number_nsz
| sym::simd_saturating_add
| sym::simd_saturating_sub
| sym::simd_carryless_mul => (1, 0, vec![param(0), param(0)], param(0)),
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1850,8 +1850,6 @@ symbols! {
simd_flog10,
simd_floor,
simd_fma,
simd_fmax,
simd_fmin,
simd_fsin,
simd_fsqrt,
simd_funnel_shl,
Expand All @@ -1865,6 +1863,8 @@ symbols! {
simd_lt,
simd_masked_load,
simd_masked_store,
simd_maximum_number_nsz,
simd_minimum_number_nsz,
simd_mul,
simd_ne,
simd_neg,
Expand Down
16 changes: 12 additions & 4 deletions library/core/src/intrinsics/simd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,19 +250,27 @@ pub const unsafe fn simd_fabs<T>(x: T) -> T;
///
/// `T` must be a vector of floating-point primitive types.
///
/// Follows IEEE-754 `minNum` semantics.
/// This behaves like IEEE 754-2019 minimumNumber, *except* that it does not order signed
/// zeros deterministically. In particular, for each vector lane:
/// If one of the arguments is NaN (quiet or signaling), then the other argument is returned. If
/// both arguments are NaN, returns NaN. If the inputs compare equal (such as for the case of `+0.0`
/// and `-0.0`), either input may be returned non-deterministically.
#[rustc_intrinsic]
#[rustc_nounwind]
pub const unsafe fn simd_fmin<T>(x: T, y: T) -> T;
pub const unsafe fn simd_minimum_number_nsz<T>(x: T, y: T) -> T;

/// Returns the maximum of two vectors, elementwise.
///
/// `T` must be a vector of floating-point primitive types.
///
/// Follows IEEE-754 `maxNum` semantics.
/// This behaves like IEEE 754-2019 maximumNumber, *except* that it does not order signed
/// zeros deterministically. In particular, for each vector lane:
/// If one of the arguments is NaN (quiet or signaling), then the other argument is returned. If
/// both arguments are NaN, returns NaN. If the inputs compare equal (such as for the case of `+0.0`
/// and `-0.0`), either input may be returned non-deterministically.
#[rustc_intrinsic]
#[rustc_nounwind]
pub const unsafe fn simd_fmax<T>(x: T, y: T) -> T;
pub const unsafe fn simd_maximum_number_nsz<T>(x: T, y: T) -> T;

/// Tests elementwise equality of two vectors.
///
Expand Down
4 changes: 2 additions & 2 deletions library/portable-simd/crates/core_simd/src/simd/num/float.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,13 +385,13 @@ macro_rules! impl_trait {
#[inline]
fn simd_min(self, other: Self) -> Self {
// Safety: `self` and `other` are float vectors
unsafe { core::intrinsics::simd::simd_fmin(self, other) }
unsafe { core::intrinsics::simd::simd_minimum_number_nsz(self, other) }
}

#[inline]
fn simd_max(self, other: Self) -> Self {
// Safety: `self` and `other` are floating point vectors
unsafe { core::intrinsics::simd::simd_fmax(self, other) }
unsafe { core::intrinsics::simd::simd_maximum_number_nsz(self, other) }
}

#[inline]
Expand Down
4 changes: 2 additions & 2 deletions library/stdarch/crates/core_arch/src/nvptx/packed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ pub unsafe fn f16x2_neg(a: f16x2) -> f16x2 {
#[cfg_attr(test, assert_instr(min.f16x2))]
#[unstable(feature = "stdarch_nvptx", issue = "111199")]
pub unsafe fn f16x2_min(a: f16x2, b: f16x2) -> f16x2 {
simd_fmin(a, b)
simd_minimum_number_nsz(a, b)
}

/// Find the minimum of two values, NaNs pass through.
Expand All @@ -123,7 +123,7 @@ pub unsafe fn f16x2_min_nan(a: f16x2, b: f16x2) -> f16x2 {
#[cfg_attr(test, assert_instr(max.f16x2))]
#[unstable(feature = "stdarch_nvptx", issue = "111199")]
pub unsafe fn f16x2_max(a: f16x2, b: f16x2) -> f16x2 {
simd_fmax(a, b)
simd_maximum_number_nsz(a, b)
}

/// Find the maximum of two values, NaNs pass through.
Expand Down
14 changes: 7 additions & 7 deletions library/stdarch/crates/core_arch/src/x86/sse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ pub fn _mm_min_ss(a: __m128, b: __m128) -> __m128 {
#[cfg_attr(test, assert_instr(minps))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub fn _mm_min_ps(a: __m128, b: __m128) -> __m128 {
// See the `test_mm_min_ps` test why this can't be implemented using `simd_fmin`.
// See the `test_mm_min_ps` test why this can't be implemented using `simd_minimum_number_nsz`.
unsafe { minps(a, b) }
}

Expand All @@ -234,7 +234,7 @@ pub fn _mm_max_ss(a: __m128, b: __m128) -> __m128 {
#[cfg_attr(test, assert_instr(maxps))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub fn _mm_max_ps(a: __m128, b: __m128) -> __m128 {
// See the `test_mm_min_ps` test why this can't be implemented using `simd_fmax`.
// See the `test_mm_min_ps` test why this can't be implemented using `simd_maximum_number_nsz`.
unsafe { maxps(a, b) }
}

Expand Down Expand Up @@ -2227,11 +2227,11 @@ mod tests {
let r = _mm_min_ps(a, b);
assert_eq_m128(r, _mm_setr_ps(-100.0, 5.0, 0.0, -10.0));

// `_mm_min_ps` can **not** be implemented using the `simd_min` rust intrinsic. `simd_min`
// is lowered by the llvm codegen backend to `llvm.minnum.v*` llvm intrinsic. This intrinsic
// doesn't specify how -0.0 is handled. Unfortunately it happens to behave different from
// the `minps` x86 instruction on x86. The `llvm.minnum.v*` llvm intrinsic equals
// `r1` to `a` and `r2` to `b`.
// `_mm_min_ps` can **not** be implemented using the `simd_minimum_number_nsz` rust
// intrinsic. That intrinsic is lowered by the llvm codegen backend to `llvm.minimumnum.v*`
// llvm intrinsic with the `nsz` attribute. The `nsz` attribute means -0.0 is handled
// non-deterministically. The `minps` x86 instruction however has a deterministic semantics
// for signed zeros.
let a = _mm_setr_ps(-0.0, 0.0, 0.0, 0.0);
let b = _mm_setr_ps(0.0, 0.0, 0.0, 0.0);
let r1 = _mm_min_ps(a, b).as_f32x4().to_bits();
Expand Down
4 changes: 2 additions & 2 deletions src/tools/miri/tests/pass/float_nan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -513,10 +513,10 @@ fn test_simd() {
F32::from(unsafe { simd_div(f32x4::splat(0.0), f32x4::splat(0.0)) }[0])
});
check_all_outcomes([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)], || {
F32::from(unsafe { simd_fmin(f32x4::splat(nan), f32x4::splat(nan)) }[0])
F32::from(unsafe { simd_minimum_number_nsz(f32x4::splat(nan), f32x4::splat(nan)) }[0])
});
check_all_outcomes([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)], || {
F32::from(unsafe { simd_fmax(f32x4::splat(nan), f32x4::splat(nan)) }[0])
F32::from(unsafe { simd_maximum_number_nsz(f32x4::splat(nan), f32x4::splat(nan)) }[0])
});
check_all_outcomes([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)], || {
F32::from(unsafe { simd_fma(f32x4::splat(nan), f32x4::splat(nan), f32x4::splat(nan)) }[0])
Expand Down
16 changes: 8 additions & 8 deletions src/tools/miri/tests/pass/intrinsics/portable-simd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,11 @@ fn simd_ops_f16() {
assert_eq!(simd_rem(a, b), f16x4::from_array([0.0, 0.0, 1.0, 2.0]));
assert_eq!(simd_fabs(b), f16x4::from_array([1.0, 2.0, 3.0, 4.0]));
assert_eq!(
simd_fmax(a, simd_mul(b, f16x4::splat(4.0))),
simd_maximum_number_nsz(a, simd_mul(b, f16x4::splat(4.0))),
f16x4::from_array([10.0, 10.0, 12.0, 10.0])
);
assert_eq!(
simd_fmin(a, simd_mul(b, f16x4::splat(4.0))),
simd_minimum_number_nsz(a, simd_mul(b, f16x4::splat(4.0))),
f16x4::from_array([4.0, 8.0, 10.0, -16.0])
);

Expand Down Expand Up @@ -134,13 +134,13 @@ fn simd_ops_f16() {
assert_eq!(simd_reduce_min(b), -4.0f16);

assert_eq!(
simd_fmax(f16x2::from_array([0.0, f16::NAN]), f16x2::from_array([f16::NAN, 0.0])),
simd_maximum_number_nsz(f16x2::from_array([0.0, f16::NAN]), f16x2::from_array([f16::NAN, 0.0])),
f16x2::from_array([0.0, 0.0])
);
assert_eq!(simd_reduce_max(f16x2::from_array([0.0, f16::NAN])), 0.0f16);
assert_eq!(simd_reduce_max(f16x2::from_array([f16::NAN, 0.0])), 0.0f16);
assert_eq!(
simd_fmin(f16x2::from_array([0.0, f16::NAN]), f16x2::from_array([f16::NAN, 0.0])),
simd_minimum_number_nsz(f16x2::from_array([0.0, f16::NAN]), f16x2::from_array([f16::NAN, 0.0])),
f16x2::from_array([0.0, 0.0])
);
assert_eq!(simd_reduce_min(f16x2::from_array([0.0, f16::NAN])), 0.0f16);
Expand Down Expand Up @@ -304,11 +304,11 @@ fn simd_ops_f128() {
assert_eq!(simd_rem(a, b), f128x4::from_array([0.0, 0.0, 1.0, 2.0]));
assert_eq!(simd_fabs(b), f128x4::from_array([1.0, 2.0, 3.0, 4.0]));
assert_eq!(
simd_fmax(a, simd_mul(b, f128x4::splat(4.0))),
simd_maximum_number_nsz(a, simd_mul(b, f128x4::splat(4.0))),
f128x4::from_array([10.0, 10.0, 12.0, 10.0])
);
assert_eq!(
simd_fmin(a, simd_mul(b, f128x4::splat(4.0))),
simd_minimum_number_nsz(a, simd_mul(b, f128x4::splat(4.0))),
f128x4::from_array([4.0, 8.0, 10.0, -16.0])
);

Expand Down Expand Up @@ -348,13 +348,13 @@ fn simd_ops_f128() {
assert_eq!(simd_reduce_min(b), -4.0f128);

assert_eq!(
simd_fmax(f128x2::from_array([0.0, f128::NAN]), f128x2::from_array([f128::NAN, 0.0])),
simd_maximum_number_nsz(f128x2::from_array([0.0, f128::NAN]), f128x2::from_array([f128::NAN, 0.0])),
f128x2::from_array([0.0, 0.0])
);
assert_eq!(simd_reduce_max(f128x2::from_array([0.0, f128::NAN])), 0.0f128);
assert_eq!(simd_reduce_max(f128x2::from_array([f128::NAN, 0.0])), 0.0f128);
assert_eq!(
simd_fmin(f128x2::from_array([0.0, f128::NAN]), f128x2::from_array([f128::NAN, 0.0])),
simd_minimum_number_nsz(f128x2::from_array([0.0, f128::NAN]), f128x2::from_array([f128::NAN, 0.0])),
f128x2::from_array([0.0, 0.0])
);
assert_eq!(simd_reduce_min(f128x2::from_array([0.0, f128::NAN])), 0.0f128);
Expand Down
10 changes: 5 additions & 5 deletions tests/codegen-llvm/simd-intrinsic/simd-intrinsic-float-minmax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,18 @@
mod minisimd;
use minisimd::*;

use std::intrinsics::simd::{simd_fmax, simd_fmin};
use std::intrinsics::simd::*;

// CHECK-LABEL: @fmin
#[no_mangle]
pub unsafe fn fmin(a: f32x4, b: f32x4) -> f32x4 {
// CHECK: call <4 x float> @llvm.minnum.v4f32
simd_fmin(a, b)
// CHECK: call nsz <4 x float> @llvm.minimumnum.v4f32
simd_minimum_number_nsz(a, b)
}

// CHECK-LABEL: @fmax
#[no_mangle]
pub unsafe fn fmax(a: f32x4, b: f32x4) -> f32x4 {
// CHECK: call <4 x float> @llvm.maxnum.v4f32
simd_fmax(a, b)
// CHECK: call nsz <4 x float> @llvm.maximumnum.v4f32
simd_maximum_number_nsz(a, b)
}
Loading
Loading