From 785fad32025ac29b3169a3c9e25b01b2835869d4 Mon Sep 17 00:00:00 2001 From: Johannes Doerfert Date: Fri, 23 Aug 2019 17:29:23 +0000 Subject: [PATCH] [Attributor] Deal with shrinking dereferenceability in a loop Summary: If we have a loop in which the dereferenceability of a pointer decreases we did slowly decrease it iteration by iteration, leading to a timeout. With this patch we detect such circular reasoning and indicate a fixpoint early. Reviewers: uenoku, sstefan1 Subscribers: hiraditya, bollu, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D66558 llvm-svn: 369784 --- llvm/lib/Transforms/IPO/Attributor.cpp | 23 ++++++++---- .../FunctionAttrs/dereferenceable.ll | 35 +++++++++++++++++-- 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp index e518994f1532..9367f482cc98 100644 --- a/llvm/lib/Transforms/IPO/Attributor.cpp +++ b/llvm/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/llvm/test/Transforms/FunctionAttrs/dereferenceable.ll b/llvm/test/Transforms/FunctionAttrs/dereferenceable.ll index f61b62e9e239..3ed32d3002fc 100644 --- a/llvm/test/Transforms/FunctionAttrs/dereferenceable.ll +++ b/llvm/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 +}