Add support for preserving specific analyses in the analysis manager. Passes can now preserve specific analyses via 'markAnalysesPreserved'.
Example: markAnalysesPreserved<DominanceInfo>(); markAnalysesPreserved<DominanceInfo, PostDominanceInfo>(); PiperOrigin-RevId: 237081454
This commit is contained in:
parent
b2fe39977e
commit
1d87b62afe
|
|
@ -44,9 +44,33 @@ public:
|
||||||
/// Mark all analyses as preserved.
|
/// Mark all analyses as preserved.
|
||||||
void preserveAll() { preservedIDs.insert(&allAnalysesID); }
|
void preserveAll() { preservedIDs.insert(&allAnalysesID); }
|
||||||
|
|
||||||
/// Returns if all analyses were marked preserved.
|
/// Returns true if all analyses were marked preserved.
|
||||||
bool isAll() const { return preservedIDs.count(&allAnalysesID); }
|
bool isAll() const { return preservedIDs.count(&allAnalysesID); }
|
||||||
|
|
||||||
|
/// Returns true if no analyses were marked preserved.
|
||||||
|
bool isNone() const { return preservedIDs.empty(); }
|
||||||
|
|
||||||
|
/// Preserve the given analyses.
|
||||||
|
template <typename AnalysisT> void preserve() {
|
||||||
|
preserve(AnalysisID::getID<AnalysisT>());
|
||||||
|
}
|
||||||
|
template <typename AnalysisT, typename AnalysisT2, typename... OtherAnalysesT>
|
||||||
|
void preserve() {
|
||||||
|
preserve<AnalysisT>();
|
||||||
|
preserve<AnalysisT2, OtherAnalysesT...>();
|
||||||
|
}
|
||||||
|
void preserve(const AnalysisID *id) { preservedIDs.insert(id); }
|
||||||
|
|
||||||
|
/// Returns if the given analysis has been marked as preserved. Note that this
|
||||||
|
/// simply checks for the presence of a given analysis ID and should not be
|
||||||
|
/// used as a general preservation checker.
|
||||||
|
template <typename AnalysisT> bool isPreserved() const {
|
||||||
|
return isPreserved(AnalysisID::getID<AnalysisT>());
|
||||||
|
}
|
||||||
|
bool isPreserved(const AnalysisID *id) const {
|
||||||
|
return preservedIDs.count(id);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// An identifier used to represent all potential analyses.
|
/// An identifier used to represent all potential analyses.
|
||||||
constexpr static AnalysisID allAnalysesID = {};
|
constexpr static AnalysisID allAnalysesID = {};
|
||||||
|
|
@ -112,11 +136,12 @@ public:
|
||||||
/// Invalidate any cached analyses based upon the given set of preserved
|
/// Invalidate any cached analyses based upon the given set of preserved
|
||||||
/// analyses.
|
/// analyses.
|
||||||
void invalidate(const detail::PreservedAnalyses &pa) {
|
void invalidate(const detail::PreservedAnalyses &pa) {
|
||||||
// If all analyses were preserved, then there is nothing to do here.
|
// Remove any analyses not marked as preserved.
|
||||||
if (pa.isAll())
|
for (auto it = results.begin(), e = results.end(); it != e;) {
|
||||||
return;
|
auto curIt = it++;
|
||||||
// TODO: Fine grain invalidation of analyses.
|
if (!pa.isPreserved(curIt->first))
|
||||||
clear();
|
results.erase(curIt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -154,7 +179,12 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invalidate any non preserved analyses,
|
/// Invalidate any non preserved analyses,
|
||||||
void invalidate(const detail::PreservedAnalyses &pa) { impl->invalidate(pa); }
|
void invalidate(const detail::PreservedAnalyses &pa) {
|
||||||
|
// If all analyses were preserved, then there is nothing to do here.
|
||||||
|
if (pa.isAll())
|
||||||
|
return;
|
||||||
|
impl->invalidate(pa);
|
||||||
|
}
|
||||||
|
|
||||||
/// Clear any held analyses.
|
/// Clear any held analyses.
|
||||||
void clear() { impl->clear(); }
|
void clear() { impl->clear(); }
|
||||||
|
|
@ -189,13 +219,23 @@ public:
|
||||||
return slice(function).getResult<AnalysisT>();
|
return slice(function).getResult<AnalysisT>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Query for a cached analysis of a function, or return null.
|
||||||
|
template <typename AnalysisT>
|
||||||
|
llvm::Optional<std::reference_wrapper<AnalysisT>>
|
||||||
|
getCachedFunctionResult(Function *function) const {
|
||||||
|
auto it = functionAnalyses.find(function);
|
||||||
|
if (it == functionAnalyses.end())
|
||||||
|
return llvm::None;
|
||||||
|
return it->second.getCachedResult<AnalysisT>();
|
||||||
|
}
|
||||||
|
|
||||||
/// Query for the analysis of a module. The analysis is computed if it does
|
/// Query for the analysis of a module. The analysis is computed if it does
|
||||||
/// not exist.
|
/// not exist.
|
||||||
template <typename AnalysisT> AnalysisT &getResult() {
|
template <typename AnalysisT> AnalysisT &getResult() {
|
||||||
return moduleAnalyses.getResult<AnalysisT>();
|
return moduleAnalyses.getResult<AnalysisT>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Query for a cached analysis for the module, or return nullptr.
|
/// Query for a cached analysis for the module, or return null.
|
||||||
template <typename AnalysisT>
|
template <typename AnalysisT>
|
||||||
llvm::Optional<std::reference_wrapper<AnalysisT>> getCachedResult() const {
|
llvm::Optional<std::reference_wrapper<AnalysisT>> getCachedResult() const {
|
||||||
return moduleAnalyses.getCachedResult<AnalysisT>();
|
return moduleAnalyses.getCachedResult<AnalysisT>();
|
||||||
|
|
|
||||||
|
|
@ -207,6 +207,14 @@ protected:
|
||||||
void markAllAnalysesPreserved() {
|
void markAllAnalysesPreserved() {
|
||||||
this->getPassState().preservedAnalyses.preserveAll();
|
this->getPassState().preservedAnalyses.preserveAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Mark the provided analyses as preserved.
|
||||||
|
template <typename... AnalysesT> void markAnalysesPreserved() {
|
||||||
|
this->getPassState().preservedAnalyses.template preserve<AnalysesT...>();
|
||||||
|
}
|
||||||
|
void markAnalysesPreserved(const AnalysisID *id) {
|
||||||
|
this->getPassState().preservedAnalyses.preserve(id);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
} // end namespace detail
|
} // end namespace detail
|
||||||
|
|
||||||
|
|
@ -242,6 +250,14 @@ struct ModulePass : public detail::PassModel<Module, T, ModulePassBase> {
|
||||||
AnalysisT &getFunctionAnalysisResult(Function *f) {
|
AnalysisT &getFunctionAnalysisResult(Function *f) {
|
||||||
return this->getAnalysisManager().template getFunctionResult<AnalysisT>(f);
|
return this->getAnalysisManager().template getFunctionResult<AnalysisT>(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns an existing analysis result for a child function if it exists.
|
||||||
|
template <typename AnalysisT>
|
||||||
|
llvm::Optional<std::reference_wrapper<AnalysisT>>
|
||||||
|
getCachedFunctionAnalysisResult(Function *f) {
|
||||||
|
return this->getAnalysisManager()
|
||||||
|
.template getCachedFunctionResult<AnalysisT>(f);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
} // end namespace mlir
|
} // end namespace mlir
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -309,10 +309,21 @@ FunctionAnalysisManager ModuleAnalysisManager::slice(Function *function) {
|
||||||
|
|
||||||
/// Invalidate any non preserved analyses.
|
/// Invalidate any non preserved analyses.
|
||||||
void ModuleAnalysisManager::invalidate(const detail::PreservedAnalyses &pa) {
|
void ModuleAnalysisManager::invalidate(const detail::PreservedAnalyses &pa) {
|
||||||
|
// If all analyses were preserved, then there is nothing to do here.
|
||||||
if (pa.isAll())
|
if (pa.isAll())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// TODO: Fine grain invalidation of analyses.
|
// Invalidate the module analyses directly.
|
||||||
moduleAnalyses.clear();
|
moduleAnalyses.invalidate(pa);
|
||||||
functionAnalyses.clear();
|
|
||||||
|
// If no analyses were preserved, then just simply clear out the function
|
||||||
|
// analysis results.
|
||||||
|
if (pa.isNone()) {
|
||||||
|
functionAnalyses.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, invalidate each function analyses.
|
||||||
|
for (auto &analysisPair : functionAnalyses)
|
||||||
|
analysisPair.second.invalidate(pa);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,12 @@ private:
|
||||||
|
|
||||||
/// Attempt to eliminate a redundant operation.
|
/// Attempt to eliminate a redundant operation.
|
||||||
bool CSE::simplifyOperation(Instruction *op) {
|
bool CSE::simplifyOperation(Instruction *op) {
|
||||||
|
// Don't simplify operations with nested blocks. We don't currently model
|
||||||
|
// equality comparisons correctly among other things. It is also unclear
|
||||||
|
// whether we would want to CSE such operations.
|
||||||
|
if (op->getNumBlockLists() != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
// TODO(riverriddle) We currently only eliminate non side-effecting
|
// TODO(riverriddle) We currently only eliminate non side-effecting
|
||||||
// operations.
|
// operations.
|
||||||
if (!op->hasNoSideEffect())
|
if (!op->hasNoSideEffect())
|
||||||
|
|
@ -230,6 +236,10 @@ void CSE::runOnFunction() {
|
||||||
for (auto *op : opsToErase)
|
for (auto *op : opsToErase)
|
||||||
op->erase();
|
op->erase();
|
||||||
opsToErase.clear();
|
opsToErase.clear();
|
||||||
|
|
||||||
|
// We currently don't remove region operations, so mark dominance as
|
||||||
|
// preserved.
|
||||||
|
markAnalysesPreserved<DominanceInfo, PostDominanceInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionPassBase *mlir::createCSEPass() { return new CSE(); }
|
FunctionPassBase *mlir::createCSEPass() { return new CSE(); }
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,112 @@
|
||||||
|
//===- AnalysisManagerTest.cpp - AnalysisManager unit tests ---------------===//
|
||||||
|
//
|
||||||
|
// Copyright 2019 The MLIR Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
#include "mlir/Pass/AnalysisManager.h"
|
||||||
|
#include "mlir/IR/Builders.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
using namespace mlir;
|
||||||
|
using namespace mlir::detail;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
/// Minimal class definitions for two analyses.
|
||||||
|
struct MyAnalysis {
|
||||||
|
MyAnalysis(Function *) {}
|
||||||
|
MyAnalysis(Module *) {}
|
||||||
|
};
|
||||||
|
struct OtherAnalysis {
|
||||||
|
OtherAnalysis(Function *) {}
|
||||||
|
OtherAnalysis(Module *) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(AnalysisManagerTest, FineGrainModuleAnalysisPreservation) {
|
||||||
|
MLIRContext context;
|
||||||
|
|
||||||
|
// Test fine grain invalidation of the module analysis manager.
|
||||||
|
std::unique_ptr<Module> module(new Module(&context));
|
||||||
|
ModuleAnalysisManager mam(&*module);
|
||||||
|
|
||||||
|
// Query two different analyses, but only preserve one before invalidating.
|
||||||
|
mam.getResult<MyAnalysis>();
|
||||||
|
mam.getResult<OtherAnalysis>();
|
||||||
|
|
||||||
|
detail::PreservedAnalyses pa;
|
||||||
|
pa.preserve<MyAnalysis>();
|
||||||
|
mam.invalidate(pa);
|
||||||
|
|
||||||
|
// Check that only MyAnalysis is preserved.
|
||||||
|
EXPECT_TRUE(mam.getCachedResult<MyAnalysis>().hasValue());
|
||||||
|
EXPECT_FALSE(mam.getCachedResult<OtherAnalysis>().hasValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(AnalysisManagerTest, FineGrainFunctionAnalysisPreservation) {
|
||||||
|
MLIRContext context;
|
||||||
|
Builder builder(&context);
|
||||||
|
|
||||||
|
// Create a function and a module.
|
||||||
|
std::unique_ptr<Module> module(new Module(&context));
|
||||||
|
Function *func1 =
|
||||||
|
new Function(builder.getUnknownLoc(), "foo",
|
||||||
|
builder.getFunctionType(llvm::None, llvm::None));
|
||||||
|
module->getFunctions().push_back(func1);
|
||||||
|
|
||||||
|
// Test fine grain invalidation of the function analysis manager.
|
||||||
|
ModuleAnalysisManager mam(&*module);
|
||||||
|
FunctionAnalysisManager fam = mam.slice(func1);
|
||||||
|
|
||||||
|
// Query two different analyses, but only preserve one before invalidating.
|
||||||
|
fam.getResult<MyAnalysis>();
|
||||||
|
fam.getResult<OtherAnalysis>();
|
||||||
|
|
||||||
|
detail::PreservedAnalyses pa;
|
||||||
|
pa.preserve<MyAnalysis>();
|
||||||
|
fam.invalidate(pa);
|
||||||
|
|
||||||
|
// Check that only MyAnalysis is preserved.
|
||||||
|
EXPECT_TRUE(fam.getCachedResult<MyAnalysis>().hasValue());
|
||||||
|
EXPECT_FALSE(fam.getCachedResult<OtherAnalysis>().hasValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(AnalysisManagerTest, FineGrainChildFunctionAnalysisPreservation) {
|
||||||
|
MLIRContext context;
|
||||||
|
Builder builder(&context);
|
||||||
|
|
||||||
|
// Create a function and a module.
|
||||||
|
std::unique_ptr<Module> module(new Module(&context));
|
||||||
|
Function *func1 =
|
||||||
|
new Function(builder.getUnknownLoc(), "foo",
|
||||||
|
builder.getFunctionType(llvm::None, llvm::None));
|
||||||
|
module->getFunctions().push_back(func1);
|
||||||
|
|
||||||
|
// Test fine grain invalidation of a function analysis from within a module
|
||||||
|
// analysis manager.
|
||||||
|
ModuleAnalysisManager mam(&*module);
|
||||||
|
|
||||||
|
// Query two different analyses, but only preserve one before invalidating.
|
||||||
|
mam.getFunctionResult<MyAnalysis>(func1);
|
||||||
|
mam.getFunctionResult<OtherAnalysis>(func1);
|
||||||
|
|
||||||
|
detail::PreservedAnalyses pa;
|
||||||
|
pa.preserve<MyAnalysis>();
|
||||||
|
mam.invalidate(pa);
|
||||||
|
|
||||||
|
// Check that only MyAnalysis is preserved.
|
||||||
|
EXPECT_TRUE(mam.getCachedFunctionResult<MyAnalysis>(func1).hasValue());
|
||||||
|
EXPECT_FALSE(mam.getCachedFunctionResult<OtherAnalysis>(func1).hasValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end namespace
|
||||||
Loading…
Reference in New Issue