Skip to content

Commit 047186c

Browse files
committed
[ValueTracking] isKnownNonZero() should take non-null-ness assumptions into consideration (PR43267)
Summary: It is pretty common to assume that something is not zero. Even optimizer itself sometimes emits such assumptions (e.g. `addAssumeNonNull()` in `PromoteMemoryToRegister.cpp`). But we currently don't deal with such assumptions :) The only way `isKnownNonZero()` handles assumptions is by calling `computeKnownBits()` which calls `computeKnownBitsFromAssume()`. But `x != 0` does not tell us anything about set bits, it only says that there are *some* set bits. So naturally, `KnownBits` does not get populated, and we fail to make use of this assumption. I propose to deal with this special case by special-casing it via adding a `isKnownNonZeroFromAssume()` that returns boolean when there is an applicable assumption. While there, we also deal with other predicates, mainly if the comparison is with constant. Fixes [[ https://bugs.llvm.org/show_bug.cgi?id=43267 | PR43267 ]]. Differential Revision: https://reviews.llvm.org/D71660
1 parent 92083a2 commit 047186c

File tree

3 files changed

+98
-25
lines changed

3 files changed

+98
-25
lines changed

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,73 @@ bool llvm::isValidAssumeForContext(const Instruction *Inv,
576576
return !isEphemeralValueOf(Inv, CxtI);
577577
}
578578

579+
static bool isKnownNonZeroFromAssume(const Value *V, const Query &Q) {
580+
// Use of assumptions is context-sensitive. If we don't have a context, we
581+
// cannot use them!
582+
if (!Q.AC || !Q.CxtI)
583+
return false;
584+
585+
// Note that the patterns below need to be kept in sync with the code
586+
// in AssumptionCache::updateAffectedValues.
587+
588+
auto CmpExcludesZero = [V](ICmpInst *Cmp) {
589+
auto m_V = m_CombineOr(m_Specific(V), m_PtrToInt(m_Specific(V)));
590+
591+
Value *RHS;
592+
CmpInst::Predicate Pred;
593+
if (!match(Cmp, m_c_ICmp(Pred, m_V, m_Value(RHS))))
594+
return false;
595+
// Canonicalize 'v' to be on the LHS of the comparison.
596+
if (Cmp->getOperand(1) != RHS)
597+
Pred = CmpInst::getSwappedPredicate(Pred);
598+
599+
// assume(v u> y) -> assume(v != 0)
600+
if (Pred == ICmpInst::ICMP_UGT)
601+
return true;
602+
603+
// assume(v != 0)
604+
// We special-case this one to ensure that we handle `assume(v != null)`.
605+
if (Pred == ICmpInst::ICMP_NE)
606+
return match(RHS, m_Zero());
607+
608+
// All other predicates - rely on generic ConstantRange handling.
609+
ConstantInt *CI;
610+
if (!match(RHS, m_ConstantInt(CI)))
611+
return false;
612+
ConstantRange RHSRange(CI->getValue());
613+
ConstantRange TrueValues =
614+
ConstantRange::makeAllowedICmpRegion(Pred, RHSRange);
615+
return !TrueValues.contains(APInt::getNullValue(CI->getBitWidth()));
616+
};
617+
618+
for (auto &AssumeVH : Q.AC->assumptionsFor(V)) {
619+
if (!AssumeVH)
620+
continue;
621+
CallInst *I = cast<CallInst>(AssumeVH);
622+
assert(I->getFunction() == Q.CxtI->getFunction() &&
623+
"Got assumption for the wrong function!");
624+
if (Q.isExcluded(I))
625+
continue;
626+
627+
// Warning: This loop can end up being somewhat performance sensitive.
628+
// We're running this loop for once for each value queried resulting in a
629+
// runtime of ~O(#assumes * #values).
630+
631+
assert(I->getCalledFunction()->getIntrinsicID() == Intrinsic::assume &&
632+
"must be an assume intrinsic");
633+
634+
Value *Arg = I->getArgOperand(0);
635+
ICmpInst *Cmp = dyn_cast<ICmpInst>(Arg);
636+
if (!Cmp)
637+
continue;
638+
639+
if (CmpExcludesZero(Cmp) && isValidAssumeForContext(I, Q.CxtI, Q.DT))
640+
return true;
641+
}
642+
643+
return false;
644+
}
645+
579646
static void computeKnownBitsFromAssume(const Value *V, KnownBits &Known,
580647
unsigned Depth, const Query &Q) {
581648
// Use of assumptions is context-sensitive. If we don't have a context, we
@@ -2079,6 +2146,9 @@ bool isKnownNonZero(const Value *V, unsigned Depth, const Query &Q) {
20792146
}
20802147
}
20812148

