mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 19:23:23 +01:00
9369556310
ClangBuildAnalyzer results show that a lot of time is spent instantiating AnalysisManager::getResultImpl across the code base: **** Templates that took longest to instantiate: 50445 ms: llvm::AnalysisManager<llvm::Function>::getResultImpl (412 times, avg 122 ms) 47797 ms: llvm::AnalysisManager<llvm::Function>::getResult<llvm::TargetLibraryAnalysis> (389 times, avg 122 ms) 46894 ms: std::tie<const unsigned long long, const bool> (2452 times, avg 19 ms) 43851 ms: llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, 4096, 4096>::Allocate (3228 times, avg 13 ms) 33911 ms: std::tie<const unsigned int, const unsigned int, const unsigned int, const unsigned int> (897 times, avg 37 ms) 33854 ms: std::tie<const unsigned long long, const unsigned long long> (1897 times, avg 17 ms) 27886 ms: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string (11156 times, avg 2 ms) I mentioned this result to @chandlerc, and he suggested this direction. AnalysisManager is already explicitly instantiated, and getResultImpl doesn't need to be inlined. Move the definition to an Impl header, and include that header in files that explicitly instantiate AnalysisManager. There are only four (real) IR units: - function - module - loop - cgscc Looking at a specific transform (ArgumentPromotion.cpp), here are three compilations before & after this change: BEFORE: $ for i in $(seq 3) ; do ./ccit.bat ; done peak memory: 258.15MB real: 0m6.297s peak memory: 257.54MB real: 0m5.906s peak memory: 257.47MB real: 0m6.219s AFTER: $ for i in $(seq 3) ; do ./ccit.bat ; done peak memory: 235.35MB real: 0m5.454s peak memory: 234.72MB real: 0m5.235s peak memory: 234.39MB real: 0m5.469s The 20MB of memory saved seems real, and the time improvement seems like it is there. Reviewed By: MaskRay Differential Revision: https://reviews.llvm.org/D73817
158 lines
5.8 KiB
C++
158 lines
5.8 KiB
C++
//===- PassManagerImpl.h - Pass management infrastructure -------*- C++ -*-===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
///
|
|
/// Provides implementations for PassManager and AnalysisManager template
|
|
/// methods. These classes should be explicitly instantiated for any IR unit,
|
|
/// and files doing the explicit instantiation should include this header.
|
|
///
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_IR_PASSMANAGERIMPL_H
|
|
#define LLVM_IR_PASSMANAGERIMPL_H
|
|
|
|
#include "llvm/IR/PassManager.h"
|
|
|
|
namespace llvm {
|
|
|
|
template <typename IRUnitT, typename... ExtraArgTs>
|
|
inline AnalysisManager<IRUnitT, ExtraArgTs...>::AnalysisManager(
|
|
bool DebugLogging)
|
|
: DebugLogging(DebugLogging) {}
|
|
|
|
template <typename IRUnitT, typename... ExtraArgTs>
|
|
inline AnalysisManager<IRUnitT, ExtraArgTs...>::AnalysisManager(
|
|
AnalysisManager &&) = default;
|
|
|
|
template <typename IRUnitT, typename... ExtraArgTs>
|
|
inline AnalysisManager<IRUnitT, ExtraArgTs...> &
|
|
AnalysisManager<IRUnitT, ExtraArgTs...>::operator=(AnalysisManager &&) =
|
|
default;
|
|
|
|
template <typename IRUnitT, typename... ExtraArgTs>
|
|
inline void
|
|
AnalysisManager<IRUnitT, ExtraArgTs...>::clear(IRUnitT &IR,
|
|
llvm::StringRef Name) {
|
|
if (DebugLogging)
|
|
dbgs() << "Clearing all analysis results for: " << Name << "\n";
|
|
|
|
auto ResultsListI = AnalysisResultLists.find(&IR);
|
|
if (ResultsListI == AnalysisResultLists.end())
|
|
return;
|
|
// Delete the map entries that point into the results list.
|
|
for (auto &IDAndResult : ResultsListI->second)
|
|
AnalysisResults.erase({IDAndResult.first, &IR});
|
|
|
|
// And actually destroy and erase the results associated with this IR.
|
|
AnalysisResultLists.erase(ResultsListI);
|
|
}
|
|
|
|
template <typename IRUnitT, typename... ExtraArgTs>
|
|
inline typename AnalysisManager<IRUnitT, ExtraArgTs...>::ResultConceptT &
|
|
AnalysisManager<IRUnitT, ExtraArgTs...>::getResultImpl(
|
|
AnalysisKey *ID, IRUnitT &IR, ExtraArgTs... ExtraArgs) {
|
|
typename AnalysisResultMapT::iterator RI;
|
|
bool Inserted;
|
|
std::tie(RI, Inserted) = AnalysisResults.insert(std::make_pair(
|
|
std::make_pair(ID, &IR), typename AnalysisResultListT::iterator()));
|
|
|
|
// If we don't have a cached result for this function, look up the pass and
|
|
// run it to produce a result, which we then add to the cache.
|
|
if (Inserted) {
|
|
auto &P = this->lookUpPass(ID);
|
|
if (DebugLogging)
|
|
dbgs() << "Running analysis: " << P.name() << " on " << IR.getName()
|
|
<< "\n";
|
|
|
|
PassInstrumentation PI;
|
|
if (ID != PassInstrumentationAnalysis::ID()) {
|
|
PI = getResult<PassInstrumentationAnalysis>(IR, ExtraArgs...);
|
|
PI.runBeforeAnalysis(P, IR);
|
|
}
|
|
|
|
AnalysisResultListT &ResultList = AnalysisResultLists[&IR];
|
|
ResultList.emplace_back(ID, P.run(IR, *this, ExtraArgs...));
|
|
|
|
PI.runAfterAnalysis(P, IR);
|
|
|
|
// P.run may have inserted elements into AnalysisResults and invalidated
|
|
// RI.
|
|
RI = AnalysisResults.find({ID, &IR});
|
|
assert(RI != AnalysisResults.end() && "we just inserted it!");
|
|
|
|
RI->second = std::prev(ResultList.end());
|
|
}
|
|
|
|
return *RI->second->second;
|
|
}
|
|
|
|
template <typename IRUnitT, typename... ExtraArgTs>
|
|
inline void AnalysisManager<IRUnitT, ExtraArgTs...>::invalidate(
|
|
IRUnitT &IR, const PreservedAnalyses &PA) {
|
|
// We're done if all analyses on this IR unit are preserved.
|
|
if (PA.allAnalysesInSetPreserved<AllAnalysesOn<IRUnitT>>())
|
|
return;
|
|
|
|
if (DebugLogging)
|
|
dbgs() << "Invalidating all non-preserved analyses for: " << IR.getName()
|
|
<< "\n";
|
|
|
|
// Track whether each analysis's result is invalidated in
|
|
// IsResultInvalidated.
|
|
SmallDenseMap<AnalysisKey *, bool, 8> IsResultInvalidated;
|
|
Invalidator Inv(IsResultInvalidated, AnalysisResults);
|
|
AnalysisResultListT &ResultsList = AnalysisResultLists[&IR];
|
|
for (auto &AnalysisResultPair : ResultsList) {
|
|
// This is basically the same thing as Invalidator::invalidate, but we
|
|
// can't call it here because we're operating on the type-erased result.
|
|
// Moreover if we instead called invalidate() directly, it would do an
|
|
// unnecessary look up in ResultsList.
|
|
AnalysisKey *ID = AnalysisResultPair.first;
|
|
auto &Result = *AnalysisResultPair.second;
|
|
|
|
auto IMapI = IsResultInvalidated.find(ID);
|
|
if (IMapI != IsResultInvalidated.end())
|
|
// This result was already handled via the Invalidator.
|
|
continue;
|
|
|
|
// Try to invalidate the result, giving it the Invalidator so it can
|
|
// recursively query for any dependencies it has and record the result.
|
|
// Note that we cannot reuse 'IMapI' here or pre-insert the ID, as
|
|
// Result.invalidate may insert things into the map, invalidating our
|
|
// iterator.
|
|
bool Inserted =
|
|
IsResultInvalidated.insert({ID, Result.invalidate(IR, PA, Inv)}).second;
|
|
(void)Inserted;
|
|
assert(Inserted && "Should never have already inserted this ID, likely "
|
|
"indicates a cycle!");
|
|
}
|
|
|
|
// Now erase the results that were marked above as invalidated.
|
|
if (!IsResultInvalidated.empty()) {
|
|
for (auto I = ResultsList.begin(), E = ResultsList.end(); I != E;) {
|
|
AnalysisKey *ID = I->first;
|
|
if (!IsResultInvalidated.lookup(ID)) {
|
|
++I;
|
|
continue;
|
|
}
|
|
|
|
if (DebugLogging)
|
|
dbgs() << "Invalidating analysis: " << this->lookUpPass(ID).name()
|
|
<< " on " << IR.getName() << "\n";
|
|
|
|
I = ResultsList.erase(I);
|
|
AnalysisResults.erase({ID, &IR});
|
|
}
|
|
}
|
|
|
|
if (ResultsList.empty())
|
|
AnalysisResultLists.erase(&IR);
|
|
}
|
|
} // end namespace llvm
|
|
|
|
#endif // LLVM_IR_PASSMANAGERIMPL_H
|