[WebAssembly] Support for floating point min and max.
authorDan Gohman <dan433584@gmail.com>
Tue, 10 Nov 2015 21:40:21 +0000 (21:40 +0000)
committerDan Gohman <dan433584@gmail.com>
Tue, 10 Nov 2015 21:40:21 +0000 (21:40 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@252653 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
lib/Target/WebAssembly/WebAssemblyInstrFloat.td
test/CodeGen/WebAssembly/f32.ll
test/CodeGen/WebAssembly/f64.ll

index baf5b2554bba67c21a4a8bca26747e977242e9ee..d813367ea85a9ccc4739fc4fd05e44e4bb9703e9 100644 (file)
@@ -132,6 +132,9 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering(
     for (auto Op : {ISD::FCEIL, ISD::FFLOOR, ISD::FTRUNC, ISD::FNEARBYINT,
                     ISD::FRINT})
       setOperationAction(Op, T, Legal);
     for (auto Op : {ISD::FCEIL, ISD::FFLOOR, ISD::FTRUNC, ISD::FNEARBYINT,
                     ISD::FRINT})
       setOperationAction(Op, T, Legal);
+    // Support minnan and maxnan, which otherwise default to expand.
+    setOperationAction(ISD::FMINNAN, T, Legal);
+    setOperationAction(ISD::FMAXNAN, T, Legal);
   }
 
   for (auto T : {MVT::i32, MVT::i64}) {
   }
 
   for (auto T : {MVT::i32, MVT::i64}) {
index 689aeac62918ba8d6549705460f6c839713a029e..232af03464acd226d79ab87557ac9c9efe5a6a1b 100644 (file)
@@ -22,6 +22,9 @@ defm ABS : UnaryFP<fabs, "abs">;
 defm NEG : UnaryFP<fneg, "neg">;
 defm COPYSIGN : BinaryFP<fcopysign, "copysign">;
 
 defm NEG : UnaryFP<fneg, "neg">;
 defm COPYSIGN : BinaryFP<fcopysign, "copysign">;
 
+defm MIN : BinaryFP<fminnan, "min">;
+defm MAX : BinaryFP<fmaxnan, "max">;
+
 defm CEIL : UnaryFP<fceil, "ceil">;
 defm FLOOR : UnaryFP<ffloor, "floor">;
 defm TRUNC : UnaryFP<ftrunc, "trunc">;
 defm CEIL : UnaryFP<fceil, "ceil">;
 defm FLOOR : UnaryFP<ffloor, "floor">;
 defm TRUNC : UnaryFP<ftrunc, "trunc">;
@@ -52,13 +55,6 @@ def : Pat<(setle f64:$lhs, f64:$rhs), (LE_F64 f64:$lhs, f64:$rhs)>;
 def : Pat<(setgt f64:$lhs, f64:$rhs), (GT_F64 f64:$lhs, f64:$rhs)>;
 def : Pat<(setge f64:$lhs, f64:$rhs), (GE_F64 f64:$lhs, f64:$rhs)>;
 
 def : Pat<(setgt f64:$lhs, f64:$rhs), (GT_F64 f64:$lhs, f64:$rhs)>;
 def : Pat<(setge f64:$lhs, f64:$rhs), (GE_F64 f64:$lhs, f64:$rhs)>;
 
-/*
- * TODO(jfb): Add the following for 32-bit and 64-bit.
- *
- * f32.min: minimum (binary operator); if either operand is NaN, returns NaN
- * f32.max: maximum (binary operator); if either operand is NaN, returns NaN
- */
-
 def SELECT_F32 : I<(outs F32:$dst), (ins I32:$cond, F32:$lhs, F32:$rhs),
                    [(set F32:$dst, (select I32:$cond, F32:$lhs, F32:$rhs))],
                    "f32.select $dst, $cond, $lhs, $rhs">;
 def SELECT_F32 : I<(outs F32:$dst), (ins I32:$cond, F32:$lhs, F32:$rhs),
                    [(set F32:$dst, (select I32:$cond, F32:$lhs, F32:$rhs))],
                    "f32.select $dst, $cond, $lhs, $rhs">;
index 1c780819a0836a40fb469327882fbb0d106a6ca8..3ae35880d0e369af092dd27793077566f535cc7c 100644 (file)
@@ -126,3 +126,27 @@ define float @nearest32_via_rint(float %x) {
   %a = call float @llvm.rint.f32(float %x)
   ret float %a
 }
   %a = call float @llvm.rint.f32(float %x)
   ret float %a
 }
+
+; Min and max tests. LLVM currently only forms fminnan and fmaxnan nodes in
+; cases where there's a single fcmp with a select and it can prove that one
+; of the arms is never NaN, so we only test that case. In the future if LLVM
+; learns to form fminnan/fmaxnan in more cases, we can write more general
+; tests.
+
+; CHECK-LABEL: fmin32:
+; CHECK: f32.min push, (get_local 1), (get_local 2){{$}}
+; CHECK-NEXT: set_local 3, pop{{$}}
+define float @fmin32(float %x) {
+  %a = fcmp ult float %x, 0.0
+  %b = select i1 %a, float %x, float 0.0
+  ret float %b
+}
+
+; CHECK-LABEL: fmax32:
+; CHECK: f32.max push, (get_local 1), (get_local 2){{$}}
+; CHECK-NEXT: set_local 3, pop{{$}}
+define float @fmax32(float %x) {
+  %a = fcmp ugt float %x, 0.0
+  %b = select i1 %a, float %x, float 0.0
+  ret float %b
+}
index 7f0578d811bd74fd3d5c64ebface2d1cffd17cdc..d5f6f3e7fe383d0da9946ea1af0fb3d5a33ca5da 100644 (file)
@@ -126,3 +126,27 @@ define double @nearest64_via_rint(double %x) {
   %a = call double @llvm.rint.f64(double %x)
   ret double %a
 }
   %a = call double @llvm.rint.f64(double %x)
   ret double %a
 }
+
+; Min and max tests. LLVM currently only forms fminnan and fmaxnan nodes in
+; cases where there's a single fcmp with a select and it can prove that one
+; of the arms is never NaN, so we only test that case. In the future if LLVM
+; learns to form fminnan/fmaxnan in more cases, we can write more general
+; tests.
+
+; CHECK-LABEL: fmin64:
+; CHECK: f64.min push, (get_local 1), (get_local 2){{$}}
+; CHECK-NEXT: set_local 3, pop{{$}}
+define double @fmin64(double %x) {
+  %a = fcmp ult double %x, 0.0
+  %b = select i1 %a, double %x, double 0.0
+  ret double %b
+}
+
+; CHECK-LABEL: fmax64:
+; CHECK: f64.max push, (get_local 1), (get_local 2){{$}}
+; CHECK-NEXT: set_local 3, pop{{$}}
+define double @fmax64(double %x) {
+  %a = fcmp ugt double %x, 0.0
+  %b = select i1 %a, double %x, double 0.0
+  ret double %b
+}