Commit 0fbb6fa8 authored by Georg Koppen's avatar Georg Koppen Committed by Matthew Finkel
Browse files

Bug 32053: Fix LLVM reproducibility issues

This patch contains two backports for reproducibility issues found and
fixed in LLVM's optimization code.

The patch from bug 42574 might not be necessary in our context as I only
witnessed problems when compiling Stylo with an older Rust (1.32.0) and
then omptimizing with LLVM 8. However, it's hard to exclude any
mismatching builds we encountered so far from being affected by that
issue, so I think it is safer to backport that patch as well.

Bug 43909 is an issue we and Mozilla definitely hit and very likely
responsible for at least the vast majority of different builds we got
over the course of the last weeks and months. Many thanks to Alex
Crichton for the invaluable help in tracking this issue down.
parent 00fcc397
From 3757213db371dcea53cae357cf9c56d1b0604f98 Mon Sep 17 00:00:00 2001
From: Alina Sbirlea <asbirlea@google.com>
Date: Fri, 12 Jul 2019 22:30:30 +0000
Subject: [PATCH] [MemorySSA] Use SetVector to avoid nondeterminism.
Summary:
Use a SetVector for DeadBlockSet.
Resolves PR42574.
Reviewers: george.burgess.iv, uabelho, dblaikie
Subscribers: jlebar, Prazek, mgrang, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D64601
llvm-svn: 365970
diff --git a/llvm/include/llvm/Analysis/MemorySSAUpdater.h b/llvm/include/llvm/Analysis/MemorySSAUpdater.h
index 169d5bd9fa8..276620bd445 100644
--- a/llvm/include/llvm/Analysis/MemorySSAUpdater.h
+++ b/llvm/include/llvm/Analysis/MemorySSAUpdater.h
@@ -32,6 +32,7 @@
#ifndef LLVM_ANALYSIS_MEMORYSSAUPDATER_H
#define LLVM_ANALYSIS_MEMORYSSAUPDATER_H
+#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
@@ -239,7 +240,7 @@ public:
/// Deleted blocks still have successor info, but their predecessor edges and
/// Phi nodes may already be updated. Instructions in DeadBlocks should be
/// deleted after this call.
- void removeBlocks(const SmallPtrSetImpl<BasicBlock *> &DeadBlocks);
+ void removeBlocks(const SmallSetVector<BasicBlock *, 8> &DeadBlocks);
/// Get handle on MemorySSA.
MemorySSA* getMemorySSA() const { return MSSA; }
diff --git a/llvm/lib/Analysis/MemorySSAUpdater.cpp b/llvm/lib/Analysis/MemorySSAUpdater.cpp
index 6c817d20368..a6c7142a697 100644
--- a/llvm/lib/Analysis/MemorySSAUpdater.cpp
+++ b/llvm/lib/Analysis/MemorySSAUpdater.cpp
@@ -1101,7 +1101,7 @@ void MemorySSAUpdater::removeMemoryAccess(MemoryAccess *MA) {
}
void MemorySSAUpdater::removeBlocks(
- const SmallPtrSetImpl<BasicBlock *> &DeadBlocks) {
+ const SmallSetVector<BasicBlock *, 8> &DeadBlocks) {
// First delete all uses of BB in MemoryPhis.
for (BasicBlock *BB : DeadBlocks) {
Instruction *TI = BB->getTerminator();
diff --git a/llvm/lib/Transforms/Scalar/LoopSimplifyCFG.cpp b/llvm/lib/Transforms/Scalar/LoopSimplifyCFG.cpp
index 2e5927f9a06..f464df26a02 100644
--- a/llvm/lib/Transforms/Scalar/LoopSimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopSimplifyCFG.cpp
@@ -388,8 +388,8 @@ private:
void deleteDeadLoopBlocks() {
DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Eager);
if (MSSAU) {
- SmallPtrSet<BasicBlock *, 8> DeadLoopBlocksSet(DeadLoopBlocks.begin(),
- DeadLoopBlocks.end());
+ SmallSetVector<BasicBlock *, 8> DeadLoopBlocksSet(DeadLoopBlocks.begin(),
+ DeadLoopBlocks.end());
MSSAU->removeBlocks(DeadLoopBlocksSet);
}
for (auto *BB : DeadLoopBlocks) {
diff --git a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
index 5a67178cef3..814cf814989 100644
--- a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
+++ b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
@@ -1436,8 +1436,8 @@ deleteDeadClonedBlocks(Loop &L, ArrayRef<BasicBlock *> ExitBlocks,
// Remove all MemorySSA in the dead blocks
if (MSSAU) {
- SmallPtrSet<BasicBlock *, 16> DeadBlockSet(DeadBlocks.begin(),
- DeadBlocks.end());
+ SmallSetVector<BasicBlock *, 8> DeadBlockSet(DeadBlocks.begin(),
+ DeadBlocks.end());
MSSAU->removeBlocks(DeadBlockSet);
}
@@ -1455,7 +1455,7 @@ static void deleteDeadBlocksFromLoop(Loop &L,
MemorySSAUpdater *MSSAU) {
// Find all the dead blocks tied to this loop, and remove them from their
// successors.
- SmallPtrSet<BasicBlock *, 16> DeadBlockSet;
+ SmallSetVector<BasicBlock *, 8> DeadBlockSet;
// Start with loop/exit blocks and get a transitive closure of reachable dead
// blocks.
diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp
index 499e611acb5..83dabcd7952 100644
--- a/llvm/lib/Transforms/Utils/Local.cpp
+++ b/llvm/lib/Transforms/Utils/Local.cpp
@@ -2211,7 +2211,7 @@ bool llvm::removeUnreachableBlocks(Function &F, LazyValueInfo *LVI,
assert(Reachable.size() < F.size());
NumRemoved += F.size()-Reachable.size();
- SmallPtrSet<BasicBlock *, 16> DeadBlockSet;
+ SmallSetVector<BasicBlock *, 8> DeadBlockSet;
for (Function::iterator I = ++F.begin(), E = F.end(); I != E; ++I) {
auto *BB = &*I;
if (Reachable.count(BB))
diff --git a/llvm/test/Analysis/MemorySSA/nondeterminism.ll b/llvm/test/Analysis/MemorySSA/nondeterminism.ll
new file mode 100644
index 00000000000..0bb3df30b58
--- /dev/null
+++ b/llvm/test/Analysis/MemorySSA/nondeterminism.ll
@@ -0,0 +1,122 @@
+; RUN: opt -simplifycfg -enable-mssa-loop-dependency -S --preserve-ll-uselistorder %s | FileCheck %s
+; REQUIRES: x86-registered-target
+; CHECK-LABEL: @n
+; CHECK: uselistorder i16 0, { 3, 2, 4, 1, 5, 0, 6 }
+
+; Note: test was added in an effort to ensure determinism when updating memoryssa. See PR42574.
+; If the uselistorder check becomes no longer relevant, the test can be disabled or removed.
+
+%rec9 = type { i16, i32, i32 }
+
+@a = global [1 x [1 x %rec9]] zeroinitializer
+
+define i16 @n() {
+ br label %..split_crit_edge
+
+..split_crit_edge: ; preds = %0
+ br label %.split
+
+bb4.us4: ; preds = %bb2.split.us32, %bb6.us28
+ %i.4.01.us5 = phi i16 [ %_tmp49.us30, %bb6.us28 ]
+ br label %g.exit4.us21
+
+bb1.i.us14: ; preds = %bb4.us4
+ br label %g.exit4.us21
+
+g.exit4.us21: ; preds = %bb1.i.us14, %g.exit4.critedge.us9
+ %i.4.02.us22 = phi i16 [ %i.4.01.us5, %bb4.us4 ], [ %i.4.01.us5, %bb1.i.us14 ]
+ br label %bb6.us28
+
+bb5.us26: ; preds = %g.exit4.us21
+ br label %bb6.us28
+
+bb6.us28: ; preds = %bb5.us26, %g.exit4.us21
+ %i.4.03.us29 = phi i16 [ %i.4.02.us22, %bb5.us26 ], [ %i.4.02.us22, %g.exit4.us21 ]
+ %_tmp49.us30 = add nuw nsw i16 %i.4.03.us29, 1
+ br label %bb4.us4
+
+bb4.us.us: ; preds = %bb2.split.us.us, %bb6.us.us
+ %i.4.01.us.us = phi i16 [ %_tmp49.us.us, %bb6.us.us ]
+ br label %bb1.i.us.us
+
+bb1.i.us.us: ; preds = %bb4.us.us
+ br label %g.exit4.us.us
+
+g.exit4.us.us: ; preds = %bb1.i.us.us, %g.exit4.critedge.us.us
+ %i.4.02.us.us = phi i16 [ %i.4.01.us.us, %bb1.i.us.us ]
+ br label %bb5.us.us
+
+bb5.us.us: ; preds = %g.exit4.us.us
+ br label %bb6.us.us
+
+bb6.us.us: ; preds = %bb5.us.us, %g.exit4.us.us
+ %i.4.03.us.us = phi i16 [ %i.4.02.us.us, %bb5.us.us ]
+ %_tmp49.us.us = add nuw nsw i16 %i.4.03.us.us, 1
+ br label %bb4.us.us
+
+
+.split: ; preds = %..split_crit_edge
+ br label %bb2
+
+bb2: ; preds = %.split, %bb7
+ %h.3.0 = phi i16 [ undef, %.split ], [ %_tmp53, %bb7 ]
+ br label %bb2.bb2.split_crit_edge
+
+bb2.bb2.split_crit_edge: ; preds = %bb2
+ br label %bb2.split
+
+bb2.split.us: ; preds = %bb2
+ br label %bb4.us
+
+bb4.us: ; preds = %bb6.us, %bb2.split.us
+ %i.4.01.us = phi i16 [ 0, %bb2.split.us ]
+ br label %bb1.i.us
+
+g.exit4.critedge.us: ; preds = %bb4.us
+ br label %g.exit4.us
+
+bb1.i.us: ; preds = %bb4.us
+ br label %g.exit4.us
+
+g.exit4.us: ; preds = %bb1.i.us, %g.exit4.critedge.us
+ %i.4.02.us = phi i16 [ %i.4.01.us, %g.exit4.critedge.us ], [ %i.4.01.us, %bb1.i.us ]
+ br label %bb5.us
+
+bb5.us: ; preds = %g.exit4.us
+ br label %bb7
+
+bb2.split: ; preds = %bb2.bb2.split_crit_edge
+ br label %bb4
+
+bb4: ; preds = %bb2.split, %bb6
+ %i.4.01 = phi i16 [ 0, %bb2.split ]
+ %_tmp16 = getelementptr [1 x [1 x %rec9]], [1 x [1 x %rec9]]* @a, i16 0, i16 %h.3.0, i16 %i.4.01, i32 0
+ %_tmp17 = load i16, i16* %_tmp16, align 1
+ br label %g.exit4.critedge
+
+bb1.i: ; preds = %bb4
+ br label %g.exit4
+
+g.exit4.critedge: ; preds = %bb4
+ %_tmp28.c = getelementptr [1 x [1 x %rec9]], [1 x [1 x %rec9]]* @a, i16 0, i16 %h.3.0, i16 %i.4.01, i32 1
+ %_tmp29.c = load i32, i32* %_tmp28.c, align 1
+ %_tmp30.c = trunc i32 %_tmp29.c to i16
+ br label %g.exit4
+
+g.exit4: ; preds = %g.exit4.critedge, %bb1.i
+ %i.4.02 = phi i16 [ %i.4.01, %g.exit4.critedge ], [ %i.4.01, %bb1.i ]
+ %_tmp41 = getelementptr [1 x [1 x %rec9]], [1 x [1 x %rec9]]* @a, i16 0, i16 %h.3.0, i16 %i.4.02, i32 2
+ br label %bb6
+
+bb5: ; preds = %g.exit4
+ br label %bb6
+
+bb6: ; preds = %bb5, %g.exit4
+ %i.4.03 = phi i16 [ %i.4.02, %bb5 ], [ %i.4.02, %g.exit4 ]
+ %_tmp49 = add nuw nsw i16 %i.4.03, 1
+ br label %bb7
+
+bb7: ; preds = %bb7.us-lcssa.us, %bb7.us-lcssa
+ %_tmp53 = add nsw i16 %h.3.0, 1
+ br label %bb2
+}
--
2.24.0
From c95310f2d4fd3c88241c3b5d6dbf6251d34a3256 Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikita.ppv@gmail.com>
Date: Sat, 16 Nov 2019 16:22:18 +0100
Subject: [PATCH] Restructure caching
Variant on D70103. The caching is switched to always use a BB to
cache entry map, which then contains per-value caches. A separate
set contains value handles with a deletion callback. This allows us
to properly invalidate overdefined values.
A possible alternative would be to always cache by value first and
have per-BB maps/sets in the each cache entry. In that case we could
use a ValueMap and would avoid the separate value handle set. I went
with the BB indexing at the top level to make it easier to integrate
D69914, but possibly that's not the right choice.
Differential Revision: https://reviews.llvm.org/D70376
diff --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp
index 110c085d3f3..aa6862cb588 100644
--- a/llvm/lib/Analysis/LazyValueInfo.cpp
+++ b/llvm/lib/Analysis/LazyValueInfo.cpp
@@ -133,12 +133,9 @@ namespace {
/// A callback value handle updates the cache when values are erased.
class LazyValueInfoCache;
struct LVIValueHandle final : public CallbackVH {
- // Needs to access getValPtr(), which is protected.
- friend struct DenseMapInfo<LVIValueHandle>;
-
LazyValueInfoCache *Parent;
- LVIValueHandle(Value *V, LazyValueInfoCache *P)
+ LVIValueHandle(Value *V, LazyValueInfoCache *P = nullptr)
: CallbackVH(V), Parent(P) { }
void deleted() override;
@@ -152,89 +149,63 @@ namespace {
/// This is the cache kept by LazyValueInfo which
/// maintains information about queries across the clients' queries.
class LazyValueInfoCache {
- /// This is all of the cached block information for exactly one Value*.
- /// The entries are sorted by the BasicBlock* of the
- /// entries, allowing us to do a lookup with a binary search.
- /// Over-defined lattice values are recorded in OverDefinedCache to reduce
- /// memory overhead.
- struct ValueCacheEntryTy {
- ValueCacheEntryTy(Value *V, LazyValueInfoCache *P) : Handle(V, P) {}
- LVIValueHandle Handle;
- SmallDenseMap<PoisoningVH<BasicBlock>, ValueLatticeElement, 4> BlockVals;
+ /// This is all of the cached information for one basic block. It contains
+ /// the per-value lattice elements, as well as a separate set for
+ /// overdefined values to reduce memory usage.
+ struct BlockCacheEntryTy {
+ SmallDenseMap<AssertingVH<Value>, ValueLatticeElement, 4> LatticeElements;
+ SmallDenseSet<AssertingVH<Value>, 4> OverDefined;
};
- /// This tracks, on a per-block basis, the set of values that are
- /// over-defined at the end of that block.
- typedef DenseMap<PoisoningVH<BasicBlock>, SmallPtrSet<Value *, 4>>
- OverDefinedCacheTy;
- /// Keep track of all blocks that we have ever seen, so we
- /// don't spend time removing unused blocks from our caches.
- DenseSet<PoisoningVH<BasicBlock> > SeenBlocks;
-
- /// This is all of the cached information for all values,
- /// mapped from Value* to key information.
- DenseMap<Value *, std::unique_ptr<ValueCacheEntryTy>> ValueCache;
- OverDefinedCacheTy OverDefinedCache;
-
+ /// Cached information per basic block.
+ DenseMap<PoisoningVH<BasicBlock>, BlockCacheEntryTy> BlockCache;
+ /// Set of value handles used to erase values from the cache on deletion.
+ DenseSet<LVIValueHandle, DenseMapInfo<Value *>> ValueHandles;
public:
void insertResult(Value *Val, BasicBlock *BB,
const ValueLatticeElement &Result) {
- SeenBlocks.insert(BB);
-
+ auto &CacheEntry = BlockCache.try_emplace(BB).first->second;
// Insert over-defined values into their own cache to reduce memory
// overhead.
if (Result.isOverdefined())
- OverDefinedCache[BB].insert(Val);
- else {
- auto It = ValueCache.find_as(Val);
- if (It == ValueCache.end()) {
- ValueCache[Val] = make_unique<ValueCacheEntryTy>(Val, this);
- It = ValueCache.find_as(Val);
- assert(It != ValueCache.end() && "Val was just added to the map!");
- }
- It->second->BlockVals[BB] = Result;
- }
- }
-
- bool isOverdefined(Value *V, BasicBlock *BB) const {
- auto ODI = OverDefinedCache.find(BB);
-
- if (ODI == OverDefinedCache.end())
- return false;
+ CacheEntry.OverDefined.insert(Val);
+ else
+ CacheEntry.LatticeElements.insert({ Val, Result });
- return ODI->second.count(V);
+ auto HandleIt = ValueHandles.find_as(Val);
+ if (HandleIt == ValueHandles.end())
+ ValueHandles.insert({ Val, this });
}
bool hasCachedValueInfo(Value *V, BasicBlock *BB) const {
- if (isOverdefined(V, BB))
- return true;
-
- auto I = ValueCache.find_as(V);
- if (I == ValueCache.end())
+ auto It = BlockCache.find(BB);
+ if (It == BlockCache.end())
return false;
- return I->second->BlockVals.count(BB);
+ return It->second.OverDefined.count(V) ||
+ It->second.LatticeElements.count(V);
}
ValueLatticeElement getCachedValueInfo(Value *V, BasicBlock *BB) const {
- if (isOverdefined(V, BB))
+ auto It = BlockCache.find(BB);
+ if (It == BlockCache.end())
+ return ValueLatticeElement();
+
+ if (It->second.OverDefined.count(V))
return ValueLatticeElement::getOverdefined();
- auto I = ValueCache.find_as(V);
- if (I == ValueCache.end())
+ auto LatticeIt = It->second.LatticeElements.find(V);
+ if (LatticeIt == It->second.LatticeElements.end())
return ValueLatticeElement();
- auto BBI = I->second->BlockVals.find(BB);
- if (BBI == I->second->BlockVals.end())
- return ValueLatticeElement();
- return BBI->second;
+
+ return LatticeIt->second;
}
/// clear - Empty the cache.
void clear() {
- SeenBlocks.clear();
- ValueCache.clear();
- OverDefinedCache.clear();
+ BlockCache.clear();
+ ValueHandles.clear();
}
/// Inform the cache that a given value has been deleted.
@@ -248,23 +219,18 @@ namespace {
/// OldSucc might have (unless also overdefined in NewSucc). This just
/// flushes elements from the cache and does not add any.
void threadEdgeImpl(BasicBlock *OldSucc,BasicBlock *NewSucc);
-
- friend struct LVIValueHandle;
};
}
void LazyValueInfoCache::eraseValue(Value *V) {
- for (auto I = OverDefinedCache.begin(), E = OverDefinedCache.end(); I != E;) {
- // Copy and increment the iterator immediately so we can erase behind
- // ourselves.
- auto Iter = I++;
- SmallPtrSetImpl<Value *> &ValueSet = Iter->second;
- ValueSet.erase(V);
- if (ValueSet.empty())
- OverDefinedCache.erase(Iter);
+ for (auto &Pair : BlockCache) {
+ Pair.second.LatticeElements.erase(V);
+ Pair.second.OverDefined.erase(V);
}
- ValueCache.erase(V);
+ auto HandleIt = ValueHandles.find_as(V);
+ if (HandleIt != ValueHandles.end())
+ ValueHandles.erase(HandleIt);
}
void LVIValueHandle::deleted() {
@@ -274,18 +240,7 @@ void LVIValueHandle::deleted() {
}
void LazyValueInfoCache::eraseBlock(BasicBlock *BB) {
- // Shortcut if we have never seen this block.
- DenseSet<PoisoningVH<BasicBlock> >::iterator I = SeenBlocks.find(BB);
- if (I == SeenBlocks.end())
- return;
- SeenBlocks.erase(I);
-
- auto ODI = OverDefinedCache.find(BB);
- if (ODI != OverDefinedCache.end())
- OverDefinedCache.erase(ODI);
-
- for (auto &I : ValueCache)
- I.second->BlockVals.erase(BB);
+ BlockCache.erase(BB);
}
void LazyValueInfoCache::threadEdgeImpl(BasicBlock *OldSucc,
@@ -303,10 +258,11 @@ void LazyValueInfoCache::threadEdgeImpl(BasicBlock *OldSucc,
std::vector<BasicBlock*> worklist;
worklist.push_back(OldSucc);
- auto I = OverDefinedCache.find(OldSucc);
- if (I == OverDefinedCache.end())
+ auto I = BlockCache.find(OldSucc);
+ if (I == BlockCache.end() || I->second.OverDefined.empty())
return; // Nothing to process here.
- SmallVector<Value *, 4> ValsToClear(I->second.begin(), I->second.end());
+ SmallVector<Value *, 4> ValsToClear(I->second.OverDefined.begin(),
+ I->second.OverDefined.end());
// Use a worklist to perform a depth-first search of OldSucc's successors.
// NOTE: We do not need a visited list since any blocks we have already
@@ -320,10 +276,10 @@ void LazyValueInfoCache::threadEdgeImpl(BasicBlock *OldSucc,
if (ToUpdate == NewSucc) continue;
// If a value was marked overdefined in OldSucc, and is here too...
- auto OI = OverDefinedCache.find(ToUpdate);
- if (OI == OverDefinedCache.end())
+ auto OI = BlockCache.find(ToUpdate);
+ if (OI == BlockCache.end() || OI->second.OverDefined.empty())
continue;
- SmallPtrSetImpl<Value *> &ValueSet = OI->second;
+ auto &ValueSet = OI->second.OverDefined;
bool changed = false;
for (Value *V : ValsToClear) {
@@ -333,11 +289,6 @@ void LazyValueInfoCache::threadEdgeImpl(BasicBlock *OldSucc,
// If we removed anything, then we potentially need to update
// blocks successors too.
changed = true;
-
- if (ValueSet.empty()) {
- OverDefinedCache.erase(OI);
- break;
- }
}
if (!changed) continue;
--
2.24.0
......@@ -20,6 +20,10 @@ tar -xf $rootdir/[% c('input_files_by_name/libcxxabi') %]
tar -xf $rootdir/[% c('input_files_by_name/lld') %]
tar -xf $rootdir/[% c('input_files_by_name/compiler-rt') %]
mv llvm-* llvm
# LLVM has reproducibility issues when optimizing bitcode, which we need to
# patch. See: #32053 for more details.
patch -p1 < $rootdir/42574.patch
patch -p1 < $rootdir/43909.patch
mv cfe-* llvm/tools/clang
mv libcxx-* llvm/projects/libcxx
mv libcxxabi-* llvm/projects/libcxxabi
......
......@@ -45,3 +45,5 @@ input_files:
enable: '[% c("var/windows") %]'
- filename: timestamp.patch
enable: '[% c("var/windows") %]'
- filename: 42574.patch
- filename: 43909.patch
From 3757213db371dcea53cae357cf9c56d1b0604f98 Mon Sep 17 00:00:00 2001
From: Alina Sbirlea <asbirlea@google.com>
Date: Fri, 12 Jul 2019 22:30:30 +0000
Subject: [PATCH] [MemorySSA] Use SetVector to avoid nondeterminism.
Summary:
Use a SetVector for DeadBlockSet.
Resolves PR42574.
Reviewers: george.burgess.iv, uabelho, dblaikie
Subscribers: jlebar, Prazek, mgrang, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D64601
llvm-svn: 365970
diff --git a/llvm/include/llvm/Analysis/MemorySSAUpdater.h b/llvm/include/llvm/Analysis/MemorySSAUpdater.h
index 169d5bd9fa8..276620bd445 100644
--- a/llvm/include/llvm/Analysis/MemorySSAUpdater.h
+++ b/llvm/include/llvm/Analysis/MemorySSAUpdater.h
@@ -32,6 +32,7 @@
#ifndef LLVM_ANALYSIS_MEMORYSSAUPDATER_H
#define LLVM_ANALYSIS_MEMORYSSAUPDATER_H
+#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
@@ -239,7 +240,7 @@ public:
/// Deleted blocks still have successor info, but their predecessor edges and
/// Phi nodes may already be updated. Instructions in DeadBlocks should be
/// deleted after this call.
- void removeBlocks(const SmallPtrSetImpl<BasicBlock *> &DeadBlocks);
+ void removeBlocks(const SmallSetVector<BasicBlock *, 8> &DeadBlocks);
/// Get handle on MemorySSA.
MemorySSA* getMemorySSA() const { return MSSA; }
diff --git a/llvm/lib/Analysis/MemorySSAUpdater.cpp b/llvm/lib/Analysis/MemorySSAUpdater.cpp
index 6c817d20368..a6c7142a697 100644
--- a/llvm/lib/Analysis/MemorySSAUpdater.cpp
+++ b/llvm/lib/Analysis/MemorySSAUpdater.cpp
@@ -1101,7 +1101,7 @@ void MemorySSAUpdater::removeMemoryAccess(MemoryAccess *MA) {
}
void MemorySSAUpdater::removeBlocks(
- const SmallPtrSetImpl<BasicBlock *> &DeadBlocks) {
+ const SmallSetVector<BasicBlock *, 8> &DeadBlocks) {
// First delete all uses of BB in MemoryPhis.
for (BasicBlock *BB : DeadBlocks) {
Instruction *TI = BB->getTerminator();
diff --git a/llvm/lib/Transforms/Scalar/LoopSimplifyCFG.cpp b/llvm/lib/Transforms/Scalar/LoopSimplifyCFG.cpp
index 2e5927f9a06..f464df26a02 100644
--- a/llvm/lib/Transforms/Scalar/LoopSimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopSimplifyCFG.cpp
@@ -388,8 +388,8 @@ private:
void deleteDeadLoopBlocks() {
DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Eager);
if (MSSAU) {
- SmallPtrSet<BasicBlock *, 8> DeadLoopBlocksSet(DeadLoopBlocks.begin(),
- DeadLoopBlocks.end());
+ SmallSetVector<BasicBlock *, 8> DeadLoopBlocksSet(DeadLoopBlocks.begin(),
+ DeadLoopBlocks.end());
MSSAU->removeBlocks(DeadLoopBlocksSet);
}
for (auto *BB : DeadLoopBlocks) {
diff --git a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
index 5a67178cef3..814cf814989 100644
--- a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
+++ b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
@@ -1436,8 +1436,8 @@ deleteDeadClonedBlocks(Loop &L, ArrayRef<BasicBlock *> ExitBlocks,
// Remove all MemorySSA in the dead blocks
if (MSSAU) {
- SmallPtrSet<BasicBlock *, 16> DeadBlockSet(DeadBlocks.begin(),
- DeadBlocks.end());
+ SmallSetVector<BasicBlock *, 8> DeadBlockSet(DeadBlocks.begin(),
+ DeadBlocks.end());
MSSAU->removeBlocks(DeadBlockSet);
}
@@ -1455,7 +1455,7 @@ static void deleteDeadBlocksFromLoop(Loop &L,
MemorySSAUpdater *MSSAU) {
// Find all the dead blocks tied to this loop, and remove them from their
// successors.
- SmallPtrSet<BasicBlock *, 16> DeadBlockSet;
+ SmallSetVector<BasicBlock *, 8> DeadBlockSet;
// Start with loop/exit blocks and get a transitive closure of reachable dead
// blocks.
diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp
index 499e611acb5..83dabcd7952 100644
--- a/llvm/lib/Transforms/Utils/Local.cpp
+++ b/llvm/lib/Transforms/Utils/Local.cpp
@@ -2211,7 +2211,7 @@ bool llvm::removeUnreachableBlocks(Function &F, LazyValueInfo *LVI,
assert(Reachable.size() < F.size());
NumRemoved += F.size()-Reachable.size();
- SmallPtrSet<BasicBlock *, 16> DeadBlockSet;
+ SmallSetVector<BasicBlock *, 8> DeadBlockSet;
for (Function::iterator I = ++F.begin(), E = F.end(); I != E; ++I) {
auto *BB = &*I;
if (Reachable.count(BB))
diff --git a/llvm/test/Analysis/MemorySSA/nondeterminism.ll b/llvm/test/Analysis/MemorySSA/nondeterminism.ll
new file mode 100644
index 00000000000..0bb3df30b58
--- /dev/null
+++ b/llvm/test/Analysis/MemorySSA/nondeterminism.ll
@@ -0,0 +1,122 @@
+; RUN: opt -simplifycfg -enable-mssa-loop-dependency -S --preserve-ll-uselistorder %s | FileCheck %s
+; REQUIRES: x86-registered-target
+; CHECK-LABEL: @n
+; CHECK: uselistorder i16 0, { 3, 2, 4, 1, 5, 0, 6 }
+
+; Note: test was added in an effort to ensure determinism when updating memoryssa. See PR42574.
+; If the uselistorder check becomes no longer relevant, the test can be disabled or removed.
+
+%rec9 = type { i16, i32, i32 }
+
+@a = global [1 x [1 x %rec9]] zeroinitializer
+
+define i16 @n() {
+ br label %..split_crit_edge
+
+..split_crit_edge: ; preds = %0
+ br label %.split
+
+bb4.us4: ; preds = %bb2.split.us32, %bb6.us28
+ %i.4.01.us5 = phi i16 [ %_tmp49.us30, %bb6.us28 ]
+ br label %g.exit4.us21
+
+bb1.i.us14: ; preds = %bb4.us4
+ br label %g.exit4.us21
+
+g.exit4.us21: ; preds = %bb1.i.us14, %g.exit4.critedge.us9