diff --git a/lib/Transforms/IPO/Attributor.cpp b/lib/Transforms/IPO/Attributor.cpp index e518994f153..9367f482cc9 100644 --- a/lib/Transforms/IPO/Attributor.cpp +++ b/lib/Transforms/IPO/Attributor.cpp @@ -1988,16 +1988,27 @@ struct AADereferenceableFloating : AADereferenceableImpl { // For now we do not try to "increase" dereferenceability due to negative // indices as we first have to come up with code to deal with loops and // for overflows of the dereferenceable bytes. - if (Offset.getSExtValue() < 0) + int64_t OffsetSExt = Offset.getSExtValue(); + if (OffsetSExt < 0) Offset = 0; T.takeAssumedDerefBytesMinimum( - std::max(int64_t(0), DerefBytes - Offset.getSExtValue())); + std::max(int64_t(0), DerefBytes - OffsetSExt)); - if (!Stripped && this == &AA) { - T.takeKnownDerefBytesMaximum( - std::max(int64_t(0), DerefBytes - Offset.getSExtValue())); - T.indicatePessimisticFixpoint(); + if (this == &AA) { + if (!Stripped) { + // If nothing was stripped IR information is all we got. + T.takeKnownDerefBytesMaximum( + std::max(int64_t(0), DerefBytes - OffsetSExt)); + T.indicatePessimisticFixpoint(); + } else if (OffsetSExt > 0) { + // If something was stripped but there is circular reasoning we look + // for the offset. If it is positive we basically decrease the + // dereferenceable bytes in a circluar loop now, which will simply + // drive them down to the known value in a very slow way which we + // can accelerate. + T.indicatePessimisticFixpoint(); + } } return T.isValidState(); diff --git a/test/Transforms/FunctionAttrs/dereferenceable.ll b/test/Transforms/FunctionAttrs/dereferenceable.ll index f61b62e9e23..3ed32d3002f 100644 --- a/test/Transforms/FunctionAttrs/dereferenceable.ll +++ b/test/Transforms/FunctionAttrs/dereferenceable.ll @@ -1,6 +1,8 @@ ; RUN: opt -attributor --attributor-disable=false -attributor-max-iterations=4 -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR +declare void @deref_phi_user(i32* %a); + ; TEST 1 ; take mininimum of return values ; @@ -52,8 +54,7 @@ define dereferenceable(4) i32* @test4(i32* dereferenceable(8) %0) local_unnamed_ ; TEST 5 ; loop in which dereferenceabily "grows" -declare void @deref_phi_user(i32* %a); -define void @deref_phi(i32* dereferenceable(4000) %a) { +define void @deref_phi_growing(i32* dereferenceable(4000) %a) { entry: br label %for.cond @@ -80,3 +81,33 @@ for.inc: ; preds = %for.body for.end: ; preds = %for.cond.cleanup ret void } + +; TEST 6 +; loop in which dereferenceabily "shrinks" +define void @deref_phi_shrinking(i32* dereferenceable(4000) %a) { +entry: + br label %for.cond + +for.cond: ; preds = %for.inc, %entry + %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ] + %a.addr.0 = phi i32* [ %a, %entry ], [ %incdec.ptr, %for.inc ] +; CHECK: call void @deref_phi_user(i32* %a.addr.0) + call void @deref_phi_user(i32* %a.addr.0) + %tmp = load i32, i32* %a.addr.0, align 4 + %cmp = icmp slt i32 %i.0, %tmp + br i1 %cmp, label %for.body, label %for.cond.cleanup + +for.cond.cleanup: ; preds = %for.cond + br label %for.end + +for.body: ; preds = %for.cond + br label %for.inc + +for.inc: ; preds = %for.body + %incdec.ptr = getelementptr inbounds i32, i32* %a.addr.0, i64 1 + %inc = add nuw nsw i32 %i.0, 1 + br label %for.cond + +for.end: ; preds = %for.cond.cleanup + ret void +}