[llvm] [ValueTracking] Compute knownbits from known fp classes (PR #86409)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Sat Mar 23 12:47:37 PDT 2024
https://github.com/dtcxzyw created https://github.com/llvm/llvm-project/pull/86409
This patch calculates knownbits from fp instructions/dominating fcmp conditions. It will enable more optimizations with signbit idioms.
>From 3516f12689f43c1ae29550221a94b5e0021f2950 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 24 Mar 2024 03:36:09 +0800
Subject: [PATCH 1/2] [ValueTracking] Add pre-commit tests. NFC.
---
.../test/Transforms/InstCombine/known-bits.ll | 169 ++++++++++++++++++
1 file changed, 169 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/known-bits.ll b/llvm/test/Transforms/InstCombine/known-bits.ll
index 58c283815cf910..cc5143bc3d75c7 100644
--- a/llvm/test/Transforms/InstCombine/known-bits.ll
+++ b/llvm/test/Transforms/InstCombine/known-bits.ll
@@ -483,5 +483,174 @@ if.else:
ret i64 13
}
+define i1 @test_sign_pos(float %x) {
+; CHECK-LABEL: @test_sign_pos(
+; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
+; CHECK-NEXT: [[Y:%.*]] = bitcast float [[FABS]] to i32
+; CHECK-NEXT: [[SIGN:%.*]] = icmp sgt i32 [[Y]], -1
+; CHECK-NEXT: ret i1 [[SIGN]]
+;
+ %fabs = call float @llvm.fabs.f32(float %x)
+ %y = bitcast float %fabs to i32
+ %sign = icmp sgt i32 %y, -1
+ ret i1 %sign
+}
+
+define i1 @test_sign_neg(float %x) {
+; CHECK-LABEL: @test_sign_neg(
+; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
+; CHECK-NEXT: [[FNABS:%.*]] = fneg float [[FABS]]
+; CHECK-NEXT: [[Y:%.*]] = bitcast float [[FNABS]] to i32
+; CHECK-NEXT: [[SIGN:%.*]] = icmp slt i32 [[Y]], 0
+; CHECK-NEXT: ret i1 [[SIGN]]
+;
+ %fabs = call float @llvm.fabs.f32(float %x)
+ %fnabs = fneg float %fabs
+ %y = bitcast float %fnabs to i32
+ %sign = icmp slt i32 %y, 0
+ ret i1 %sign
+}
+
+define <2 x i1> @test_sign_pos_vec(<2 x float> %x) {
+; CHECK-LABEL: @test_sign_pos_vec(
+; CHECK-NEXT: [[FABS:%.*]] = call <2 x float> @llvm.fabs.v2f32(<2 x float> [[X:%.*]])
+; CHECK-NEXT: [[Y:%.*]] = bitcast <2 x float> [[FABS]] to <2 x i32>
+; CHECK-NEXT: [[SIGN:%.*]] = icmp slt <2 x i32> [[Y]], zeroinitializer
+; CHECK-NEXT: ret <2 x i1> [[SIGN]]
+;
+ %fabs = call <2 x float> @llvm.fabs.v2f32(<2 x float> %x)
+ %y = bitcast <2 x float> %fabs to <2 x i32>
+ %sign = icmp slt <2 x i32> %y, zeroinitializer
+ ret <2 x i1> %sign
+}
+
+define i32 @test_inf_only(float nofpclass(nan sub norm zero) %x) {
+; CHECK-LABEL: @test_inf_only(
+; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
+; CHECK-NEXT: [[AND:%.*]] = bitcast float [[TMP1]] to i32
+; CHECK-NEXT: ret i32 [[AND]]
+;
+ %y = bitcast float %x to i32
+ %and = and i32 %y, 2147483647
+ ret i32 %and
+}
+
+define i32 @test_zero_only(float nofpclass(nan sub norm inf) %x) {
+; CHECK-LABEL: @test_zero_only(
+; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
+; CHECK-NEXT: [[AND:%.*]] = bitcast float [[TMP1]] to i32
+; CHECK-NEXT: ret i32 [[AND]]
+;
+ %y = bitcast float %x to i32
+ %and = and i32 %y, 2147483647
+ ret i32 %and
+}
+
+define i32 @test_inf_nan_only(float nofpclass(sub norm zero) %x) {
+; CHECK-LABEL: @test_inf_nan_only(
+; CHECK-NEXT: [[Y:%.*]] = bitcast float [[X:%.*]] to i32
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y]], 2130706432
+; CHECK-NEXT: ret i32 [[AND]]
+;
+ %y = bitcast float %x to i32
+ %and = and i32 %y, 2130706432
+ ret i32 %and
+}
+
+define i32 @test_sub_zero_only(float nofpclass(nan norm inf) %x) {
+; CHECK-LABEL: @test_sub_zero_only(
+; CHECK-NEXT: [[Y:%.*]] = bitcast float [[X:%.*]] to i32
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y]], 2130706432
+; CHECK-NEXT: ret i32 [[AND]]
+;
+ %y = bitcast float %x to i32
+ %and = and i32 %y, 2130706432
+ ret i32 %and
+}
+
+define i32 @test_inf_zero_only(float nofpclass(nan norm sub) %x) {
+; CHECK-LABEL: @test_inf_zero_only(
+; CHECK-NEXT: [[Y:%.*]] = bitcast float [[X:%.*]] to i32
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y]], 16777215
+; CHECK-NEXT: ret i32 [[AND]]
+;
+ %y = bitcast float %x to i32
+ %and = and i32 %y, 16777215
+ ret i32 %and
+}
+
+define i1 @test_simplify_icmp(i32 %x) {
+; CHECK-LABEL: @test_simplify_icmp(
+; CHECK-NEXT: [[CONV_I_I:%.*]] = uitofp i32 [[X:%.*]] to double
+; CHECK-NEXT: [[TMP1:%.*]] = bitcast double [[CONV_I_I]] to i64
+; CHECK-NEXT: [[SHR_I_MASK_I:%.*]] = and i64 [[TMP1]], -140737488355328
+; CHECK-NEXT: [[CMP_I:%.*]] = icmp eq i64 [[SHR_I_MASK_I]], -1970324836974592
+; CHECK-NEXT: ret i1 [[CMP_I]]
+;
+ %conv.i.i = uitofp i32 %x to double
+ %3 = bitcast double %conv.i.i to i64
+ %shr.i.mask.i = and i64 %3, -140737488355328
+ %cmp.i = icmp eq i64 %shr.i.mask.i, -1970324836974592
+ ret i1 %cmp.i
+}
+
+define i16 @test_simplify_mask(i32 %ui, float %x) {
+; CHECK-LABEL: @test_simplify_mask(
+; CHECK-NEXT: [[CONV:%.*]] = uitofp i32 [[UI:%.*]] to float
+; CHECK-NEXT: [[CMP:%.*]] = fcmp ogt float [[CONV]], [[X:%.*]]
+; CHECK-NEXT: br i1 [[CMP]], label [[IF_ELSE:%.*]], label [[IF_END:%.*]]
+; CHECK: if.end:
+; CHECK-NEXT: [[CAST:%.*]] = bitcast float [[CONV]] to i32
+; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[CAST]], 16
+; CHECK-NEXT: [[TRUNC:%.*]] = trunc i32 [[SHR]] to i16
+; CHECK-NEXT: [[AND:%.*]] = and i16 [[TRUNC]], -32768
+; CHECK-NEXT: [[OR:%.*]] = or disjoint i16 [[AND]], 31744
+; CHECK-NEXT: ret i16 [[OR]]
+; CHECK: if.else:
+; CHECK-NEXT: ret i16 0
+;
+ %conv = uitofp i32 %ui to float
+ %cmp = fcmp olt float %x, %conv
+ br i1 %cmp, label %if.else, label %if.end
+
+if.end:
+ %cast = bitcast float %conv to i32
+ %shr = lshr i32 %cast, 16
+ %trunc = trunc i32 %shr to i16
+ %and = and i16 %trunc, -32768
+ %or = or disjoint i16 %and, 31744
+ ret i16 %or
+
+if.else:
+ ret i16 0
+}
+
+; TODO: %cmp always evaluates to false
+
+define i1 @test_simplify_icmp2(double %x) {
+; CHECK-LABEL: @test_simplify_icmp2(
+; CHECK-NEXT: [[ABS:%.*]] = tail call double @llvm.fabs.f64(double [[X:%.*]])
+; CHECK-NEXT: [[COND:%.*]] = fcmp oeq double [[ABS]], 0x7FF0000000000000
+; CHECK-NEXT: br i1 [[COND]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[CAST:%.*]] = bitcast double [[X]] to i64
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[CAST]], 3458764513820540928
+; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK: if.else:
+; CHECK-NEXT: ret i1 false
+;
+ %abs = tail call double @llvm.fabs.f64(double %x)
+ %cond = fcmp oeq double %abs, 0x7FF0000000000000
+ br i1 %cond, label %if.then, label %if.else
+
+if.then:
+ %cast = bitcast double %x to i64
+ %cmp = icmp eq i64 %cast, 3458764513820540928
+ ret i1 %cmp
+
+if.else:
+ ret i1 false
+}
+
declare void @use(i1)
declare void @sink(i8)
>From 099349d6736bfa404c3b44e3dac1024694a27df4 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 24 Mar 2024 03:38:27 +0800
Subject: [PATCH 2/2] [ValueTracking] Infer knownbits from fp classes
---
llvm/include/llvm/Analysis/ValueTracking.h | 5 ++
llvm/lib/Analysis/ValueTracking.cpp | 31 ++++++++++++
.../test/Transforms/InstCombine/known-bits.ll | 49 ++++---------------
3 files changed, 46 insertions(+), 39 deletions(-)
diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h
index 3970efba18cc8c..697482caed6c4a 100644
--- a/llvm/include/llvm/Analysis/ValueTracking.h
+++ b/llvm/include/llvm/Analysis/ValueTracking.h
@@ -263,6 +263,11 @@ struct KnownFPClass {
return (KnownFPClasses & Mask) == fcNone;
}
+ /// Return true if it's known this can only be one of the mask entries.
+ bool isKnownOnly(FPClassTest Mask) const {
+ return (KnownFPClasses & ~Mask) == fcNone;
+ }
+
bool isUnknown() const {
return KnownFPClasses == fcAllFlags && !SignBit;
}
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 797665cf06c875..a2bcf1d278829c 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -1105,6 +1105,37 @@ static void computeKnownBitsFromOperator(const Operator *I,
break;
}
+ Value *V;
+ // Handle bitcast from floating point to integer.
+ if (match(const_cast<Operator *>(I), m_ElementWiseBitCast(m_Value(V))) &&
+ V->getType()->isFPOrFPVectorTy()) {
+ KnownFPClass Result = computeKnownFPClass(V, fcAllFlags, Depth + 1, Q);
+ if (Result.SignBit) {
+ if (*Result.SignBit)
+ Known.makeNegative();
+ else
+ Known.makeNonNegative();
+ }
+
+ Type *FPType = V->getType()->getScalarType();
+ int MantissaWidth = FPType->getFPMantissaWidth();
+ if (MantissaWidth != -1) {
+ if (Result.isKnownOnly(fcInf)) {
+ Known.Zero.setLowBits(MantissaWidth);
+ Known.One.setBits(MantissaWidth, BitWidth - 1);
+ } else if (Result.isKnownOnly(fcZero))
+ Known.Zero.setLowBits(BitWidth - 1);
+ else if (Result.isKnownOnly(fcInf | fcNan))
+ Known.One.setBits(MantissaWidth, BitWidth - 1);
+ else if (Result.isKnownOnly(fcSubnormal | fcZero))
+ Known.Zero.setBits(MantissaWidth, BitWidth - 1);
+ else if (Result.isKnownOnly(fcInf | fcZero))
+ Known.Zero.setLowBits(MantissaWidth);
+ }
+
+ break;
+ }
+
// Handle cast from vector integer type to scalar or vector integer.
auto *SrcVecTy = dyn_cast<FixedVectorType>(SrcTy);
if (!SrcVecTy || !SrcVecTy->getElementType()->isIntegerTy() ||
diff --git a/llvm/test/Transforms/InstCombine/known-bits.ll b/llvm/test/Transforms/InstCombine/known-bits.ll
index cc5143bc3d75c7..60c94f99298235 100644
--- a/llvm/test/Transforms/InstCombine/known-bits.ll
+++ b/llvm/test/Transforms/InstCombine/known-bits.ll
@@ -485,10 +485,7 @@ if.else:
define i1 @test_sign_pos(float %x) {
; CHECK-LABEL: @test_sign_pos(
-; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
-; CHECK-NEXT: [[Y:%.*]] = bitcast float [[FABS]] to i32
-; CHECK-NEXT: [[SIGN:%.*]] = icmp sgt i32 [[Y]], -1
-; CHECK-NEXT: ret i1 [[SIGN]]
+; CHECK-NEXT: ret i1 true
;
%fabs = call float @llvm.fabs.f32(float %x)
%y = bitcast float %fabs to i32
@@ -498,11 +495,7 @@ define i1 @test_sign_pos(float %x) {
define i1 @test_sign_neg(float %x) {
; CHECK-LABEL: @test_sign_neg(
-; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
-; CHECK-NEXT: [[FNABS:%.*]] = fneg float [[FABS]]
-; CHECK-NEXT: [[Y:%.*]] = bitcast float [[FNABS]] to i32
-; CHECK-NEXT: [[SIGN:%.*]] = icmp slt i32 [[Y]], 0
-; CHECK-NEXT: ret i1 [[SIGN]]
+; CHECK-NEXT: ret i1 true
;
%fabs = call float @llvm.fabs.f32(float %x)
%fnabs = fneg float %fabs
@@ -513,10 +506,7 @@ define i1 @test_sign_neg(float %x) {
define <2 x i1> @test_sign_pos_vec(<2 x float> %x) {
; CHECK-LABEL: @test_sign_pos_vec(
-; CHECK-NEXT: [[FABS:%.*]] = call <2 x float> @llvm.fabs.v2f32(<2 x float> [[X:%.*]])
-; CHECK-NEXT: [[Y:%.*]] = bitcast <2 x float> [[FABS]] to <2 x i32>
-; CHECK-NEXT: [[SIGN:%.*]] = icmp slt <2 x i32> [[Y]], zeroinitializer
-; CHECK-NEXT: ret <2 x i1> [[SIGN]]
+; CHECK-NEXT: ret <2 x i1> zeroinitializer
;
%fabs = call <2 x float> @llvm.fabs.v2f32(<2 x float> %x)
%y = bitcast <2 x float> %fabs to <2 x i32>
@@ -526,9 +516,7 @@ define <2 x i1> @test_sign_pos_vec(<2 x float> %x) {
define i32 @test_inf_only(float nofpclass(nan sub norm zero) %x) {
; CHECK-LABEL: @test_inf_only(
-; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
-; CHECK-NEXT: [[AND:%.*]] = bitcast float [[TMP1]] to i32
-; CHECK-NEXT: ret i32 [[AND]]
+; CHECK-NEXT: ret i32 2130706432
;
%y = bitcast float %x to i32
%and = and i32 %y, 2147483647
@@ -537,9 +525,7 @@ define i32 @test_inf_only(float nofpclass(nan sub norm zero) %x) {
define i32 @test_zero_only(float nofpclass(nan sub norm inf) %x) {
; CHECK-LABEL: @test_zero_only(
-; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
-; CHECK-NEXT: [[AND:%.*]] = bitcast float [[TMP1]] to i32
-; CHECK-NEXT: ret i32 [[AND]]
+; CHECK-NEXT: ret i32 0
;
%y = bitcast float %x to i32
%and = and i32 %y, 2147483647
@@ -548,9 +534,7 @@ define i32 @test_zero_only(float nofpclass(nan sub norm inf) %x) {
define i32 @test_inf_nan_only(float nofpclass(sub norm zero) %x) {
; CHECK-LABEL: @test_inf_nan_only(
-; CHECK-NEXT: [[Y:%.*]] = bitcast float [[X:%.*]] to i32
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y]], 2130706432
-; CHECK-NEXT: ret i32 [[AND]]
+; CHECK-NEXT: ret i32 2130706432
;
%y = bitcast float %x to i32
%and = and i32 %y, 2130706432
@@ -559,9 +543,7 @@ define i32 @test_inf_nan_only(float nofpclass(sub norm zero) %x) {
define i32 @test_sub_zero_only(float nofpclass(nan norm inf) %x) {
; CHECK-LABEL: @test_sub_zero_only(
-; CHECK-NEXT: [[Y:%.*]] = bitcast float [[X:%.*]] to i32
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y]], 2130706432
-; CHECK-NEXT: ret i32 [[AND]]
+; CHECK-NEXT: ret i32 0
;
%y = bitcast float %x to i32
%and = and i32 %y, 2130706432
@@ -570,9 +552,7 @@ define i32 @test_sub_zero_only(float nofpclass(nan norm inf) %x) {
define i32 @test_inf_zero_only(float nofpclass(nan norm sub) %x) {
; CHECK-LABEL: @test_inf_zero_only(
-; CHECK-NEXT: [[Y:%.*]] = bitcast float [[X:%.*]] to i32
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y]], 16777215
-; CHECK-NEXT: ret i32 [[AND]]
+; CHECK-NEXT: ret i32 0
;
%y = bitcast float %x to i32
%and = and i32 %y, 16777215
@@ -581,11 +561,7 @@ define i32 @test_inf_zero_only(float nofpclass(nan norm sub) %x) {
define i1 @test_simplify_icmp(i32 %x) {
; CHECK-LABEL: @test_simplify_icmp(
-; CHECK-NEXT: [[CONV_I_I:%.*]] = uitofp i32 [[X:%.*]] to double
-; CHECK-NEXT: [[TMP1:%.*]] = bitcast double [[CONV_I_I]] to i64
-; CHECK-NEXT: [[SHR_I_MASK_I:%.*]] = and i64 [[TMP1]], -140737488355328
-; CHECK-NEXT: [[CMP_I:%.*]] = icmp eq i64 [[SHR_I_MASK_I]], -1970324836974592
-; CHECK-NEXT: ret i1 [[CMP_I]]
+; CHECK-NEXT: ret i1 false
;
%conv.i.i = uitofp i32 %x to double
%3 = bitcast double %conv.i.i to i64
@@ -600,12 +576,7 @@ define i16 @test_simplify_mask(i32 %ui, float %x) {
; CHECK-NEXT: [[CMP:%.*]] = fcmp ogt float [[CONV]], [[X:%.*]]
; CHECK-NEXT: br i1 [[CMP]], label [[IF_ELSE:%.*]], label [[IF_END:%.*]]
; CHECK: if.end:
-; CHECK-NEXT: [[CAST:%.*]] = bitcast float [[CONV]] to i32
-; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[CAST]], 16
-; CHECK-NEXT: [[TRUNC:%.*]] = trunc i32 [[SHR]] to i16
-; CHECK-NEXT: [[AND:%.*]] = and i16 [[TRUNC]], -32768
-; CHECK-NEXT: [[OR:%.*]] = or disjoint i16 [[AND]], 31744
-; CHECK-NEXT: ret i16 [[OR]]
+; CHECK-NEXT: ret i16 31744
; CHECK: if.else:
; CHECK-NEXT: ret i16 0
;
More information about the llvm-commits
mailing list