Update prebuilt Clang to r416183b from Android.
https://android.googlesource.com/platform/prebuilts/clang/host/
linux-x86/+/06a71ddac05c22edb2d10b590e1769b3f8619bef
clang 12.0.5 (based on r416183b) from build 7284624.
Change-Id: I277a316abcf47307562d8b748b84870f31a72866
Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
diff --git a/linux-x64/clang/include/llvm/IR/PassManager.h b/linux-x64/clang/include/llvm/IR/PassManager.h
index 37fe2a5..c669565 100644
--- a/linux-x64/clang/include/llvm/IR/PassManager.h
+++ b/linux-x64/clang/include/llvm/IR/PassManager.h
@@ -38,6 +38,7 @@
#define LLVM_IR_PASSMANAGER_H
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/TinyPtrVector.h"
@@ -45,9 +46,10 @@
#include "llvm/IR/Module.h"
#include "llvm/IR/PassInstrumentation.h"
#include "llvm/IR/PassManagerInternal.h"
+#include "llvm/Pass.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/TypeName.h"
-#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
#include <cstring>
@@ -418,7 +420,7 @@
typename PassT::Result
getAnalysisResultUnpackTuple(AnalysisManagerT &AM, IRUnitT &IR,
std::tuple<ArgTs...> Args,
- llvm::index_sequence<Ns...>) {
+ std::index_sequence<Ns...>) {
(void)Args;
return AM.template getResult<PassT>(IR, std::get<Ns>(Args)...);
}
@@ -435,7 +437,7 @@
std::tuple<MainArgTs...> Args) {
return (getAnalysisResultUnpackTuple<
PassT, IRUnitT>)(AM, IR, Args,
- llvm::index_sequence_for<AnalysisArgTs...>{});
+ std::index_sequence_for<AnalysisArgTs...>{});
}
} // namespace detail
@@ -502,9 +504,6 @@
for (unsigned Idx = 0, Size = Passes.size(); Idx != Size; ++Idx) {
auto *P = Passes[Idx].get();
- if (DebugLogging)
- dbgs() << "Running pass: " << P->name() << " on " << IR.getName()
- << "\n";
// Check the PassInstrumentation's BeforePass callbacks before running the
// pass, skip its execution completely if asked to (callback returns
@@ -512,11 +511,15 @@
if (!PI.runBeforePass<IRUnitT>(*P, IR))
continue;
- PreservedAnalyses PassPA = P->run(IR, AM, ExtraArgs...);
+ PreservedAnalyses PassPA;
+ {
+ TimeTraceScope TimeScope(P->name(), IR.getName());
+ PassPA = P->run(IR, AM, ExtraArgs...);
+ }
// Call onto PassInstrumentation's AfterPass callbacks immediately after
// running the pass.
- PI.runAfterPass<IRUnitT>(*P, IR);
+ PI.runAfterPass<IRUnitT>(*P, IR, PassPA);
// Update the analysis manager as each pass runs and potentially
// invalidates analyses.
@@ -545,7 +548,9 @@
return PA;
}
- template <typename PassT> void addPass(PassT Pass) {
+ template <typename PassT>
+ std::enable_if_t<!std::is_same<PassT, PassManager>::value>
+ addPass(PassT Pass) {
using PassModelT =
detail::PassModel<IRUnitT, PassT, PreservedAnalyses, AnalysisManagerT,
ExtraArgTs...>;
@@ -553,7 +558,24 @@
Passes.emplace_back(new PassModelT(std::move(Pass)));
}
-private:
+ /// When adding a pass manager pass that has the same type as this pass
+ /// manager, simply move the passes over. This is because we don't have use
+ /// cases rely on executing nested pass managers. Doing this could reduce
+ /// implementation complexity and avoid potential invalidation issues that may
+ /// happen with nested pass managers of the same type.
+ template <typename PassT>
+ std::enable_if_t<std::is_same<PassT, PassManager>::value>
+ addPass(PassT &&Pass) {
+ for (auto &P : Pass.Passes)
+ Passes.emplace_back(std::move(P));
+ }
+
+ /// Returns if the pass manager contains any passes.
+ bool isEmpty() const { return Passes.empty(); }
+
+ static bool isRequired() { return true; }
+
+protected:
using PassConceptT =
detail::PassConcept<IRUnitT, AnalysisManagerT, ExtraArgTs...>;
@@ -643,7 +665,7 @@
/// when any of its embedded analysis results end up invalidated. We pass an
/// \c Invalidator object as an argument to \c invalidate() in order to let
/// the analysis results themselves define the dependency graph on the fly.
- /// This lets us avoid building building an explicit representation of the
+ /// This lets us avoid building an explicit representation of the
/// dependencies between analysis results.
class Invalidator {
public:
@@ -726,9 +748,9 @@
/// Construct an empty analysis manager.
///
/// If \p DebugLogging is true, we'll log our progress to llvm::dbgs().
- AnalysisManager(bool DebugLogging = false) : DebugLogging(DebugLogging) {}
- AnalysisManager(AnalysisManager &&) = default;
- AnalysisManager &operator=(AnalysisManager &&) = default;
+ AnalysisManager(bool DebugLogging = false);
+ AnalysisManager(AnalysisManager &&);
+ AnalysisManager &operator=(AnalysisManager &&);
/// Returns true if the analysis manager has an empty results cache.
bool empty() const {
@@ -743,20 +765,7 @@
/// This doesn't invalidate, but instead simply deletes, the relevant results.
/// It is useful when the IR is being removed and we want to clear out all the
/// memory pinned for it.
- void 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);
- }
+ void clear(IRUnitT &IR, llvm::StringRef Name);
/// Clear all analysis results cached by this AnalysisManager.
///
@@ -807,6 +816,16 @@
return &static_cast<ResultModelT *>(ResultConcept)->Result;
}
+ /// Verify that the given Result cannot be invalidated, assert otherwise.
+ template <typename PassT>
+ void verifyNotInvalidated(IRUnitT &IR, typename PassT::Result *Result) const {
+ PreservedAnalyses PA = PreservedAnalyses::none();
+ SmallDenseMap<AnalysisKey *, bool, 8> IsResultInvalidated;
+ Invalidator Inv(IsResultInvalidated, AnalysisResults);
+ assert(!Result->invalidate(IR, PA, Inv) &&
+ "Cached result cannot be invalidated");
+ }
+
/// Register an analysis pass with the manager.
///
/// The parameter is a callable whose result is an analysis pass. This allows
@@ -841,7 +860,7 @@
return true;
}
- /// Invalidate a specific analysis pass for an IR module.
+ /// Invalidate a specific analysis pass for an IR unit.
///
/// Note that the analysis result can disregard invalidation, if it determines
/// it is in fact still valid.
@@ -855,67 +874,7 @@
///
/// Walk through all of the analyses pertaining to this unit of IR and
/// invalidate them, unless they are preserved by the PreservedAnalyses set.
- void 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);
- }
+ void invalidate(IRUnitT &IR, const PreservedAnalyses &PA);
private:
/// Look up a registered analysis pass.
@@ -936,41 +895,7 @@
/// Get an analysis result, running the pass if necessary.
ResultConceptT &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;
- }
+ ExtraArgTs... ExtraArgs);
/// Get a cached analysis result or return null.
ResultConceptT *getCachedResultImpl(AnalysisKey *ID, IRUnitT &IR) const {
@@ -979,7 +904,7 @@
return RI == AnalysisResults.end() ? nullptr : &*RI->second->second;
}
- /// Invalidate a function pass result.
+ /// Invalidate a pass result for a IR unit.
void invalidateImpl(AnalysisKey *ID, IRUnitT &IR) {
typename AnalysisResultMapT::iterator RI =
AnalysisResults.find({ID, &IR});
@@ -993,20 +918,20 @@
AnalysisResults.erase(RI);
}
- /// Map type from module analysis pass ID to pass concept pointer.
+ /// Map type from analysis pass ID to pass concept pointer.
using AnalysisPassMapT =
DenseMap<AnalysisKey *, std::unique_ptr<PassConceptT>>;
- /// Collection of module analysis passes, indexed by ID.
+ /// Collection of analysis passes, indexed by ID.
AnalysisPassMapT AnalysisPasses;
- /// Map from function to a list of function analysis results.
+ /// Map from IR unit to a list of analysis results.
///
- /// Provides linear time removal of all analysis results for a function and
+ /// Provides linear time removal of all analysis results for a IR unit and
/// the ultimate storage for a particular cached analysis result.
AnalysisResultListMapT AnalysisResultLists;
- /// Map from an analysis ID and function to a particular cached
+ /// Map from an analysis ID and IR unit to a particular cached
/// analysis result.
AnalysisResultMapT AnalysisResults;
@@ -1150,7 +1075,16 @@
///
/// This proxy only exposes the const interface of the outer analysis manager,
/// to indicate that you cannot cause an outer analysis to run from within an
-/// inner pass. Instead, you must rely on the \c getCachedResult API.
+/// inner pass. Instead, you must rely on the \c getCachedResult API. This is
+/// due to keeping potential future concurrency in mind. To give an example,
+/// running a module analysis before any function passes may give a different
+/// result than running it in a function pass. Both may be valid, but it would
+/// produce non-deterministic results. GlobalsAA is a good analysis example,
+/// because the cached information has the mod/ref info for all memory for each
+/// function at the time the analysis was computed. The information is still
+/// valid after a function transformation, but it may be *different* if
+/// recomputed after that transform. GlobalsAA is never invalidated.
+
///
/// This proxy doesn't manage invalidation in any way -- that is handled by the
/// recursive return path of each layer of the pass manager. A consequence of
@@ -1164,9 +1098,26 @@
/// Result proxy object for \c OuterAnalysisManagerProxy.
class Result {
public:
- explicit Result(const AnalysisManagerT &AM) : AM(&AM) {}
+ explicit Result(const AnalysisManagerT &OuterAM) : OuterAM(&OuterAM) {}
- const AnalysisManagerT &getManager() const { return *AM; }
+ /// Get a cached analysis. If the analysis can be invalidated, this will
+ /// assert.
+ template <typename PassT, typename IRUnitTParam>
+ typename PassT::Result *getCachedResult(IRUnitTParam &IR) const {
+ typename PassT::Result *Res =
+ OuterAM->template getCachedResult<PassT>(IR);
+ if (Res)
+ OuterAM->template verifyNotInvalidated<PassT>(IR, Res);
+ return Res;
+ }
+
+ /// Method provided for unit testing, not intended for general use.
+ template <typename PassT, typename IRUnitTParam>
+ bool cachedResultExists(IRUnitTParam &IR) const {
+ typename PassT::Result *Res =
+ OuterAM->template getCachedResult<PassT>(IR);
+ return Res != nullptr;
+ }
/// When invalidation occurs, remove any registered invalidation events.
bool invalidate(
@@ -1178,9 +1129,9 @@
for (auto &KeyValuePair : OuterAnalysisInvalidationMap) {
AnalysisKey *OuterID = KeyValuePair.first;
auto &InnerIDs = KeyValuePair.second;
- InnerIDs.erase(llvm::remove_if(InnerIDs, [&](AnalysisKey *InnerID) {
- return Inv.invalidate(InnerID, IRUnit, PA); }),
- InnerIDs.end());
+ llvm::erase_if(InnerIDs, [&](AnalysisKey *InnerID) {
+ return Inv.invalidate(InnerID, IRUnit, PA);
+ });
if (InnerIDs.empty())
DeadKeys.push_back(OuterID);
}
@@ -1204,9 +1155,7 @@
// analyses that all trigger invalidation on the same outer analysis,
// this entire system should be changed to some other deterministic
// data structure such as a `SetVector` of a pair of pointers.
- auto InvalidatedIt = std::find(InvalidatedIDList.begin(),
- InvalidatedIDList.end(), InvalidatedID);
- if (InvalidatedIt == InvalidatedIDList.end())
+ if (!llvm::is_contained(InvalidatedIDList, InvalidatedID))
InvalidatedIDList.push_back(InvalidatedID);
}
@@ -1218,7 +1167,7 @@
}
private:
- const AnalysisManagerT *AM;
+ const AnalysisManagerT *OuterAM;
/// A map from an outer analysis ID to the set of this IR-unit's analyses
/// which need to be invalidated.
@@ -1226,14 +1175,15 @@
OuterAnalysisInvalidationMap;
};
- OuterAnalysisManagerProxy(const AnalysisManagerT &AM) : AM(&AM) {}
+ OuterAnalysisManagerProxy(const AnalysisManagerT &OuterAM)
+ : OuterAM(&OuterAM) {}
/// Run the analysis pass and create our proxy result object.
- /// Nothing to see here, it just forwards the \c AM reference into the
+ /// Nothing to see here, it just forwards the \c OuterAM reference into the
/// result.
Result run(IRUnitT &, AnalysisManager<IRUnitT, ExtraArgTs...> &,
ExtraArgTs...) {
- return Result(*AM);
+ return Result(*OuterAM);
}
private:
@@ -1242,7 +1192,7 @@
static AnalysisKey Key;
- const AnalysisManagerT *AM;
+ const AnalysisManagerT *OuterAM;
};
template <typename AnalysisManagerT, typename IRUnitT, typename... ExtraArgTs>
@@ -1278,66 +1228,34 @@
/// Note that although function passes can access module analyses, module
/// analyses are not invalidated while the function passes are running, so they
/// may be stale. Function analyses will not be stale.
-template <typename FunctionPassT>
class ModuleToFunctionPassAdaptor
- : public PassInfoMixin<ModuleToFunctionPassAdaptor<FunctionPassT>> {
+ : public PassInfoMixin<ModuleToFunctionPassAdaptor> {
public:
- explicit ModuleToFunctionPassAdaptor(FunctionPassT Pass)
+ using PassConceptT = detail::PassConcept<Function, FunctionAnalysisManager>;
+
+ explicit ModuleToFunctionPassAdaptor(std::unique_ptr<PassConceptT> Pass)
: Pass(std::move(Pass)) {}
/// Runs the function pass across every function in the module.
- PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) {
- FunctionAnalysisManager &FAM =
- AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
+ PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
- // Request PassInstrumentation from analysis manager, will use it to run
- // instrumenting callbacks for the passes later.
- PassInstrumentation PI = AM.getResult<PassInstrumentationAnalysis>(M);
-
- PreservedAnalyses PA = PreservedAnalyses::all();
- for (Function &F : M) {
- if (F.isDeclaration())
- continue;
-
- // Check the PassInstrumentation's BeforePass callbacks before running the
- // pass, skip its execution completely if asked to (callback returns
- // false).
- if (!PI.runBeforePass<Function>(Pass, F))
- continue;
- PreservedAnalyses PassPA = Pass.run(F, FAM);
-
- PI.runAfterPass(Pass, F);
-
- // We know that the function pass couldn't have invalidated any other
- // function's analyses (that's the contract of a function pass), so
- // directly handle the function analysis manager's invalidation here.
- FAM.invalidate(F, PassPA);
-
- // Then intersect the preserved set so that invalidation of module
- // analyses will eventually occur when the module pass completes.
- PA.intersect(std::move(PassPA));
- }
-
- // The FunctionAnalysisManagerModuleProxy is preserved because (we assume)
- // the function passes we ran didn't add or remove any functions.
- //
- // We also preserve all analyses on Functions, because we did all the
- // invalidation we needed to do above.
- PA.preserveSet<AllAnalysesOn<Function>>();
- PA.preserve<FunctionAnalysisManagerModuleProxy>();
- return PA;
- }
+ static bool isRequired() { return true; }
private:
- FunctionPassT Pass;
+ std::unique_ptr<PassConceptT> Pass;
};
/// A function to deduce a function pass type and wrap it in the
/// templated adaptor.
template <typename FunctionPassT>
-ModuleToFunctionPassAdaptor<FunctionPassT>
+ModuleToFunctionPassAdaptor
createModuleToFunctionPassAdaptor(FunctionPassT Pass) {
- return ModuleToFunctionPassAdaptor<FunctionPassT>(std::move(Pass));
+ using PassModelT =
+ detail::PassModel<Function, FunctionPassT, PreservedAnalyses,
+ FunctionAnalysisManager>;
+
+ return ModuleToFunctionPassAdaptor(
+ std::make_unique<PassModelT>(std::move(Pass)));
}
/// A utility pass template to force an analysis result to be available.
@@ -1368,6 +1286,7 @@
return PreservedAnalyses::all();
}
+ static bool isRequired() { return true; }
};
/// A no-op pass template which simply forces a specific analysis result
@@ -1428,8 +1347,9 @@
// false).
if (!PI.runBeforePass<IRUnitT>(P, IR))
continue;
- PA.intersect(P.run(IR, AM, std::forward<Ts>(Args)...));
- PI.runAfterPass(P, IR);
+ PreservedAnalyses IterPA = P.run(IR, AM, std::forward<Ts>(Args)...);
+ PA.intersect(IterPA);
+ PI.runAfterPass(P, IR, IterPA);
}
return PA;
}