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