173 changes: 97 additions & 76 deletions llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2041,20 +2041,112 @@ Value *LibCallSimplifier::optimizeStringMemoryLibCall(CallInst *CI,
return nullptr;
}

Value *LibCallSimplifier::optimizeFloatingPointLibCall(CallInst *CI,
LibFunc Func,
IRBuilder<> &Builder) {
// Don't optimize calls that require strict floating point semantics.
if (CI->isStrictFP())
return nullptr;

switch (Func) {
case LibFunc_cosf:
case LibFunc_cos:
case LibFunc_cosl:
return optimizeCos(CI, Builder);
case LibFunc_sinpif:
case LibFunc_sinpi:
case LibFunc_cospif:
case LibFunc_cospi:
return optimizeSinCosPi(CI, Builder);
case LibFunc_powf:
case LibFunc_pow:
case LibFunc_powl:
return optimizePow(CI, Builder);
case LibFunc_exp2l:
case LibFunc_exp2:
case LibFunc_exp2f:
return optimizeExp2(CI, Builder);
case LibFunc_fabsf:
case LibFunc_fabs:
case LibFunc_fabsl:
return replaceUnaryCall(CI, Builder, Intrinsic::fabs);
case LibFunc_sqrtf:
case LibFunc_sqrt:
case LibFunc_sqrtl:
return optimizeSqrt(CI, Builder);
case LibFunc_log:
case LibFunc_log10:
case LibFunc_log1p:
case LibFunc_log2:
case LibFunc_logb:
return optimizeLog(CI, Builder);
case LibFunc_tan:
case LibFunc_tanf:
case LibFunc_tanl:
return optimizeTan(CI, Builder);
case LibFunc_ceil:
return replaceUnaryCall(CI, Builder, Intrinsic::ceil);
case LibFunc_floor:
return replaceUnaryCall(CI, Builder, Intrinsic::floor);
case LibFunc_round:
return replaceUnaryCall(CI, Builder, Intrinsic::round);
case LibFunc_nearbyint:
return replaceUnaryCall(CI, Builder, Intrinsic::nearbyint);
case LibFunc_rint:
return replaceUnaryCall(CI, Builder, Intrinsic::rint);
case LibFunc_trunc:
return replaceUnaryCall(CI, Builder, Intrinsic::trunc);
case LibFunc_acos:
case LibFunc_acosh:
case LibFunc_asin:
case LibFunc_asinh:
case LibFunc_atan:
case LibFunc_atanh:
case LibFunc_cbrt:
case LibFunc_cosh:
case LibFunc_exp:
case LibFunc_exp10:
case LibFunc_expm1:
case LibFunc_sin:
case LibFunc_sinh:
case LibFunc_tanh:
if (UnsafeFPShrink && hasFloatVersion(CI->getCalledFunction()->getName()))
return optimizeUnaryDoubleFP(CI, Builder, true);
return nullptr;
case LibFunc_copysign:
if (hasFloatVersion(CI->getCalledFunction()->getName()))
return optimizeBinaryDoubleFP(CI, Builder);
return nullptr;
case LibFunc_fminf:
case LibFunc_fmin:
case LibFunc_fminl:
case LibFunc_fmaxf:
case LibFunc_fmax:
case LibFunc_fmaxl:
return optimizeFMinFMax(CI, Builder);
default:
return nullptr;
}
}

