[llvm] [KnownFPClass] Add support for non-intrinsic math libcalls (PR #216234)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 21 16:55:26 PDT 2026
https://github.com/ZERICO2005 updated https://github.com/llvm/llvm-project/pull/216234
>From 0d9884777065b8c8127ed4cbae38934cc9a4b6ed Mon Sep 17 00:00:00 2001
From: zerico <zerico2005 at gmail.com>
Date: Thu, 13 Aug 2026 20:42:00 -0600
Subject: [PATCH] [KnownFPClass] Add support for non-intrinsic math libcalls
---
llvm/include/llvm/Support/KnownFPClass.h | 7 +
llvm/lib/Analysis/ValueTracking.cpp | 44 +++
llvm/lib/Support/KnownFPClass.cpp | 30 ++
.../known-fpclass-nonintrinsic-libcall.ll | 27 ++
.../Transforms/Attributor/nofpclass-acosh.ll | 36 +++
.../Transforms/Attributor/nofpclass-cbrt.ll | 262 ++++++++++++++++++
llvm/unittests/Analysis/ValueTrackingTest.cpp | 77 +++++
7 files changed, 483 insertions(+)
create mode 100644 llvm/test/Analysis/ValueTracking/known-fpclass-nonintrinsic-libcall.ll
create mode 100644 llvm/test/Transforms/Attributor/nofpclass-acosh.ll
create mode 100644 llvm/test/Transforms/Attributor/nofpclass-cbrt.ll
diff --git a/llvm/include/llvm/Support/KnownFPClass.h b/llvm/include/llvm/Support/KnownFPClass.h
index dadf4133d826b..3af0d2f1fb53f 100644
--- a/llvm/include/llvm/Support/KnownFPClass.h
+++ b/llvm/include/llvm/Support/KnownFPClass.h
@@ -323,6 +323,9 @@ struct KnownFPClass {
/// Report known values for tanh
LLVM_ABI static KnownFPClass tanh(const KnownFPClass &Src);
+ /// Report known values for acosh
+ LLVM_ABI static KnownFPClass acosh(const KnownFPClass &Src);
+
/// Report known values for asin
LLVM_ABI static KnownFPClass asin(const KnownFPClass &Src);
@@ -448,6 +451,10 @@ struct KnownFPClass {
static LLVM_ABI KnownFPClass
sqrt(const KnownFPClass &Src, DenormalMode Mode = DenormalMode::getDynamic());
+ /// Propagate known class for cbrt
+ LLVM_ABI static KnownFPClass
+ cbrt(const KnownFPClass &Src, DenormalMode Mode = DenormalMode::getDynamic());
+
/// Propagate known class for fpext.
static LLVM_ABI KnownFPClass fpext(const KnownFPClass &KnownSrc,
const fltSemantics &DstTy,
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 55f6696fe4914..280314f017df0 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5765,6 +5765,50 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
Known.knownNot(fcSubnormal);
break;
}
+ case Intrinsic::not_intrinsic: {
+ // Recognize the libcall directly for functions with no intrinsic
+ // equivalent. TLI validates the declaration's prototype and rejects calls
+ // marked 'nobuiltin'. Do not recognize locally-defined functions.
+ if (!Q.TLI)
+ break;
+ const Function *F = II->getCalledFunction();
+ if (!F || F->hasLocalLinkage())
+ break;
+ LibFunc Func;
+ if (!Q.TLI->getLibFunc(*II, Func))
+ break;
+
+ switch (Func) {
+ case LibFunc_acosh:
+ case LibFunc_acoshf:
+ case LibFunc_acoshl: {
+ KnownFPClass KnownSrc;
+ computeKnownFPClass(II->getArgOperand(0), DemandedElts,
+ InterestedClasses, KnownSrc, Q, Depth + 1);
+ Known = KnownFPClass::acosh(KnownSrc);
+ break;
+ }
+ case LibFunc_cbrt:
+ case LibFunc_cbrtf:
+ case LibFunc_cbrtl: {
+ KnownFPClass KnownSrc;
+ computeKnownFPClass(II->getArgOperand(0), DemandedElts,
+ InterestedClasses, KnownSrc, Q, Depth + 1);
+ const Function *Caller = II->getFunction();
+ const fltSemantics &FltSem =
+ Op->getType()->getScalarType()->getFltSemantics();
+ DenormalMode Mode =
+ Caller ? Caller->getDenormalMode(FltSem)
+ : DenormalMode::getDynamic();
+ Known = KnownFPClass::cbrt(KnownSrc, Mode);
+ break;
+ }
+ default:
+ break;
+ }
+
+ break;
+ }
default:
break;
}
diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index ac9406ecd0280..397c8f0977ced 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -583,6 +583,26 @@ KnownFPClass KnownFPClass::sqrt(const KnownFPClass &KnownSrc,
return Known;
}
+KnownFPClass KnownFPClass::cbrt(const KnownFPClass &KnownSrc,
+ DenormalMode Mode) {
+ KnownFPClass Known;
+
+ Known.propagateNonNaN(KnownSrc);
+
+ // cbrt is never subnormal for the same reason that sqrt is never subnormal.
+ Known.knownNot(fcSubnormal);
+
+ // cbrt(x) == +0.0 iff x == +0.0
+ if (KnownSrc.isKnownNeverLogicalPosZero(Mode))
+ Known.knownNot(fcPosZero);
+
+ // cbrt(x) == -0.0 iff x == -0.0
+ if (KnownSrc.isKnownNeverLogicalNegZero(Mode))
+ Known.knownNot(fcNegZero);
+
+ return Known;
+}
+
KnownFPClass KnownFPClass::sin(const KnownFPClass &KnownSrc) {
KnownFPClass Known;
@@ -650,6 +670,16 @@ KnownFPClass KnownFPClass::tanh(const KnownFPClass &KnownSrc) {
return Known;
}
+KnownFPClass KnownFPClass::acosh(const KnownFPClass &KnownSrc) {
+ KnownFPClass Known;
+
+ Known.knownNot(fcNegative);
+
+ Known.propagateNonSNaN(KnownSrc);
+
+ return Known;
+}
+
KnownFPClass KnownFPClass::asin(const KnownFPClass &KnownSrc) {
KnownFPClass Known;
diff --git a/llvm/test/Analysis/ValueTracking/known-fpclass-nonintrinsic-libcall.ll b/llvm/test/Analysis/ValueTracking/known-fpclass-nonintrinsic-libcall.ll
new file mode 100644
index 0000000000000..d22ffdbe29cc5
--- /dev/null
+++ b/llvm/test/Analysis/ValueTracking/known-fpclass-nonintrinsic-libcall.ll
@@ -0,0 +1,27 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes=instsimplify < %s -S | FileCheck %s
+
+declare float @acoshf(float)
+declare float @cbrtf(float)
+
+define i1 @acosh_nonnegative(float %x) {
+; CHECK-LABEL: define i1 @acosh_nonnegative(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT: [[ACOSH:%.*]] = call float @acoshf(float [[X]])
+; CHECK-NEXT: ret i1 true
+;
+ %acosh = call float @acoshf(float %x)
+ %cmp = fcmp uge float %acosh, 0.0
+ ret i1 %cmp
+}
+
+define i1 @cbrt_nonnan(float nofpclass(nan) %x) {
+; CHECK-LABEL: define i1 @cbrt_nonnan(
+; CHECK-SAME: float nofpclass(nan) [[X:%.*]]) {
+; CHECK-NEXT: [[CBRT:%.*]] = call float @cbrtf(float [[X]])
+; CHECK-NEXT: ret i1 false
+;
+ %cbrt = call float @cbrtf(float %x)
+ %cmp = fcmp uno float %cbrt, 0.0
+ ret i1 %cmp
+}
diff --git a/llvm/test/Transforms/Attributor/nofpclass-acosh.ll b/llvm/test/Transforms/Attributor/nofpclass-acosh.ll
new file mode 100644
index 0000000000000..b000283b4e2d3
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/nofpclass-acosh.ll
@@ -0,0 +1,36 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -S < %s | FileCheck %s
+
+declare float @acoshf(float)
+
+; acosh is never negative.
+define float @ret_acosh(float %arg) {
+; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_acosh(
+; CHECK-SAME: float [[ARG:%.*]]) {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @acoshf(float [[ARG]])
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @acoshf(float %arg)
+ ret float %call
+}
+
+; A non-NaN input below 1 can still produce a quiet NaN.
+define float @ret_acosh_nonnan(float nofpclass(nan) %arg) {
+; CHECK-LABEL: define nofpclass(snan ninf nzero nsub nnorm) float @ret_acosh_nonnan(
+; CHECK-SAME: float nofpclass(nan) [[ARG:%.*]]) {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(snan ninf nzero nsub nnorm) float @acoshf(float nofpclass(nan) [[ARG]])
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @acoshf(float %arg)
+ ret float %call
+}
+
+define float @ret_acosh_nonsnan(float nofpclass(snan) %arg) {
+; CHECK-LABEL: define nofpclass(snan ninf nzero nsub nnorm) float @ret_acosh_nonsnan(
+; CHECK-SAME: float nofpclass(snan) [[ARG:%.*]]) {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(snan ninf nzero nsub nnorm) float @acoshf(float nofpclass(snan) [[ARG]])
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @acoshf(float %arg)
+ ret float %call
+}
diff --git a/llvm/test/Transforms/Attributor/nofpclass-cbrt.ll b/llvm/test/Transforms/Attributor/nofpclass-cbrt.ll
new file mode 100644
index 0000000000000..f8145adfc363f
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/nofpclass-cbrt.ll
@@ -0,0 +1,262 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -S < %s | FileCheck %s
+
+declare float @cbrtf(float)
+
+define float @ret_cbrt(float %arg) {
+; CHECK-LABEL: define nofpclass(sub) float @ret_cbrt(
+; CHECK-SAME: float [[ARG:%.*]]) {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(sub) float @cbrtf(float [[ARG]])
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @cbrtf(float %arg)
+ ret float %call
+}
+
+define float @ret_cbrt_nonnan(float nofpclass(nan) %arg) {
+; CHECK-LABEL: define nofpclass(nan sub) float @ret_cbrt_nonnan(
+; CHECK-SAME: float nofpclass(nan) [[ARG:%.*]]) {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan sub) float @cbrtf(float nofpclass(nan) [[ARG]])
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @cbrtf(float %arg)
+ ret float %call
+}
+
+define float @ret_cbrt_nonqnan(float nofpclass(qnan) %arg) {
+; CHECK-LABEL: define nofpclass(sub) float @ret_cbrt_nonqnan(
+; CHECK-SAME: float nofpclass(qnan) [[ARG:%.*]]) {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(sub) float @cbrtf(float nofpclass(qnan) [[ARG]])
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @cbrtf(float %arg)
+ ret float %call
+}
+
+define float @ret_cbrt_nonsnan(float nofpclass(snan) %arg) {
+; CHECK-LABEL: define nofpclass(snan sub) float @ret_cbrt_nonsnan(
+; CHECK-SAME: float nofpclass(snan) [[ARG:%.*]]) {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(snan sub) float @cbrtf(float nofpclass(snan) [[ARG]])
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @cbrtf(float %arg)
+ ret float %call
+}
+
+define float @ret_cbrt_positive(float nofpclass(nan ninf nzero nsub nnorm) %arg) {
+; CHECK-LABEL: define nofpclass(nan nzero sub) float @ret_cbrt_positive(
+; CHECK-SAME: float nofpclass(nan ninf nzero nsub nnorm) [[ARG:%.*]]) {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan nzero sub) float @cbrtf(float nofpclass(nan ninf nzero nsub nnorm) [[ARG]])
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @cbrtf(float %arg)
+ ret float %call
+}
+
+define float @ret_cbrt_negative(float nofpclass(nan pinf pzero psub pnorm) %arg) {
+; CHECK-LABEL: define nofpclass(nan pzero sub) float @ret_cbrt_negative(
+; CHECK-SAME: float nofpclass(nan pinf pzero psub pnorm) [[ARG:%.*]]) {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan pzero sub) float @cbrtf(float nofpclass(nan pinf pzero psub pnorm) [[ARG]])
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @cbrtf(float %arg)
+ ret float %call
+}
+
+define float @ret_cbrt_normal(float nofpclass(nan inf sub zero) %arg) {
+; CHECK-LABEL: define nofpclass(nan zero sub) float @ret_cbrt_normal(
+; CHECK-SAME: float nofpclass(nan inf zero sub) [[ARG:%.*]]) {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan zero sub) float @cbrtf(float nofpclass(nan inf zero sub) [[ARG]])
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @cbrtf(float %arg)
+ ret float %call
+}
+
+define float @ret_cbrt_posnormal(float nofpclass(nan ninf nzero sub nnorm) %arg) {
+; CHECK-LABEL: define nofpclass(nan nzero sub) float @ret_cbrt_posnormal(
+; CHECK-SAME: float nofpclass(nan ninf nzero sub nnorm) [[ARG:%.*]]) {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan nzero sub) float @cbrtf(float nofpclass(nan ninf nzero sub nnorm) [[ARG]])
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @cbrtf(float %arg)
+ ret float %call
+}
+
+define float @ret_cbrt_negnormal(float nofpclass(nan pinf pzero sub pnorm) %arg) {
+; CHECK-LABEL: define nofpclass(nan pzero sub) float @ret_cbrt_negnormal(
+; CHECK-SAME: float nofpclass(nan pinf pzero sub pnorm) [[ARG:%.*]]) {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan pzero sub) float @cbrtf(float nofpclass(nan pinf pzero sub pnorm) [[ARG]])
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @cbrtf(float %arg)
+ ret float %call
+}
+
+define float @ret_cbrt_finite(float nofpclass(nan inf) %arg) {
+; CHECK-LABEL: define nofpclass(nan sub) float @ret_cbrt_finite(
+; CHECK-SAME: float nofpclass(nan inf) [[ARG:%.*]]) {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan sub) float @cbrtf(float nofpclass(nan inf) [[ARG]])
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @cbrtf(float %arg)
+ ret float %call
+}
+
+define float @ret_cbrt_posfinite(float nofpclass(nan inf nzero nsub nnorm) %arg) {
+; CHECK-LABEL: define nofpclass(nan nzero sub) float @ret_cbrt_posfinite(
+; CHECK-SAME: float nofpclass(nan inf nzero nsub nnorm) [[ARG:%.*]]) {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan nzero sub) float @cbrtf(float nofpclass(nan inf nzero nsub nnorm) [[ARG]])
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @cbrtf(float %arg)
+ ret float %call
+}
+
+define float @ret_cbrt_negfinite(float nofpclass(nan inf pzero psub pnorm) %arg) {
+; CHECK-LABEL: define nofpclass(nan pzero sub) float @ret_cbrt_negfinite(
+; CHECK-SAME: float nofpclass(nan inf pzero psub pnorm) [[ARG:%.*]]) {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan pzero sub) float @cbrtf(float nofpclass(nan inf pzero psub pnorm) [[ARG]])
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @cbrtf(float %arg)
+ ret float %call
+}
+
+; cbrt cannot produce a subnormal result, so only the input denormal mode
+; affects the following tests.
+
+define float @ret_cbrt_ieee_psub(float nofpclass(nan inf zero nsub norm) %arg) #0 {
+; CHECK-LABEL: define nofpclass(nan zero sub) float @ret_cbrt_ieee_psub(
+; CHECK-SAME: float nofpclass(nan inf zero nsub norm) [[ARG:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT: [[CBRT:%.*]] = call nofpclass(nan zero sub) float @cbrtf(float nofpclass(nan inf zero nsub norm) [[ARG]])
+; CHECK-NEXT: ret float [[CBRT]]
+;
+ %cbrt = call float @cbrtf(float %arg)
+ ret float %cbrt
+}
+
+define float @ret_cbrt_ieee_nsub(float nofpclass(nan inf zero psub norm) %arg) #0 {
+; CHECK-LABEL: define nofpclass(nan zero sub) float @ret_cbrt_ieee_nsub(
+; CHECK-SAME: float nofpclass(nan inf zero psub norm) [[ARG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[CBRT:%.*]] = call nofpclass(nan zero sub) float @cbrtf(float nofpclass(nan inf zero psub norm) [[ARG]])
+; CHECK-NEXT: ret float [[CBRT]]
+;
+ %cbrt = call float @cbrtf(float %arg)
+ ret float %cbrt
+}
+
+define float @ret_cbrt_ieee_sub(float nofpclass(nan inf zero norm) %arg) #0 {
+; CHECK-LABEL: define nofpclass(nan zero sub) float @ret_cbrt_ieee_sub(
+; CHECK-SAME: float nofpclass(nan inf zero norm) [[ARG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[CBRT:%.*]] = call nofpclass(nan zero sub) float @cbrtf(float nofpclass(nan inf zero norm) [[ARG]])
+; CHECK-NEXT: ret float [[CBRT]]
+;
+ %cbrt = call float @cbrtf(float %arg)
+ ret float %cbrt
+}
+
+define float @ret_cbrt_ieee_pzero(float nofpclass(nan inf nzero sub norm) %arg) #0 {
+; CHECK-LABEL: define nofpclass(nan nzero sub) float @ret_cbrt_ieee_pzero(
+; CHECK-SAME: float nofpclass(nan inf nzero sub norm) [[ARG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[CBRT:%.*]] = call nofpclass(nan nzero sub) float @cbrtf(float nofpclass(nan inf nzero sub norm) [[ARG]])
+; CHECK-NEXT: ret float [[CBRT]]
+;
+ %cbrt = call float @cbrtf(float %arg)
+ ret float %cbrt
+}
+
+define float @ret_cbrt_ieee_nzero(float nofpclass(nan inf pzero sub norm) %arg) #0 {
+; CHECK-LABEL: define nofpclass(nan pzero sub) float @ret_cbrt_ieee_nzero(
+; CHECK-SAME: float nofpclass(nan inf pzero sub norm) [[ARG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[CBRT:%.*]] = call nofpclass(nan pzero sub) float @cbrtf(float nofpclass(nan inf pzero sub norm) [[ARG]])
+; CHECK-NEXT: ret float [[CBRT]]
+;
+ %cbrt = call float @cbrtf(float %arg)
+ ret float %cbrt
+}
+
+define float @ret_cbrt_ieee_zero(float nofpclass(nan inf sub norm) %arg) #0 {
+; CHECK-LABEL: define nofpclass(nan sub) float @ret_cbrt_ieee_zero(
+; CHECK-SAME: float nofpclass(nan inf sub norm) [[ARG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[CBRT:%.*]] = call nofpclass(nan sub) float @cbrtf(float nofpclass(nan inf sub norm) [[ARG]])
+; CHECK-NEXT: ret float [[CBRT]]
+;
+ %cbrt = call float @cbrtf(float %arg)
+ ret float %cbrt
+}
+
+define float @ret_cbrt_daz_psub(float nofpclass(nan inf zero nsub norm) %arg) #1 {
+; CHECK-LABEL: define nofpclass(nan nzero sub) float @ret_cbrt_daz_psub(
+; CHECK-SAME: float nofpclass(nan inf zero nsub norm) [[ARG:%.*]]) #[[ATTR1:[0-9]+]] {
+; CHECK-NEXT: [[CBRT:%.*]] = call nofpclass(nan nzero sub) float @cbrtf(float nofpclass(nan inf zero nsub norm) [[ARG]])
+; CHECK-NEXT: ret float [[CBRT]]
+;
+ %cbrt = call float @cbrtf(float %arg)
+ ret float %cbrt
+}
+
+define float @ret_cbrt_daz_nsub(float nofpclass(nan inf zero psub norm) %arg) #1 {
+; CHECK-LABEL: define nofpclass(nan pzero sub) float @ret_cbrt_daz_nsub(
+; CHECK-SAME: float nofpclass(nan inf zero psub norm) [[ARG:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[CBRT:%.*]] = call nofpclass(nan pzero sub) float @cbrtf(float nofpclass(nan inf zero psub norm) [[ARG]])
+; CHECK-NEXT: ret float [[CBRT]]
+;
+ %cbrt = call float @cbrtf(float %arg)
+ ret float %cbrt
+}
+
+define float @ret_cbrt_daz_sub(float nofpclass(nan inf zero norm) %arg) #1 {
+; CHECK-LABEL: define nofpclass(nan sub) float @ret_cbrt_daz_sub(
+; CHECK-SAME: float nofpclass(nan inf zero norm) [[ARG:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[CBRT:%.*]] = call nofpclass(nan sub) float @cbrtf(float nofpclass(nan inf zero norm) [[ARG]])
+; CHECK-NEXT: ret float [[CBRT]]
+;
+ %cbrt = call float @cbrtf(float %arg)
+ ret float %cbrt
+}
+
+define float @ret_cbrt_dapz_sub(float nofpclass(nan inf zero norm) %arg) #2 {
+; CHECK-LABEL: define nofpclass(nan nzero sub) float @ret_cbrt_dapz_sub(
+; CHECK-SAME: float nofpclass(nan inf zero norm) [[ARG:%.*]]) #[[ATTR2:[0-9]+]] {
+; CHECK-NEXT: [[CBRT:%.*]] = call nofpclass(nan nzero sub) float @cbrtf(float nofpclass(nan inf zero norm) [[ARG]])
+; CHECK-NEXT: ret float [[CBRT]]
+;
+ %cbrt = call float @cbrtf(float %arg)
+ ret float %cbrt
+}
+
+define float @ret_cbrt_dynamic_psub(float nofpclass(nan inf zero nsub norm) %arg) #3 {
+; CHECK-LABEL: define nofpclass(nan nzero sub) float @ret_cbrt_dynamic_psub(
+; CHECK-SAME: float nofpclass(nan inf zero nsub norm) [[ARG:%.*]]) #[[ATTR3:[0-9]+]] {
+; CHECK-NEXT: [[CBRT:%.*]] = call nofpclass(nan nzero sub) float @cbrtf(float nofpclass(nan inf zero nsub norm) [[ARG]])
+; CHECK-NEXT: ret float [[CBRT]]
+;
+ %cbrt = call float @cbrtf(float %arg)
+ ret float %cbrt
+}
+
+define float @ret_cbrt_dynamic_nsub(float nofpclass(nan inf zero psub norm) %arg) #3 {
+; CHECK-LABEL: define nofpclass(nan sub) float @ret_cbrt_dynamic_nsub(
+; CHECK-SAME: float nofpclass(nan inf zero psub norm) [[ARG:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT: [[CBRT:%.*]] = call nofpclass(nan sub) float @cbrtf(float nofpclass(nan inf zero psub norm) [[ARG]])
+; CHECK-NEXT: ret float [[CBRT]]
+;
+ %cbrt = call float @cbrtf(float %arg)
+ ret float %cbrt
+}
+
+define float @ret_cbrt_dynamic_sub(float nofpclass(nan inf zero norm) %arg) #3 {
+; CHECK-LABEL: define nofpclass(nan sub) float @ret_cbrt_dynamic_sub(
+; CHECK-SAME: float nofpclass(nan inf zero norm) [[ARG:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT: [[CBRT:%.*]] = call nofpclass(nan sub) float @cbrtf(float nofpclass(nan inf zero norm) [[ARG]])
+; CHECK-NEXT: ret float [[CBRT]]
+;
+ %cbrt = call float @cbrtf(float %arg)
+ ret float %cbrt
+}
+
+attributes #0 = { denormal_fpenv(ieee|ieee) }
+attributes #1 = { denormal_fpenv(ieee|preservesign) }
+attributes #2 = { denormal_fpenv(ieee|positivezero) }
+attributes #3 = { denormal_fpenv(ieee|dynamic) }
diff --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp
index 382cf0f2b57ed..267a7d3a7b5b9 100644
--- a/llvm/unittests/Analysis/ValueTrackingTest.cpp
+++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp
@@ -10,6 +10,7 @@
#include "llvm/ADT/FloatingPointMode.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/FloatingPointPredicateUtils.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/IR/ConstantRange.h"
#include "llvm/IR/Dominators.h"
@@ -2380,6 +2381,82 @@ TEST_F(ComputeKnownFPClassTest, SqrtNszSignBit) {
}
}
+TEST_F(ComputeKnownFPClassTest, CbrtLibCall) {
+ parseAssembly(R"(
+ declare float @cbrtf(float)
+
+ define float @test(float nofpclass(nan) %arg) {
+ %A = call float @cbrtf(float %arg)
+ ret float %A
+ })");
+
+ TargetLibraryInfoImpl TLII(M->getTargetTriple());
+ TargetLibraryInfo TLI(TLII);
+
+ EXPECT_EQ(fcInf | fcNormal | fcZero,
+ computeKnownFPClass(A, M->getDataLayout(), fcAllFlags, &TLI)
+ .KnownFPClasses);
+}
+
+TEST_F(ComputeKnownFPClassTest, CbrtLibCallRequiresTLIAndBuiltin) {
+ parseAssembly(R"(
+ declare float @cbrtf(float)
+
+ define float @test(float %arg) {
+ %A = call float @cbrtf(float %arg)
+ %A2 = call float @cbrtf(float %arg) #0
+ ret float %A2
+ }
+
+ attributes #0 = { nobuiltin }
+ )");
+
+ TargetLibraryInfoImpl TLII(M->getTargetTriple());
+ TargetLibraryInfo TLI(TLII);
+
+ EXPECT_EQ(fcAllFlags,
+ computeKnownFPClass(A, M->getDataLayout()).KnownFPClasses);
+ EXPECT_EQ(fcAllFlags,
+ computeKnownFPClass(A2, M->getDataLayout(), fcAllFlags, &TLI)
+ .KnownFPClasses);
+}
+
+TEST_F(ComputeKnownFPClassTest, CbrtLibCallLocalDefinition) {
+ parseAssembly(R"(
+ define internal float @cbrtf(float %arg) {
+ ret float %arg
+ }
+
+ define float @test(float %arg) {
+ %A = call float @cbrtf(float %arg)
+ ret float %A
+ })");
+
+ TargetLibraryInfoImpl TLII(M->getTargetTriple());
+ TargetLibraryInfo TLI(TLII);
+
+ EXPECT_EQ(fcAllFlags,
+ computeKnownFPClass(A, M->getDataLayout(), fcAllFlags, &TLI)
+ .KnownFPClasses);
+}
+
+TEST_F(ComputeKnownFPClassTest, CbrtLibCallInvalidPrototype) {
+ parseAssembly(R"(
+ declare double @cbrtf(double)
+
+ define double @test(double %arg) {
+ %A = call double @cbrtf(double %arg)
+ ret double %A
+ })");
+
+ TargetLibraryInfoImpl TLII(M->getTargetTriple());
+ TargetLibraryInfo TLI(TLII);
+
+ EXPECT_EQ(fcAllFlags,
+ computeKnownFPClass(A, M->getDataLayout(), fcAllFlags, &TLI)
+ .KnownFPClasses);
+}
+
TEST_F(ComputeKnownFPClassTest, Constants) {
parseAssembly("declare float @func()\n"
"define float @test() {\n"
More information about the llvm-commits
mailing list