116 lines
4.5 KiB
C++
116 lines
4.5 KiB
C++
//===- LivenessAnalysis.h - Liveness analysis -------------------*- 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements liveness analysis using the sparse backward data-flow
|
|
// analysis framework. Theoretically, liveness analysis assigns liveness to each
|
|
// (value, program point) pair in the program and it is thus a dense analysis.
|
|
// However, since values are immutable in MLIR, a sparse analysis, which will
|
|
// assign liveness to each value in the program, suffices here.
|
|
//
|
|
// Liveness analysis has many applications. It can be used to avoid the
|
|
// computation of extraneous operations that have no effect on the memory or the
|
|
// final output of a program. It can also be used to optimize register
|
|
// allocation. Both of these applications help achieve one very important goal:
|
|
// reducing runtime.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef MLIR_ANALYSIS_DATAFLOW_LIVENESSANALYSIS_H
|
|
#define MLIR_ANALYSIS_DATAFLOW_LIVENESSANALYSIS_H
|
|
|
|
#include <mlir/Analysis/DataFlow/SparseAnalysis.h>
|
|
#include <optional>
|
|
|
|
namespace mlir::dataflow {
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Liveness
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// This lattice represents, for a given value, whether or not it is "live".
|
|
///
|
|
/// A value is considered "live" iff it:
|
|
/// (1) has memory effects OR
|
|
/// (2) is returned by a public function OR
|
|
/// (3) is used to compute a value of type (1) or (2).
|
|
/// It is also to be noted that a value could be of multiple types (1/2/3) at
|
|
/// the same time.
|
|
///
|
|
/// A value "has memory effects" iff it:
|
|
/// (1.a) is an operand of an op with memory effects OR
|
|
/// (1.b) is a non-forwarded branch operand and its branch op could take the
|
|
/// control to a block that has an op with memory effects OR
|
|
/// (1.c) is a non-forwarded call operand.
|
|
///
|
|
/// A value `A` is said to be "used to compute" value `B` iff `B` cannot be
|
|
/// computed in the absence of `A`. Thus, in this implementation, we say that
|
|
/// value `A` is used to compute value `B` iff:
|
|
/// (3.a) `B` is a result of an op with operand `A` OR
|
|
/// (3.b) `A` is used to compute some value `C` and `C` is used to compute
|
|
/// `B`.
|
|
struct Liveness : public AbstractSparseLattice {
|
|
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(Liveness)
|
|
using AbstractSparseLattice::AbstractSparseLattice;
|
|
|
|
void print(raw_ostream &os) const override;
|
|
|
|
ChangeResult markLive();
|
|
|
|
ChangeResult meet(const AbstractSparseLattice &other) override;
|
|
|
|
// At the beginning of the analysis, everything is marked "not live" and as
|
|
// the analysis progresses, values are marked "live" if they are found to be
|
|
// live.
|
|
bool isLive = false;
|
|
};
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// LivenessAnalysis
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// An analysis that, by going backwards along the dataflow graph, annotates
|
|
/// each value with a boolean storing true iff it is "live".
|
|
class LivenessAnalysis : public SparseBackwardDataFlowAnalysis<Liveness> {
|
|
public:
|
|
using SparseBackwardDataFlowAnalysis::SparseBackwardDataFlowAnalysis;
|
|
|
|
LogicalResult visitOperation(Operation *op, ArrayRef<Liveness *> operands,
|
|
ArrayRef<const Liveness *> results) override;
|
|
|
|
void visitBranchOperand(OpOperand &operand) override;
|
|
|
|
void visitCallOperand(OpOperand &operand) override;
|
|
|
|
void setToExitState(Liveness *lattice) override;
|
|
|
|
void visitNonControlFlowArguments(RegionSuccessor &successor,
|
|
ArrayRef<BlockArgument> arguments) override;
|
|
};
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// RunLivenessAnalysis
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// Runs liveness analysis on the IR defined by `op`.
|
|
struct RunLivenessAnalysis {
|
|
public:
|
|
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(RunLivenessAnalysis)
|
|
|
|
RunLivenessAnalysis(Operation *op);
|
|
|
|
const Liveness *getLiveness(Value val);
|
|
|
|
private:
|
|
/// Stores the result of the liveness analysis that was run.
|
|
DataFlowSolver solver;
|
|
};
|
|
|
|
} // end namespace mlir::dataflow
|
|
|
|
#endif // MLIR_ANALYSIS_DATAFLOW_LIVENESSANALYSIS_H
|