Skip to content

Commit 2185318

Browse files
authored
LowerTypeTests: Fix quadratic complexity (try 2).
Currently we have quadratic complexity in LowerTypeTests because ScopedSaveAliaseesAndUsed loops over all aliases for each disjoint set, and the number of aliases and number of disjoint sets is roughly proportional to the program size. Fix that by moving ScopedSaveAliaseesAndUsed to LowerTypeTestsModule::lower() so that we do this only once. Reland of llvm#135875 with fix for bug that caused check-lld test failures. The fix is to only remove functions from llvm.used/llvm.compiler.used because buildBitSetsFromGlobalVariables, which now runs while ScopedSaveAliaseesAndUsed is in scope, will delete global variables, which would otherwise lead to a use-after-free when they are added back to llvm.used or llvm.compiler.used. Reviewers: fmayer, vitalybuka Reviewed By: fmayer Pull Request: llvm#136053
1 parent eef9782 commit 2185318

File tree

1 file changed

+107
-87
lines changed

1 file changed

+107
-87
lines changed

llvm/lib/Transforms/IPO/LowerTypeTests.cpp

Lines changed: 107 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,30 @@ struct ScopedSaveAliaseesAndUsed {
352352
std::vector<std::pair<GlobalAlias *, Function *>> FunctionAliases;
353353
std::vector<std::pair<GlobalIFunc *, Function *>> ResolverIFuncs;
354354

355+
// This function only removes functions from llvm.used and llvm.compiler.used.
356+
// We cannot remove global variables because they need to follow RAUW, as
357+
// they may be deleted by buildBitSetsFromGlobalVariables.
358+
void collectAndEraseUsedFunctions(Module &M,
359+
SmallVectorImpl<GlobalValue *> &Vec,
360+
bool CompilerUsed) {
361+
auto *GV = collectUsedGlobalVariables(M, Vec, CompilerUsed);
362+
if (!GV)
363+
return;
364+
// There's no API to only remove certain array elements from
365+
// llvm.used/llvm.compiler.used, so we remove all of them and add back only
366+
// the non-functions.
367+
GV->eraseFromParent();
368+
auto NonFuncBegin =
369+
std::stable_partition(Vec.begin(), Vec.end(), [](GlobalValue *GV) {
370+
return isa<Function>(GV);
371+
});
372+
if (CompilerUsed)
373+
appendToCompilerUsed(M, {NonFuncBegin, Vec.end()});
374+
else
375+
appendToUsed(M, {NonFuncBegin, Vec.end()});
376+
Vec.resize(NonFuncBegin - Vec.begin());
377+
}
378+
355379
ScopedSaveAliaseesAndUsed(Module &M) : M(M) {
356380
// The users of this class want to replace all function references except
357381
// for aliases and llvm.used/llvm.compiler.used with references to a jump
@@ -365,10 +389,8 @@ struct ScopedSaveAliaseesAndUsed {
365389
// llvm.used/llvm.compiler.used and aliases, erase the used lists, let RAUW
366390
// replace the aliasees and then set them back to their original values at
367391
// the end.
368-
if (GlobalVariable *GV = collectUsedGlobalVariables(M, Used, false))
369-
GV->eraseFromParent();
370-
if (GlobalVariable *GV = collectUsedGlobalVariables(M, CompilerUsed, true))
371-
GV->eraseFromParent();
392+
collectAndEraseUsedFunctions(M, Used, false);
393+
collectAndEraseUsedFunctions(M, CompilerUsed, true);
372394

373395
for (auto &GA : M.aliases()) {
374396
// FIXME: This should look past all aliases not just interposable ones,
@@ -1669,61 +1691,55 @@ void LowerTypeTestsModule::buildBitSetsFromFunctionsNative(
16691691

16701692
lowerTypeTestCalls(TypeIds, JumpTable, GlobalLayout);
16711693

1672-
{
1673-
ScopedSaveAliaseesAndUsed S(M);
1694+
// Build aliases pointing to offsets into the jump table, and replace
1695+
// references to the original functions with references to the aliases.
1696+
for (unsigned I = 0; I != Functions.size(); ++I) {
1697+
Function *F = cast<Function>(Functions[I]->getGlobal());
1698+
bool IsJumpTableCanonical = Functions[I]->isJumpTableCanonical();
16741699

1675-
// Build aliases pointing to offsets into the jump table, and replace
1676-
// references to the original functions with references to the aliases.
1677-
for (unsigned I = 0; I != Functions.size(); ++I) {
1678-
Function *F = cast<Function>(Functions[I]->getGlobal());
1679-
bool IsJumpTableCanonical = Functions[I]->isJumpTableCanonical();
1680-
1681-
Constant *CombinedGlobalElemPtr = ConstantExpr::getInBoundsGetElementPtr(
1682-
JumpTableType, JumpTable,
1683-
ArrayRef<Constant *>{ConstantInt::get(IntPtrTy, 0),
1684-
ConstantInt::get(IntPtrTy, I)});
1685-
1686-
const bool IsExported = Functions[I]->isExported();
1687-
if (!IsJumpTableCanonical) {
1688-
GlobalValue::LinkageTypes LT = IsExported
1689-
? GlobalValue::ExternalLinkage
1690-
: GlobalValue::InternalLinkage;
1691-
GlobalAlias *JtAlias = GlobalAlias::create(F->getValueType(), 0, LT,
1692-
F->getName() + ".cfi_jt",
1693-
CombinedGlobalElemPtr, &M);
1694-
if (IsExported)
1695-
JtAlias->setVisibility(GlobalValue::HiddenVisibility);
1696-
else
1697-
appendToUsed(M, {JtAlias});
1698-
}
1700+
Constant *CombinedGlobalElemPtr = ConstantExpr::getInBoundsGetElementPtr(
1701+
JumpTableType, JumpTable,
1702+
ArrayRef<Constant *>{ConstantInt::get(IntPtrTy, 0),
1703+
ConstantInt::get(IntPtrTy, I)});
1704+
1705+
const bool IsExported = Functions[I]->isExported();
1706+
if (!IsJumpTableCanonical) {
1707+
GlobalValue::LinkageTypes LT = IsExported ? GlobalValue::ExternalLinkage
1708+
: GlobalValue::InternalLinkage;
1709+
GlobalAlias *JtAlias = GlobalAlias::create(F->getValueType(), 0, LT,
1710+
F->getName() + ".cfi_jt",
1711+
CombinedGlobalElemPtr, &M);
1712+
if (IsExported)
1713+
JtAlias->setVisibility(GlobalValue::HiddenVisibility);
1714+
else
1715+
appendToUsed(M, {JtAlias});
1716+
}
16991717

1700-
if (IsExported) {
1701-
if (IsJumpTableCanonical)
1702-
ExportSummary->cfiFunctionDefs().emplace(F->getName());
1703-
else
1704-
ExportSummary->cfiFunctionDecls().emplace(F->getName());
1705-
}
1718+
if (IsExported) {
1719+
if (IsJumpTableCanonical)
1720+
ExportSummary->cfiFunctionDefs().emplace(F->getName());
1721+
else
1722+
ExportSummary->cfiFunctionDecls().emplace(F->getName());
1723+
}
17061724

1707-
if (!IsJumpTableCanonical) {
1708-
if (F->hasExternalWeakLinkage())
1709-
replaceWeakDeclarationWithJumpTablePtr(F, CombinedGlobalElemPtr,
1710-
IsJumpTableCanonical);
1711-
else
1712-
replaceCfiUses(F, CombinedGlobalElemPtr, IsJumpTableCanonical);
1713-
} else {
1714-
assert(F->getType()->getAddressSpace() == 0);
1715-
1716-
GlobalAlias *FAlias =
1717-
GlobalAlias::create(F->getValueType(), 0, F->getLinkage(), "",
1718-
CombinedGlobalElemPtr, &M);
1719-
FAlias->setVisibility(F->getVisibility());
1720-
FAlias->takeName(F);
1721-
if (FAlias->hasName())
1722-
F->setName(FAlias->getName() + ".cfi");
1723-
replaceCfiUses(F, FAlias, IsJumpTableCanonical);
1724-
if (!F->hasLocalLinkage())
1725-
F->setVisibility(GlobalVariable::HiddenVisibility);
1726-
}
1725+
if (!IsJumpTableCanonical) {
1726+
if (F->hasExternalWeakLinkage())
1727+
replaceWeakDeclarationWithJumpTablePtr(F, CombinedGlobalElemPtr,
1728+
IsJumpTableCanonical);
1729+
else
1730+
replaceCfiUses(F, CombinedGlobalElemPtr, IsJumpTableCanonical);
1731+
} else {
1732+
assert(F->getType()->getAddressSpace() == 0);
1733+
1734+
GlobalAlias *FAlias = GlobalAlias::create(
1735+
F->getValueType(), 0, F->getLinkage(), "", CombinedGlobalElemPtr, &M);
1736+
FAlias->setVisibility(F->getVisibility());
1737+
FAlias->takeName(F);
1738+
if (FAlias->hasName())
1739+
F->setName(FAlias->getName() + ".cfi");
1740+
replaceCfiUses(F, FAlias, IsJumpTableCanonical);
1741+
if (!F->hasLocalLinkage())
1742+
F->setVisibility(GlobalVariable::HiddenVisibility);
17271743
}
17281744
}
17291745

@@ -2339,39 +2355,43 @@ bool LowerTypeTestsModule::lower() {
23392355
if (GlobalClasses.empty())
23402356
return false;
23412357

2342-
// For each disjoint set we found...
2343-
for (const auto &C : GlobalClasses) {
2344-
if (!C->isLeader())
2345-
continue;
2346-
2347-
++NumTypeIdDisjointSets;
2348-
// Build the list of type identifiers in this disjoint set.
2349-
std::vector<Metadata *> TypeIds;
2350-
std::vector<GlobalTypeMember *> Globals;
2351-
std::vector<ICallBranchFunnel *> ICallBranchFunnels;
2352-
for (auto M : GlobalClasses.members(*C)) {
2353-
if (isa<Metadata *>(M))
2354-
TypeIds.push_back(cast<Metadata *>(M));
2355-
else if (isa<GlobalTypeMember *>(M))
2356-
Globals.push_back(cast<GlobalTypeMember *>(M));
2357-
else
2358-
ICallBranchFunnels.push_back(cast<ICallBranchFunnel *>(M));
2359-
}
2360-
2361-
// Order type identifiers by unique ID for determinism. This ordering is
2362-
// stable as there is a one-to-one mapping between metadata and unique IDs.
2363-
llvm::sort(TypeIds, [&](Metadata *M1, Metadata *M2) {
2364-
return TypeIdInfo[M1].UniqueId < TypeIdInfo[M2].UniqueId;
2365-
});
2358+
{
2359+
ScopedSaveAliaseesAndUsed S(M);
2360+
// For each disjoint set we found...
2361+
for (const auto &C : GlobalClasses) {
2362+
if (!C->isLeader())
2363+
continue;
23662364

2367-
// Same for the branch funnels.
2368-
llvm::sort(ICallBranchFunnels,
2369-
[&](ICallBranchFunnel *F1, ICallBranchFunnel *F2) {
2370-
return F1->UniqueId < F2->UniqueId;
2371-
});
2365+
++NumTypeIdDisjointSets;
2366+
// Build the list of type identifiers in this disjoint set.
2367+
std::vector<Metadata *> TypeIds;
2368+
std::vector<GlobalTypeMember *> Globals;
2369+
std::vector<ICallBranchFunnel *> ICallBranchFunnels;
2370+
for (auto M : GlobalClasses.members(*C)) {
2371+
if (isa<Metadata *>(M))
2372+
TypeIds.push_back(cast<Metadata *>(M));
2373+
else if (isa<GlobalTypeMember *>(M))
2374+
Globals.push_back(cast<GlobalTypeMember *>(M));
2375+
else
2376+
ICallBranchFunnels.push_back(cast<ICallBranchFunnel *>(M));
2377+
}
23722378

2373-
// Build bitsets for this disjoint set.
2374-
buildBitSetsFromDisjointSet(TypeIds, Globals, ICallBranchFunnels);
2379+
// Order type identifiers by unique ID for determinism. This ordering is
2380+
// stable as there is a one-to-one mapping between metadata and unique
2381+
// IDs.
2382+
llvm::sort(TypeIds, [&](Metadata *M1, Metadata *M2) {
2383+
return TypeIdInfo[M1].UniqueId < TypeIdInfo[M2].UniqueId;
2384+
});
2385+
2386+
// Same for the branch funnels.
2387+
llvm::sort(ICallBranchFunnels,
2388+
[&](ICallBranchFunnel *F1, ICallBranchFunnel *F2) {
2389+
return F1->UniqueId < F2->UniqueId;
2390+
});
2391+
2392+
// Build bitsets for this disjoint set.
2393+
buildBitSetsFromDisjointSet(TypeIds, Globals, ICallBranchFunnels);
2394+
}
23752395
}
23762396

23772397
allocateByteArrays();

0 commit comments

Comments
 (0)