diff --git a/llvm/lib/Target/VE/VEISelLowering.cpp b/llvm/lib/Target/VE/VEISelLowering.cpp --- a/llvm/lib/Target/VE/VEISelLowering.cpp +++ b/llvm/lib/Target/VE/VEISelLowering.cpp @@ -249,6 +249,11 @@ setOperationAction(ISD::FSQRT, VT, Expand); } + // VE has single and double FMINNUM and FMAXNUM + for (MVT VT : {MVT::f32, MVT::f64}) { + setOperationAction({ISD::FMAXNUM, ISD::FMINNUM}, VT, Legal); + } + /// } Floating-point math functions /// Atomic instructions { diff --git a/llvm/test/CodeGen/VE/Scalar/maxnum.ll b/llvm/test/CodeGen/VE/Scalar/maxnum.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/VE/Scalar/maxnum.ll @@ -0,0 +1,162 @@ +; RUN: llc < %s -mtriple=ve | FileCheck %s + +;;; Test ‘llvm.maxnum.*’ intrinsic +;;; +;;; Syntax: +;;; This is an overloaded intrinsic. You can use llvm.maxnum on any +;;; floating-point or vector of floating-point type. Not all targets +;;; support all types however. +;;; +;;; declare float @llvm.maxnum.f32(float %Val0, float %Val1) +;;; declare double @llvm.maxnum.f64(double %Val0, double %Val1) +;;; declare x86_fp80 @llvm.maxnum.f80(x86_fp80 %Val0, x86_fp80 %Val1) +;;; declare fp128 @llvm.maxnum.f128(fp128 %Val0, fp128 %Val1) +;;; declare ppc_fp128 @llvm.maxnum.ppcf128(ppc_fp128 %Val0, ppc_fp128 %Val1) +;;; +;;; Overview: +;;; The ‘llvm.maxnum.*’ intrinsics return the maximum of the two arguments. +;;; +;;; Arguments: +;;; The arguments and return value are floating-point numbers of the same +;;; type. +;;; +;;; Semantics: +;;; Follows the IEEE-754 semantics for maxNum except for the handling of +;;; signaling NaNs. This matches the behavior of libm’s fmax. +;;; +;;; If either operand is a NaN, returns the other non-NaN operand. +;;; Returns NaN only if both operands are NaN. The returned NaN is +;;; always quiet. If the operands compare equal, returns a value +;;; that compares equal to both operands. This means that +;;; fmax(+/-0.0, +/-0.0) could return either -0.0 or 0.0. +;;; +;;; Unlike the IEEE-754 2008 behavior, this does not distinguish between +;;; signaling and quiet NaN inputs. If a target’s implementation follows +;;; the standard and returns a quiet NaN if either input is a signaling +;;; NaN, the intrinsic lowering is responsible for quieting the inputs +;;; to correctly return the non-NaN input (e.g. by using the equivalent +;;; of llvm.canonicalize). +;;; +;;; Note: +;;; We test only float/double/fp128. + +; Function Attrs: mustprogress nofree nosync nounwind readnone willreturn +define float @func_fp_fmax_var_float(float noundef %0, float noundef %1) { +; CHECK-LABEL: func_fp_fmax_var_float: +; CHECK: # %bb.0: +; CHECK-NEXT: fmax.s %s0, %s0, %s1 +; CHECK-NEXT: b.l.t (, %s10) + %3 = tail call fast float @llvm.maxnum.f32(float %0, float %1) + ret float %3 +} + +; Function Attrs: mustprogress nocallback nofree nosync nounwind readnone speculatable willreturn +declare float @llvm.maxnum.f32(float, float) + +; Function Attrs: mustprogress nofree nosync nounwind readnone willreturn +define double @func_fp_fmax_var_double(double noundef %0, double noundef %1) { +; CHECK-LABEL: func_fp_fmax_var_double: +; CHECK: # %bb.0: +; CHECK-NEXT: fmax.d %s0, %s0, %s1 +; CHECK-NEXT: b.l.t (, %s10) + %3 = tail call fast double @llvm.maxnum.f64(double %0, double %1) + ret double %3 +} + +; Function Attrs: mustprogress nocallback nofree nosync nounwind readnone speculatable willreturn +declare double @llvm.maxnum.f64(double, double) + +; Function Attrs: mustprogress nofree nosync nounwind readnone willreturn +define fp128 @func_fp_fmax_var_quad(fp128 noundef %0, fp128 noundef %1) { +; CHECK-LABEL: func_fp_fmax_var_quad: +; CHECK: # %bb.0: +; CHECK-NEXT: fcmp.q %s4, %s0, %s2 +; CHECK-NEXT: cmov.d.gt %s2, %s0, %s4 +; CHECK-NEXT: cmov.d.gt %s3, %s1, %s4 +; CHECK-NEXT: or %s0, 0, %s2 +; CHECK-NEXT: or %s1, 0, %s3 +; CHECK-NEXT: b.l.t (, %s10) + %3 = tail call fast fp128 @llvm.maxnum.f128(fp128 %0, fp128 %1) + ret fp128 %3 +} + +; Function Attrs: mustprogress nocallback nofree nosync nounwind readnone speculatable willreturn +declare fp128 @llvm.maxnum.f128(fp128, fp128) + +; Function Attrs: mustprogress nofree nosync nounwind readnone willreturn +define float @func_fp_fmax_zero_float(float noundef %0) { +; CHECK-LABEL: func_fp_fmax_zero_float: +; CHECK: # %bb.0: +; CHECK-NEXT: fmax.s %s0, %s0, (0)1 +; CHECK-NEXT: b.l.t (, %s10) + %2 = tail call fast float @llvm.maxnum.f32(float %0, float 0.000000e+00) + ret float %2 +} + +; Function Attrs: mustprogress nofree nosync nounwind readnone willreturn +define double @func_fp_fmax_zero_double(double noundef %0) { +; CHECK-LABEL: func_fp_fmax_zero_double: +; CHECK: # %bb.0: +; CHECK-NEXT: fmax.d %s0, %s0, (0)1 +; CHECK-NEXT: b.l.t (, %s10) + %2 = tail call fast double @llvm.maxnum.f64(double %0, double 0.000000e+00) + ret double %2 +} + +; Function Attrs: mustprogress nofree nosync nounwind readnone willreturn +define fp128 @func_fp_fmax_zero_quad(fp128 noundef %0) { +; CHECK-LABEL: func_fp_fmax_zero_quad: +; CHECK: # %bb.0: +; CHECK-NEXT: lea %s2, .LCPI{{[0-9]+}}_0@lo +; CHECK-NEXT: and %s2, %s2, (32)0 +; CHECK-NEXT: lea.sl %s4, .LCPI{{[0-9]+}}_0@hi(, %s2) +; CHECK-NEXT: ld %s2, 8(, %s4) +; CHECK-NEXT: ld %s3, (, %s4) +; CHECK-NEXT: fcmp.q %s4, %s0, %s2 +; CHECK-NEXT: cmov.d.gt %s2, %s0, %s4 +; CHECK-NEXT: cmov.d.gt %s3, %s1, %s4 +; CHECK-NEXT: or %s0, 0, %s2 +; CHECK-NEXT: or %s1, 0, %s3 +; CHECK-NEXT: b.l.t (, %s10) + %2 = tail call fast fp128 @llvm.maxnum.f128(fp128 %0, fp128 0xL00000000000000000000000000000000) + ret fp128 %2 +} + +; Function Attrs: mustprogress nofree nosync nounwind readnone willreturn +define float @func_fp_fmax_const_float(float noundef %0) { +; CHECK-LABEL: func_fp_fmax_const_float: +; CHECK: # %bb.0: +; CHECK-NEXT: fmax.s %s0, %s0, (2)1 +; CHECK-NEXT: b.l.t (, %s10) + %2 = tail call fast float @llvm.maxnum.f32(float %0, float -2.000000e+00) + ret float %2 +} + +; Function Attrs: mustprogress nofree nosync nounwind readnone willreturn +define double @func_fp_fmax_const_double(double noundef %0) { +; CHECK-LABEL: func_fp_fmax_const_double: +; CHECK: # %bb.0: +; CHECK-NEXT: fmax.d %s0, %s0, (2)1 +; CHECK-NEXT: b.l.t (, %s10) + %2 = tail call fast double @llvm.maxnum.f64(double %0, double -2.000000e+00) + ret double %2 +} + +; Function Attrs: mustprogress nofree nosync nounwind readnone willreturn +define fp128 @func_fp_fmax_const_quad(fp128 noundef %0) { +; CHECK-LABEL: func_fp_fmax_const_quad: +; CHECK: # %bb.0: +; CHECK-NEXT: lea %s2, .LCPI{{[0-9]+}}_0@lo +; CHECK-NEXT: and %s2, %s2, (32)0 +; CHECK-NEXT: lea.sl %s4, .LCPI{{[0-9]+}}_0@hi(, %s2) +; CHECK-NEXT: ld %s2, 8(, %s4) +; CHECK-NEXT: ld %s3, (, %s4) +; CHECK-NEXT: fcmp.q %s4, %s0, %s2 +; CHECK-NEXT: cmov.d.gt %s2, %s0, %s4 +; CHECK-NEXT: cmov.d.gt %s3, %s1, %s4 +; CHECK-NEXT: or %s0, 0, %s2 +; CHECK-NEXT: or %s1, 0, %s3 +; CHECK-NEXT: b.l.t (, %s10) + %2 = tail call fast fp128 @llvm.maxnum.f128(fp128 %0, fp128 0xL0000000000000000C000000000000000) + ret fp128 %2 +} diff --git a/llvm/test/CodeGen/VE/Scalar/minnum.ll b/llvm/test/CodeGen/VE/Scalar/minnum.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/VE/Scalar/minnum.ll @@ -0,0 +1,162 @@ +; RUN: llc < %s -mtriple=ve | FileCheck %s + +;;; Test ‘llvm.minnum.*’ intrinsic +;;; +;;; Syntax: +;;; This is an overloaded intrinsic. You can use llvm.minnum on any +;;; floating-point or vector of floating-point type. Not all targets +;;; support all types however. +;;; +;;; declare float @llvm.minnum.f32(float %Val0, float %Val1) +;;; declare double @llvm.minnum.f64(double %Val0, double %Val1) +;;; declare x86_fp80 @llvm.minnum.f80(x86_fp80 %Val0, x86_fp80 %Val1) +;;; declare fp128 @llvm.minnum.f128(fp128 %Val0, fp128 %Val1) +;;; declare ppc_fp128 @llvm.minnum.ppcf128(ppc_fp128 %Val0, ppc_fp128 %Val1) +;;; +;;; Overview: +;;; The ‘llvm.minnum.*’ intrinsics return the minimum of the two arguments. +;;; +;;; Arguments: +;;; The arguments and return value are floating-point numbers of the same +;;; type. +;;; +;;; Semantics: +;;; Follows the IEEE-754 semantics for minNum, except for handling of +;;; signaling NaNs. This match’s the behavior of libm’s fmin. +;;; +;;; If either operand is a NaN, returns the other non-NaN operand. +;;; Returns NaN only if both operands are NaN. The returned NaN is +;;; always quiet. If the operands compare equal, returns a value +;;; that compares equal to both operands. This means that +;;; fmin(+/-0.0, +/-0.0) could return either -0.0 or 0.0. +;;; +;;; Unlike the IEEE-754 2008 behavior, this does not distinguish between +;;; signaling and quiet NaN inputs. If a target’s implementation follows +;;; the standard and returns a quiet NaN if either input is a signaling +;;; NaN, the intrinsic lowering is responsible for quieting the inputs +;;; to correctly return the non-NaN input (e.g. by using the equivalent +;;; of llvm.canonicalize). +;;; +;;; Note: +;;; We test only float/double/fp128. + +; Function Attrs: mustprogress nofree nosync nounwind readnone willreturn +define float @func_fp_fmin_var_float(float noundef %0, float noundef %1) { +; CHECK-LABEL: func_fp_fmin_var_float: +; CHECK: # %bb.0: +; CHECK-NEXT: fmin.s %s0, %s0, %s1 +; CHECK-NEXT: b.l.t (, %s10) + %3 = tail call fast float @llvm.minnum.f32(float %0, float %1) + ret float %3 +} + +; Function Attrs: mustprogress nocallback nofree nosync nounwind readnone speculatable willreturn +declare float @llvm.minnum.f32(float, float) + +; Function Attrs: mustprogress nofree nosync nounwind readnone willreturn +define double @func_fp_fmin_var_double(double noundef %0, double noundef %1) { +; CHECK-LABEL: func_fp_fmin_var_double: +; CHECK: # %bb.0: +; CHECK-NEXT: fmin.d %s0, %s0, %s1 +; CHECK-NEXT: b.l.t (, %s10) + %3 = tail call fast double @llvm.minnum.f64(double %0, double %1) + ret double %3 +} + +; Function Attrs: mustprogress nocallback nofree nosync nounwind readnone speculatable willreturn +declare double @llvm.minnum.f64(double, double) + +; Function Attrs: mustprogress nofree nosync nounwind readnone willreturn +define fp128 @func_fp_fmin_var_quad(fp128 noundef %0, fp128 noundef %1) { +; CHECK-LABEL: func_fp_fmin_var_quad: +; CHECK: # %bb.0: +; CHECK-NEXT: fcmp.q %s4, %s0, %s2 +; CHECK-NEXT: cmov.d.lt %s2, %s0, %s4 +; CHECK-NEXT: cmov.d.lt %s3, %s1, %s4 +; CHECK-NEXT: or %s0, 0, %s2 +; CHECK-NEXT: or %s1, 0, %s3 +; CHECK-NEXT: b.l.t (, %s10) + %3 = tail call fast fp128 @llvm.minnum.f128(fp128 %0, fp128 %1) + ret fp128 %3 +} + +; Function Attrs: mustprogress nocallback nofree nosync nounwind readnone speculatable willreturn +declare fp128 @llvm.minnum.f128(fp128, fp128) + +; Function Attrs: mustprogress nofree nosync nounwind readnone willreturn +define float @func_fp_fmin_zero_float(float noundef %0) { +; CHECK-LABEL: func_fp_fmin_zero_float: +; CHECK: # %bb.0: +; CHECK-NEXT: fmin.s %s0, %s0, (0)1 +; CHECK-NEXT: b.l.t (, %s10) + %2 = tail call fast float @llvm.minnum.f32(float %0, float 0.000000e+00) + ret float %2 +} + +; Function Attrs: mustprogress nofree nosync nounwind readnone willreturn +define double @func_fp_fmin_zero_double(double noundef %0) { +; CHECK-LABEL: func_fp_fmin_zero_double: +; CHECK: # %bb.0: +; CHECK-NEXT: fmin.d %s0, %s0, (0)1 +; CHECK-NEXT: b.l.t (, %s10) + %2 = tail call fast double @llvm.minnum.f64(double %0, double 0.000000e+00) + ret double %2 +} + +; Function Attrs: mustprogress nofree nosync nounwind readnone willreturn +define fp128 @func_fp_fmin_zero_quad(fp128 noundef %0) { +; CHECK-LABEL: func_fp_fmin_zero_quad: +; CHECK: # %bb.0: +; CHECK-NEXT: lea %s2, .LCPI{{[0-9]+}}_0@lo +; CHECK-NEXT: and %s2, %s2, (32)0 +; CHECK-NEXT: lea.sl %s4, .LCPI{{[0-9]+}}_0@hi(, %s2) +; CHECK-NEXT: ld %s2, 8(, %s4) +; CHECK-NEXT: ld %s3, (, %s4) +; CHECK-NEXT: fcmp.q %s4, %s0, %s2 +; CHECK-NEXT: cmov.d.lt %s2, %s0, %s4 +; CHECK-NEXT: cmov.d.lt %s3, %s1, %s4 +; CHECK-NEXT: or %s0, 0, %s2 +; CHECK-NEXT: or %s1, 0, %s3 +; CHECK-NEXT: b.l.t (, %s10) + %2 = tail call fast fp128 @llvm.minnum.f128(fp128 %0, fp128 0xL00000000000000000000000000000000) + ret fp128 %2 +} + +; Function Attrs: mustprogress nofree nosync nounwind readnone willreturn +define float @func_fp_fmin_const_float(float noundef %0) { +; CHECK-LABEL: func_fp_fmin_const_float: +; CHECK: # %bb.0: +; CHECK-NEXT: fmin.s %s0, %s0, (2)1 +; CHECK-NEXT: b.l.t (, %s10) + %2 = tail call fast float @llvm.minnum.f32(float %0, float -2.000000e+00) + ret float %2 +} + +; Function Attrs: mustprogress nofree nosync nounwind readnone willreturn +define double @func_fp_fmin_const_double(double noundef %0) { +; CHECK-LABEL: func_fp_fmin_const_double: +; CHECK: # %bb.0: +; CHECK-NEXT: fmin.d %s0, %s0, (2)1 +; CHECK-NEXT: b.l.t (, %s10) + %2 = tail call fast double @llvm.minnum.f64(double %0, double -2.000000e+00) + ret double %2 +} + +; Function Attrs: mustprogress nofree nosync nounwind readnone willreturn +define fp128 @func_fp_fmin_const_quad(fp128 noundef %0) { +; CHECK-LABEL: func_fp_fmin_const_quad: +; CHECK: # %bb.0: +; CHECK-NEXT: lea %s2, .LCPI{{[0-9]+}}_0@lo +; CHECK-NEXT: and %s2, %s2, (32)0 +; CHECK-NEXT: lea.sl %s4, .LCPI{{[0-9]+}}_0@hi(, %s2) +; CHECK-NEXT: ld %s2, 8(, %s4) +; CHECK-NEXT: ld %s3, (, %s4) +; CHECK-NEXT: fcmp.q %s4, %s0, %s2 +; CHECK-NEXT: cmov.d.lt %s2, %s0, %s4 +; CHECK-NEXT: cmov.d.lt %s3, %s1, %s4 +; CHECK-NEXT: or %s0, 0, %s2 +; CHECK-NEXT: or %s1, 0, %s3 +; CHECK-NEXT: b.l.t (, %s10) + %2 = tail call fast fp128 @llvm.minnum.f128(fp128 %0, fp128 0xL0000000000000000C000000000000000) + ret fp128 %2 +}