[llvm] [SimplifyLibCalls] Fold more FP libcalls to intrinsics. (PR #227697)

via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 30 06:05:55 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Florian Hahn (fhahn)

<details>
<summary>Changes</summary>

Previously SimplifyLibCalls would only replace a subset of libcalls with
intrinsics.

It looks like a number of intrinsics are currently not handled, but that
looks unintentional unless I am missing something.

This patch adds a number of missing intrinsics to be converted.

This should ensure middle-end passes only have to deal with the
intrinsic versions.

Should mostly be NFC end-to-end:
https://github.com/dtcxzyw/llvm-opt-benchmark-nightly/pull/1505.

---

Patch is 21.16 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/227697.diff


4 Files Affected:

- (modified) llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp (+25-3) 
- (added) llvm/test/Transforms/InstCombine/X86/fp-libcall-to-intrinsic.ll (+483) 
- (modified) llvm/test/Transforms/InstCombine/float-shrink-compare.ll (+1-1) 
- (modified) llvm/test/Transforms/InstCombine/sqrt.ll (+5-5) 


``````````diff
diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
index f6235b5b98fcb..5b965d79bdb9a 100644
--- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
@@ -4207,7 +4207,11 @@ Value *LibCallSimplifier::optimizeFloatingPointLibCall(CallInst *CI,
   case LibFunc_sqrtf:
   case LibFunc_sqrt:
   case LibFunc_sqrtl:
-    return optimizeSqrt(CI, Builder);
+    if (Value *V = optimizeSqrt(CI, Builder))
+      return V;
+    if (CI->doesNotAccessMemory())
+      return replaceUnaryCall(CI, Builder, Intrinsic::sqrt);
+    return nullptr;
   case LibFunc_fmod:
   case LibFunc_fmodf:
   case LibFunc_fmodl:
@@ -4244,19 +4248,33 @@ Value *LibCallSimplifier::optimizeFloatingPointLibCall(CallInst *CI,
   case LibFunc_atanhf:
   case LibFunc_atanhl:
     return optimizeTrigInversionPairs(CI, Builder);
+  case LibFunc_ceilf:
   case LibFunc_ceil:
+  case LibFunc_ceill:
     return replaceUnaryCall(CI, Builder, Intrinsic::ceil);
+  case LibFunc_floorf:
   case LibFunc_floor:
+  case LibFunc_floorl:
     return replaceUnaryCall(CI, Builder, Intrinsic::floor);
+  case LibFunc_roundf:
   case LibFunc_round:
+  case LibFunc_roundl:
     return replaceUnaryCall(CI, Builder, Intrinsic::round);
+  case LibFunc_roundevenf:
   case LibFunc_roundeven:
+  case LibFunc_roundevenl:
     return replaceUnaryCall(CI, Builder, Intrinsic::roundeven);
+  case LibFunc_nearbyintf:
   case LibFunc_nearbyint:
+  case LibFunc_nearbyintl:
     return replaceUnaryCall(CI, Builder, Intrinsic::nearbyint);
+  case LibFunc_rintf:
   case LibFunc_rint:
+  case LibFunc_rintl:
     return replaceUnaryCall(CI, Builder, Intrinsic::rint);
+  case LibFunc_truncf:
   case LibFunc_trunc:
+  case LibFunc_truncl:
     return replaceUnaryCall(CI, Builder, Intrinsic::trunc);
   case LibFunc_sin:
   case LibFunc_cos:
@@ -4282,8 +4300,12 @@ Value *LibCallSimplifier::optimizeFloatingPointLibCall(CallInst *CI,
     return nullptr;
   case LibFunc_copysign:
     if (hasFloatVersion(M, CI->getCalledFunction()->getName()))
-      return optimizeBinaryDoubleFP(CI, Builder, TLI);
-    return nullptr;
+      if (Value *V = optimizeBinaryDoubleFP(CI, Builder, TLI))
+        return V;
+    [[fallthrough]];
+  case LibFunc_copysignf:
+  case LibFunc_copysignl:
+    return replaceBinaryCall(CI, Builder, Intrinsic::copysign);
   case LibFunc_fdim:
   case LibFunc_fdimf:
   case LibFunc_fdiml:
diff --git a/llvm/test/Transforms/InstCombine/X86/fp-libcall-to-intrinsic.ll b/llvm/test/Transforms/InstCombine/X86/fp-libcall-to-intrinsic.ll
new file mode 100644
index 0000000000000..064b104fdd9d5
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/X86/fp-libcall-to-intrinsic.ll
@@ -0,0 +1,483 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -S -passes=instcombine -mtriple=x86_64-unknown-linux-gnu %s | FileCheck %s
+
+; Rounding functions, sqrt and copysign libcalls are replaced by the
+; corresponding intrinsics. sqrt may set errno, so it is only replaced if the
+; call does not access memory.
+
+define float @ceilf_libcall(float %x) {
+; CHECK-LABEL: define float @ceilf_libcall(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call float @llvm.ceil.f32(float [[X]])
+; CHECK-NEXT:    ret float [[R]]
+;
+  %r = call float @ceilf(float %x)
+  ret float %r
+}
+
+define double @ceil_libcall(double %x) {
+; CHECK-LABEL: define double @ceil_libcall(
+; CHECK-SAME: double [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call double @llvm.ceil.f64(double [[X]])
+; CHECK-NEXT:    ret double [[R]]
+;
+  %r = call double @ceil(double %x)
+  ret double %r
+}
+
+define x86_fp80 @ceill_libcall(x86_fp80 %x) {
+; CHECK-LABEL: define x86_fp80 @ceill_libcall(
+; CHECK-SAME: x86_fp80 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call x86_fp80 @llvm.ceil.f80(x86_fp80 [[X]])
+; CHECK-NEXT:    ret x86_fp80 [[R]]
+;
+  %r = call x86_fp80 @ceill(x86_fp80 %x)
+  ret x86_fp80 %r
+}
+
+define float @floorf_libcall(float %x) {
+; CHECK-LABEL: define float @floorf_libcall(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call float @llvm.floor.f32(float [[X]])
+; CHECK-NEXT:    ret float [[R]]
+;
+  %r = call float @floorf(float %x)
+  ret float %r
+}
+
+define double @floor_libcall(double %x) {
+; CHECK-LABEL: define double @floor_libcall(
+; CHECK-SAME: double [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call double @llvm.floor.f64(double [[X]])
+; CHECK-NEXT:    ret double [[R]]
+;
+  %r = call double @floor(double %x)
+  ret double %r
+}
+
+define x86_fp80 @floorl_libcall(x86_fp80 %x) {
+; CHECK-LABEL: define x86_fp80 @floorl_libcall(
+; CHECK-SAME: x86_fp80 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call x86_fp80 @llvm.floor.f80(x86_fp80 [[X]])
+; CHECK-NEXT:    ret x86_fp80 [[R]]
+;
+  %r = call x86_fp80 @floorl(x86_fp80 %x)
+  ret x86_fp80 %r
+}
+
+define float @roundf_libcall(float %x) {
+; CHECK-LABEL: define float @roundf_libcall(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call float @llvm.round.f32(float [[X]])
+; CHECK-NEXT:    ret float [[R]]
+;
+  %r = call float @roundf(float %x)
+  ret float %r
+}
+
+define double @round_libcall(double %x) {
+; CHECK-LABEL: define double @round_libcall(
+; CHECK-SAME: double [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call double @llvm.round.f64(double [[X]])
+; CHECK-NEXT:    ret double [[R]]
+;
+  %r = call double @round(double %x)
+  ret double %r
+}
+
+define x86_fp80 @roundl_libcall(x86_fp80 %x) {
+; CHECK-LABEL: define x86_fp80 @roundl_libcall(
+; CHECK-SAME: x86_fp80 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call x86_fp80 @llvm.round.f80(x86_fp80 [[X]])
+; CHECK-NEXT:    ret x86_fp80 [[R]]
+;
+  %r = call x86_fp80 @roundl(x86_fp80 %x)
+  ret x86_fp80 %r
+}
+
+define float @roundevenf_libcall(float %x) {
+; CHECK-LABEL: define float @roundevenf_libcall(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call float @llvm.roundeven.f32(float [[X]])
+; CHECK-NEXT:    ret float [[R]]
+;
+  %r = call float @roundevenf(float %x)
+  ret float %r
+}
+
+define double @roundeven_libcall(double %x) {
+; CHECK-LABEL: define double @roundeven_libcall(
+; CHECK-SAME: double [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call double @llvm.roundeven.f64(double [[X]])
+; CHECK-NEXT:    ret double [[R]]
+;
+  %r = call double @roundeven(double %x)
+  ret double %r
+}
+
+define x86_fp80 @roundevenl_libcall(x86_fp80 %x) {
+; CHECK-LABEL: define x86_fp80 @roundevenl_libcall(
+; CHECK-SAME: x86_fp80 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call x86_fp80 @llvm.roundeven.f80(x86_fp80 [[X]])
+; CHECK-NEXT:    ret x86_fp80 [[R]]
+;
+  %r = call x86_fp80 @roundevenl(x86_fp80 %x)
+  ret x86_fp80 %r
+}
+
+define float @nearbyintf_libcall(float %x) {
+; CHECK-LABEL: define float @nearbyintf_libcall(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call float @llvm.nearbyint.f32(float [[X]])
+; CHECK-NEXT:    ret float [[R]]
+;
+  %r = call float @nearbyintf(float %x)
+  ret float %r
+}
+
+define double @nearbyint_libcall(double %x) {
+; CHECK-LABEL: define double @nearbyint_libcall(
+; CHECK-SAME: double [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call double @llvm.nearbyint.f64(double [[X]])
+; CHECK-NEXT:    ret double [[R]]
+;
+  %r = call double @nearbyint(double %x)
+  ret double %r
+}
+
+define x86_fp80 @nearbyintl_libcall(x86_fp80 %x) {
+; CHECK-LABEL: define x86_fp80 @nearbyintl_libcall(
+; CHECK-SAME: x86_fp80 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call x86_fp80 @llvm.nearbyint.f80(x86_fp80 [[X]])
+; CHECK-NEXT:    ret x86_fp80 [[R]]
+;
+  %r = call x86_fp80 @nearbyintl(x86_fp80 %x)
+  ret x86_fp80 %r
+}
+
+define float @rintf_libcall(float %x) {
+; CHECK-LABEL: define float @rintf_libcall(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call float @llvm.rint.f32(float [[X]])
+; CHECK-NEXT:    ret float [[R]]
+;
+  %r = call float @rintf(float %x)
+  ret float %r
+}
+
+define double @rint_libcall(double %x) {
+; CHECK-LABEL: define double @rint_libcall(
+; CHECK-SAME: double [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call double @llvm.rint.f64(double [[X]])
+; CHECK-NEXT:    ret double [[R]]
+;
+  %r = call double @rint(double %x)
+  ret double %r
+}
+
+define x86_fp80 @rintl_libcall(x86_fp80 %x) {
+; CHECK-LABEL: define x86_fp80 @rintl_libcall(
+; CHECK-SAME: x86_fp80 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call x86_fp80 @llvm.rint.f80(x86_fp80 [[X]])
+; CHECK-NEXT:    ret x86_fp80 [[R]]
+;
+  %r = call x86_fp80 @rintl(x86_fp80 %x)
+  ret x86_fp80 %r
+}
+
+define float @truncf_libcall(float %x) {
+; CHECK-LABEL: define float @truncf_libcall(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call float @llvm.trunc.f32(float [[X]])
+; CHECK-NEXT:    ret float [[R]]
+;
+  %r = call float @truncf(float %x)
+  ret float %r
+}
+
+define double @trunc_libcall(double %x) {
+; CHECK-LABEL: define double @trunc_libcall(
+; CHECK-SAME: double [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call double @llvm.trunc.f64(double [[X]])
+; CHECK-NEXT:    ret double [[R]]
+;
+  %r = call double @trunc(double %x)
+  ret double %r
+}
+
+define x86_fp80 @truncl_libcall(x86_fp80 %x) {
+; CHECK-LABEL: define x86_fp80 @truncl_libcall(
+; CHECK-SAME: x86_fp80 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call x86_fp80 @llvm.trunc.f80(x86_fp80 [[X]])
+; CHECK-NEXT:    ret x86_fp80 [[R]]
+;
+  %r = call x86_fp80 @truncl(x86_fp80 %x)
+  ret x86_fp80 %r
+}
+
+define float @floorf_libcall_fmf_tail(float %x) {
+; CHECK-LABEL: define float @floorf_libcall_fmf_tail(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = tail call nnan ninf float @llvm.floor.f32(float [[X]])
+; CHECK-NEXT:    ret float [[R]]
+;
+  %r = tail call nnan ninf float @floorf(float %x)
+  ret float %r
+}
+
+define float @floorf_libcall_strictfp(float %x) strictfp {
+; CHECK-LABEL: define float @floorf_libcall_strictfp(
+; CHECK-SAME: float [[X:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT:    [[R:%.*]] = call float @floorf(float [[X]]) #[[ATTR0]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %r = call float @floorf(float %x) strictfp
+  ret float %r
+}
+
+define float @floorf_libcall_nobuiltin(float %x) {
+; CHECK-LABEL: define float @floorf_libcall_nobuiltin(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call float @floorf(float [[X]]) #[[ATTR3:[0-9]+]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %r = call float @floorf(float %x) nobuiltin
+  ret float %r
+}
+
+define x86_fp80 @rintl_libcall_strictfp(x86_fp80 %x) strictfp {
+; CHECK-LABEL: define x86_fp80 @rintl_libcall_strictfp(
+; CHECK-SAME: x86_fp80 [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[R:%.*]] = call x86_fp80 @rintl(x86_fp80 [[X]]) #[[ATTR0]]
+; CHECK-NEXT:    ret x86_fp80 [[R]]
+;
+  %r = call x86_fp80 @rintl(x86_fp80 %x) strictfp
+  ret x86_fp80 %r
+}
+
+define float @sqrtf_libcall_readnone(float %x) {
+; CHECK-LABEL: define float @sqrtf_libcall_readnone(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call float @llvm.sqrt.f32(float [[X]])
+; CHECK-NEXT:    ret float [[R]]
+;
+  %r = call float @sqrtf(float %x) memory(none)
+  ret float %r
+}
+
+define float @sqrtf_libcall_errno(float %x) {
+; CHECK-LABEL: define float @sqrtf_libcall_errno(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call float @sqrtf(float [[X]])
+; CHECK-NEXT:    ret float [[R]]
+;
+  %r = call float @sqrtf(float %x)
+  ret float %r
+}
+
+define double @sqrt_libcall_readnone(double %x) {
+; CHECK-LABEL: define double @sqrt_libcall_readnone(
+; CHECK-SAME: double [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call double @llvm.sqrt.f64(double [[X]])
+; CHECK-NEXT:    ret double [[R]]
+;
+  %r = call double @sqrt(double %x) memory(none)
+  ret double %r
+}
+
+define double @sqrt_libcall_errno(double %x) {
+; CHECK-LABEL: define double @sqrt_libcall_errno(
+; CHECK-SAME: double [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call double @sqrt(double [[X]])
+; CHECK-NEXT:    ret double [[R]]
+;
+  %r = call double @sqrt(double %x)
+  ret double %r
+}
+
+define x86_fp80 @sqrtl_libcall_readnone(x86_fp80 %x) {
+; CHECK-LABEL: define x86_fp80 @sqrtl_libcall_readnone(
+; CHECK-SAME: x86_fp80 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call x86_fp80 @llvm.sqrt.f80(x86_fp80 [[X]])
+; CHECK-NEXT:    ret x86_fp80 [[R]]
+;
+  %r = call x86_fp80 @sqrtl(x86_fp80 %x) memory(none)
+  ret x86_fp80 %r
+}
+
+define x86_fp80 @sqrtl_libcall_errno(x86_fp80 %x) {
+; CHECK-LABEL: define x86_fp80 @sqrtl_libcall_errno(
+; CHECK-SAME: x86_fp80 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call x86_fp80 @sqrtl(x86_fp80 [[X]])
+; CHECK-NEXT:    ret x86_fp80 [[R]]
+;
+  %r = call x86_fp80 @sqrtl(x86_fp80 %x)
+  ret x86_fp80 %r
+}
+
+define float @sqrtf_libcall_readnone_fmf_tail(float %x) {
+; CHECK-LABEL: define float @sqrtf_libcall_readnone_fmf_tail(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = tail call nnan nsz float @llvm.sqrt.f32(float [[X]])
+; CHECK-NEXT:    ret float [[R]]
+;
+  %r = tail call nnan nsz float @sqrtf(float %x) memory(none)
+  ret float %r
+}
+
+define float @sqrtf_libcall_errno_memory_write(float %x) {
+; CHECK-LABEL: define float @sqrtf_libcall_errno_memory_write(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call float @sqrtf(float [[X]]) #[[ATTR4:[0-9]+]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %r = call float @sqrtf(float %x) memory(errnomem: write)
+  ret float %r
+}
+
+define float @sqrtf_libcall_readnone_strictfp(float %x) strictfp {
+; CHECK-LABEL: define float @sqrtf_libcall_readnone_strictfp(
+; CHECK-SAME: float [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[R:%.*]] = call float @sqrtf(float [[X]]) #[[ATTR5:[0-9]+]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %r = call float @sqrtf(float %x) strictfp memory(none)
+  ret float %r
+}
+
+define float @sqrtf_libcall_readnone_nobuiltin(float %x) {
+; CHECK-LABEL: define float @sqrtf_libcall_readnone_nobuiltin(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call float @sqrtf(float [[X]]) #[[ATTR6:[0-9]+]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %r = call float @sqrtf(float %x) nobuiltin memory(none)
+  ret float %r
+}
+
+; sqrt(fpext x) is shrunk to sqrtf(x) first and then replaced by the intrinsic.
+define float @sqrt_libcall_readnone_shrink(float %x) {
+; CHECK-LABEL: define float @sqrt_libcall_readnone_shrink(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT:    [[SQRTF:%.*]] = call float @llvm.sqrt.f32(float [[X]])
+; CHECK-NEXT:    ret float [[SQRTF]]
+;
+  %ext = fpext float %x to double
+  %r = call double @sqrt(double %ext) memory(none)
+  %trunc = fptrunc double %r to float
+  ret float %trunc
+}
+
+; The fabs fold for fast sqrt is applied before replacing the call.
+define double @sqrt_libcall_readnone_fast_mul(double %x) {
+; CHECK-LABEL: define double @sqrt_libcall_readnone_fast_mul(
+; CHECK-SAME: double [[X:%.*]]) {
+; CHECK-NEXT:    [[FABS:%.*]] = call fast double @llvm.fabs.f64(double [[X]])
+; CHECK-NEXT:    ret double [[FABS]]
+;
+  %mul = fmul fast double %x, %x
+  %r = call fast double @sqrt(double %mul) memory(none)
+  ret double %r
+}
+
+define float @copysignf_libcall(float %x, float %y) {
+; CHECK-LABEL: define float @copysignf_libcall(
+; CHECK-SAME: float [[X:%.*]], float [[Y:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call float @llvm.copysign.f32(float [[X]], float [[Y]])
+; CHECK-NEXT:    ret float [[R]]
+;
+  %r = call float @copysignf(float %x, float %y)
+  ret float %r
+}
+
+define double @copysign_libcall(double %x, double %y) {
+; CHECK-LABEL: define double @copysign_libcall(
+; CHECK-SAME: double [[X:%.*]], double [[Y:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call double @llvm.copysign.f64(double [[X]], double [[Y]])
+; CHECK-NEXT:    ret double [[R]]
+;
+  %r = call double @copysign(double %x, double %y)
+  ret double %r
+}
+
+define x86_fp80 @copysignl_libcall(x86_fp80 %x, x86_fp80 %y) {
+; CHECK-LABEL: define x86_fp80 @copysignl_libcall(
+; CHECK-SAME: x86_fp80 [[X:%.*]], x86_fp80 [[Y:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call x86_fp80 @llvm.copysign.f80(x86_fp80 [[X]], x86_fp80 [[Y]])
+; CHECK-NEXT:    ret x86_fp80 [[R]]
+;
+  %r = call x86_fp80 @copysignl(x86_fp80 %x, x86_fp80 %y)
+  ret x86_fp80 %r
+}
+
+define double @copysign_libcall_fmf_tail(double %x, double %y) {
+; CHECK-LABEL: define double @copysign_libcall_fmf_tail(
+; CHECK-SAME: double [[X:%.*]], double [[Y:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = tail call nnan double @llvm.copysign.f64(double [[X]], double [[Y]])
+; CHECK-NEXT:    ret double [[R]]
+;
+  %r = tail call nnan double @copysign(double %x, double %y)
+  ret double %r
+}
+
+; copysign((double)x, (double)y) is still shrunk to float.
+define double @copysign_libcall_shrink(float %x, float %y) {
+; CHECK-LABEL: define double @copysign_libcall_shrink(
+; CHECK-SAME: float [[X:%.*]], float [[Y:%.*]]) {
+; CHECK-NEXT:    [[COPYSIGNF:%.*]] = call float @llvm.copysign.f32(float [[X]], float [[Y]])
+; CHECK-NEXT:    [[R:%.*]] = fpext float [[COPYSIGNF]] to double
+; CHECK-NEXT:    ret double [[R]]
+;
+  %x.ext = fpext float %x to double
+  %y.ext = fpext float %y to double
+  %r = call double @copysign(double %x.ext, double %y.ext)
+  ret double %r
+}
+
+define float @copysignf_libcall_strictfp(float %x, float %y) strictfp {
+; CHECK-LABEL: define float @copysignf_libcall_strictfp(
+; CHECK-SAME: float [[X:%.*]], float [[Y:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[R:%.*]] = call float @copysignf(float [[X]], float [[Y]]) #[[ATTR0]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %r = call float @copysignf(float %x, float %y) strictfp
+  ret float %r
+}
+
+define float @copysignf_libcall_nobuiltin(float %x, float %y) {
+; CHECK-LABEL: define float @copysignf_libcall_nobuiltin(
+; CHECK-SAME: float [[X:%.*]], float [[Y:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call float @copysignf(float [[X]], float [[Y]]) #[[ATTR3]]
+; CHECK-NEXT:    ret float [[R]]
+;
+  %r = call float @copysignf(float %x, float %y) nobuiltin
+  ret float %r
+}
+
+declare float @ceilf(float)
+declare double @ceil(double)
+declare x86_fp80 @ceill(x86_fp80)
+declare float @floorf(float)
+declare double @floor(double)
+declare x86_fp80 @floorl(x86_fp80)
+declare float @roundf(float)
+declare double @round(double)
+declare x86_fp80 @roundl(x86_fp80)
+declare float @roundevenf(float)
+declare double @roundeven(double)
+declare x86_fp80 @roundevenl(x86_fp80)
+declare float @nearbyintf(float)
+declare double @nearbyint(double)
+declare x86_fp80 @nearbyintl(x86_fp80)
+declare float @rintf(float)
+declare double @rint(double)
+declare x86_fp80 @rintl(x86_fp80)
+declare float @truncf(float)
+declare double @trunc(double)
+declare x86_fp80 @truncl(x86_fp80)
+declare float @sqrtf(float)
+declare double @sqrt(double)
+declare x86_fp80 @sqrtl(x86_fp80)
+declare float @copysignf(float, float)
+declare double @copysign(double, double)
+declare x86_fp80 @copysignl(x86_fp80, x86_fp80)
diff --git a/llvm/test/Transforms/InstCombine/float-shrink-compare.ll b/llvm/test/Transforms/InstCombine/float-shrink-compare.ll
index 6383feff3a6ee..450dcf879bb01 100644
--- a/llvm/test/Transforms/InstCombine/float-shrink-compare.ll
+++ b/llvm/test/Transforms/InstCombine/float-shrink-compare.ll
@@ -493,7 +493,7 @@ define i1 @test_fmaximum_num(float %x, float %y, float %z) {
 
 define i1 @test19(float %x, float %y, float %z) {
 ; CHECK-LABEL: @test19(
-; CHECK-NEXT:    [[COPYSIGNF:%.*]] = call float @copysignf(float [[X:%.*]], float [[Y:%.*]]) #[[ATTR0:[0-9]+]]
+; CHECK-NEXT:    [[COPYSIGNF:%.*]] = call float @llvm.copysign.f32(float [[X:%.*]], float [[Y:%.*]])
 ; CHECK-NEXT:    [[TMP1:%.*]] = fcmp oeq float [[COPYSIGNF]], [[Z:%.*]]
 ; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
diff --git a/llvm/test/Transforms/InstCombine/sqrt.ll b/llvm/test/Transforms/InstCombine/sqrt.ll
index 5965c98ceb231..fc58a46bcd178 100644
--- a/llvm/test/Transforms/InstCombine/sqrt.ll
+++ b/llvm/test/Transforms/InstCombine/sqrt.ll
@@ -3,7 +3,7 @@
 
 define float @test1(float %x) nounwind readnone ssp {
 ; CHECK-LABEL: @test1(
-; CHECK-NEXT:    [[SQRTF:%.*]] = call float @sqrtf(float [[X:%.*]]) #[[ATTR4:[0-9]+]]
+; CHECK-NEXT:    [[SQRTF:%.*]] = call float @llvm.sqrt.f32(float [[X:%.*]])
 ; CHECK-NEXT:    ret float [[SQRTF]]
 ;
   %conv = fpext float %x to double
@@ -16,7 +16,7 @@ define float @test1(float %x) nounwind readnone ssp {
 
 define float @test2(float %x) nounwind readnone ssp {
 ; CHECK-LABEL: @test2(
-; CHECK-NEXT:    [[SQRTF:%.*]] = call float @sqrtf(float [...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/227697


More information about the llvm-commits mailing list