mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-26 07:36:08 +00:00

MLIR's data flow analysis (especially dense data flow analysis) constructs a lattice at every lattice anchor (which, for dense data flow, means every program point). As the program grows larger, the time and space complexity can become unmanageable. However, in many programs, the lattice values at numerous lattice anchors are actually identical. We can leverage this observation to improve the complexity of data flow analysis. This patch introducing equivalence lattice anchor to group lattice anchors that must contains identical lattice on certain state to improve the time and space footprint of data flow.
170 lines
5.7 KiB
C++
170 lines
5.7 KiB
C++
//===- DataFlowFramework.cpp - A generic framework for data-flow analysis -===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "mlir/Analysis/DataFlowFramework.h"
|
|
#include "mlir/IR/Location.h"
|
|
#include "mlir/IR/Operation.h"
|
|
#include "mlir/IR/Value.h"
|
|
#include "llvm/ADT/ScopeExit.h"
|
|
#include "llvm/ADT/iterator.h"
|
|
#include "llvm/Config/abi-breaking.h"
|
|
#include "llvm/Support/Casting.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
#define DEBUG_TYPE "dataflow"
|
|
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
|
|
#define DATAFLOW_DEBUG(X) LLVM_DEBUG(X)
|
|
#else
|
|
#define DATAFLOW_DEBUG(X)
|
|
#endif // LLVM_ENABLE_ABI_BREAKING_CHECKS
|
|
|
|
using namespace mlir;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// GenericLatticeAnchor
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
GenericLatticeAnchor::~GenericLatticeAnchor() = default;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// AnalysisState
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
AnalysisState::~AnalysisState() = default;
|
|
|
|
void AnalysisState::addDependency(ProgramPoint *dependent,
|
|
DataFlowAnalysis *analysis) {
|
|
auto inserted = dependents.insert({dependent, analysis});
|
|
(void)inserted;
|
|
DATAFLOW_DEBUG({
|
|
if (inserted) {
|
|
llvm::dbgs() << "Creating dependency between " << debugName << " of "
|
|
<< anchor << "\nand " << debugName << " on " << dependent
|
|
<< "\n";
|
|
}
|
|
});
|
|
}
|
|
|
|
void AnalysisState::dump() const { print(llvm::errs()); }
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// ProgramPoint
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
void ProgramPoint::print(raw_ostream &os) const {
|
|
if (isNull()) {
|
|
os << "<NULL POINT>";
|
|
return;
|
|
}
|
|
if (!isBlockStart()) {
|
|
os << "<after operation>:";
|
|
return getPrevOp()->print(os, OpPrintingFlags().skipRegions());
|
|
}
|
|
os << "<before operation>:";
|
|
return getNextOp()->print(os, OpPrintingFlags().skipRegions());
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// LatticeAnchor
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
void LatticeAnchor::print(raw_ostream &os) const {
|
|
if (isNull()) {
|
|
os << "<NULL POINT>";
|
|
return;
|
|
}
|
|
if (auto *LatticeAnchor = llvm::dyn_cast<GenericLatticeAnchor *>(*this))
|
|
return LatticeAnchor->print(os);
|
|
if (auto value = llvm::dyn_cast<Value>(*this)) {
|
|
return value.print(os, OpPrintingFlags().skipRegions());
|
|
}
|
|
|
|
return llvm::cast<ProgramPoint *>(*this)->print(os);
|
|
}
|
|
|
|
Location LatticeAnchor::getLoc() const {
|
|
if (auto *LatticeAnchor = llvm::dyn_cast<GenericLatticeAnchor *>(*this))
|
|
return LatticeAnchor->getLoc();
|
|
if (auto value = llvm::dyn_cast<Value>(*this))
|
|
return value.getLoc();
|
|
|
|
ProgramPoint *pp = llvm::cast<ProgramPoint *>(*this);
|
|
if (!pp->isBlockStart())
|
|
return pp->getPrevOp()->getLoc();
|
|
return pp->getBlock()->getParent()->getLoc();
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// DataFlowSolver
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
LogicalResult DataFlowSolver::initializeAndRun(Operation *top) {
|
|
// Enable enqueue to the worklist.
|
|
isRunning = true;
|
|
auto guard = llvm::make_scope_exit([&]() { isRunning = false; });
|
|
|
|
// Initialize equivalent lattice anchors.
|
|
for (DataFlowAnalysis &analysis : llvm::make_pointee_range(childAnalyses)) {
|
|
analysis.initializeEquivalentLatticeAnchor(top);
|
|
}
|
|
|
|
// Initialize the analyses.
|
|
for (DataFlowAnalysis &analysis : llvm::make_pointee_range(childAnalyses)) {
|
|
DATAFLOW_DEBUG(llvm::dbgs()
|
|
<< "Priming analysis: " << analysis.debugName << "\n");
|
|
if (failed(analysis.initialize(top)))
|
|
return failure();
|
|
}
|
|
|
|
// Run the analysis until fixpoint.
|
|
// Iterate until all states are in some initialized state and the worklist
|
|
// is exhausted.
|
|
while (!worklist.empty()) {
|
|
auto [point, analysis] = worklist.front();
|
|
worklist.pop();
|
|
|
|
DATAFLOW_DEBUG(llvm::dbgs() << "Invoking '" << analysis->debugName
|
|
<< "' on: " << point << "\n");
|
|
if (failed(analysis->visit(point)))
|
|
return failure();
|
|
}
|
|
|
|
return success();
|
|
}
|
|
|
|
void DataFlowSolver::propagateIfChanged(AnalysisState *state,
|
|
ChangeResult changed) {
|
|
assert(isRunning &&
|
|
"DataFlowSolver is not running, should not use propagateIfChanged");
|
|
if (changed == ChangeResult::Change) {
|
|
DATAFLOW_DEBUG(llvm::dbgs() << "Propagating update to " << state->debugName
|
|
<< " of " << state->anchor << "\n"
|
|
<< "Value: " << *state << "\n");
|
|
state->onUpdate(this);
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// DataFlowAnalysis
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
DataFlowAnalysis::~DataFlowAnalysis() = default;
|
|
|
|
DataFlowAnalysis::DataFlowAnalysis(DataFlowSolver &solver) : solver(solver) {}
|
|
|
|
void DataFlowAnalysis::addDependency(AnalysisState *state,
|
|
ProgramPoint *point) {
|
|
state->addDependency(point, this);
|
|
}
|
|
|
|
void DataFlowAnalysis::propagateIfChanged(AnalysisState *state,
|
|
ChangeResult changed) {
|
|
solver.propagateIfChanged(state, changed);
|
|
}
|