[llvm] [ValueTracking] Handle assume(!(trunc X)) in computeKnownBitsFromContext (PR #219854)
Rohan Jha via llvm-commits
llvm-commits at lists.llvm.org
Sun Sep 13 12:28:25 PDT 2026
https://github.com/rohan11235813 updated https://github.com/llvm/llvm-project/pull/219854
>From 1c9624fac2c8c5e7311391705826b6af64ed3058 Mon Sep 17 00:00:00 2001
From: rohan11235813 <rohanj at quadric.io>
Date: Sat, 29 Aug 2026 14:46:12 -0700
Subject: [PATCH] [ValueTracking] Handle assume(!(trunc X)) in
computeKnownBitsFromContext
---
llvm/lib/Analysis/ValueTracking.cpp | 14 +++++
llvm/test/Transforms/InstCombine/assume.ll | 63 ++++++++++++++++++++
llvm/test/Transforms/InstSimplify/compare.ll | 3 +-
3 files changed, 78 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index ac49dbc8d76d3a..c18184cdb41f88 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -1145,6 +1145,20 @@ void llvm::computeKnownBitsFromContext(const Value *V, KnownBits &Known,
Known.One.setBit(0);
return;
}
+ // assume(!(trunc V)) -> the low bit of V is zero.
+ Value *NotOp;
+ if (match(Arg, m_Not(m_Value(NotOp, m_Trunc(m_Specific(V))))) &&
+ (Q.AllowEphemerals ||
+ (Q.CxtI != Arg && Q.CxtI != NotOp && Q.CxtI != V)) &&
+ isValidAssumeForContext(I, Q.allowEphemerals(true))) {
+ auto *NotTrunc = cast<TruncInst>(NotOp);
+ if (NotTrunc->hasNoUnsignedWrap()) {
+ Known = KnownBits::makeConstant(APInt(BitWidth, 0));
+ return;
+ }
+ Known.Zero.setBit(0);
+ return;
+ }
// The remaining tests are all recursive, so bail out if we hit the limit.
if (Depth == MaxAnalysisRecursionDepth)
diff --git a/llvm/test/Transforms/InstCombine/assume.ll b/llvm/test/Transforms/InstCombine/assume.ll
index ff59947939a60e..7cb76176886875 100644
--- a/llvm/test/Transforms/InstCombine/assume.ll
+++ b/llvm/test/Transforms/InstCombine/assume.ll
@@ -1332,6 +1332,69 @@ define i1 @neg_assume_trunc_eq_one(i8 %x) {
ret i1 %q
}
+define i1 @assume_not_trunc_nuw_eq_zero(i8 %x) {
+; CHECK-LABEL: @assume_not_trunc_nuw_eq_zero(
+; CHECK-NEXT: [[A:%.*]] = trunc nuw i8 [[X:%.*]] to i1
+; CHECK-NEXT: [[N:%.*]] = xor i1 [[A]], true
+; CHECK-NEXT: call void @llvm.assume(i1 [[N]])
+; CHECK-NEXT: ret i1 true
+;
+ %a = trunc nuw i8 %x to i1
+ %n = xor i1 %a, true
+ call void @llvm.assume(i1 %n)
+ %q = icmp eq i8 %x, 0
+ ret i1 %q
+}
+
+define i1 @neg_assume_not_trunc_eq_zero(i8 %x) {
+; CHECK-LABEL: @neg_assume_not_trunc_eq_zero(
+; CHECK-NEXT: [[A:%.*]] = trunc i8 [[X:%.*]] to i1
+; CHECK-NEXT: [[N:%.*]] = xor i1 [[A]], true
+; CHECK-NEXT: call void @llvm.assume(i1 [[N]])
+; CHECK-NEXT: [[Q:%.*]] = icmp eq i8 [[X]], 0
+; CHECK-NEXT: ret i1 [[Q]]
+;
+ %a = trunc i8 %x to i1
+ %n = xor i1 %a, true
+ call void @llvm.assume(i1 %n)
+ %q = icmp eq i8 %x, 0
+ ret i1 %q
+}
+
+define i8 @assume_not_trunc_low_bit(i8 %x) {
+; CHECK-LABEL: @assume_not_trunc_low_bit(
+; CHECK-NEXT: [[A:%.*]] = trunc i8 [[X:%.*]] to i1
+; CHECK-NEXT: [[N:%.*]] = xor i1 [[A]], true
+; CHECK-NEXT: call void @llvm.assume(i1 [[N]])
+; CHECK-NEXT: ret i8 0
+;
+ %a = trunc i8 %x to i1
+ %n = xor i1 %a, true
+ call void @llvm.assume(i1 %n)
+ %q = and i8 %x, 1
+ ret i8 %q
+}
+
+; The condition has a use other than the assume. The fact is still available to
+; %q, which is not one of the assumption's ephemeral values, and the assume
+; itself is preserved -- simplifying %a or %n with it would make the assumption
+; vacuous and delete it.
+define i8 @assume_not_trunc_multi_use(i8 %x) {
+; CHECK-LABEL: @assume_not_trunc_multi_use(
+; CHECK-NEXT: [[A:%.*]] = trunc i8 [[X:%.*]] to i1
+; CHECK-NEXT: [[N:%.*]] = xor i1 [[A]], true
+; CHECK-NEXT: call void @llvm.assume(i1 [[N]])
+; CHECK-NEXT: call void @use(i1 [[N]])
+; CHECK-NEXT: ret i8 0
+;
+ %a = trunc i8 %x to i1
+ %n = xor i1 %a, true
+ call void @llvm.assume(i1 %n)
+ call void @use(i1 %n)
+ %q = and i8 %x, 1
+ ret i8 %q
+}
+
define void @assume_dereferenceable_0(ptr %ptr) {
; CHECK-LABEL: @assume_dereferenceable_0(
; CHECK-NEXT: ret void
diff --git a/llvm/test/Transforms/InstSimplify/compare.ll b/llvm/test/Transforms/InstSimplify/compare.ll
index 18768a9d24e311..5b037e51a119a0 100644
--- a/llvm/test/Transforms/InstSimplify/compare.ll
+++ b/llvm/test/Transforms/InstSimplify/compare.ll
@@ -3545,8 +3545,7 @@ define i1 @icmp_eq_false_by_trunc(i8 %x) {
; CHECK-NEXT: [[TRUNC:%.*]] = trunc i8 [[X:%.*]] to i1
; CHECK-NEXT: [[NOT:%.*]] = xor i1 [[TRUNC]], true
; CHECK-NEXT: call void @llvm.assume(i1 [[NOT]])
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X]], 1
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 false
;
%trunc = trunc i8 %x to i1
%not = xor i1 %trunc, true
More information about the llvm-commits
mailing list