[llvm] [ValueTracking] use KnownBits to compute fpclass from bitcast (PR #97762)
Alex MacLean via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 5 09:01:41 PDT 2024
https://github.com/AlexMaclean updated https://github.com/llvm/llvm-project/pull/97762
>From c2913d1074c5bfa771379d68e9ba728a3d1d1ce5 Mon Sep 17 00:00:00 2001
From: Alex MacLean <amaclean at nvidia.com>
Date: Mon, 1 Jul 2024 17:06:56 +0000
Subject: [PATCH 1/2] [ValueTracking] use KnownBits to compute fpclass from
bitcast
---
llvm/lib/Analysis/ValueTracking.cpp | 30 ++++++
llvm/test/Transforms/Attributor/nofpclass.ll | 104 +++++++++++++++++++
2 files changed, 134 insertions(+)
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 85abf00774a02..a16c8e3d48403 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5805,6 +5805,36 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
break;
}
+ case Instruction::BitCast: {
+ const Type *Ty = Op->getType();
+ const Value *Casted = Op->getOperand(0);
+ if (Ty->isVectorTy() || !Casted->getType()->isIntOrIntVectorTy())
+ break;
+
+ KnownBits Bits(Ty->getScalarSizeInBits());
+ computeKnownBits(Casted, Bits, Depth + 1, Q);
+
+ // Transfer information from the sign bit.
+ if (Bits.Zero.isSignBitSet())
+ Known.signBitMustBeZero();
+ else if (Bits.One.isSignBitSet())
+ Known.signBitMustBeOne();
+
+ if (Ty->isIEEE()) {
+ // IEEE floats are NaN when all bits of the exponent plus at least one of
+ // the fraction bits are 1. This means:
+ // - If we assume unknown bits are 0 and the value is NaN, it will
+ // always be NaN
+ // - If we assume unknown bits are 1 and the value is not NaN, it can
+ // never be NaN
+ if (APFloat(Ty->getFltSemantics(), Bits.One).isNaN())
+ Known.KnownFPClasses = fcNan;
+ else if (!APFloat(Ty->getFltSemantics(), ~Bits.Zero).isNaN())
+ Known.knownNot(fcNan);
+ }
+
+ break;
+ }
default:
break;
}
diff --git a/llvm/test/Transforms/Attributor/nofpclass.ll b/llvm/test/Transforms/Attributor/nofpclass.ll
index 781ba636c3ab3..c5d562a436b33 100644
--- a/llvm/test/Transforms/Attributor/nofpclass.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass.ll
@@ -2690,6 +2690,110 @@ entry:
ret double %abs
}
+define float @bitcast_to_float_sign_0(i32 %arg) {
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @bitcast_to_float_sign_0
+; CHECK-SAME: (i32 [[ARG:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[ARG]], 1
+; CHECK-NEXT: [[TMP2:%.*]] = bitcast i32 [[TMP1]] to float
+; CHECK-NEXT: ret float [[TMP2]]
+;
+ %1 = lshr i32 %arg, 1
+ %2 = bitcast i32 %1 to float
+ ret float %2
+}
+
+define float @bitcast_to_float_nnan(i32 %arg) {
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @bitcast_to_float_nnan
+; CHECK-SAME: (i32 [[ARG:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[ARG]], 2
+; CHECK-NEXT: [[TMP2:%.*]] = bitcast i32 [[TMP1]] to float
+; CHECK-NEXT: ret float [[TMP2]]
+;
+ %1 = lshr i32 %arg, 2
+ %2 = bitcast i32 %1 to float
+ ret float %2
+}
+
+define float @bitcast_to_float_sign_1(i32 %arg) {
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @bitcast_to_float_sign_1
+; CHECK-SAME: (i32 [[ARG:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[ARG]], -2147483648
+; CHECK-NEXT: [[TMP2:%.*]] = bitcast i32 [[TMP1]] to float
+; CHECK-NEXT: ret float [[TMP2]]
+;
+ %1 = or i32 %arg, -2147483648
+ %2 = bitcast i32 %1 to float
+ ret float %2
+}
+
+define float @bitcast_to_float_nan(i32 %arg) {
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-LABEL: define nofpclass(inf zero sub norm) float @bitcast_to_float_nan
+; CHECK-SAME: (i32 [[ARG:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[ARG]], 2139095041
+; CHECK-NEXT: [[TMP2:%.*]] = bitcast i32 [[TMP1]] to float
+; CHECK-NEXT: ret float [[TMP2]]
+;
+ %1 = or i32 %arg, 2139095041
+ %2 = bitcast i32 %1 to float
+ ret float %2
+}
+
+define double @bitcast_to_double_sign_0(i64 %arg) {
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) double @bitcast_to_double_sign_0
+; CHECK-SAME: (i64 [[ARG:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT: [[TMP1:%.*]] = lshr i64 [[ARG]], 1
+; CHECK-NEXT: [[TMP2:%.*]] = bitcast i64 [[TMP1]] to double
+; CHECK-NEXT: ret double [[TMP2]]
+;
+ %1 = lshr i64 %arg, 1
+ %2 = bitcast i64 %1 to double
+ ret double %2
+}
+
+define double @bitcast_to_double_nnan(i64 %arg) {
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) double @bitcast_to_double_nnan
+; CHECK-SAME: (i64 [[ARG:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT: [[TMP1:%.*]] = lshr i64 [[ARG]], 2
+; CHECK-NEXT: [[TMP2:%.*]] = bitcast i64 [[TMP1]] to double
+; CHECK-NEXT: ret double [[TMP2]]
+;
+ %1 = lshr i64 %arg, 2
+ %2 = bitcast i64 %1 to double
+ ret double %2
+}
+
+define double @bitcast_to_double_sign_1(i64 %arg) {
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) double @bitcast_to_double_sign_1
+; CHECK-SAME: (i64 [[ARG:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT: [[TMP1:%.*]] = or i64 [[ARG]], -9223372036854775808
+; CHECK-NEXT: [[TMP2:%.*]] = bitcast i64 [[TMP1]] to double
+; CHECK-NEXT: ret double [[TMP2]]
+;
+ %1 = or i64 %arg, -9223372036854775808
+ %2 = bitcast i64 %1 to double
+ ret double %2
+}
+
+define double @bitcast_to_double_nan(i64 %arg) {
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-LABEL: define nofpclass(inf zero sub norm) double @bitcast_to_double_nan
+; CHECK-SAME: (i64 [[ARG:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT: [[TMP1:%.*]] = or i64 [[ARG]], -4503599627370495
+; CHECK-NEXT: [[TMP2:%.*]] = bitcast i64 [[TMP1]] to double
+; CHECK-NEXT: ret double [[TMP2]]
+;
+ %1 = or i64 %arg, -4503599627370495
+ %2 = bitcast i64 %1 to double
+ ret double %2
+}
+
declare i64 @_Z13get_global_idj(i32 noundef)
attributes #0 = { "denormal-fp-math"="preserve-sign,preserve-sign" }
>From 3db13768fb40b7a1dbe6bbd32dfeb9ed5c9215ed Mon Sep 17 00:00:00 2001
From: Alex MacLean <alex at alex-maclean.com>
Date: Fri, 5 Jul 2024 09:01:33 -0700
Subject: [PATCH 2/2] Update llvm/lib/Analysis/ValueTracking.cpp
Co-authored-by: Yingwei Zheng <dtcxzyw at qq.com>
---
llvm/lib/Analysis/ValueTracking.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index a16c8e3d48403..35baffedbf255 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5815,7 +5815,7 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
computeKnownBits(Casted, Bits, Depth + 1, Q);
// Transfer information from the sign bit.
- if (Bits.Zero.isSignBitSet())
+ if (Bits.isNonNegative())
Known.signBitMustBeZero();
else if (Bits.One.isSignBitSet())
Known.signBitMustBeOne();
More information about the llvm-commits
mailing list