<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body text="#000000" bgcolor="#FFFFFF">
<p>Is there any chance <valid_pointer> is a inbounds geps?
Without that, I can't see the connection to the patch.</p>
<p>Philip<br>
</p>
<div class="moz-cite-prefix">On 8/26/19 5:05 PM, Jordan Rupprecht
wrote:<br>
</div>
<blockquote type="cite"
cite="mid:CABC7LbRqX7Yep96+XO1J6UM5UvCPwZHogad7=9nWqkWGvnmXxQ@mail.gmail.com">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<div dir="ltr">btw, we're seeing something that looks like
miscompiles with this patch (& after the fix in r369795).
The code looks pretty well defined (passes asan/msan/etc.).
<div><br>
</div>
<div>I'm trying to reduce it into something that actually
triggers the bug, but it vaguely looks like:</div>
<div>struct Foo {</div>
<div> bool IsValid() const { return x; }</div>
<div> Foo(char *y): x(y) {}</div>
<div> char *x;</div>
<div>}</div>
<div><br>
</div>
<div>Foo get() {</div>
<div> return some_condition ? Foo(<valid pointer>) :
Foo(nullptr);</div>
<div>}</div>
<div><br>
</div>
<div>void doSomething() {</div>
<div> Foo foo = get();</div>
<div> if (foo.IsValid()) { .. }</div>
<div>}</div>
<div><br>
</div>
<div>What I'm observing is get() go down the branch of
some_condition being true and returning Foo(<valid
pointer>), but foo.IsValid() is returning false.</div>
<div><br>
Given that context, is there anything you might see is a
subtle bug with this patch?</div>
</div>
<br>
<div class="gmail_quote">
<div dir="ltr" class="gmail_attr">On Fri, Aug 23, 2019 at 10:57
AM Philip Reames via llvm-commits <<a
href="mailto:llvm-commits@lists.llvm.org"
moz-do-not-send="true">llvm-commits@lists.llvm.org</a>>
wrote:<br>
</div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px
0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Author:
reames<br>
Date: Fri Aug 23 10:58:58 2019<br>
New Revision: 369789<br>
<br>
URL: <a
href="http://llvm.org/viewvc/llvm-project?rev=369789&view=rev"
rel="noreferrer" target="_blank" moz-do-not-send="true">http://llvm.org/viewvc/llvm-project?rev=369789&view=rev</a><br>
Log:<br>
[InstCombine] icmp eq/ne (gep inbounds P, Idx..), null ->
icmp eq/ne P, null<br>
<br>
This generalizes the isGEPKnownNonNull rule from ValueTracking
to apply when we do not know if the base is non-null, and thus
need to replace one condition with another.<br>
<br>
The core notion is that since an inbounds GEP can only form
null if the base pointer is null and the offset is zero.
However, if the offset is non-zero, the the "inbounds" marker
makes the result poison. Thus, we're free to ignore the case
where the offset is non-zero. Similarly, there's no case under
which a non-null base can result in a null result without
generating poison.<br>
<br>
Differential Revision: <a
href="https://reviews.llvm.org/D66608" rel="noreferrer"
target="_blank" moz-do-not-send="true">https://reviews.llvm.org/D66608</a><br>
<br>
<br>
Added:<br>
llvm/trunk/test/Transforms/InstCombine/gep-inbounds-null.ll<br>
Modified:<br>
llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp<br>
<br>
Modified:
llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp<br>
URL: <a
href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp?rev=369789&r1=369788&r2=369789&view=diff"
rel="noreferrer" target="_blank" moz-do-not-send="true">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp?rev=369789&r1=369788&r2=369789&view=diff</a><br>
==============================================================================<br>
---
llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp
(original)<br>
+++
llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp
Fri Aug 23 10:58:58 2019<br>
@@ -894,6 +894,27 @@ Instruction *InstCombiner::foldGEPICmp(G<br>
Offset = EmitGEPOffset(GEPLHS);<br>
return new ICmpInst(ICmpInst::getSignedPredicate(Cond),
Offset,<br>
Constant::getNullValue(Offset->getType()));<br>
+ } else if (GEPLHS->isInBounds() &&
ICmpInst::isEquality(Cond) &&<br>
+ GEPLHS->getType()->isPointerTy()
&& // TODO: extend to vector geps<br>
+ isa<Constant>(RHS) &&
cast<Constant>(RHS)->isNullValue() &&<br>
+ !NullPointerIsDefined(I.getFunction(),<br>
+
RHS->getType()->getPointerAddressSpace())) {<br>
+ // For most address spaces, an allocation can't be placed
at null, but null<br>
+ // itself is treated as a 0 size allocation in the in
bounds rules. Thus,<br>
+ // the only valid inbounds address derived from null, is
null itself.<br>
+ // Thus, we have four cases to consider:<br>
+ // 1) Base == nullptr, Offset == 0 -> inbounds, null<br>
+ // 2) Base == nullptr, Offset != 0 -> poison as the
result is out of bounds<br>
+ // 3) Base != nullptr, Offset == (-base) -> poison
(crossing allocations)<br>
+ // 4) Base != nullptr, Offset != (-base) -> nonnull
(and possibly poison)<br>
+ //<br>
+ // (Note if we're indexing a type of size 0, that simply
collapses into one<br>
+ // of the buckets above.)<br>
+ //<br>
+ // In general, we're allowed to make values less poison
(i.e. remove<br>
+ // sources of full UB), so in this case, we just select
between the two<br>
+ // non-poison cases (1 and 4 above).<br>
+ return new ICmpInst(Cond, GEPLHS->getPointerOperand(),
RHS);<br>
} else if (GEPOperator *GEPRHS =
dyn_cast<GEPOperator>(RHS)) {<br>
// If the base pointers are different, but the indices
are the same, just<br>
// compare the base pointer.<br>
<br>
Added:
llvm/trunk/test/Transforms/InstCombine/gep-inbounds-null.ll<br>
URL: <a
href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/gep-inbounds-null.ll?rev=369789&view=auto"
rel="noreferrer" target="_blank" moz-do-not-send="true">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/gep-inbounds-null.ll?rev=369789&view=auto</a><br>
==============================================================================<br>
---
llvm/trunk/test/Transforms/InstCombine/gep-inbounds-null.ll
(added)<br>
+++
llvm/trunk/test/Transforms/InstCombine/gep-inbounds-null.ll
Fri Aug 23 10:58:58 2019<br>
@@ -0,0 +1,184 @@<br>
+; NOTE: Assertions have been autogenerated by
utils/update_test_checks.py<br>
+; RUN: opt -S < %s -instcombine | FileCheck %s<br>
+<br>
+;; Start by showing the results of constant folding (which
doesn't use<br>
+;; the poison implied by gep for the nonnull cases).<br>
+<br>
+define i1 @test_ne_constants_null() {<br>
+; CHECK-LABEL: @test_ne_constants_null(<br>
+; CHECK-NEXT: entry:<br>
+; CHECK-NEXT: ret i1 false<br>
+;<br>
+entry:<br>
+ %gep = getelementptr inbounds i8, i8* null, i64 0<br>
+ %cnd = icmp ne i8* %gep, null<br>
+ ret i1 %cnd<br>
+}<br>
+<br>
+define i1 @test_ne_constants_nonnull() {<br>
+; CHECK-LABEL: @test_ne_constants_nonnull(<br>
+; CHECK-NEXT: entry:<br>
+; CHECK-NEXT: ret i1 true<br>
+;<br>
+entry:<br>
+ %gep = getelementptr inbounds i8, i8* null, i64 1<br>
+ %cnd = icmp ne i8* %gep, null<br>
+ ret i1 %cnd<br>
+}<br>
+<br>
+define i1 @test_eq_constants_null() {<br>
+; CHECK-LABEL: @test_eq_constants_null(<br>
+; CHECK-NEXT: entry:<br>
+; CHECK-NEXT: ret i1 true<br>
+;<br>
+entry:<br>
+ %gep = getelementptr inbounds i8, i8* null, i64 0<br>
+ %cnd = icmp eq i8* %gep, null<br>
+ ret i1 %cnd<br>
+}<br>
+<br>
+define i1 @test_eq_constants_nonnull() {<br>
+; CHECK-LABEL: @test_eq_constants_nonnull(<br>
+; CHECK-NEXT: entry:<br>
+; CHECK-NEXT: ret i1 false<br>
+;<br>
+entry:<br>
+ %gep = getelementptr inbounds i8, i8* null, i64 1<br>
+ %cnd = icmp eq i8* %gep, null<br>
+ ret i1 %cnd<br>
+}<br>
+<br>
+;; Then show the results for non-constants. These use the
inbounds provided<br>
+;; UB fact to ignore the possible overflow cases.<br>
+<br>
+define i1 @test_ne(i8* %base, i64 %idx) {<br>
+; CHECK-LABEL: @test_ne(<br>
+; CHECK-NEXT: entry:<br>
+; CHECK-NEXT: [[CND:%.*]] = icmp ne i8* [[BASE:%.*]], null<br>
+; CHECK-NEXT: ret i1 [[CND]]<br>
+;<br>
+entry:<br>
+ %gep = getelementptr inbounds i8, i8* %base, i64 %idx<br>
+ %cnd = icmp ne i8* %gep, null<br>
+ ret i1 %cnd<br>
+}<br>
+<br>
+define i1 @test_eq(i8* %base, i64 %idx) {<br>
+; CHECK-LABEL: @test_eq(<br>
+; CHECK-NEXT: entry:<br>
+; CHECK-NEXT: [[CND:%.*]] = icmp eq i8* [[BASE:%.*]], null<br>
+; CHECK-NEXT: ret i1 [[CND]]<br>
+;<br>
+entry:<br>
+ %gep = getelementptr inbounds i8, i8* %base, i64 %idx<br>
+ %cnd = icmp eq i8* %gep, null<br>
+ ret i1 %cnd<br>
+}<br>
+<br>
+;; TODO: vectors not yet handled<br>
+define <2 x i1> @test_vector_base(<2 x i8*>
%base, i64 %idx) {<br>
+; CHECK-LABEL: @test_vector_base(<br>
+; CHECK-NEXT: entry:<br>
+; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8,
<2 x i8*> [[BASE:%.*]], i64 [[IDX:%.*]]<br>
+; CHECK-NEXT: [[CND:%.*]] = icmp eq <2 x i8*>
[[GEP]], zeroinitializer<br>
+; CHECK-NEXT: ret <2 x i1> [[CND]]<br>
+;<br>
+entry:<br>
+ %gep = getelementptr inbounds i8, <2 x i8*> %base,
i64 %idx<br>
+ %cnd = icmp eq <2 x i8*> %gep, zeroinitializer<br>
+ ret <2 x i1> %cnd<br>
+}<br>
+<br>
+define <2 x i1> @test_vector_index(i8* %base, <2 x
i64> %idx) {<br>
+; CHECK-LABEL: @test_vector_index(<br>
+; CHECK-NEXT: entry:<br>
+; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, i8*
[[BASE:%.*]], <2 x i64> [[IDX:%.*]]<br>
+; CHECK-NEXT: [[CND:%.*]] = icmp eq <2 x i8*>
[[GEP]], zeroinitializer<br>
+; CHECK-NEXT: ret <2 x i1> [[CND]]<br>
+;<br>
+entry:<br>
+ %gep = getelementptr inbounds i8, i8* %base, <2 x
i64> %idx<br>
+ %cnd = icmp eq <2 x i8*> %gep, zeroinitializer<br>
+ ret <2 x i1> %cnd<br>
+}<br>
+<br>
+;; These two show instsimplify's reasoning getting to the
non-zero offsets<br>
+;; before instcombine does.<br>
+<br>
+define i1 @test_eq_pos_idx(i8* %base) {<br>
+; CHECK-LABEL: @test_eq_pos_idx(<br>
+; CHECK-NEXT: entry:<br>
+; CHECK-NEXT: ret i1 false<br>
+;<br>
+entry:<br>
+ %gep = getelementptr inbounds i8, i8* %base, i64 1<br>
+ %cnd = icmp eq i8* %gep, null<br>
+ ret i1 %cnd<br>
+}<br>
+<br>
+define i1 @test_eq_neg_idx(i8* %base) {<br>
+; CHECK-LABEL: @test_eq_neg_idx(<br>
+; CHECK-NEXT: entry:<br>
+; CHECK-NEXT: ret i1 false<br>
+;<br>
+entry:<br>
+ %gep = getelementptr inbounds i8, i8* %base, i64 -1<br>
+ %cnd = icmp eq i8* %gep, null<br>
+ ret i1 %cnd<br>
+}<br>
+<br>
+;; Show an example with a zero sized type since that's<br>
+;; a cornercase which keeps getting mentioned. The GEP<br>
+;; produces %base regardless of the value of the index<br>
+;; expression.<br>
+define i1 @test_size0({}* %base, i64 %idx) {<br>
+; CHECK-LABEL: @test_size0(<br>
+; CHECK-NEXT: entry:<br>
+; CHECK-NEXT: [[CND:%.*]] = icmp ne {}* [[BASE:%.*]], null<br>
+; CHECK-NEXT: ret i1 [[CND]]<br>
+;<br>
+entry:<br>
+ %gep = getelementptr inbounds {}, {}* %base, i64 %idx<br>
+ %cnd = icmp ne {}* %gep, null<br>
+ ret i1 %cnd<br>
+}<br>
+define i1 @test_size0_nonzero_offset({}* %base) {<br>
+; CHECK-LABEL: @test_size0_nonzero_offset(<br>
+; CHECK-NEXT: entry:<br>
+; CHECK-NEXT: [[CND:%.*]] = icmp ne {}* [[BASE:%.*]], null<br>
+; CHECK-NEXT: ret i1 [[CND]]<br>
+;<br>
+entry:<br>
+ %gep = getelementptr inbounds {}, {}* %base, i64 15<br>
+ %cnd = icmp ne {}* %gep, null<br>
+ ret i1 %cnd<br>
+}<br>
+<br>
+<br>
+;; Finally, some negative tests for sanity checking.<br>
+<br>
+define i1 @neq_noinbounds(i8* %base, i64 %idx) {<br>
+; CHECK-LABEL: @neq_noinbounds(<br>
+; CHECK-NEXT: entry:<br>
+; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, i8*
[[BASE:%.*]], i64 [[IDX:%.*]]<br>
+; CHECK-NEXT: [[CND:%.*]] = icmp ne i8* [[GEP]], null<br>
+; CHECK-NEXT: ret i1 [[CND]]<br>
+;<br>
+entry:<br>
+ %gep = getelementptr i8, i8* %base, i64 %idx<br>
+ %cnd = icmp ne i8* %gep, null<br>
+ ret i1 %cnd<br>
+}<br>
+<br>
+define i1 @neg_objectatnull(i8 addrspace(2)* %base, i64 %idx)
{<br>
+; CHECK-LABEL: @neg_objectatnull(<br>
+; CHECK-NEXT: entry:<br>
+; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, i8
addrspace(2)* [[BASE:%.*]], i64 [[IDX:%.*]]<br>
+; CHECK-NEXT: [[CND:%.*]] = icmp eq i8 addrspace(2)*
[[GEP]], null<br>
+; CHECK-NEXT: ret i1 [[CND]]<br>
+;<br>
+entry:<br>
+ %gep = getelementptr inbounds i8, i8 addrspace(2)* %base,
i64 %idx<br>
+ %cnd = icmp eq i8 addrspace(2)* %gep, null<br>
+ ret i1 %cnd<br>
+}<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org" target="_blank"
moz-do-not-send="true">llvm-commits@lists.llvm.org</a><br>
<a
href="https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits"
rel="noreferrer" target="_blank" moz-do-not-send="true">https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote>
</div>
</blockquote>
</body>
</html>