LowerTypeTests: Fix non-determinism in code that handles icall branch funnels.

This was exposed by enabling expensive checks, which causes llvm::sort
to sort randomly.

Differential Revision: https://reviews.llvm.org/D45901

llvm-svn: 331573
This commit is contained in:
Peter Collingbourne 2018-05-05 00:51:55 +00:00
parent 60609c9f12
commit e04ecc88de
1 changed files with 26 additions and 13 deletions

View File

@ -297,11 +297,13 @@ public:
struct ICallBranchFunnel final
: TrailingObjects<ICallBranchFunnel, GlobalTypeMember *> {
static ICallBranchFunnel *create(BumpPtrAllocator &Alloc, CallInst *CI,
ArrayRef<GlobalTypeMember *> Targets) {
ArrayRef<GlobalTypeMember *> Targets,
unsigned UniqueId) {
auto *Call = static_cast<ICallBranchFunnel *>(
Alloc.Allocate(totalSizeToAlloc<GlobalTypeMember *>(Targets.size()),
alignof(ICallBranchFunnel)));
Call->CI = CI;
Call->UniqueId = UniqueId;
Call->NTargets = Targets.size();
std::uninitialized_copy(Targets.begin(), Targets.end(),
Call->getTrailingObjects<GlobalTypeMember *>());
@ -313,6 +315,8 @@ struct ICallBranchFunnel final
return makeArrayRef(getTrailingObjects<GlobalTypeMember *>(), NTargets);
}
unsigned UniqueId;
private:
size_t NTargets;
};
@ -1664,11 +1668,11 @@ bool LowerTypeTestsModule::lower() {
// identifiers.
BumpPtrAllocator Alloc;
struct TIInfo {
unsigned Index;
unsigned UniqueId;
std::vector<GlobalTypeMember *> RefGlobals;
};
DenseMap<Metadata *, TIInfo> TypeIdInfo;
unsigned I = 0;
unsigned CurUniqueId = 0;
SmallVector<MDNode *, 2> Types;
struct ExportedFunctionInfo {
@ -1756,7 +1760,7 @@ bool LowerTypeTestsModule::lower() {
for (MDNode *Type : Types) {
verifyTypeMDNode(&GO, Type);
auto &Info = TypeIdInfo[Type->getOperand(1)];
Info.Index = ++I;
Info.UniqueId = ++CurUniqueId;
Info.RefGlobals.push_back(GTM);
}
}
@ -1825,8 +1829,9 @@ bool LowerTypeTestsModule::lower() {
}
GlobalClasses.unionSets(
CurSet, GlobalClasses.findLeader(GlobalClasses.insert(
ICallBranchFunnel::create(Alloc, CI, Targets))));
CurSet, GlobalClasses.findLeader(
GlobalClasses.insert(ICallBranchFunnel::create(
Alloc, CI, Targets, ++CurUniqueId))));
}
}
@ -1863,13 +1868,15 @@ bool LowerTypeTestsModule::lower() {
continue;
++NumTypeIdDisjointSets;
unsigned MaxIndex = 0;
unsigned MaxUniqueId = 0;
for (GlobalClassesTy::member_iterator MI = GlobalClasses.member_begin(I);
MI != GlobalClasses.member_end(); ++MI) {
if ((*MI).is<Metadata *>())
MaxIndex = std::max(MaxIndex, TypeIdInfo[MI->get<Metadata *>()].Index);
if (auto *MD = MI->dyn_cast<Metadata *>())
MaxUniqueId = std::max(MaxUniqueId, TypeIdInfo[MD].UniqueId);
else if (auto *BF = MI->dyn_cast<ICallBranchFunnel *>())
MaxUniqueId = std::max(MaxUniqueId, BF->UniqueId);
}
Sets.emplace_back(I, MaxIndex);
Sets.emplace_back(I, MaxUniqueId);
}
llvm::sort(Sets.begin(), Sets.end(),
[](const std::pair<GlobalClassesTy::iterator, unsigned> &S1,
@ -1894,12 +1901,18 @@ bool LowerTypeTestsModule::lower() {
ICallBranchFunnels.push_back(MI->get<ICallBranchFunnel *>());
}
// Order type identifiers by global index for determinism. This ordering is
// stable as there is a one-to-one mapping between metadata and indices.
// Order type identifiers by unique ID for determinism. This ordering is
// stable as there is a one-to-one mapping between metadata and unique IDs.
llvm::sort(TypeIds.begin(), TypeIds.end(), [&](Metadata *M1, Metadata *M2) {
return TypeIdInfo[M1].Index < TypeIdInfo[M2].Index;
return TypeIdInfo[M1].UniqueId < TypeIdInfo[M2].UniqueId;
});
// Same for the branch funnels.
llvm::sort(ICallBranchFunnels.begin(), ICallBranchFunnels.end(),
[&](ICallBranchFunnel *F1, ICallBranchFunnel *F2) {
return F1->UniqueId < F2->UniqueId;
});
// Build bitsets for this disjoint set.
buildBitSetsFromDisjointSet(TypeIds, Globals, ICallBranchFunnels);
}