Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fdim constant fold #109235

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open

Fdim constant fold #109235

wants to merge 2 commits into from

Conversation

braw-lee
Copy link
Contributor

2nd PR to fix #108695

based on #108702

Signed-off-by: Kushal Pal <kushalpal109@gmail.com>
Signed-off-by: Kushal Pal <kushalpal109@gmail.com>
@llvmbot
Copy link
Collaborator

llvmbot commented Sep 19, 2024

@llvm/pr-subscribers-llvm-analysis

@llvm/pr-subscribers-llvm-transforms

Author: None (braw-lee)

Changes

2nd PR to fix #108695

based on #108702


Full diff: https://github.com/llvm/llvm-project/pull/109235.diff

9 Files Affected:

  • (modified) llvm/include/llvm/Analysis/TargetLibraryInfo.def (+15)
  • (modified) llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h (+1)
  • (modified) llvm/lib/Analysis/TargetLibraryInfo.cpp (+2)
  • (modified) llvm/lib/Transforms/Utils/BuildLibCalls.cpp (+3)
  • (modified) llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp (+39)
  • (modified) llvm/test/Transforms/InferFunctionAttrs/annotate.ll (+10)
  • (added) llvm/test/Transforms/InstCombine/fdim.ll (+37)
  • (modified) llvm/test/tools/llvm-tli-checker/ps4-tli-check.yaml (+16-4)
  • (modified) llvm/unittests/Analysis/TargetLibraryInfoTest.cpp (+3)
diff --git a/llvm/include/llvm/Analysis/TargetLibraryInfo.def b/llvm/include/llvm/Analysis/TargetLibraryInfo.def
index 5914324b286c05..a18952f038cc31 100644
--- a/llvm/include/llvm/Analysis/TargetLibraryInfo.def
+++ b/llvm/include/llvm/Analysis/TargetLibraryInfo.def
@@ -2067,6 +2067,21 @@ TLI_DEFINE_ENUM_INTERNAL(remquol)
 TLI_DEFINE_STRING_INTERNAL("remquol")
 TLI_DEFINE_SIG_INTERNAL(LDbl, LDbl, LDbl, Ptr)
 
+/// double fdim(double x, double y);
+TLI_DEFINE_ENUM_INTERNAL(fdim)
+TLI_DEFINE_STRING_INTERNAL("fdim")
+TLI_DEFINE_SIG_INTERNAL(Dbl, Dbl, Dbl)
+
+/// float fdimf(float x, float y);
+TLI_DEFINE_ENUM_INTERNAL(fdimf)
+TLI_DEFINE_STRING_INTERNAL("fdimf")
+TLI_DEFINE_SIG_INTERNAL(Flt, Flt, Flt)
+
+/// long double fdiml(long double x, long double y);
+TLI_DEFINE_ENUM_INTERNAL(fdiml)
+TLI_DEFINE_STRING_INTERNAL("fdiml")
+TLI_DEFINE_SIG_INTERNAL(LDbl, LDbl, LDbl)
+
 /// int remove(const char *path);
 TLI_DEFINE_ENUM_INTERNAL(remove)
 TLI_DEFINE_STRING_INTERNAL("remove")
