X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FAnalysis%2FMemoryDependenceAnalysis.cpp;h=f7180aae69edcfa789fa9263e888a8973e0873ef;hb=3666e7f4c161c50e5f6dcb0e015ca16bf69fb941;hp=5657aea0d9f810fd4ed6ca9880e3705e64ecb04d;hpb=273fd11da9c2c6581844c91dad6901986c50ed12;p=oota-llvm.git diff --git a/lib/Analysis/MemoryDependenceAnalysis.cpp b/lib/Analysis/MemoryDependenceAnalysis.cpp index 5657aea0d9f..f7180aae69e 100644 --- a/lib/Analysis/MemoryDependenceAnalysis.cpp +++ b/lib/Analysis/MemoryDependenceAnalysis.cpp @@ -370,6 +370,36 @@ getPointerDependencyFrom(const AliasAnalysis::Location &MemLoc, bool isLoad, int64_t MemLocOffset = 0; unsigned Limit = BlockScanLimit; bool isInvariantLoad = false; + + // We must be careful with atomic accesses, as they may allow another thread + // to touch this location, cloberring it. We are conservative: if the + // QueryInst is not a simple (non-atomic) memory access, we automatically + // return getClobber. + // If it is simple, we know based on the results of + // "Compiler testing via a theory of sound optimisations in the C11/C++11 + // memory model" in PLDI 2013, that a non-atomic location can only be + // clobbered between a pair of a release and an acquire action, with no + // access to the location in between. + // Here is an example for giving the general intuition behind this rule. + // In the following code: + // store x 0; + // release action; [1] + // acquire action; [4] + // %val = load x; + // It is unsafe to replace %val by 0 because another thread may be running: + // acquire action; [2] + // store x 42; + // release action; [3] + // with synchronization from 1 to 2 and from 3 to 4, resulting in %val + // being 42. A key property of this program however is that if either + // 1 or 4 were missing, there would be a race between the store of 42 + // either the store of 0 or the load (making the whole progam racy). + // The paper mentionned above shows that the same property is respected + // by every program that can detect any optimisation of that kind: either + // it is racy (undefined) or there is a release followed by an acquire + // between the pair of accesses under consideration. + bool HasSeenAcquire = false; + if (isLoad && QueryInst) { LoadInst *LI = dyn_cast(QueryInst); if (LI && LI->getMetadata(LLVMContext::MD_invariant_load) != nullptr) @@ -412,19 +442,25 @@ getPointerDependencyFrom(const AliasAnalysis::Location &MemLoc, bool isLoad, // be accessing the location. if (LoadInst *LI = dyn_cast(Inst)) { // Atomic loads have complications involved. - // A monotonic load is OK if the query inst is itself not atomic. + // A Monotonic (or higher) load is OK if the query inst is itself not atomic. + // An Acquire (or higher) load sets the HasSeenAcquire flag, so that any + // release store will know to return getClobber. // FIXME: This is overly conservative. if (!LI->isUnordered()) { if (!QueryInst) return MemDepResult::getClobber(LI); - if (LI->getOrdering() != Monotonic) - return MemDepResult::getClobber(LI); - if (auto *QueryLI = dyn_cast(QueryInst)) + if (auto *QueryLI = dyn_cast(QueryInst)) { if (!QueryLI->isSimple()) return MemDepResult::getClobber(LI); - if (auto *QuerySI = dyn_cast(QueryInst)) + } else if (auto *QuerySI = dyn_cast(QueryInst)) { if (!QuerySI->isSimple()) return MemDepResult::getClobber(LI); + } else if (QueryInst->mayReadOrWriteMemory()) { + return MemDepResult::getClobber(LI); + } + + if (isAtLeastAcquire(LI->getOrdering())) + HasSeenAcquire = true; } // FIXME: this is overly conservative. @@ -490,19 +526,25 @@ getPointerDependencyFrom(const AliasAnalysis::Location &MemLoc, bool isLoad, if (StoreInst *SI = dyn_cast(Inst)) { // Atomic stores have complications involved. - // A monotonic store is OK if the query inst is itself not atomic. + // A Monotonic store is OK if the query inst is itself not atomic. + // A Release (or higher) store further requires that no acquire load + // has been seen. // FIXME: This is overly conservative. if (!SI->isUnordered()) { if (!QueryInst) return MemDepResult::getClobber(SI); - if (SI->getOrdering() != Monotonic) - return MemDepResult::getClobber(SI); - if (auto *QueryLI = dyn_cast(QueryInst)) + if (auto *QueryLI = dyn_cast(QueryInst)) { if (!QueryLI->isSimple()) return MemDepResult::getClobber(SI); - if (auto *QuerySI = dyn_cast(QueryInst)) + } else if (auto *QuerySI = dyn_cast(QueryInst)) { if (!QuerySI->isSimple()) return MemDepResult::getClobber(SI); + } else if (QueryInst->mayReadOrWriteMemory()) { + return MemDepResult::getClobber(SI); + } + + if (HasSeenAcquire && isAtLeastRelease(SI->getOrdering())) + return MemDepResult::getClobber(SI); } // FIXME: this is overly conservative. @@ -903,7 +945,7 @@ GetNonLocalInfoForBlock(const AliasAnalysis::Location &Loc, return Dep; } -/// SortNonLocalDepInfoCache - Sort the a NonLocalDepInfo cache, given a certain +/// SortNonLocalDepInfoCache - Sort the NonLocalDepInfo cache, given a certain /// number of elements in the array that are already properly ordered. This is /// optimized for the case when only a few entries are added. static void