[llvm] [KnownFPClass] Add support for non-intrinsic math libcalls (PR #216234)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 24 21:48:49 PDT 2026
https://github.com/ZERICO2005 updated https://github.com/llvm/llvm-project/pull/216234
>From 1f65ef116d436d7a04495ca0cc4fa2dd519fd06a 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 | 43 +++
llvm/lib/Support/KnownFPClass.cpp | 30 ++
.../Transforms/Attributor/nofpclass-acosh.ll | 47 +++
.../Transforms/Attributor/nofpclass-cbrt.ll | 273 ++++++++++++++++++
...ss-nonintrinsic-longdouble-f128-aarch64.ll | 27 ++
...ass-nonintrinsic-longdouble-f128-x86-64.ll | 27 ++
...ass-nonintrinsic-longdouble-f80-aarch64.ll | 27 ++
...lass-nonintrinsic-longdouble-f80-x86-64.ll | 27 ++
...-libfunc-nonintrinsic-invalid-prototype.ll | 16 +
.../fp-libfunc-nonintrinsic-libcall.ll | 27 ++
.../fp-libfunc-nonintrinsic-local.ll | 22 ++
.../fp-libfunc-nonintrinsic-recognition.ll | 31 ++
13 files changed, 604 insertions(+)
create mode 100644 llvm/test/Transforms/Attributor/nofpclass-acosh.ll
create mode 100644 llvm/test/Transforms/Attributor/nofpclass-cbrt.ll
create mode 100644 llvm/test/Transforms/Attributor/nofpclass-nonintrinsic-longdouble-f128-aarch64.ll
create mode 100644 llvm/test/Transforms/Attributor/nofpclass-nonintrinsic-longdouble-f128-x86-64.ll
create mode 100644 llvm/test/Transforms/Attributor/nofpclass-nonintrinsic-longdouble-f80-aarch64.ll
create mode 100644 llvm/test/Transforms/Attributor/nofpclass-nonintrinsic-longdouble-f80-x86-64.ll
create mode 100644 llvm/test/Transforms/InstSimplify/fp-libfunc-nonintrinsic-invalid-prototype.ll
create mode 100644 llvm/test/Transforms/InstSimplify/fp-libfunc-nonintrinsic-libcall.ll
create mode 100644 llvm/test/Transforms/InstSimplify/fp-libfunc-nonintrinsic-local.ll
create mode 100644 llvm/test/Transforms/InstSimplify/fp-libfunc-nonintrinsic-recognition.ll
diff --git a/llvm/include/llvm/Support/KnownFPClass.h b/llvm/include/llvm/Support/KnownFPClass.h
index 60b5ae3d7e5be..865960590b393 100644
--- a/llvm/include/llvm/Support/KnownFPClass.h
+++ b/llvm/include/llvm/Support/KnownFPClass.h
@@ -326,6 +326,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);
@@ -451,6 +454,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 d4951ef705493..fcc074ad414cf 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5763,6 +5763,49 @@ 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 = Q.TLI->getLibFunc(*II);
+ if (Func == NotLibFunc)
+ 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 37a6160b316ff..76aea722ee752 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -616,6 +616,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;
@@ -683,6 +703,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/Transforms/Attributor/nofpclass-acosh.ll b/llvm/test/Transforms/Attributor/nofpclass-acosh.ll
new file mode 100644
index 0000000000000..c73dd365136e6
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/nofpclass-acosh.ll
@@ -0,0 +1,47 @@
+; 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)
+declare double @acosh(double)
+
+; acosh is never negative.
+define float @ret_acoshf(float %arg) {
+; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_acoshf(
+; 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
+}
+
+define double @ret_acosh(double %arg) {
+; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) double @ret_acosh(
+; CHECK-SAME: double [[ARG:%.*]]) {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) double @acosh(double [[ARG]])
+; CHECK-NEXT: ret double [[CALL]]
+;
+ %call = call double @acosh(double %arg)
+ ret double %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..109907f0f6205
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/nofpclass-cbrt.ll
@@ -0,0 +1,273 @@
+; 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)
+declare double @cbrt(double)
+
+define float @ret_cbrtf(float %arg) {
+; CHECK-LABEL: define nofpclass(sub) float @ret_cbrtf(
+; 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 double @ret_cbrt(double %arg) {
+; CHECK-LABEL: define nofpclass(sub) double @ret_cbrt(
+; CHECK-SAME: double [[ARG:%.*]]) {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(sub) double @cbrt(double [[ARG]])
+; CHECK-NEXT: ret double [[CALL]]
+;
+ %call = call double @cbrt(double %arg)
+ ret double %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/test/Transforms/Attributor/nofpclass-nonintrinsic-longdouble-f128-aarch64.ll b/llvm/test/Transforms/Attributor/nofpclass-nonintrinsic-longdouble-f128-aarch64.ll
new file mode 100644
index 0000000000000..013cd2c4f1ddc
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/nofpclass-nonintrinsic-longdouble-f128-aarch64.ll
@@ -0,0 +1,27 @@
+; 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
+
+target triple = "aarch64-unknown-linux-gnu"
+
+declare fp128 @acoshl(fp128)
+declare fp128 @cbrtl(fp128)
+
+define fp128 @ret_acoshl(fp128 %arg) {
+; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) fp128 @ret_acoshl(
+; CHECK-SAME: fp128 [[ARG:%.*]]) {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) fp128 @acoshl(fp128 [[ARG]])
+; CHECK-NEXT: ret fp128 [[CALL]]
+;
+ %call = call fp128 @acoshl(fp128 %arg)
+ ret fp128 %call
+}
+
+define fp128 @ret_cbrtl(fp128 %arg) {
+; CHECK-LABEL: define nofpclass(sub) fp128 @ret_cbrtl(
+; CHECK-SAME: fp128 [[ARG:%.*]]) {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(sub) fp128 @cbrtl(fp128 [[ARG]])
+; CHECK-NEXT: ret fp128 [[CALL]]
+;
+ %call = call fp128 @cbrtl(fp128 %arg)
+ ret fp128 %call
+}
diff --git a/llvm/test/Transforms/Attributor/nofpclass-nonintrinsic-longdouble-f128-x86-64.ll b/llvm/test/Transforms/Attributor/nofpclass-nonintrinsic-longdouble-f128-x86-64.ll
new file mode 100644
index 0000000000000..e5f7db3a32842
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/nofpclass-nonintrinsic-longdouble-f128-x86-64.ll
@@ -0,0 +1,27 @@
+; 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
+
+target triple = "x86_64-unknown-linux-gnu"
+
+declare fp128 @acoshl(fp128)
+declare fp128 @cbrtl(fp128)
+
+define fp128 @ret_acoshl(fp128 %arg) {
+; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) fp128 @ret_acoshl(
+; CHECK-SAME: fp128 [[ARG:%.*]]) {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) fp128 @acoshl(fp128 [[ARG]])
+; CHECK-NEXT: ret fp128 [[CALL]]
+;
+ %call = call fp128 @acoshl(fp128 %arg)
+ ret fp128 %call
+}
+
+define fp128 @ret_cbrtl(fp128 %arg) {
+; CHECK-LABEL: define nofpclass(sub) fp128 @ret_cbrtl(
+; CHECK-SAME: fp128 [[ARG:%.*]]) {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(sub) fp128 @cbrtl(fp128 [[ARG]])
+; CHECK-NEXT: ret fp128 [[CALL]]
+;
+ %call = call fp128 @cbrtl(fp128 %arg)
+ ret fp128 %call
+}
diff --git a/llvm/test/Transforms/Attributor/nofpclass-nonintrinsic-longdouble-f80-aarch64.ll b/llvm/test/Transforms/Attributor/nofpclass-nonintrinsic-longdouble-f80-aarch64.ll
new file mode 100644
index 0000000000000..cb185e6bae383
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/nofpclass-nonintrinsic-longdouble-f80-aarch64.ll
@@ -0,0 +1,27 @@
+; 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
+
+target triple = "aarch64-unknown-linux-gnu"
+
+declare x86_fp80 @acoshl(x86_fp80)
+declare x86_fp80 @cbrtl(x86_fp80)
+
+define x86_fp80 @ret_acoshl(x86_fp80 %arg) {
+; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) x86_fp80 @ret_acoshl(
+; CHECK-SAME: x86_fp80 [[ARG:%.*]]) {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) x86_fp80 @acoshl(x86_fp80 [[ARG]])
+; CHECK-NEXT: ret x86_fp80 [[CALL]]
+;
+ %call = call x86_fp80 @acoshl(x86_fp80 %arg)
+ ret x86_fp80 %call
+}
+
+define x86_fp80 @ret_cbrtl(x86_fp80 %arg) {
+; CHECK-LABEL: define nofpclass(sub) x86_fp80 @ret_cbrtl(
+; CHECK-SAME: x86_fp80 [[ARG:%.*]]) {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(sub) x86_fp80 @cbrtl(x86_fp80 [[ARG]])
+; CHECK-NEXT: ret x86_fp80 [[CALL]]
+;
+ %call = call x86_fp80 @cbrtl(x86_fp80 %arg)
+ ret x86_fp80 %call
+}
diff --git a/llvm/test/Transforms/Attributor/nofpclass-nonintrinsic-longdouble-f80-x86-64.ll b/llvm/test/Transforms/Attributor/nofpclass-nonintrinsic-longdouble-f80-x86-64.ll
new file mode 100644
index 0000000000000..e9609cb29b3ae
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/nofpclass-nonintrinsic-longdouble-f80-x86-64.ll
@@ -0,0 +1,27 @@
+; 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
+
+target triple = "x86_64-unknown-linux-gnu"
+
+declare x86_fp80 @acoshl(x86_fp80)
+declare x86_fp80 @cbrtl(x86_fp80)
+
+define x86_fp80 @ret_acoshl(x86_fp80 %arg) {
+; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) x86_fp80 @ret_acoshl(
+; CHECK-SAME: x86_fp80 [[ARG:%.*]]) {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) x86_fp80 @acoshl(x86_fp80 [[ARG]])
+; CHECK-NEXT: ret x86_fp80 [[CALL]]
+;
+ %call = call x86_fp80 @acoshl(x86_fp80 %arg)
+ ret x86_fp80 %call
+}
+
+define x86_fp80 @ret_cbrtl(x86_fp80 %arg) {
+; CHECK-LABEL: define nofpclass(sub) x86_fp80 @ret_cbrtl(
+; CHECK-SAME: x86_fp80 [[ARG:%.*]]) {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(sub) x86_fp80 @cbrtl(x86_fp80 [[ARG]])
+; CHECK-NEXT: ret x86_fp80 [[CALL]]
+;
+ %call = call x86_fp80 @cbrtl(x86_fp80 %arg)
+ ret x86_fp80 %call
+}
diff --git a/llvm/test/Transforms/InstSimplify/fp-libfunc-nonintrinsic-invalid-prototype.ll b/llvm/test/Transforms/InstSimplify/fp-libfunc-nonintrinsic-invalid-prototype.ll
new file mode 100644
index 0000000000000..7279619f132e8
--- /dev/null
+++ b/llvm/test/Transforms/InstSimplify/fp-libfunc-nonintrinsic-invalid-prototype.ll
@@ -0,0 +1,16 @@
+; 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 @cbrtf(i32)
+
+define i1 @cbrtf_invalid_prototype(i32 %x) {
+; CHECK-LABEL: define i1 @cbrtf_invalid_prototype(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT: [[CBRT:%.*]] = call float @cbrtf(i32 [[X]])
+; CHECK-NEXT: [[CMP:%.*]] = fcmp uno float [[CBRT]], 0.000000e+00
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %cbrt = call float @cbrtf(i32 %x)
+ %cmp = fcmp uno float %cbrt, 0.0
+ ret i1 %cmp
+}
diff --git a/llvm/test/Transforms/InstSimplify/fp-libfunc-nonintrinsic-libcall.ll b/llvm/test/Transforms/InstSimplify/fp-libfunc-nonintrinsic-libcall.ll
new file mode 100644
index 0000000000000..ebb3c3968be6a
--- /dev/null
+++ b/llvm/test/Transforms/InstSimplify/fp-libfunc-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 @acoshf_nonnegative(float %x) {
+; CHECK-LABEL: define i1 @acoshf_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 @cbrtf_nonnan(float nofpclass(nan) %x) {
+; CHECK-LABEL: define i1 @cbrtf_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/InstSimplify/fp-libfunc-nonintrinsic-local.ll b/llvm/test/Transforms/InstSimplify/fp-libfunc-nonintrinsic-local.ll
new file mode 100644
index 0000000000000..1622a6432bc70
--- /dev/null
+++ b/llvm/test/Transforms/InstSimplify/fp-libfunc-nonintrinsic-local.ll
@@ -0,0 +1,22 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes=instsimplify < %s -S | FileCheck %s
+
+define internal float @cbrtf(float %x) {
+; CHECK-LABEL: define internal float @cbrtf(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT: ret float [[X]]
+;
+ ret float %x
+}
+
+define i1 @cbrtf_local_definition(float nofpclass(nan) %x) {
+; CHECK-LABEL: define i1 @cbrtf_local_definition(
+; CHECK-SAME: float nofpclass(nan) [[X:%.*]]) {
+; CHECK-NEXT: [[CBRT:%.*]] = call float @cbrtf(float [[X]])
+; CHECK-NEXT: [[CMP:%.*]] = fcmp uno float [[CBRT]], 0.000000e+00
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %cbrt = call float @cbrtf(float %x)
+ %cmp = fcmp uno float %cbrt, 0.0
+ ret i1 %cmp
+}
diff --git a/llvm/test/Transforms/InstSimplify/fp-libfunc-nonintrinsic-recognition.ll b/llvm/test/Transforms/InstSimplify/fp-libfunc-nonintrinsic-recognition.ll
new file mode 100644
index 0000000000000..5fd18366cf57d
--- /dev/null
+++ b/llvm/test/Transforms/InstSimplify/fp-libfunc-nonintrinsic-recognition.ll
@@ -0,0 +1,31 @@
+; 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 @cbrtf(float)
+
+; A mismatched call-site type makes getCalledFunction() return nullptr.
+define i1 @cbrtf_mistyped_call(double nofpclass(nan) %x) {
+; CHECK-LABEL: define i1 @cbrtf_mistyped_call(
+; CHECK-SAME: double nofpclass(nan) [[X:%.*]]) {
+; CHECK-NEXT: [[CBRT:%.*]] = call double @cbrtf(double [[X]])
+; CHECK-NEXT: [[CMP:%.*]] = fcmp uno double [[CBRT]], 0.000000e+00
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %cbrt = call double @cbrtf(double %x)
+ %cmp = fcmp uno double %cbrt, 0.0
+ ret i1 %cmp
+}
+
+define i1 @cbrtf_nobuiltin(float nofpclass(nan) %x) {
+; CHECK-LABEL: define i1 @cbrtf_nobuiltin(
+; CHECK-SAME: float nofpclass(nan) [[X:%.*]]) {
+; CHECK-NEXT: [[CBRT:%.*]] = call float @cbrtf(float [[X]]) #[[ATTR0:[0-9]+]]
+; CHECK-NEXT: [[CMP:%.*]] = fcmp uno float [[CBRT]], 0.000000e+00
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %cbrt = call float @cbrtf(float %x) nobuiltin
+ %cmp = fcmp uno float %cbrt, 0.0
+ ret i1 %cmp
+}
+
+attributes #0 = { nobuiltin }
More information about the llvm-commits
mailing list