[llvm] 16a0629 - [ValueTracking] Compute known FPClass from signbit idiom (#80740)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Feb 14 04:53:19 PST 2024
Author: Yingwei Zheng
Date: 2024-02-14T20:53:16+08:00
New Revision: 16a0629e7c16cc1ec1a5066c57be3044a1e00395
URL: https://github.com/llvm/llvm-project/commit/16a0629e7c16cc1ec1a5066c57be3044a1e00395
DIFF: https://github.com/llvm/llvm-project/commit/16a0629e7c16cc1ec1a5066c57be3044a1e00395.diff
LOG: [ValueTracking] Compute known FPClass from signbit idiom (#80740)
This patch improves `computeKnownFPClass` by using context-sensitive
information from `DomConditionCache`.
The motivation of this patch is to optimize the following case found in
[fmt/format.h](https://github.com/fmtlib/fmt/blob/e17bc67547a66cdd378ca6a90c56b865d30d6168/include/fmt/format.h#L3555-L3566):
```
define float @test(float %x, i1 %cond) {
%i32 = bitcast float %x to i32
%cmp = icmp slt i32 %i32, 0
br i1 %cmp, label %if.then1, label %if.else
if.then1:
%fneg = fneg float %x
br label %if.end
if.else:
br i1 %cond, label %if.then2, label %if.end
if.then2:
br label %if.end
if.end:
%value = phi float [ %fneg, %if.then1 ], [ %x, %if.then2 ], [ %x, %if.else ]
%ret = call float @llvm.fabs.f32(float %value)
ret float %ret
}
```
We can prove the sign bit of %value is always zero. Then the fabs can be
eliminated.
This pattern also exists in cpython/duckdb/oiio/openexr.
Compile-time impact:
https://llvm-compile-time-tracker.com/compare.php?from=f82e0809ba12170e2f648f8a1ac01e78ef06c958&to=041218bf5491996edd828cc15b3aec5a59ddc636&stat=instructions:u
|stage1-O3|stage1-ReleaseThinLTO|stage1-ReleaseLTO-g|stage1-O0-g|stage2-O3|stage2-O0-g|stage2-clang|
|--|--|--|--|--|--|--|
|-0.00%|+0.01%|+0.00%|-0.03%|+0.00%|+0.00%|+0.02%|
Added:
Modified:
llvm/lib/Analysis/DomConditionCache.cpp
llvm/lib/Analysis/ValueTracking.cpp
llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll
Removed:
################################################################################
diff --git a/llvm/lib/Analysis/DomConditionCache.cpp b/llvm/lib/Analysis/DomConditionCache.cpp
index c07a8a76f111df..274f3ff44b2a6f 100644
--- a/llvm/lib/Analysis/DomConditionCache.cpp
+++ b/llvm/lib/Analysis/DomConditionCache.cpp
@@ -66,6 +66,11 @@ static void findAffectedValues(Value *Cond,
// A > C3 && A < C4.
if (match(A, m_Add(m_Value(X), m_ConstantInt())))
AddAffected(X);
+ // Handle icmp slt/sgt (bitcast X to int), 0/-1, which is supported by
+ // computeKnownFPClass().
+ if ((Pred == ICmpInst::ICMP_SLT || Pred == ICmpInst::ICMP_SGT) &&
+ match(A, m_ElementWiseBitCast(m_Value(X))))
+ Affected.push_back(X);
}
} else if (match(Cond, m_CombineOr(m_FCmp(Pred, m_Value(A), m_Constant()),
m_Intrinsic<Intrinsic::is_fpclass>(
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 6c42facea3b2b3..cc1d5b74dcfc53 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -4272,7 +4272,7 @@ static void computeKnownFPClassFromCond(const Value *V, Value *Cond,
Value *LHS;
uint64_t ClassVal = 0;
const APFloat *CRHS;
- // TODO: handle sign-bit check idiom
+ const APInt *RHS;
if (match(Cond, m_FCmp(Pred, m_Value(LHS), m_APFloat(CRHS)))) {
auto [CmpVal, MaskIfTrue, MaskIfFalse] = fcmpImpliesClass(
Pred, *CxtI->getParent()->getParent(), LHS, *CRHS, LHS != V);
@@ -4282,6 +4282,15 @@ static void computeKnownFPClassFromCond(const Value *V, Value *Cond,
m_Value(LHS), m_ConstantInt(ClassVal)))) {
FPClassTest Mask = static_cast<FPClassTest>(ClassVal);
KnownFromContext.knownNot(CondIsTrue ? ~Mask : Mask);
+ } else if (match(Cond, m_ICmp(Pred, m_ElementWiseBitCast(m_Value(LHS)),
+ m_APInt(RHS)))) {
+ bool TrueIfSigned;
+ if (!isSignBitCheck(Pred, *RHS, TrueIfSigned))
+ return;
+ if (TrueIfSigned == CondIsTrue)
+ KnownFromContext.signBitMustBeOne();
+ else
+ KnownFromContext.signBitMustBeZero();
}
}
diff --git a/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll b/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll
index 5d4840159dc9a0..d40cd7fd503ecc 100644
--- a/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll
+++ b/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll
@@ -320,3 +320,118 @@ if.else:
%ret = call i1 @llvm.is.fpclass.f32(float %x, i32 783)
ret i1 %ret
}
+
+define float @test_signbit_check(float %x, i1 %cond) {
+; CHECK-LABEL: define float @test_signbit_check(
+; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT: [[I32:%.*]] = bitcast float [[X]] to i32
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I32]], 0
+; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN1:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then1:
+; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[X]]
+; CHECK-NEXT: br label [[IF_END:%.*]]
+; CHECK: if.else:
+; CHECK-NEXT: br i1 [[COND]], label [[IF_THEN2:%.*]], label [[IF_END]]
+; CHECK: if.then2:
+; CHECK-NEXT: br label [[IF_END]]
+; CHECK: if.end:
+; CHECK-NEXT: [[VALUE:%.*]] = phi float [ [[FNEG]], [[IF_THEN1]] ], [ [[X]], [[IF_THEN2]] ], [ [[X]], [[IF_ELSE]] ]
+; CHECK-NEXT: ret float [[VALUE]]
+;
+ %i32 = bitcast float %x to i32
+ %cmp = icmp slt i32 %i32, 0
+ br i1 %cmp, label %if.then1, label %if.else
+
+if.then1:
+ %fneg = fneg float %x
+ br label %if.end
+
+if.else:
+ br i1 %cond, label %if.then2, label %if.end
+
+if.then2:
+ br label %if.end
+
+if.end:
+ %value = phi float [ %fneg, %if.then1 ], [ %x, %if.then2 ], [ %x, %if.else ]
+ %ret = call float @llvm.fabs.f32(float %value)
+ ret float %ret
+}
+
+define float @test_signbit_check_fail(float %x, i1 %cond) {
+; CHECK-LABEL: define float @test_signbit_check_fail(
+; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT: [[I32:%.*]] = bitcast float [[X]] to i32
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I32]], 0
+; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN1:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then1:
+; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[X]]
+; CHECK-NEXT: br label [[IF_END:%.*]]
+; CHECK: if.else:
+; CHECK-NEXT: br i1 [[COND]], label [[IF_THEN2:%.*]], label [[IF_END]]
+; CHECK: if.then2:
+; CHECK-NEXT: [[FNEG2:%.*]] = fneg float [[X]]
+; CHECK-NEXT: br label [[IF_END]]
+; CHECK: if.end:
+; CHECK-NEXT: [[VALUE:%.*]] = phi float [ [[FNEG]], [[IF_THEN1]] ], [ [[FNEG2]], [[IF_THEN2]] ], [ [[X]], [[IF_ELSE]] ]
+; CHECK-NEXT: [[RET:%.*]] = call float @llvm.fabs.f32(float [[VALUE]])
+; CHECK-NEXT: ret float [[RET]]
+;
+ %i32 = bitcast float %x to i32
+ %cmp = icmp slt i32 %i32, 0
+ br i1 %cmp, label %if.then1, label %if.else
+
+if.then1:
+ %fneg = fneg float %x
+ br label %if.end
+
+if.else:
+ br i1 %cond, label %if.then2, label %if.end
+
+if.then2:
+ %fneg2 = fneg float %x
+ br label %if.end
+
+if.end:
+ %value = phi float [ %fneg, %if.then1 ], [ %fneg2, %if.then2 ], [ %x, %if.else ]
+ %ret = call float @llvm.fabs.f32(float %value)
+ ret float %ret
+}
+
+define <2 x float> @test_signbit_check_wrong_type(<2 x float> %x, i1 %cond) {
+; CHECK-LABEL: define <2 x float> @test_signbit_check_wrong_type(
+; CHECK-SAME: <2 x float> [[X:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT: [[I32:%.*]] = bitcast <2 x float> [[X]] to i64
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[I32]], 0
+; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN1:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then1:
+; CHECK-NEXT: [[FNEG:%.*]] = fneg <2 x float> [[X]]
+; CHECK-NEXT: br label [[IF_END:%.*]]
+; CHECK: if.else:
+; CHECK-NEXT: br i1 [[COND]], label [[IF_THEN2:%.*]], label [[IF_END]]
+; CHECK: if.then2:
+; CHECK-NEXT: br label [[IF_END]]
+; CHECK: if.end:
+; CHECK-NEXT: [[VALUE:%.*]] = phi <2 x float> [ [[FNEG]], [[IF_THEN1]] ], [ [[X]], [[IF_THEN2]] ], [ [[X]], [[IF_ELSE]] ]
+; CHECK-NEXT: [[RET:%.*]] = call <2 x float> @llvm.fabs.v2f32(<2 x float> [[VALUE]])
+; CHECK-NEXT: ret <2 x float> [[RET]]
+;
+ %i32 = bitcast <2 x float> %x to i64
+ %cmp = icmp slt i64 %i32, 0
+ br i1 %cmp, label %if.then1, label %if.else
+
+if.then1:
+ %fneg = fneg <2 x float> %x
+ br label %if.end
+
+if.else:
+ br i1 %cond, label %if.then2, label %if.end
+
+if.then2:
+ br label %if.end
+
+if.end:
+ %value = phi <2 x float> [ %fneg, %if.then1 ], [ %x, %if.then2 ], [ %x, %if.else ]
+ %ret = call <2 x float> @llvm.fabs.v2f32(<2 x float> %value)
+ ret <2 x float> %ret
+}
More information about the llvm-commits
mailing list