diff options
author | Manman Ren <mren@apple.com> | 2013-01-04 19:19:47 +0000 |
---|---|---|
committer | Manman Ren <mren@apple.com> | 2013-01-04 19:19:47 +0000 |
commit | c55bd47105ef8e362cfb2a2c97ee3e23145aca4d (patch) | |
tree | dcfd58c47215cc7c814d162ce379239be6b1e587 | |
parent | 63723e5bf8bc1e5b699733cb79992b720b20f0d5 (diff) |
Memory Dependence Analysis: fix a miscompile that uses DT to approxmiate the
reachablity.
We conservatively approximate the reachability analysis by saying it is not
reachable if there is a single path starting from "From" and the path does not
reach "To".
rdar://12801584
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@171512 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Analysis/AliasAnalysis.cpp | 38 | ||||
-rw-r--r-- | test/Transforms/GVN/MemdepMiscompile.ll | 54 |
2 files changed, 88 insertions, 4 deletions
diff --git a/lib/Analysis/AliasAnalysis.cpp b/lib/Analysis/AliasAnalysis.cpp index 7b2e60dd0f..f32bd70698 100644 --- a/lib/Analysis/AliasAnalysis.cpp +++ b/lib/Analysis/AliasAnalysis.cpp @@ -361,8 +361,28 @@ AliasAnalysis::getModRefInfo(const AtomicRMWInst *RMW, const Location &Loc) { } namespace { + // Conservatively return true. Return false, if there is a single path + // starting from "From" and the path does not reach "To". + static bool hasPath(const BasicBlock *From, const BasicBlock *To) { + const unsigned MaxCheck = 5; + const BasicBlock *Current = From; + for (unsigned I = 0; I < MaxCheck; I++) { + unsigned NumSuccs = Current->getTerminator()->getNumSuccessors(); + if (NumSuccs > 1) + return true; + if (NumSuccs == 0) + return false; + Current = Current->getTerminator()->getSuccessor(0); + if (Current == To) + return true; + } + return true; + } + /// Only find pointer captures which happen before the given instruction. Uses /// the dominator tree to determine whether one instruction is before another. + /// Only support the case where the Value is defined in the same basic block + /// as the given instruction and the use. struct CapturesBefore : public CaptureTracker { CapturesBefore(const Instruction *I, DominatorTree *DT) : BeforeHere(I), DT(DT), Captured(false) {} @@ -372,8 +392,15 @@ namespace { bool shouldExplore(Use *U) { Instruction *I = cast<Instruction>(U->getUser()); BasicBlock *BB = I->getParent(); - if (BeforeHere != I && - (!DT->isReachableFromEntry(BB) || DT->dominates(BeforeHere, I))) + // We explore this usage only if the usage can reach "BeforeHere". + // If use is not reachable from entry, there is no need to explore. + if (BeforeHere != I && !DT->isReachableFromEntry(BB)) + return false; + // If the value is defined in the same basic block as use and BeforeHere, + // there is no need to explore the use if BeforeHere dominates use. + // Check whether there is a path from I to BeforeHere. + if (BeforeHere != I && DT->dominates(BeforeHere, I) && + !hasPath(BB, BeforeHere->getParent())) return false; return true; } @@ -381,8 +408,11 @@ namespace { bool captured(Use *U) { Instruction *I = cast<Instruction>(U->getUser()); BasicBlock *BB = I->getParent(); - if (BeforeHere != I && - (!DT->isReachableFromEntry(BB) || DT->dominates(BeforeHere, I))) + // Same logic as in shouldExplore. + if (BeforeHere != I && !DT->isReachableFromEntry(BB)) + return false; + if (BeforeHere != I && DT->dominates(BeforeHere, I) && + !hasPath(BB, BeforeHere->getParent())) return false; Captured = true; return true; diff --git a/test/Transforms/GVN/MemdepMiscompile.ll b/test/Transforms/GVN/MemdepMiscompile.ll new file mode 100644 index 0000000000..d420169615 --- /dev/null +++ b/test/Transforms/GVN/MemdepMiscompile.ll @@ -0,0 +1,54 @@ +; RUN: opt < %s -basicaa -gvn -S | FileCheck %s +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" +target triple = "x86_64-apple-macosx10.7.0" + +; rdar://12801584 +; Value of %shouldExit can be changed by RunInMode. +; Make sure we do not replace load %shouldExit in while.cond.backedge +; with a phi node where the value from while.body is 0. +define i32 @test() nounwind ssp { +entry: +; CHECK: test() +; CHECK: while.body: +; CHECK: call void @RunInMode +; CHECK: br i1 %tobool, label %while.cond.backedge, label %if.then +; CHECK: while.cond.backedge: +; CHECK: load i32* %shouldExit +; CHECK: br i1 %cmp, label %while.body + %shouldExit = alloca i32, align 4 + %tasksIdle = alloca i32, align 4 + store i32 0, i32* %shouldExit, align 4 + store i32 0, i32* %tasksIdle, align 4 + call void @CTestInitialize(i32* %tasksIdle) nounwind + %0 = load i32* %shouldExit, align 4 + %cmp1 = icmp eq i32 %0, 0 + br i1 %cmp1, label %while.body.lr.ph, label %while.end + +while.body.lr.ph: + br label %while.body + +while.body: + call void @RunInMode(i32 100) nounwind + %1 = load i32* %tasksIdle, align 4 + %tobool = icmp eq i32 %1, 0 + br i1 %tobool, label %while.cond.backedge, label %if.then + +if.then: + store i32 0, i32* %tasksIdle, align 4 + call void @TimerCreate(i32* %shouldExit) nounwind + br label %while.cond.backedge + +while.cond.backedge: + %2 = load i32* %shouldExit, align 4 + %cmp = icmp eq i32 %2, 0 + br i1 %cmp, label %while.body, label %while.cond.while.end_crit_edge + +while.cond.while.end_crit_edge: + br label %while.end + +while.end: + ret i32 0 +} +declare void @CTestInitialize(i32*) +declare void @RunInMode(i32) +declare void @TimerCreate(i32*) |