From 0b1e6a1296caf95c66057c6cdd3b63a8f3157717 Mon Sep 17 00:00:00 2001 From: Alex MacLean Date: Mon, 26 Aug 2024 17:47:46 +0000 Subject: [PATCH] address comments --- llvm/lib/Analysis/ValueTracking.cpp | 26 ++++ llvm/test/Transforms/Attributor/nofpclass.ll | 129 ++++++++++++++++++- 2 files changed, 152 insertions(+), 3 deletions(-) diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 8ecaeef90b31b8..15e8716d256656 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -5948,6 +5948,32 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts, Known.KnownFPClasses = fcNan; else if (!APFloat(Ty->getFltSemantics(), ~Bits.Zero).isNaN()) Known.knownNot(fcNan); + + // Build KnownBits representing Inf and check if it must be equal or + // unequal to this value. + auto InfKB = KnownBits::makeConstant( + APFloat::getInf(Ty->getFltSemantics(), false).bitcastToAPInt()); + InfKB = InfKB.intersectWith(KnownBits::makeConstant( + APFloat::getInf(Ty->getFltSemantics(), true).bitcastToAPInt())); + if (const auto InfResult = KnownBits::eq(Bits, InfKB)) { + assert(!InfResult.value()); + Known.knownNot(fcInf); + } else if (Bits == InfKB) { + Known.KnownFPClasses = fcInf; + } + + // Build KnownBits representing Zero and check if it must be equal or + // unequal to this value. + auto ZeroKB = KnownBits::makeConstant( + APFloat::getZero(Ty->getFltSemantics(), false).bitcastToAPInt()); + ZeroKB = ZeroKB.intersectWith(KnownBits::makeConstant( + APFloat::getZero(Ty->getFltSemantics(), true).bitcastToAPInt())); + if (const auto ZeroResult = KnownBits::eq(Bits, ZeroKB)) { + assert(!ZeroResult.value()); + Known.knownNot(fcZero); + } else if (Bits == ZeroKB) { + Known.KnownFPClasses = fcZero; + } } break; diff --git a/llvm/test/Transforms/Attributor/nofpclass.ll b/llvm/test/Transforms/Attributor/nofpclass.ll index 5ea688113eb19e..2a6780b60211cf 100644 --- a/llvm/test/Transforms/Attributor/nofpclass.ll +++ b/llvm/test/Transforms/Attributor/nofpclass.ll @@ -2685,6 +2685,20 @@ define @scalable_splat_zero() { ; See https://github.com/llvm/llvm-project/issues/78507 define double @call_abs(double noundef %__x) { +; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) +; TUNIT-LABEL: define noundef nofpclass(ninf nzero nsub nnorm) double @call_abs +; TUNIT-SAME: (double noundef [[__X:%.*]]) #[[ATTR3]] { +; TUNIT-NEXT: entry: +; TUNIT-NEXT: [[ABS:%.*]] = tail call noundef nofpclass(ninf nzero nsub nnorm) double @llvm.fabs.f64(double noundef [[__X]]) #[[ATTR22]] +; TUNIT-NEXT: ret double [[ABS]] +; +; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) +; CGSCC-LABEL: define noundef nofpclass(ninf nzero nsub nnorm) double @call_abs +; CGSCC-SAME: (double noundef [[__X:%.*]]) #[[ATTR3]] { +; CGSCC-NEXT: entry: +; CGSCC-NEXT: [[ABS:%.*]] = tail call noundef nofpclass(ninf nzero nsub nnorm) double @llvm.fabs.f64(double noundef [[__X]]) #[[ATTR19]] +; CGSCC-NEXT: ret double [[ABS]] +; entry: %abs = tail call double @llvm.fabs.f64(double %__x) ret double %abs @@ -2705,7 +2719,7 @@ define float @bitcast_to_float_sign_0(i32 %arg) { 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-LABEL: define nofpclass(nan inf nzero nsub nnorm) float @bitcast_to_float_nnan ; CHECK-SAME: (i32 [[ARG:%.*]]) #[[ATTR3]] { ; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[ARG]], 2 ; CHECK-NEXT: [[CAST:%.*]] = bitcast i32 [[SHR]] to float @@ -2742,6 +2756,47 @@ define float @bitcast_to_float_nan(i32 %arg) { ret float %cast } +define float @bitcast_to_float_zero(i32 %arg) { +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define nofpclass(nan inf sub norm) float @bitcast_to_float_zero +; CHECK-SAME: (i32 [[ARG:%.*]]) #[[ATTR3]] { +; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[ARG]], 31 +; CHECK-NEXT: [[CAST:%.*]] = bitcast i32 [[SHL]] to float +; CHECK-NEXT: ret float [[CAST]] +; + %shl = shl i32 %arg, 31 + %cast = bitcast i32 %shl to float + ret float %cast +} + +define float @bitcast_to_float_nzero(i32 %arg) { +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define nofpclass(zero) float @bitcast_to_float_nzero +; CHECK-SAME: (i32 [[ARG:%.*]]) #[[ATTR3]] { +; CHECK-NEXT: [[OR:%.*]] = or i32 [[ARG]], 134217728 +; CHECK-NEXT: [[CAST:%.*]] = bitcast i32 [[OR]] to float +; CHECK-NEXT: ret float [[CAST]] +; + %or = or i32 %arg, 134217728 + %cast = bitcast i32 %or to float + ret float %cast +} + +define float @bitcast_to_float_inf(i32 %arg) { +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define nofpclass(nan zero sub norm) float @bitcast_to_float_inf +; CHECK-SAME: (i32 [[ARG:%.*]]) #[[ATTR3]] { +; CHECK-NEXT: [[SHR:%.*]] = shl i32 [[ARG]], 31 +; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHR]], 2139095040 +; CHECK-NEXT: [[CAST:%.*]] = bitcast i32 [[OR]] to float +; CHECK-NEXT: ret float [[CAST]] +; + %shr = shl i32 %arg, 31 + %or = or i32 %shr, 2139095040 + %cast = bitcast i32 %or to float + ret float %cast +} + 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 @@ -2757,7 +2812,7 @@ define double @bitcast_to_double_sign_0(i64 %arg) { 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-LABEL: define nofpclass(nan inf nzero nsub nnorm) double @bitcast_to_double_nnan ; CHECK-SAME: (i64 [[ARG:%.*]]) #[[ATTR3]] { ; CHECK-NEXT: [[SHR:%.*]] = lshr i64 [[ARG]], 2 ; CHECK-NEXT: [[CAST:%.*]] = bitcast i64 [[SHR]] to double @@ -2795,6 +2850,48 @@ define double @bitcast_to_double_nan(i64 %arg) { } +define double @bitcast_to_double_zero(i64 %arg) { +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define nofpclass(nan inf sub norm) double @bitcast_to_double_zero +; CHECK-SAME: (i64 [[ARG:%.*]]) #[[ATTR3]] { +; CHECK-NEXT: [[SHL:%.*]] = shl i64 [[ARG]], 63 +; CHECK-NEXT: [[CAST:%.*]] = bitcast i64 [[SHL]] to double +; CHECK-NEXT: ret double [[CAST]] +; + %shl = shl i64 %arg, 63 + %cast = bitcast i64 %shl to double + ret double %cast +} + +define double @bitcast_to_double_nzero(i64 %arg) { +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define nofpclass(zero) double @bitcast_to_double_nzero +; CHECK-SAME: (i64 [[ARG:%.*]]) #[[ATTR3]] { +; CHECK-NEXT: [[OR:%.*]] = or i64 [[ARG]], 1152921504606846976 +; CHECK-NEXT: [[CAST:%.*]] = bitcast i64 [[OR]] to double +; CHECK-NEXT: ret double [[CAST]] +; + %or = or i64 %arg, 1152921504606846976 + %cast = bitcast i64 %or to double + ret double %cast +} + +define double @bitcast_to_double_inf(i64 %arg) { +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define nofpclass(nan zero sub norm) double @bitcast_to_double_inf +; CHECK-SAME: (i64 [[ARG:%.*]]) #[[ATTR3]] { +; CHECK-NEXT: [[SHR:%.*]] = shl i64 [[ARG]], 63 +; CHECK-NEXT: [[OR:%.*]] = or i64 [[SHR]], 9218868437227405312 +; CHECK-NEXT: [[CAST:%.*]] = bitcast i64 [[OR]] to double +; CHECK-NEXT: ret double [[CAST]] +; + %shr = shl i64 %arg, 63 + %or = or i64 %shr, 9218868437227405312 + %cast = bitcast i64 %or to double + ret double %cast +} + + define <2 x float> @bitcast_to_float_vect_sign_0(<2 x i32> %arg) { ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) <2 x float> @bitcast_to_float_vect_sign_0 @@ -2810,7 +2907,7 @@ define <2 x float> @bitcast_to_float_vect_sign_0(<2 x i32> %arg) { define <2 x float> @bitcast_to_float_vect_nnan(<2 x i32> %arg) { ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) -; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) <2 x float> @bitcast_to_float_vect_nnan +; CHECK-LABEL: define nofpclass(nan inf nzero nsub nnorm) <2 x float> @bitcast_to_float_vect_nnan ; CHECK-SAME: (<2 x i32> [[ARG:%.*]]) #[[ATTR3]] { ; CHECK-NEXT: [[SHR:%.*]] = lshr <2 x i32> [[ARG]], ; CHECK-NEXT: [[CAST:%.*]] = bitcast <2 x i32> [[SHR]] to <2 x float> @@ -2847,6 +2944,32 @@ define <2 x float> @bitcast_to_float_vect_nan(<2 x i32> %arg) { ret <2 x float> %cast } +define <2 x float> @bitcast_to_float_vect_conservative_1(<2 x i32> %arg) { +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define <2 x float> @bitcast_to_float_vect_conservative_1 +; CHECK-SAME: (<2 x i32> [[ARG:%.*]]) #[[ATTR3]] { +; CHECK-NEXT: [[OR:%.*]] = or <2 x i32> [[ARG]], +; CHECK-NEXT: [[CAST:%.*]] = bitcast <2 x i32> [[OR]] to <2 x float> +; CHECK-NEXT: ret <2 x float> [[CAST]] +; + %or = or <2 x i32> %arg, + %cast = bitcast <2 x i32> %or to <2 x float> + ret <2 x float> %cast +} + +define <2 x float> @bitcast_to_float_vect_conservative_2(<2 x i32> %arg) { +; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) +; CHECK-LABEL: define <2 x float> @bitcast_to_float_vect_conservative_2 +; CHECK-SAME: (<2 x i32> [[ARG:%.*]]) #[[ATTR3]] { +; CHECK-NEXT: [[OR:%.*]] = or <2 x i32> [[ARG]], +; CHECK-NEXT: [[CAST:%.*]] = bitcast <2 x i32> [[OR]] to <2 x float> +; CHECK-NEXT: ret <2 x float> [[CAST]] +; + %or = or <2 x i32> %arg, + %cast = bitcast <2 x i32> %or to <2 x float> + ret <2 x float> %cast +} + declare i64 @_Z13get_global_idj(i32 noundef) attributes #0 = { "denormal-fp-math"="preserve-sign,preserve-sign" }