diff --git a/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h b/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h
index 2e7a0ec29ed999..467a8f25386b71 100644
--- a/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h
+++ b/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h
@@ -211,6 +211,7 @@ class LibCallSimplifier {
   Value *optimizeTrigInversionPairs(CallInst *CI, IRBuilderBase &B);
   Value *optimizeSymmetric(CallInst *CI, LibFunc Func, IRBuilderBase &B);
   Value *optimizeRemquo(CallInst *CI, IRBuilderBase &B);
+  Value *optimizeFdim(CallInst *CI, IRBuilderBase &B);
   // Wrapper for all floating point library call optimizations
   Value *optimizeFloatingPointLibCall(CallInst *CI, LibFunc Func,
                                       IRBuilderBase &B);
diff --git a/llvm/lib/Analysis/TargetLibraryInfo.cpp b/llvm/lib/Analysis/TargetLibraryInfo.cpp
index 47413239f3c6cc..1785d77bca985c 100644
--- a/llvm/lib/Analysis/TargetLibraryInfo.cpp
+++ b/llvm/lib/Analysis/TargetLibraryInfo.cpp
@@ -306,6 +306,7 @@ static void initializeLibCalls(TargetLibraryInfoImpl &TLI, const Triple &T,
       TLI.setUnavailable(LibFunc_powf);
       TLI.setUnavailable(LibFunc_remainderf);
       TLI.setUnavailable(LibFunc_remquof);
+      TLI.setUnavailable(LibFunc_fdimf);
       TLI.setUnavailable(LibFunc_sinf);
       TLI.setUnavailable(LibFunc_sinhf);
       TLI.setUnavailable(LibFunc_sqrtf);
@@ -337,6 +338,7 @@ static void initializeLibCalls(TargetLibraryInfoImpl &TLI, const Triple &T,
     TLI.setUnavailable(LibFunc_powl);
     TLI.setUnavailable(LibFunc_remainderl);
     TLI.setUnavailable(LibFunc_remquol);
+    TLI.setUnavailable(LibFunc_fdiml);
     TLI.setUnavailable(LibFunc_sinl);
     TLI.setUnavailable(LibFunc_sinhl);
     TLI.setUnavailable(LibFunc_sqrtl);
diff --git a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
index b0da19813f0a4b..abe0d8c3d2e999 100644
--- a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
@@ -1191,6 +1191,9 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
   case LibFunc_fabs:
   case LibFunc_fabsf:
   case LibFunc_fabsl:
+  case LibFunc_fdim:
+  case LibFunc_fdiml:
+  case LibFunc_fdimf:
   case LibFunc_ffs:
   case LibFunc_ffsl:
   case LibFunc_ffsll:
diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
index 917f81863cf673..5f3bb5fa060729 100644
--- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
@@ -3080,6 +3080,41 @@ Value *LibCallSimplifier::optimizeRemquo(CallInst *CI, IRBuilderBase &B) {
   return ConstantFP::get(CI->getType(), Rem);
 }
 
+/// Constant folds fdim
+Value *LibCallSimplifier::optimizeFdim(CallInst *CI, IRBuilderBase &B) {
+  const APFloat *X, *Y;
+  // Check if both values are constants
+  if (!match(CI->getArgOperand(0), m_APFloat(X)) ||
+      !match(CI->getArgOperand(1), m_APFloat(Y)))
+    return nullptr;
+  // If either argument is NaN, NaN is returned
+  if (X->isNaN() || Y->isNaN())
+    return ConstantFP::getQNaN(CI->getType());
+
+  // If the difference if negative, return +0.0
+  if (*X <= *Y)
+    return ConstantFP::get(CI->getType(), 0.0);
+
+  APFloat ReturnVal = *X;
+  APFloat::opStatus Status =
+      ReturnVal.subtract(*Y, RoundingMode::NearestTiesToEven);
+  switch (Status) {
+  case APFloat::opStatus::opOK:
+    break;
+  case APFloat::opStatus::opOverflow:
+    return ConstantFP::get(
+        CI->getType(),
+        APFloat::getLargest(X->getSemantics(), /*Negative=*/false));
+  case APFloat::opStatus::opUnderflow:
+    return ConstantFP::get(
+        CI->getType(),
+        APFloat::getLargest(X->getSemantics(), /*Negative=*/true));
+  default:
+    return nullptr;
+  }
+  return ConstantFP::get(CI->getType(), ReturnVal);
+}
+
 //===----------------------------------------------------------------------===//
 // Integer Library Call Optimizations
 //===----------------------------------------------------------------------===//
@@ -4009,6 +4044,10 @@ Value *LibCallSimplifier::optimizeFloatingPointLibCall(CallInst *CI,
     if (hasFloatVersion(M, CI->getCalledFunction()->getName()))
       return optimizeBinaryDoubleFP(CI, Builder, TLI);
     return nullptr;
+  case LibFunc_fdim:
+  case LibFunc_fdimf:
+  case LibFunc_fdiml:
+    return optimizeFdim(CI, Builder);
   case LibFunc_fminf:
   case LibFunc_fmin:
   case LibFunc_fminl:
diff --git a/llvm/test/Transforms/InferFunctionAttrs/annotate.ll b/llvm/test/Transforms/InferFunctionAttrs/annotate.ll
index bc0d7a509e1f5d..267a288345dc10 100644
--- a/llvm/test/Transforms/InferFunctionAttrs/annotate.ll
+++ b/llvm/test/Transforms/InferFunctionAttrs/annotate.ll
@@ -830,6 +830,16 @@ declare float @remquof(float, float, ptr)
 ; CHECK: declare x86_fp80 @remquol(x86_fp80, x86_fp80, ptr nocapture) [[NOFREE_NOUNWIND_WILLRETURN_WRITEONLY]]
 declare x86_fp80 @remquol(x86_fp80, x86_fp80, ptr)
 
+
+; CHECK: declare double @fdim(double, double) [[NOFREE_NOUNWIND_WILLRETURN_WRITEONLY]]
+declare double @fdim(double, double)
+
+; CHECK: declare float @fdimf(float, float) [[NOFREE_NOUNWIND_WILLRETURN_WRITEONLY]]
+declare float @fdimf(float, float)
+
+; CHECK: declare x86_fp80 @fdiml(x86_fp80, x86_fp80) [[NOFREE_NOUNWIND_WILLRETURN_WRITEONLY]]
+declare x86_fp80 @fdiml(x86_fp80, x86_fp80)
+
 ; CHECK: declare noundef i32 @rename(ptr nocapture noundef readonly, ptr nocapture noundef readonly) [[NOFREE_NOUNWIND]]
 declare i32 @rename(ptr, ptr)
 
diff --git a/llvm/test/Transforms/InstCombine/fdim.ll b/llvm/test/Transforms/InstCombine/fdim.ll
new file mode 100644
index 00000000000000..6213262f1af1e7
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/fdim.ll
@@ -0,0 +1,37 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+define double @fdim_double() {
+; CHECK-LABEL: define double @fdim_double() {
+; CHECK-NEXT:    ret double 2.500000e+00
+;
+  %dim = call double @fdim (double 10.5, double 8.0)
+  ret double %dim
+}
+
+define double @fdim_double1() {
+; CHECK-LABEL: define double @fdim_double1() {
+; CHECK-NEXT:    ret double 0.000000e+00
+;
+  %dim = call double @fdim (double 7.0, double 8.0)
+  ret double %dim
+}
+
+define float @fdim_float() {
+; CHECK-LABEL: define float @fdim_float() {
+; CHECK-NEXT:    ret float 2.500000e+00
+;
+  %dim = call float @fdimf (float 10.5, float 8.0)
+  ret float %dim
+}
+
+define float @fdim_float1() {
+; CHECK-LABEL: define float @fdim_float1() {
+; CHECK-NEXT:    ret float 0.000000e+00
+;
+  %dim = call float @fdimf (float 7.0, float 8.0)
+  ret float %dim
+}
+
+declare double @fdim(double, double)
+declare float @fdimf(float, float)
diff --git a/llvm/test/tools/llvm-tli-checker/ps4-tli-check.yaml b/llvm/test/tools/llvm-tli-checker/ps4-tli-check.yaml
index 47aeb0ad8fdef9..767a962402b783 100644
--- a/llvm/test/tools/llvm-tli-checker/ps4-tli-check.yaml
+++ b/llvm/test/tools/llvm-tli-checker/ps4-tli-check.yaml
@@ -34,7 +34,7 @@
 #
 # CHECK: << Total TLI yes SDK no:  18
 # CHECK: >> Total TLI no  SDK yes: 0
-# CHECK: == Total TLI yes SDK yes: 250
+# CHECK: == Total TLI yes SDK yes: 253
 #
 # WRONG_DETAIL: << TLI yes SDK no : '_ZdaPv' aka operator delete[](void*)
 # WRONG_DETAIL: >> TLI no  SDK yes: '_ZdaPvj' aka operator delete[](void*, unsigned int)
@@ -48,14 +48,14 @@
 # WRONG_DETAIL: << TLI yes SDK no : 'fminimum_numl'
 # WRONG_SUMMARY: << Total TLI yes SDK no:  19{{$}}
 # WRONG_SUMMARY: >> Total TLI no  SDK yes: 1{{$}}
-# WRONG_SUMMARY: == Total TLI yes SDK yes: 249
+# WRONG_SUMMARY: == Total TLI yes SDK yes: 252
 #
 ## The -COUNT suffix doesn't care if there are too many matches, so check
 ## the exact count first; the two directives should add up to that.
 ## Yes, this means additions to TLI will fail this test, but the argument
 ## to -COUNT can't be an expression.
-# AVAIL: TLI knows 501 symbols, 268 available
-# AVAIL-COUNT-268: {{^}} available
+# AVAIL: TLI knows 504 symbols, 271 available
+# AVAIL-COUNT-271: {{^}} available
 # AVAIL-NOT:       {{^}} available
 # UNAVAIL-COUNT-233: not available
 # UNAVAIL-NOT:       not available
@@ -814,6 +814,18 @@ DynamicSymbols:
     Type:            STT_FUNC
     Section:         .text
     Binding:         STB_GLOBAL
+  - Name:            fdim
+    Type:            STT_FUNC
+    Section:         .text
+    Binding:         STB_GLOBAL
+  - Name:            fdimf
+    Type:            STT_FUNC
+    Section:         .text
+    Binding:         STB_GLOBAL
+  - Name:            fdiml
+    Type:            STT_FUNC
+    Section:         .text
+    Binding:         STB_GLOBAL
   - Name:            rewind
     Type:            STT_FUNC
     Section:         .text
diff --git a/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp b/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
index c081c44ed35d00..ed6a91ce611acf 100644
--- a/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
+++ b/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
@@ -317,6 +317,9 @@ TEST_F(TargetLibraryInfoTest, ValidProto) {
       "declare double @remquo(double, double, ptr)\n"
       "declare float @remquof(float, float, ptr)\n"
       "declare x86_fp80 @remquol(x86_fp80, x86_fp80, ptr)\n"
+      "declare double @fdim(double, double)\n"
+      "declare float @fdimf(float, float)\n"
+      "declare x86_fp80 @fdiml(x86_fp80, x86_fp80)\n"
       "declare i32 @rename(i8*, i8*)\n"
       "declare void @rewind(%struct*)\n"
       "declare double @rint(double)\n"

@dtcxzyw dtcxzyw requested a review from arsenm September 19, 2024 07:50
case APFloat::opStatus::opOverflow:
return ConstantFP::get(
CI->getType(),
APFloat::getLargest(X->getSemantics(), /*Negative=*/false));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The result should be inf. Please add a tests for fdim(1e308, -1e308).

BTW, it would be better to use fmax(x - y, 0) instead of handling all corner cases yourself.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, I read that on cppref but wasn't sure if it will handle all corner cases,
will change to that

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The special cases also set errno, in which case we cannot perform the fold unless the call is memory(none)

case APFloat::opStatus::opUnderflow:
return ConstantFP::get(
CI->getType(),
APFloat::getLargest(X->getSemantics(), /*Negative=*/true));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is incorrect. Underflow means the result is subnormal.

@arsenm arsenm added the floating-point Floating-point math label Sep 20, 2024
case APFloat::opStatus::opOverflow:
return ConstantFP::get(
CI->getType(),
APFloat::getLargest(X->getSemantics(), /*Negative=*/false));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The special cases also set errno, in which case we cannot perform the fold unless the call is memory(none)

%dim = call float @fdimf (float 7.0, float 8.0)
ret float %dim
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs tests for all the edge cases. Can you also test poison/undef arguments in each position

; CHECK-LABEL: define double @fdim_double1() {
; CHECK-NEXT: ret double 0.000000e+00
;
%dim = call double @fdim (double 7.0, double 8.0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra space before ( in all functions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

fdim(x, y) is not folded at the compilation time when (x, y) is constant
4 participants