By calling this function after every link, we introduce quadratic
behavior during full LTO links that primarily affects links involving
large numbers of constant arrays, such as the full LTO part of a
ThinLTO link which will involve large numbers of vtable constants.
Removing this call resulted in a 1.3x speedup in the indexing phase
of a large internal Google binary.
This call was originally introduced to reduce memory consumption during
full LTO (see commit dab999d54f), but it
doesn't seem to be the case that this helps any more. I ran 3 stage2
links of clang with full LTO and ThinLTO with and without this change
and measured the max RSS. The results were as follows (all in KB):
```
FullLTO before 22362512 22383524 22387456
after 22383496 22365356 22364352
ThinLTO before 4391404 4478192 4383468
after 4399220 4363100 4417688
```
As you can see, any max RSS differences are in the noise.
Reviewers: nikic, teresajohnson
Reviewed By: teresajohnson, nikic
Pull Request: https://github.com/llvm/llvm-project/pull/137081
238 lines
7.8 KiB
C++
238 lines
7.8 KiB
C++
//===- LLVMContextImpl.cpp - Implement LLVMContextImpl --------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements the opaque LLVMContextImpl.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "LLVMContextImpl.h"
|
|
#include "AttributeImpl.h"
|
|
#include "llvm/ADT/SetVector.h"
|
|
#include "llvm/ADT/StringMapEntry.h"
|
|
#include "llvm/ADT/iterator.h"
|
|
#include "llvm/IR/DiagnosticHandler.h"
|
|
#include "llvm/IR/LLVMRemarkStreamer.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/IR/OptBisect.h"
|
|
#include "llvm/IR/Type.h"
|
|
#include "llvm/IR/Use.h"
|
|
#include "llvm/IR/User.h"
|
|
#include "llvm/Remarks/RemarkStreamer.h"
|
|
#include "llvm/Support/Compiler.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include <cassert>
|
|
#include <utility>
|
|
|
|
using namespace llvm;
|
|
|
|
LLVMContextImpl::LLVMContextImpl(LLVMContext &C)
|
|
: DiagHandler(std::make_unique<DiagnosticHandler>()),
|
|
VoidTy(C, Type::VoidTyID), LabelTy(C, Type::LabelTyID),
|
|
HalfTy(C, Type::HalfTyID), BFloatTy(C, Type::BFloatTyID),
|
|
FloatTy(C, Type::FloatTyID), DoubleTy(C, Type::DoubleTyID),
|
|
MetadataTy(C, Type::MetadataTyID), TokenTy(C, Type::TokenTyID),
|
|
X86_FP80Ty(C, Type::X86_FP80TyID), FP128Ty(C, Type::FP128TyID),
|
|
PPC_FP128Ty(C, Type::PPC_FP128TyID), X86_AMXTy(C, Type::X86_AMXTyID),
|
|
Int1Ty(C, 1), Int8Ty(C, 8), Int16Ty(C, 16), Int32Ty(C, 32),
|
|
Int64Ty(C, 64), Int128Ty(C, 128) {}
|
|
|
|
LLVMContextImpl::~LLVMContextImpl() {
|
|
#ifndef NDEBUG
|
|
// Check that any variable location records that fell off the end of a block
|
|
// when it's terminator was removed were eventually replaced. This assertion
|
|
// firing indicates that DbgVariableRecords went missing during the lifetime
|
|
// of the LLVMContext.
|
|
assert(TrailingDbgRecords.empty() && "DbgRecords in blocks not cleaned");
|
|
#endif
|
|
|
|
// NOTE: We need to delete the contents of OwnedModules, but Module's dtor
|
|
// will call LLVMContextImpl::removeModule, thus invalidating iterators into
|
|
// the container. Avoid iterators during this operation:
|
|
while (!OwnedModules.empty())
|
|
delete *OwnedModules.begin();
|
|
|
|
#ifndef NDEBUG
|
|
// Check for metadata references from leaked Values.
|
|
for (auto &Pair : ValueMetadata)
|
|
Pair.first->dump();
|
|
assert(ValueMetadata.empty() && "Values with metadata have been leaked");
|
|
#endif
|
|
|
|
// Drop references for MDNodes. Do this before Values get deleted to avoid
|
|
// unnecessary RAUW when nodes are still unresolved.
|
|
for (auto *I : DistinctMDNodes)
|
|
I->dropAllReferences();
|
|
#define HANDLE_MDNODE_LEAF_UNIQUABLE(CLASS) \
|
|
for (auto *I : CLASS##s) \
|
|
I->dropAllReferences();
|
|
#include "llvm/IR/Metadata.def"
|
|
|
|
// Also drop references that come from the Value bridges.
|
|
for (auto &Pair : ValuesAsMetadata)
|
|
Pair.second->dropUsers();
|
|
for (auto &Pair : MetadataAsValues)
|
|
Pair.second->dropUse();
|
|
// Do not untrack ValueAsMetadata references for DIArgLists, as they have
|
|
// already been more efficiently untracked above.
|
|
for (DIArgList *AL : DIArgLists) {
|
|
AL->dropAllReferences(/* Untrack */ false);
|
|
delete AL;
|
|
}
|
|
DIArgLists.clear();
|
|
|
|
// Destroy MDNodes.
|
|
for (MDNode *I : DistinctMDNodes)
|
|
I->deleteAsSubclass();
|
|
|
|
for (auto *ConstantRangeListAttribute : ConstantRangeListAttributes)
|
|
ConstantRangeListAttribute->~ConstantRangeListAttributeImpl();
|
|
#define HANDLE_MDNODE_LEAF_UNIQUABLE(CLASS) \
|
|
for (CLASS * I : CLASS##s) \
|
|
delete I;
|
|
#include "llvm/IR/Metadata.def"
|
|
|
|
// Free the constants.
|
|
for (auto *I : ExprConstants)
|
|
I->dropAllReferences();
|
|
for (auto *I : ArrayConstants)
|
|
I->dropAllReferences();
|
|
for (auto *I : StructConstants)
|
|
I->dropAllReferences();
|
|
for (auto *I : VectorConstants)
|
|
I->dropAllReferences();
|
|
ExprConstants.freeConstants();
|
|
ArrayConstants.freeConstants();
|
|
StructConstants.freeConstants();
|
|
VectorConstants.freeConstants();
|
|
InlineAsms.freeConstants();
|
|
|
|
CAZConstants.clear();
|
|
CPNConstants.clear();
|
|
CTNConstants.clear();
|
|
UVConstants.clear();
|
|
PVConstants.clear();
|
|
IntZeroConstants.clear();
|
|
IntOneConstants.clear();
|
|
IntConstants.clear();
|
|
IntSplatConstants.clear();
|
|
FPConstants.clear();
|
|
FPSplatConstants.clear();
|
|
CDSConstants.clear();
|
|
|
|
// Destroy attribute node lists.
|
|
for (FoldingSetIterator<AttributeSetNode> I = AttrsSetNodes.begin(),
|
|
E = AttrsSetNodes.end(); I != E; ) {
|
|
FoldingSetIterator<AttributeSetNode> Elem = I++;
|
|
delete &*Elem;
|
|
}
|
|
|
|
// Destroy MetadataAsValues.
|
|
{
|
|
SmallVector<MetadataAsValue *, 8> MDVs;
|
|
MDVs.reserve(MetadataAsValues.size());
|
|
for (auto &Pair : MetadataAsValues)
|
|
MDVs.push_back(Pair.second);
|
|
MetadataAsValues.clear();
|
|
for (auto *V : MDVs)
|
|
delete V;
|
|
}
|
|
|
|
// Destroy ValuesAsMetadata.
|
|
for (auto &Pair : ValuesAsMetadata)
|
|
delete Pair.second;
|
|
}
|
|
|
|
namespace llvm {
|
|
|
|
/// Make MDOperand transparent for hashing.
|
|
///
|
|
/// This overload of an implementation detail of the hashing library makes
|
|
/// MDOperand hash to the same value as a \a Metadata pointer.
|
|
///
|
|
/// Note that overloading \a hash_value() as follows:
|
|
///
|
|
/// \code
|
|
/// size_t hash_value(const MDOperand &X) { return hash_value(X.get()); }
|
|
/// \endcode
|
|
///
|
|
/// does not cause MDOperand to be transparent. In particular, a bare pointer
|
|
/// doesn't get hashed before it's combined, whereas \a MDOperand would.
|
|
static const Metadata *get_hashable_data(const MDOperand &X) { return X.get(); }
|
|
|
|
} // end namespace llvm
|
|
|
|
unsigned MDNodeOpsKey::calculateHash(MDNode *N, unsigned Offset) {
|
|
unsigned Hash = hash_combine_range(N->op_begin() + Offset, N->op_end());
|
|
#ifndef NDEBUG
|
|
{
|
|
SmallVector<Metadata *, 8> MDs(drop_begin(N->operands(), Offset));
|
|
unsigned RawHash = calculateHash(MDs);
|
|
assert(Hash == RawHash &&
|
|
"Expected hash of MDOperand to equal hash of Metadata*");
|
|
}
|
|
#endif
|
|
return Hash;
|
|
}
|
|
|
|
unsigned MDNodeOpsKey::calculateHash(ArrayRef<Metadata *> Ops) {
|
|
return hash_combine_range(Ops);
|
|
}
|
|
|
|
StringMapEntry<uint32_t> *LLVMContextImpl::getOrInsertBundleTag(StringRef Tag) {
|
|
uint32_t NewIdx = BundleTagCache.size();
|
|
return &*(BundleTagCache.insert(std::make_pair(Tag, NewIdx)).first);
|
|
}
|
|
|
|
void LLVMContextImpl::getOperandBundleTags(SmallVectorImpl<StringRef> &Tags) const {
|
|
Tags.resize(BundleTagCache.size());
|
|
for (const auto &T : BundleTagCache)
|
|
Tags[T.second] = T.first();
|
|
}
|
|
|
|
uint32_t LLVMContextImpl::getOperandBundleTagID(StringRef Tag) const {
|
|
auto I = BundleTagCache.find(Tag);
|
|
assert(I != BundleTagCache.end() && "Unknown tag!");
|
|
return I->second;
|
|
}
|
|
|
|
SyncScope::ID LLVMContextImpl::getOrInsertSyncScopeID(StringRef SSN) {
|
|
auto NewSSID = SSC.size();
|
|
assert(NewSSID < std::numeric_limits<SyncScope::ID>::max() &&
|
|
"Hit the maximum number of synchronization scopes allowed!");
|
|
return SSC.insert(std::make_pair(SSN, SyncScope::ID(NewSSID))).first->second;
|
|
}
|
|
|
|
void LLVMContextImpl::getSyncScopeNames(
|
|
SmallVectorImpl<StringRef> &SSNs) const {
|
|
SSNs.resize(SSC.size());
|
|
for (const auto &SSE : SSC)
|
|
SSNs[SSE.second] = SSE.first();
|
|
}
|
|
|
|
std::optional<StringRef>
|
|
LLVMContextImpl::getSyncScopeName(SyncScope::ID Id) const {
|
|
for (const auto &SSE : SSC) {
|
|
if (SSE.second != Id)
|
|
continue;
|
|
return SSE.first();
|
|
}
|
|
return std::nullopt;
|
|
}
|
|
|
|
/// Gets the OptPassGate for this LLVMContextImpl, which defaults to the
|
|
/// singleton OptBisect if not explicitly set.
|
|
OptPassGate &LLVMContextImpl::getOptPassGate() const {
|
|
if (!OPG)
|
|
OPG = &getGlobalPassGate();
|
|
return *OPG;
|
|
}
|
|
|
|
void LLVMContextImpl::setOptPassGate(OptPassGate& OPG) {
|
|
this->OPG = &OPG;
|
|
}
|