From: Sanjoy Das Date: Tue, 10 May 2016 02:35:44 +0000 (+0000) Subject: [ValueTracking] Use guards to prove non-nullness of a value X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b93f14ae0606be04af98063966eeb1bdbf6d8e48;p=llvm [ValueTracking] Use guards to prove non-nullness of a value Reviewers: apilipenko, majnemer, reames Subscribers: mcrosier, llvm-commits Differential Revision: http://reviews.llvm.org/D20044 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@269008 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Analysis/ValueTracking.cpp b/lib/Analysis/ValueTracking.cpp index 52b1e444731..19fef59e1f3 100644 --- a/lib/Analysis/ValueTracking.cpp +++ b/lib/Analysis/ValueTracking.cpp @@ -3212,17 +3212,19 @@ static bool isKnownNonNullFromDominatingCondition(const Value *V, continue; for (auto *CmpU : U->users()) { - const BranchInst *BI = dyn_cast(CmpU); - if (!BI) - continue; - - assert(BI->isConditional() && "uses a comparison!"); + if (const BranchInst *BI = dyn_cast(CmpU)) { + assert(BI->isConditional() && "uses a comparison!"); - BasicBlock *NonNullSuccessor = - BI->getSuccessor(Pred == ICmpInst::ICMP_EQ ? 1 : 0); - BasicBlockEdge Edge(BI->getParent(), NonNullSuccessor); - if (Edge.isSingleEdge() && DT->dominates(Edge, CtxI->getParent())) + BasicBlock *NonNullSuccessor = + BI->getSuccessor(Pred == ICmpInst::ICMP_EQ ? 1 : 0); + BasicBlockEdge Edge(BI->getParent(), NonNullSuccessor); + if (Edge.isSingleEdge() && DT->dominates(Edge, CtxI->getParent())) + return true; + } else if (Pred == ICmpInst::ICMP_NE && + match(CmpU, m_Intrinsic()) && + DT->dominates(cast(CmpU), CtxI)) { return true; + } } } diff --git a/test/Transforms/LICM/hoist-deref-load.ll b/test/Transforms/LICM/hoist-deref-load.ll index 6564015687d..a9a6dfc0219 100644 --- a/test/Transforms/LICM/hoist-deref-load.ll +++ b/test/Transforms/LICM/hoist-deref-load.ll @@ -469,5 +469,90 @@ for.end: ; preds = %for.inc, %entry ret void } +declare void @llvm.experimental.guard(i1, ...) + +define void @test12(i32* noalias %a, i32* %b, i32* dereferenceable_or_null(4) %c, i32 %n) #0 { +; Prove non-null ness of %c via a guard, not a branch. + +; CHECK-LABEL: @test12( +entry: + %not_null = icmp ne i32* %c, null + call void(i1, ...) @llvm.experimental.guard(i1 %not_null) [ "deopt"() ] + %cmp11 = icmp sgt i32 %n, 0 + br i1 %cmp11, label %for.body, label %for.end + +; CHECK: for.body.preheader: +; CHECK-NEXT: [[VAL:%[^ ]]] = load i32, i32* %c, align 4 +; CHECK-NEXT: br label %for.body + + +for.body: ; preds = %entry, %for.inc + %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ] + %arrayidx = getelementptr inbounds i32, i32* %a, i64 %indvars.iv + %0 = load i32, i32* %arrayidx, align 4 + %cmp1 = icmp sgt i32 %0, 0 + br i1 %cmp1, label %if.then, label %for.inc + +if.then: ; preds = %for.body + %1 = load i32, i32* %c, align 4 + %arrayidx3 = getelementptr inbounds i32, i32* %b, i64 %indvars.iv + %2 = load i32, i32* %arrayidx3, align 4 + %mul = mul nsw i32 %2, %1 + store i32 %mul, i32* %arrayidx, align 4 + br label %for.inc + +for.inc: ; preds = %for.body, %if.then + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + %lftr.wideiv = trunc i64 %indvars.iv.next to i32 + %exitcond = icmp eq i32 %lftr.wideiv, %n + br i1 %exitcond, label %for.end, label %for.body + +for.end: ; preds = %for.inc, %entry, %entry + ret void +} + +define void @test13(i32* noalias %a, i32* %b, i32* dereferenceable_or_null(4) %c, i32 %n) #0 { +; Like @test12, but has a post-dominating guard, which cannot be used +; to prove %c is nonnull at the point of the load. + +; CHECK-LABEL: @test13( +entry: + %not_null = icmp ne i32* %c, null + %cmp11 = icmp sgt i32 %n, 0 + br i1 %cmp11, label %for.body, label %for.end + +; CHECK: for.body.preheader: +; CHECK-NOT: load i32, i32* %c +; CHECK: br label %for.body + +for.body: ; preds = %entry, %for.inc + %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ] + %arrayidx = getelementptr inbounds i32, i32* %a, i64 %indvars.iv + %0 = load i32, i32* %arrayidx, align 4 + %cmp1 = icmp sgt i32 %0, 0 + br i1 %cmp1, label %if.then, label %for.inc + +if.then: ; preds = %for.body +; CHECK: if.then: +; CHECK: load i32, i32* %c +; CHECK: br label %for.inc + %1 = load i32, i32* %c, align 4 + %arrayidx3 = getelementptr inbounds i32, i32* %b, i64 %indvars.iv + %2 = load i32, i32* %arrayidx3, align 4 + %mul = mul nsw i32 %2, %1 + store i32 %mul, i32* %arrayidx, align 4 + br label %for.inc + +for.inc: ; preds = %for.body, %if.then + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + %lftr.wideiv = trunc i64 %indvars.iv.next to i32 + %exitcond = icmp eq i32 %lftr.wideiv, %n + br i1 %exitcond, label %for.end, label %for.body + +for.end: ; preds = %for.inc, %entry, %entry + call void(i1, ...) @llvm.experimental.guard(i1 %not_null) [ "deopt"() ] + ret void +} + attributes #0 = { nounwind uwtable } !0 = !{i64 4}