Value *LibCallSimplifier::optimizeCall(CallInst *CI) {
// TODO: Split out the code below that operates on FP calls so that
// we can all non-FP calls with the StrictFP attribute to be
// optimized.
if (CI->isNoBuiltin())
return nullptr;

LibFunc Func;
Function *Callee = CI->getCalledFunction();
StringRef FuncName = Callee->getName();

SmallVector<OperandBundleDef, 2> OpBundles;
CI->getOperandBundlesAsDefs(OpBundles);
IRBuilder<> Builder(CI, /*FPMathTag=*/nullptr, OpBundles);
bool isCallingConvC = isCallingConvCCompatible(CI);

// Command-line parameter overrides instruction attribute.
// This can't be moved to optimizeFloatingPointLibCall() because it may be
// used by the intrinsic optimizations.
if (EnableUnsafeFPShrink.getNumOccurrences() > 0)
UnsafeFPShrink = EnableUnsafeFPShrink;
else if (isa<FPMathOperator>(CI) && CI->hasUnsafeAlgebra())
Expand All @@ -2064,6 +2156,8 @@ Value *LibCallSimplifier::optimizeCall(CallInst *CI) {
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(CI)) {
if (!isCallingConvC)
return nullptr;
// The FP intrinsics have corresponding constrained versions so we don't
// need to check for the StrictFP attribute here.
switch (II->getIntrinsicID()) {
case Intrinsic::pow:
return optimizePow(CI, Builder);
Expand Down Expand Up @@ -2104,32 +2198,9 @@ Value *LibCallSimplifier::optimizeCall(CallInst *CI) {
return nullptr;
if (Value *V = optimizeStringMemoryLibCall(CI, Builder))
return V;
if (Value *V = optimizeFloatingPointLibCall(CI, Func, Builder))
return V;
switch (Func) {
case LibFunc_cosf:
case LibFunc_cos:
case LibFunc_cosl:
return optimizeCos(CI, Builder);
case LibFunc_sinpif:
case LibFunc_sinpi:
case LibFunc_cospif:
case LibFunc_cospi:
return optimizeSinCosPi(CI, Builder);
case LibFunc_powf:
case LibFunc_pow:
case LibFunc_powl:
return optimizePow(CI, Builder);
case LibFunc_exp2l:
case LibFunc_exp2:
case LibFunc_exp2f:
return optimizeExp2(CI, Builder);
case LibFunc_fabsf:
case LibFunc_fabs:
case LibFunc_fabsl:
return replaceUnaryCall(CI, Builder, Intrinsic::fabs);
case LibFunc_sqrtf:
case LibFunc_sqrt:
case LibFunc_sqrtl:
return optimizeSqrt(CI, Builder);
case LibFunc_ffs:
case LibFunc_ffsl:
case LibFunc_ffsll:
Expand Down Expand Up @@ -2158,65 +2229,15 @@ Value *LibCallSimplifier::optimizeCall(CallInst *CI) {
return optimizeFWrite(CI, Builder);
case LibFunc_fputs:
return optimizeFPuts(CI, Builder);
case LibFunc_log:
case LibFunc_log10:
case LibFunc_log1p:
case LibFunc_log2:
case LibFunc_logb:
return optimizeLog(CI, Builder);
case LibFunc_puts:
return optimizePuts(CI, Builder);
case LibFunc_tan:
case LibFunc_tanf:
case LibFunc_tanl:
return optimizeTan(CI, Builder);
case LibFunc_perror:
return optimizeErrorReporting(CI, Builder);
case LibFunc_vfprintf:
case LibFunc_fiprintf:
return optimizeErrorReporting(CI, Builder, 0);
case LibFunc_fputc:
return optimizeErrorReporting(CI, Builder, 1);
case LibFunc_ceil:
return replaceUnaryCall(CI, Builder, Intrinsic::ceil);
case LibFunc_floor:
return replaceUnaryCall(CI, Builder, Intrinsic::floor);
case LibFunc_round:
return replaceUnaryCall(CI, Builder, Intrinsic::round);
case LibFunc_nearbyint:
return replaceUnaryCall(CI, Builder, Intrinsic::nearbyint);
case LibFunc_rint:
return replaceUnaryCall(CI, Builder, Intrinsic::rint);
case LibFunc_trunc:
return replaceUnaryCall(CI, Builder, Intrinsic::trunc);
case LibFunc_acos:
case LibFunc_acosh:
case LibFunc_asin:
case LibFunc_asinh:
case LibFunc_atan:
case LibFunc_atanh:
case LibFunc_cbrt:
case LibFunc_cosh:
case LibFunc_exp:
case LibFunc_exp10:
case LibFunc_expm1:
case LibFunc_sin:
case LibFunc_sinh:
case LibFunc_tanh:
if (UnsafeFPShrink && hasFloatVersion(FuncName))
return optimizeUnaryDoubleFP(CI, Builder, true);
return nullptr;
case LibFunc_copysign:
if (hasFloatVersion(FuncName))
return optimizeBinaryDoubleFP(CI, Builder);
return nullptr;
case LibFunc_fminf:
case LibFunc_fmin:
case LibFunc_fminl:
case LibFunc_fmaxf:
case LibFunc_fmax:
case LibFunc_fmaxl:
return optimizeFMinFMax(CI, Builder);
default:
return nullptr;
}
Expand Down
5 changes: 5 additions & 0 deletions llvm/test/Bitcode/compatibility.ll
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,7 @@ declare void @f.inaccessiblememonly() inaccessiblememonly
; CHECK: declare void @f.inaccessiblememonly() #33
declare void @f.inaccessiblemem_or_argmemonly() inaccessiblemem_or_argmemonly
; CHECK: declare void @f.inaccessiblemem_or_argmemonly() #34
declare void @f.strictfp() #35

; Functions -- section
declare void @f.section() section "80"
Expand Down Expand Up @@ -1252,6 +1253,9 @@ exit:
call void @f.nobuiltin() builtin
; CHECK: call void @f.nobuiltin() #42

call void @f.strictfp() strictfp
; CHECK: call void @f.strictfp() #43

call fastcc noalias i32* @f.noalias() noinline
; CHECK: call fastcc noalias i32* @f.noalias() #12
tail call ghccc nonnull i32* @f.nonnull() minsize
Expand Down Expand Up @@ -1670,6 +1674,7 @@ define i8** @constexpr() {
; CHECK: attributes #40 = { writeonly }
; CHECK: attributes #41 = { speculatable }
; CHECK: attributes #42 = { builtin }
; CHECK: attributes #43 = { strictfp }

;; Metadata

Expand Down
4 changes: 4 additions & 0 deletions llvm/test/Transforms/DCE/calls-errno.ll
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ entry:
; CHECK-NEXT: %cos3 = call double @cos(double 0.000000e+00)
%cos3 = call double @cos(double 0.000000e+00) nobuiltin

; cos(1) strictfp sets FP status flags
; CHECK-NEXT: %cos4 = call double @cos(double 1.000000e+00)
%cos4 = call double @cos(double 1.000000e+00) strictfp

; pow(0, 1) is 0
%pow1 = call double @pow(double 0x7FF0000000000000, double 1.000000e+00)

Expand Down
11 changes: 11 additions & 0 deletions llvm/test/Transforms/InstCombine/constant-fold-libfunc.ll
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,20 @@ define double @test_simplify_acos() {
ret double %pi
}

; Check that we don't constant fold builtin functions.

define double @test_acos_nobuiltin() {
; CHECK-LABEL: @test_acos_nobuiltin
%pi = call double @acos(double -1.000000e+00) nobuiltin
; CHECK: call double @acos(double -1.000000e+00)
ret double %pi
}

; Check that we don't constant fold strictfp results that require rounding.

define double @test_acos_strictfp() {
; CHECK-LABEL: @test_acos_strictfp
%pi = call double @acos(double -1.000000e+00) strictfp
; CHECK: call double @acos(double -1.000000e+00)
ret double %pi
}
9 changes: 9 additions & 0 deletions llvm/test/Transforms/InstCombine/memcpy-1.ll
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,12 @@ define i8* @test_simplify1(i8* %mem1, i8* %mem2, i32 %size) {
ret i8* %ret
}

; Verify that the strictfp attr doesn't block this optimization.

define i8* @test_simplify2(i8* %mem1, i8* %mem2, i32 %size) {
; CHECK-LABEL: @test_simplify2(
%ret = call i8* @memcpy(i8* %mem1, i8* %mem2, i32 %size) strictfp
; CHECK: call void @llvm.memcpy
ret i8* %ret
; CHECK: ret i8* %mem1
}
1 change: 1 addition & 0 deletions llvm/utils/vim/syntax/llvm.vim
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ syn keyword llvmKeyword
\ ssp
\ sspreq
\ sspstrong
\ strictfp
\ swiftcc
\ tail
\ target
Expand Down