2149+
if (isKnownNonZeroFromAssume(V, Q))
2150+
return true;
2151+
20822152
// Some of the tests below are recursive, so bail out if we hit the limit.
20832153
if (Depth++ >= MaxDepth)
20842154
return false;

llvm/test/Transforms/InstCombine/assume.ll

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,7 @@ define i1 @nonnull2(i32* %a) {
252252
; CHECK-NEXT: [[LOAD:%.*]] = load i32, i32* [[A:%.*]], align 4
253253
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[LOAD]], 0
254254
; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP]])
255-
; CHECK-NEXT: [[RVAL:%.*]] = icmp eq i32 [[LOAD]], 0
256-
; CHECK-NEXT: ret i1 [[RVAL]]
255+
; CHECK-NEXT: ret i1 false
257256
;
258257
%load = load i32, i32* %a
259258
%cmp = icmp ne i32 %load, 0
@@ -273,10 +272,10 @@ define i1 @nonnull3(i32** %a, i1 %control) {
273272
; CHECK: taken:
274273
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32* [[LOAD]], null
275274
; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP]])
276-
; CHECK-NEXT: [[RVAL:%.*]] = icmp eq i32* [[LOAD]], null
277-
; CHECK-NEXT: ret i1 [[RVAL]]
275+
; CHECK-NEXT: ret i1 false
278276
; CHECK: not_taken:
279-
; CHECK-NEXT: ret i1 true
277+
; CHECK-NEXT: [[RVAL_2:%.*]] = icmp sgt i32* [[LOAD]], null
278+
; CHECK-NEXT: ret i1 [[RVAL_2]]
280279
;
281280
entry:
282281
%load = load i32*, i32** %a
@@ -287,7 +286,8 @@ taken:
287286
%rval = icmp eq i32* %load, null
288287
ret i1 %rval
289288
not_taken:
290-
ret i1 true
289+
%rval.2 = icmp sgt i32* %load, null
290+
ret i1 %rval.2
291291
}
292292

293293
; Make sure the above canonicalization does not trigger
@@ -300,8 +300,7 @@ define i1 @nonnull4(i32** %a) {
300300
; CHECK-NEXT: tail call void @escape(i32* [[LOAD]])
301301
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32* [[LOAD]], null
302302
; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP]])
303-
; CHECK-NEXT: [[RVAL:%.*]] = icmp eq i32* [[LOAD]], null
304-
; CHECK-NEXT: ret i1 [[RVAL]]
303+
; CHECK-NEXT: ret i1 false
305304
;
306305
%load = load i32*, i32** %a
307306
;; This call may throw!
@@ -353,12 +352,12 @@ define i32 @assumption_conflicts_with_known_bits(i32 %a, i32 %b) {
353352

354353
define void @debug_interference(i8 %x) {
355354
; CHECK-LABEL: @debug_interference(
356-
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 [[X:%.*]], 0
355+
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 [[X:%.*]], 0
357356
; CHECK-NEXT: tail call void @llvm.dbg.value(metadata i32 5, metadata !7, metadata !DIExpression()), !dbg !9
358-
; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP1]])
357+
; CHECK-NEXT: tail call void @llvm.assume(i1 false)
359358
; CHECK-NEXT: tail call void @llvm.dbg.value(metadata i32 5, metadata !7, metadata !DIExpression()), !dbg !9
360359
; CHECK-NEXT: tail call void @llvm.dbg.value(metadata i32 5, metadata !7, metadata !DIExpression()), !dbg !9
361-
; CHECK-NEXT: tail call void @llvm.assume(i1 false)
360+
; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP2]])
362361
; CHECK-NEXT: ret void
363362
;
364363
%cmp1 = icmp eq i8 %x, 0

