[llvm] 1e9b6b8 - [InstCombine] convert FP min/max with negated op to fabs

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 23 07:42:49 PDT 2021


Author: Sanjay Patel
Date: 2021-06-23T10:41:39-04:00
New Revision: 1e9b6b89a7b5c49612018b120c2c142106056f82

URL: https://github.com/llvm/llvm-project/commit/1e9b6b89a7b5c49612018b120c2c142106056f82
DIFF: https://github.com/llvm/llvm-project/commit/1e9b6b89a7b5c49612018b120c2c142106056f82.diff

LOG: [InstCombine] convert FP min/max with negated op to fabs

This is part of improving floating-point patterns seen in:
https://llvm.org/PR39480

We don't require any FMF because the 2 potential corner cases
(-0.0 and NaN) are correctly handled without FMF:
1. -0.0 is treated as strictly less than +0.0 with
   maximum/minimum, so fabs/fneg work as expected.
2. +/- 0.0 with maxnum/minnum is indeterminate, so
   transforming to fabs/fneg is more defined.
3. The sign of a NaN may be altered by this transform,
   but that is allowed in the default FP environment.

If there are FMF, they are propagated from the min/max call to
one or both new operands which seems to agree with Alive2:
https://alive2.llvm.org/ce/z/bem_xC

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
    llvm/test/Transforms/InstCombine/maximum.ll
    llvm/test/Transforms/InstCombine/maxnum.ll
    llvm/test/Transforms/InstCombine/minimum.ll
    llvm/test/Transforms/InstCombine/minnum.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index d5aa3b69fe74..e211b42747dd 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -1376,6 +1376,19 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
       return new FPExtInst(NewCall, II->getType());
     }
 
