### Rationale
For a program point where we cannot reason about incoming dataflow (e.g. an argument of an entry block), the framework needs to initialize the state.
Currently, `AbstractSparseDataFlowAnalysis` initializes such state to the "pessimistic fixpoint", and `AbstractDenseDataFlowAnalysis` calls the state's `reset()` function.
However, entry states aren't necessarily the pessimistic fixpoint. Example: in reaching definition, the pessimistic fixpoint is `{all definitions}`, but the entry state is `{}`.
This awkwardness might be why the dense analysis API currently uses `reset()` instead of `markPessimisticFixpoint()`.
This patch consolidates entry point initialization into a single function `setToEntryState()`.
### API Location
Note that `setToEntryState()` is defined in the analysis rather than the lattice, so that we allow different analyses to use the same lattice but different entry states.
### Removal of the concept of optimistic/known value
The concept of optimistic/known value is too specific to SCCP.
Furthermore, the known value is not really used: In the current SCCP implementation, the known value (pessimistic fixpoint) is always `Attribute{}` (non-constant). This means there's no point storing a `knownValue` in each state.
If we do need to re-introduce optimistic/known value, we should put it in the SCCP analysis, not the sparse analysis API.
### Terminology
Please let me know if "entry state" is a good terminology.
I chose "entry" from Wikipedia (https://en.wikipedia.org/wiki/Data-flow_analysis#Basic_principles).
Another term I can think of is "boundary" (https://suif.stanford.edu/~courses/cs243/lectures/L3-DFA2-revised.pdf) which might be better since it also makes sense for backward analysis.
Reviewed By: Mogball
Differential Revision: https://reviews.llvm.org/D132086
131 lines
4.2 KiB
C++
131 lines
4.2 KiB
C++
//===- TestDeadCodeAnalysis.cpp - Test dead code 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/DataFlow/ConstantPropagationAnalysis.h"
|
|
#include "mlir/Analysis/DataFlow/DeadCodeAnalysis.h"
|
|
#include "mlir/IR/Matchers.h"
|
|
#include "mlir/Pass/Pass.h"
|
|
|
|
using namespace mlir;
|
|
using namespace mlir::dataflow;
|
|
|
|
/// Print the liveness of every block, control-flow edge, and the predecessors
|
|
/// of all regions, callables, and calls.
|
|
static void printAnalysisResults(DataFlowSolver &solver, Operation *op,
|
|
raw_ostream &os) {
|
|
op->walk([&](Operation *op) {
|
|
auto tag = op->getAttrOfType<StringAttr>("tag");
|
|
if (!tag)
|
|
return;
|
|
os << tag.getValue() << ":\n";
|
|
for (Region ®ion : op->getRegions()) {
|
|
os << " region #" << region.getRegionNumber() << "\n";
|
|
for (Block &block : region) {
|
|
os << " ";
|
|
block.printAsOperand(os);
|
|
os << " = ";
|
|
auto *live = solver.lookupState<Executable>(&block);
|
|
if (live)
|
|
os << *live;
|
|
else
|
|
os << "dead";
|
|
os << "\n";
|
|
for (Block *pred : block.getPredecessors()) {
|
|
os << " from ";
|
|
pred->printAsOperand(os);
|
|
os << " = ";
|
|
auto *live = solver.lookupState<Executable>(
|
|
solver.getProgramPoint<CFGEdge>(pred, &block));
|
|
if (live)
|
|
os << *live;
|
|
else
|
|
os << "dead";
|
|
os << "\n";
|
|
}
|
|
}
|
|
if (!region.empty()) {
|
|
auto *preds = solver.lookupState<PredecessorState>(®ion.front());
|
|
if (preds)
|
|
os << "region_preds: " << *preds << "\n";
|
|
}
|
|
}
|
|
auto *preds = solver.lookupState<PredecessorState>(op);
|
|
if (preds)
|
|
os << "op_preds: " << *preds << "\n";
|
|
});
|
|
}
|
|
|
|
namespace {
|
|
/// This is a simple analysis that implements a transfer function for constant
|
|
/// operations.
|
|
struct ConstantAnalysis : public DataFlowAnalysis {
|
|
using DataFlowAnalysis::DataFlowAnalysis;
|
|
|
|
LogicalResult initialize(Operation *top) override {
|
|
WalkResult result = top->walk([&](Operation *op) {
|
|
if (failed(visit(op)))
|
|
return WalkResult::interrupt();
|
|
return WalkResult::advance();
|
|
});
|
|
return success(!result.wasInterrupted());
|
|
}
|
|
|
|
LogicalResult visit(ProgramPoint point) override {
|
|
Operation *op = point.get<Operation *>();
|
|
Attribute value;
|
|
if (matchPattern(op, m_Constant(&value))) {
|
|
auto *constant = getOrCreate<Lattice<ConstantValue>>(op->getResult(0));
|
|
propagateIfChanged(
|
|
constant, constant->join(ConstantValue(value, op->getDialect())));
|
|
return success();
|
|
}
|
|
setAllToUnknownConstants(op->getResults());
|
|
for (Region ®ion : op->getRegions())
|
|
setAllToUnknownConstants(region.getArguments());
|
|
return success();
|
|
}
|
|
|
|
/// Set all given values as not constants.
|
|
void setAllToUnknownConstants(ValueRange values) {
|
|
for (Value value : values) {
|
|
auto *constant = getOrCreate<Lattice<ConstantValue>>(value);
|
|
propagateIfChanged(constant,
|
|
constant->join(ConstantValue::getUnknownConstant()));
|
|
}
|
|
}
|
|
};
|
|
|
|
/// This is a simple pass that runs dead code analysis with a constant value
|
|
/// provider that only understands constant operations.
|
|
struct TestDeadCodeAnalysisPass
|
|
: public PassWrapper<TestDeadCodeAnalysisPass, OperationPass<>> {
|
|
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestDeadCodeAnalysisPass)
|
|
|
|
StringRef getArgument() const override { return "test-dead-code-analysis"; }
|
|
|
|
void runOnOperation() override {
|
|
Operation *op = getOperation();
|
|
|
|
DataFlowSolver solver;
|
|
solver.load<DeadCodeAnalysis>();
|
|
solver.load<ConstantAnalysis>();
|
|
if (failed(solver.initializeAndRun(op)))
|
|
return signalPassFailure();
|
|
printAnalysisResults(solver, op, llvm::errs());
|
|
}
|
|
};
|
|
} // end anonymous namespace
|
|
|
|
namespace mlir {
|
|
namespace test {
|
|
void registerTestDeadCodeAnalysisPass() {
|
|
PassRegistration<TestDeadCodeAnalysisPass>();
|
|
}
|
|
} // end namespace test
|
|
} // end namespace mlir
|