diff --git a/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h b/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h index 2d3d2ada6183a7..128502b99d9a37 100644 --- a/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h +++ b/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h @@ -212,6 +212,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/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp index 6799d333fb2844..0dc0696e327847 100644 --- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -3109,6 +3109,33 @@ Value *LibCallSimplifier::optimizeRemquo(CallInst *CI, IRBuilderBase &B) { return ConstantFP::get(CI->getType(), Rem); } +/// Constant folds fdim +Value *LibCallSimplifier::optimizeFdim(CallInst *CI, IRBuilderBase &B) { + // Cannot perform the fold unless the call has attribute memory(none) + if (!CI->doesNotAccessMemory()) + return nullptr; + + // TODO : Handle undef values + // Propagate poison if any + if (isa(CI->getArgOperand(0))) + return CI->getArgOperand(0); + if (isa(CI->getArgOperand(1))) + return CI->getArgOperand(1); + + 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; + + APFloat Difference = *X; + Difference.subtract(*Y, RoundingMode::NearestTiesToEven); + + APFloat MaxVal = + maximum(Difference, APFloat::getZero(CI->getType()->getFltSemantics())); + return ConstantFP::get(CI->getType(), MaxVal); +} + //===----------------------------------------------------------------------===// // Integer Library Call Optimizations //===----------------------------------------------------------------------===// @@ -4042,6 +4069,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/InstCombine/fdim.ll b/llvm/test/Transforms/InstCombine/fdim.ll new file mode 100644 index 00000000000000..5329a8f5c84880 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/fdim.ll @@ -0,0 +1,139 @@ +; 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 0.000000e+00 +; + %dim = call float @fdimf(float 1.500000e+00, float 8.0) + ret float %dim +} + +define float @fdim_float1() { +; CHECK-LABEL: define float @fdim_float1() { +; CHECK-NEXT: ret float 2.000000e+00 +; + %dim = call float @fdimf(float 1.000000e+01, float 8.0) + ret float %dim +} + +define double @fdim_poison1() { +; CHECK-LABEL: define double @fdim_poison1() { +; CHECK-NEXT: ret double poison +; + %dim = call double @fdim(double poison, double 1.0) + ret double %dim +} + +define double @fdim_poison2() { +; CHECK-LABEL: define double @fdim_poison2() { +; CHECK-NEXT: ret double poison +; + %dim = call double @fdim(double 1.0, double poison) + ret double %dim +} + +define double @fdim_poison3() { +; CHECK-LABEL: define double @fdim_poison3() { +; CHECK-NEXT: ret double poison +; + %dim = call double @fdim(double poison, double poison) + ret double %dim +} + +; undef folding is not implemented yet +define double @fdim_undef1() { +; CHECK-LABEL: define double @fdim_undef1() { +; CHECK-NEXT: [[DIM:%.*]] = call double @fdim(double undef, double 1.000000e+00) +; CHECK-NEXT: ret double [[DIM]] +; + %dim = call double @fdim(double undef, double 1.0) + ret double %dim +} + +define double @fdim_inf_ninf() { +; CHECK-LABEL: define double @fdim_inf_ninf() { +; CHECK-NEXT: ret double 0x7FF0000000000000 +; + %dim = call double @fdim(double 0x7FF0000000000000, double 0x8000000000000000 ) + ret double %dim +} + +define double @fdim_inf() { +; CHECK-LABEL: define double @fdim_inf() { +; CHECK-NEXT: ret double 0x7FF8000000000000 +; + %dim = call double @fdim(double 0x7FF0000000000000, double 0x7FF0000000000000) + ret double %dim +} + +define double @fdim_nzero() { +; CHECK-LABEL: define double @fdim_nzero() { +; CHECK-NEXT: ret double 0.000000e+00 +; + %dim = call double @fdim(double -0.0, double +0.0) + ret double %dim +} + +define double @fdim_strictfp() { +; CHECK-LABEL: define double @fdim_strictfp() { +; CHECK-NEXT: [[DIM:%.*]] = call double @fdim(double 1.000000e+01, double 8.000000e+00) #[[ATTR1:[0-9]+]] +; CHECK-NEXT: ret double [[DIM]] +; + %dim = call double @fdim(double 10.0, double 8.0) strictfp + ret double %dim +} + +define double @fdim_nan1() { +; CHECK-LABEL: define double @fdim_nan1() { +; CHECK-NEXT: ret double 0x7FF8000000000000 +; + %dim = call double @fdim(double 10.0, double 0x7FF8000000000000) + ret double %dim +} + + +define double @fdim_nan2() { +; CHECK-LABEL: define double @fdim_nan2() { +; CHECK-NEXT: ret double 0x7FF8000000000000 +; + %dim = call double @fdim(double 0x7FF8000000000000, double 1.4) + ret double %dim +} + +define double @fdim_snan1() { +; CHECK-LABEL: define double @fdim_snan1() { +; CHECK-NEXT: ret double 0x7FFC000000000000 +; + %dim = call double @fdim(double 0x7FF4000000000000, double 1.4) + ret double %dim +} + +define double @fdim_snan2() { +; CHECK-LABEL: define double @fdim_snan2() { +; CHECK-NEXT: ret double 0x7FFC000000000000 +; + %dim = call double @fdim(double 1.7, double 0x7FF4000000000000) + ret double %dim +} + +declare double @fdim(double, double) #0 +declare float @fdimf(float, float) #0 + +attributes #0 = { memory(none) } diff --git a/llvm/test/Transforms/InstCombine/win-fdim.ll b/llvm/test/Transforms/InstCombine/win-fdim.ll new file mode 100644 index 00000000000000..a2e9de77cb58d6 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/win-fdim.ll @@ -0,0 +1,36 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt %s -passes=instcombine -S -mtriple=i386-pc-windows-msvc | FileCheck %s --check-prefixes=MSVC19 + +define double @fdim_double() { +; MSVC19-LABEL: define double @fdim_double() { +; MSVC19-NEXT: ret double 2.500000e+00 +; + %dim = call double @fdim(double 10.5, double 8.0) + ret double %dim +} + +;fdimf is not supported by windows +define float @fdim_float() { +; MSVC19-LABEL: define float @fdim_float() { +; MSVC19-NEXT: [[DIM:%.*]] = call float @fdimf(float 1.500000e+00, float 8.000000e+00) +; MSVC19-NEXT: ret float [[DIM]] +; + %dim = call float @fdimf(float 1.500000e+00, float 8.0) + ret float %dim +} + +;fdiml is not supported by windows +define fp128 @fdim_long() { +; MSVC19-LABEL: define fp128 @fdim_long() { +; MSVC19-NEXT: [[DIM:%.*]] = call fp128 @fdiml(fp128 0xL00000000000000000000000000000000, fp128 0xL00000000000000000000000000000000) +; MSVC19-NEXT: ret fp128 [[DIM]] +; + %dim = call fp128 @fdiml(fp128 0xL00000000000000000000000000000000 , fp128 0xL00000000000000000000000000000000) + ret fp128 %dim +} + +declare double @fdim(double, double) #0 +declare float @fdimf(float, float) #0 +declare fp128 @fdiml(fp128, fp128) #0 + +attributes #0 = { memory(none) }