llvm/test/Transforms/InstSimplify/assume-non-zero.ll

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ define i1 @nonnull0_true(i8* %x) {
1010
; CHECK-LABEL: @nonnull0_true(
1111
; CHECK-NEXT: [[A:%.*]] = icmp ne i8* [[X:%.*]], null
1212
; CHECK-NEXT: call void @llvm.assume(i1 [[A]])
13-
; CHECK-NEXT: [[Q:%.*]] = icmp ne i8* [[X]], null
14-
; CHECK-NEXT: ret i1 [[Q]]
13+
; CHECK-NEXT: ret i1 true
1514
;
1615
%a = icmp ne i8* %x, null
1716
call void @llvm.assume(i1 %a)
@@ -24,8 +23,7 @@ define i1 @nonnull1_true(i8* %x) {
2423
; CHECK-NEXT: [[INTPTR:%.*]] = ptrtoint i8* [[X:%.*]] to i64
2524
; CHECK-NEXT: [[A:%.*]] = icmp ne i64 [[INTPTR]], 0
2625
; CHECK-NEXT: call void @llvm.assume(i1 [[A]])
27-
; CHECK-NEXT: [[Q:%.*]] = icmp ne i8* [[X]], null
28-
; CHECK-NEXT: ret i1 [[Q]]
26+
; CHECK-NEXT: ret i1 true
2927
;
3028
%intptr = ptrtoint i8* %x to i64
3129
%a = icmp ne i64 %intptr, 0
@@ -38,14 +36,24 @@ define i1 @nonnull2_true(i8 %x, i8 %y) {
3836
; CHECK-LABEL: @nonnull2_true(
3937
; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 [[X:%.*]], [[Y:%.*]]
4038
; CHECK-NEXT: call void @llvm.assume(i1 [[A]])
41-
; CHECK-NEXT: [[Q:%.*]] = icmp ne i8 [[X]], 0
42-
; CHECK-NEXT: ret i1 [[Q]]
39+
; CHECK-NEXT: ret i1 true
4340
;
4441
%a = icmp ugt i8 %x, %y
4542
call void @llvm.assume(i1 %a)
4643
%q = icmp ne i8 %x, 0
4744
ret i1 %q
4845
}
46+
define i1 @nonnull2_true_swapped(i8 %x, i8 %y) {
47+
; CHECK-LABEL: @nonnull2_true_swapped(
48+
; CHECK-NEXT: [[A:%.*]] = icmp ult i8 [[Y:%.*]], [[X:%.*]]
49+
; CHECK-NEXT: call void @llvm.assume(i1 [[A]])
50+
; CHECK-NEXT: ret i1 true
51+
;
52+
%a = icmp ult i8 %y, %x
53+
call void @llvm.assume(i1 %a)
54+
%q = icmp ne i8 %x, 0
55+
ret i1 %q
56+
}
4957

5058
define i1 @nonnull3_unknown(i8 %x) {
5159
; CHECK-LABEL: @nonnull3_unknown(
@@ -61,8 +69,7 @@ define i1 @nonnull4_true(i8 %x) {
6169
; CHECK-LABEL: @nonnull4_true(
6270
; CHECK-NEXT: [[A:%.*]] = icmp uge i8 [[X:%.*]], 1
6371
; CHECK-NEXT: call void @llvm.assume(i1 [[A]])
64-
; CHECK-NEXT: [[Q:%.*]] = icmp ne i8 [[X]], 0
65-
; CHECK-NEXT: ret i1 [[Q]]
72+
; CHECK-NEXT: ret i1 true
6673
;
6774
%a = icmp uge i8 %x, 1
6875
call void @llvm.assume(i1 %a)
@@ -86,8 +93,7 @@ define i1 @nonnull6_true(i8 %x) {
8693
; CHECK-LABEL: @nonnull6_true(
8794
; CHECK-NEXT: [[A:%.*]] = icmp sgt i8 [[X:%.*]], 0
8895
; CHECK-NEXT: call void @llvm.assume(i1 [[A]])
89-
; CHECK-NEXT: [[Q:%.*]] = icmp ne i8 [[X]], 0
90-
; CHECK-NEXT: ret i1 [[Q]]
96+
; CHECK-NEXT: ret i1 true
9197
;
9298
%a = icmp sgt i8 %x, 0
9399
call void @llvm.assume(i1 %a)
@@ -98,8 +104,7 @@ define i1 @nonnull7_true(i8 %x) {
98104
; CHECK-LABEL: @nonnull7_true(
99105
; CHECK-NEXT: [[A:%.*]] = icmp sgt i8 [[X:%.*]], 1
100106
; CHECK-NEXT: call void @llvm.assume(i1 [[A]])
101-
; CHECK-NEXT: [[Q:%.*]] = icmp ne i8 [[X]], 0
102-
; CHECK-NEXT: ret i1 [[Q]]
107+
; CHECK-NEXT: ret i1 true
103108
;
104109
%a = icmp sgt i8 %x, 1
105110
call void @llvm.assume(i1 %a)
@@ -135,8 +140,7 @@ define i1 @nonnull10_true(i8 %x) {
135140
; CHECK-LABEL: @nonnull10_true(
136141
; CHECK-NEXT: [[A:%.*]] = icmp sge i8 [[X:%.*]], 1
137142
; CHECK-NEXT: call void @llvm.assume(i1 [[A]])
138-
; CHECK-NEXT: [[Q:%.*]] = icmp ne i8 [[X]], 0
139-
; CHECK-NEXT: ret i1 [[Q]]
143+
; CHECK-NEXT: ret i1 true
140144
;
141145
%a = icmp sge i8 %x, 1
142146
call void @llvm.assume(i1 %a)

0 commit comments

Comments
 (0)