From 51cc8a7d2da7d0e1cae0613f7d6bc1d2fd70af5c Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 10 Nov 2015 21:40:21 +0000 Subject: [PATCH] [WebAssembly] Support for floating point min and max. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@252653 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../WebAssembly/WebAssemblyISelLowering.cpp | 3 +++ .../WebAssembly/WebAssemblyInstrFloat.td | 10 +++----- test/CodeGen/WebAssembly/f32.ll | 24 +++++++++++++++++++ test/CodeGen/WebAssembly/f64.ll | 24 +++++++++++++++++++ 4 files changed, 54 insertions(+), 7 deletions(-) diff --git a/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp index baf5b2554bb..d813367ea85 100644 --- a/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -132,6 +132,9 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering( 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}) { diff --git a/lib/Target/WebAssembly/WebAssemblyInstrFloat.td b/lib/Target/WebAssembly/WebAssemblyInstrFloat.td index 689aeac6291..232af03464a 100644 --- a/lib/Target/WebAssembly/WebAssemblyInstrFloat.td +++ b/lib/Target/WebAssembly/WebAssemblyInstrFloat.td @@ -22,6 +22,9 @@ defm ABS : UnaryFP; defm NEG : UnaryFP; defm COPYSIGN : BinaryFP; +defm MIN : BinaryFP; +defm MAX : BinaryFP; + defm CEIL : UnaryFP; defm FLOOR : UnaryFP; defm TRUNC : UnaryFP; @@ -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)>; -/* - * 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">; diff --git a/test/CodeGen/WebAssembly/f32.ll b/test/CodeGen/WebAssembly/f32.ll index 1c780819a08..3ae35880d0e 100644 --- a/test/CodeGen/WebAssembly/f32.ll +++ b/test/CodeGen/WebAssembly/f32.ll @@ -126,3 +126,27 @@ define float @nearest32_via_rint(float %x) { %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 +} diff --git a/test/CodeGen/WebAssembly/f64.ll b/test/CodeGen/WebAssembly/f64.ll index 7f0578d811b..d5f6f3e7fe3 100644 --- a/test/CodeGen/WebAssembly/f64.ll +++ b/test/CodeGen/WebAssembly/f64.ll @@ -126,3 +126,27 @@ define double @nearest64_via_rint(double %x) { %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 +} -- 2.34.1