+    // max X, -X --> fabs X
+    // min X, -X --> -(fabs X)
+    // TODO: Remove one-use limitation? That is obviously better for max.
+    //       It would be an extra instruction for min (fnabs), but that is
+    //       still likely better for analysis and codegen.
+    if ((match(Arg0, m_OneUse(m_FNeg(m_Value(X)))) && Arg1 == X) ||
+        (match(Arg1, m_OneUse(m_FNeg(m_Value(X)))) && Arg0 == X)) {
+      Value *R = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, X, II);
+      if (IID == Intrinsic::minimum || IID == Intrinsic::minnum)
+        R = Builder.CreateFNegFMF(R, II);
+      return replaceInstUsesWith(*II, R);
+    }
+
     break;
   }
   case Intrinsic::fmuladd: {

diff  --git a/llvm/test/Transforms/InstCombine/maximum.ll b/llvm/test/Transforms/InstCombine/maximum.ll
index 70bf6a922857..1b34a084fe1e 100644
--- a/llvm/test/Transforms/InstCombine/maximum.ll
+++ b/llvm/test/Transforms/InstCombine/maximum.ll
@@ -414,9 +414,8 @@ define float @reduce_precision_fmf(float %x, float %y) {
 
 define float @negated_op(float %x) {
 ; CHECK-LABEL: @negated_op(
-; CHECK-NEXT:    [[NEGX:%.*]] = fneg float [[X:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = call float @llvm.maximum.f32(float [[X]], float [[NEGX]])
-; CHECK-NEXT:    ret float [[R]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
+; CHECK-NEXT:    ret float [[TMP1]]
 ;
   %negx = fneg float %x
   %r = call float @llvm.maximum.f32(float %x, float %negx)
@@ -425,9 +424,8 @@ define float @negated_op(float %x) {
 
 define <2 x double> @negated_op_fmf_commute_vec(<2 x double> %x) {
 ; CHECK-LABEL: @negated_op_fmf_commute_vec(
-; CHECK-NEXT:    [[NEGX:%.*]] = fneg <2 x double> [[X:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = call nnan ninf nsz <2 x double> @llvm.maximum.v2f64(<2 x double> [[NEGX]], <2 x double> [[X]])
-; CHECK-NEXT:    ret <2 x double> [[R]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call nnan ninf nsz <2 x double> @llvm.fabs.v2f64(<2 x double> [[X:%.*]])
+; CHECK-NEXT:    ret <2 x double> [[TMP1]]
 ;
   %negx = fneg <2 x double> %x
   %r = call nsz nnan ninf <2 x double> @llvm.maximum.v2f64(<2 x double> %negx, <2 x double> %x)

diff  --git a/llvm/test/Transforms/InstCombine/maxnum.ll b/llvm/test/Transforms/InstCombine/maxnum.ll
index f7e7a3cb9f0e..a43f0aeb268a 100644
--- a/llvm/test/Transforms/InstCombine/maxnum.ll
+++ b/llvm/test/Transforms/InstCombine/maxnum.ll
@@ -436,9 +436,8 @@ define float @reduce_precision_multi_use_1(float %x, float %y) {
 
 define float @negated_op(float %x) {
 ; CHECK-LABEL: @negated_op(
-; CHECK-NEXT:    [[NEGX:%.*]] = fneg float [[X:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = call float @llvm.maxnum.f32(float [[NEGX]], float [[X]])
-; CHECK-NEXT:    ret float [[R]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
+; CHECK-NEXT:    ret float [[TMP1]]
 ;
   %negx = fneg float %x
   %r = call float @llvm.maxnum.f32(float %negx, float %x)
@@ -447,9 +446,8 @@ define float @negated_op(float %x) {
 
 define <2 x double> @negated_op_fmf_commute_vec(<2 x double> %x) {
 ; CHECK-LABEL: @negated_op_fmf_commute_vec(
-; CHECK-NEXT:    [[NEGX:%.*]] = fneg <2 x double> [[X:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = call nnan ninf nsz <2 x double> @llvm.maxnum.v2f64(<2 x double> [[X]], <2 x double> [[NEGX]])
-; CHECK-NEXT:    ret <2 x double> [[R]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call nnan ninf nsz <2 x double> @llvm.fabs.v2f64(<2 x double> [[X:%.*]])
+; CHECK-NEXT:    ret <2 x double> [[TMP1]]
 ;
   %negx = fneg <2 x double> %x
   %r = call nsz nnan ninf <2 x double> @llvm.maxnum.v2f64(<2 x double> %x, <2 x double> %negx)

diff  --git a/llvm/test/Transforms/InstCombine/minimum.ll b/llvm/test/Transforms/InstCombine/minimum.ll
index 2c12792713b7..635b9ec8dd8d 100644
--- a/llvm/test/Transforms/InstCombine/minimum.ll
+++ b/llvm/test/Transforms/InstCombine/minimum.ll
@@ -439,9 +439,9 @@ define float @reduce_precision_fmf(float %x, float %y) {
 
 define float @negated_op(float %x) {
 ; CHECK-LABEL: @negated_op(
-; CHECK-NEXT:    [[NEGX:%.*]] = fneg float [[X:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = call float @llvm.minimum.f32(float [[X]], float [[NEGX]])
-; CHECK-NEXT:    ret float [[R]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
+; CHECK-NEXT:    [[TMP2:%.*]] = fneg float [[TMP1]]
+; CHECK-NEXT:    ret float [[TMP2]]
 ;
   %negx = fneg float %x
   %r = call float @llvm.minimum.f32(float %x, float %negx)
@@ -450,9 +450,9 @@ define float @negated_op(float %x) {
 
 define <2 x double> @negated_op_fmf_commute_vec(<2 x double> %x) {
 ; CHECK-LABEL: @negated_op_fmf_commute_vec(
-; CHECK-NEXT:    [[NEGX:%.*]] = fneg <2 x double> [[X:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = call nnan ninf nsz <2 x double> @llvm.minimum.v2f64(<2 x double> [[NEGX]], <2 x double> [[X]])
-; CHECK-NEXT:    ret <2 x double> [[R]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call nnan ninf nsz <2 x double> @llvm.fabs.v2f64(<2 x double> [[X:%.*]])
+; CHECK-NEXT:    [[TMP2:%.*]] = fneg nnan ninf nsz <2 x double> [[TMP1]]
+; CHECK-NEXT:    ret <2 x double> [[TMP2]]
 ;
   %negx = fneg <2 x double> %x
   %r = call nsz nnan ninf <2 x double> @llvm.minimum.v2f64(<2 x double> %negx, <2 x double> %x)

diff  --git a/llvm/test/Transforms/InstCombine/minnum.ll b/llvm/test/Transforms/InstCombine/minnum.ll
index ccae0957a0e3..621c05de7630 100644
--- a/llvm/test/Transforms/InstCombine/minnum.ll
+++ b/llvm/test/Transforms/InstCombine/minnum.ll
@@ -473,9 +473,9 @@ define float @reduce_precision_multi_use_1(float %x, float %y) {
 
 define float @negated_op(float %x) {
 ; CHECK-LABEL: @negated_op(
-; CHECK-NEXT:    [[NEGX:%.*]] = fneg float [[X:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = call float @llvm.minnum.f32(float [[X]], float [[NEGX]])
-; CHECK-NEXT:    ret float [[R]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
+; CHECK-NEXT:    [[TMP2:%.*]] = fneg float [[TMP1]]
+; CHECK-NEXT:    ret float [[TMP2]]
 ;
   %negx = fneg float %x
   %r = call float @llvm.minnum.f32(float %x, float %negx)
@@ -484,9 +484,9 @@ define float @negated_op(float %x) {
 
 define <2 x double> @negated_op_fmf_commute_vec(<2 x double> %x) {
 ; CHECK-LABEL: @negated_op_fmf_commute_vec(
-; CHECK-NEXT:    [[NEGX:%.*]] = fneg <2 x double> [[X:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = call nnan ninf nsz <2 x double> @llvm.minnum.v2f64(<2 x double> [[NEGX]], <2 x double> [[X]])
-; CHECK-NEXT:    ret <2 x double> [[R]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call nnan ninf nsz <2 x double> @llvm.fabs.v2f64(<2 x double> [[X:%.*]])
+; CHECK-NEXT:    [[TMP2:%.*]] = fneg nnan ninf nsz <2 x double> [[TMP1]]
+; CHECK-NEXT:    ret <2 x double> [[TMP2]]
 ;
   %negx = fneg <2 x double> %x
   %r = call nsz nnan ninf <2 x double> @llvm.minnum.v2f64(<2 x double> %negx, <2 x double> %x)


        


More information about the llvm-commits mailing list