[Transforms] Move generally applicable passes to transforms (#6087)

SSA maximization and merge block insertion are generally applicable transformations and so shouldn't be nested within CFToHandshake.
This commit is contained in:
Morten Borup Petersen 2023-09-08 16:03:22 +02:00 committed by GitHub
parent 96ab076f32
commit ac85f16f30
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 106 additions and 100 deletions

View File

@ -17,6 +17,7 @@
#include "circt/Dialect/Handshake/HandshakeOps.h"
#include "circt/Dialect/Handshake/HandshakePasses.h"
#include "circt/Support/BackedgeBuilder.h"
#include "circt/Transforms/Passes.h"
#include "mlir/Transforms/DialectConversion.h"
#include <memory>
@ -28,63 +29,6 @@ class OperationPass;
} // namespace mlir
namespace circt {
/// Strategy class to control the behavior of SSA maximization. The class
/// exposes overridable filter functions to dynamically select which blocks,
/// block arguments, operations, and operation results should be put into
/// maximal SSA form. All filter functions should return true whenever the
/// entity they operate on should be considered for SSA maximization. By
/// default, all filter functions always return true.
class SSAMaximizationStrategy {
public:
/// Determines whether a block should have the values it defines (i.e., block
/// arguments and operation results within the block) SSA maximized.
virtual bool maximizeBlock(Block *block);
/// Determines whether a block argument should be SSA maximized.
virtual bool maximizeArgument(BlockArgument arg);
/// Determines whether an operation should have its results SSA maximized.
virtual bool maximizeOp(Operation *op);
/// Determines whether an operation's result should be SSA maximized.
virtual bool maximizeResult(OpResult res);
virtual ~SSAMaximizationStrategy() = default;
};
/// Converts a single value within a function into maximal SSA form. This
/// removes any implicit dataflow of this specific value within the enclosing
/// function. The function adds new block arguments wherever necessary to carry
/// the value explicitly between blocks.
/// Succeeds when it was possible to convert the value into maximal SSA form.
LogicalResult maximizeSSA(Value value, PatternRewriter &rewriter);
/// Considers all of an operation's results for SSA maximization, following a
/// provided strategy. This removes any implicit dataflow of the selected
/// operation's results within the enclosing function. The function adds new
/// block arguments wherever necessary to carry the results explicitly between
/// blocks. Succeeds when it was possible to convert the selected operation's
/// results into maximal SSA form.
LogicalResult maximizeSSA(Operation *op, SSAMaximizationStrategy &strategy,
PatternRewriter &rewriter);
/// Considers all values defined by a block (i.e., block arguments and operation
/// results within the block) for SSA maximization, following a provided
/// strategy. This removes any implicit dataflow of the selected values within
/// the enclosing function. The function adds new block arguments wherever
/// necessary to carry the values explicitly between blocks. Succeeds when it
/// was possible to convert the selected values defined by the block into
/// maximal SSA form.
LogicalResult maximizeSSA(Block *block, SSAMaximizationStrategy &strategy,
PatternRewriter &rewriter);
/// Considers all blocks within a region for SSA maximization, following a
/// provided strategy. This removes any implicit dataflow of the values defined
/// by selected blocks within the region. The function adds new block arguments
/// wherever necessary to carry the region's values explicitly between blocks.
/// Succeeds when it was possible to convert all of the values defined by
/// selected blocks into maximal SSA form.
LogicalResult maximizeSSA(Region &region, SSAMaximizationStrategy &strategy,
PatternRewriter &rewriter);
namespace handshake {
// ============================================================================
@ -309,12 +253,6 @@ insertMergeBlocks(mlir::Region &r, mlir::ConversionPatternRewriter &rewriter);
std::unique_ptr<mlir::Pass> createInsertMergeBlocksPass();
// Returns true if the region is into maximal SSA form i.e., if all the values
// within the region are in maximal SSA form.
bool isRegionSSAMaximized(Region &region);
std::unique_ptr<mlir::Pass> createMaximizeSSAPass();
} // namespace circt
#endif // CIRCT_CONVERSION_CFTOHANDSHAKE_H_

View File

@ -599,36 +599,6 @@ def HandshakeRemoveBlock : Pass<"handshake-remove-block-structure", "handshake::
let constructor = "circt::createHandshakeRemoveBlockPass()";
}
def InsertMergeBlocks : Pass<"insert-merge-blocks", "::mlir::ModuleOp"> {
let summary = "Insert explicit merge blocks";
let description = [{
This pass inserts additional merge blocks for each block with more than
two successors. A merge block is a block that only contains one operation,
a terminator, and has two predecessors.
The order successors are merged together mirrors the order different control
paths are created. Thus, each block with two successors will have a corresponding
merge block.
This pass brings the CFG into a canonical form for further transformations.
Treats loops and sub-CFGs with irregular control flow like single blocks.
}];
let constructor = "circt::createInsertMergeBlocksPass()";
let dependentDialects = ["mlir::cf::ControlFlowDialect", "mlir::func::FuncDialect"];
}
def MaximizeSSA : Pass<"maximize-ssa", "::mlir::ModuleOp"> {
let summary = "Convert every function in the module into maximal SSA form";
let description = [{
Convert the region within every function into maximal SSA form. This
ensures that every value used within a block is also defined within the
block, making dataflow explicit and removing block dominance-based dataflow
semantics. The pass achieves this by adding block arguments wherever
necessary to forward values to the block(s) where they are used.
}];
let constructor = "circt::createMaximizeSSAPass()";
}
//===----------------------------------------------------------------------===//
// ConvertToArcs
//===----------------------------------------------------------------------===//

View File

@ -29,6 +29,8 @@ std::unique_ptr<mlir::Pass> createFlattenMemRefPass();
std::unique_ptr<mlir::Pass> createFlattenMemRefCallsPass();
std::unique_ptr<mlir::Pass> createStripDebugInfoWithPredPass(
const std::function<bool(mlir::Location)> &pred);
std::unique_ptr<mlir::Pass> createMaximizeSSAPass();
std::unique_ptr<mlir::Pass> createInsertMergeBlocksPass();
//===----------------------------------------------------------------------===//
// Utility functions.
@ -38,6 +40,73 @@ std::unique_ptr<mlir::Pass> createStripDebugInfoWithPredPass(
// shape of size 1).
bool isUniDimensional(mlir::MemRefType memref);
// Returns true if the region is into maximal SSA form i.e., if all the values
// within the region are in maximal SSA form.
bool isRegionSSAMaximized(Region &region);
/// Strategy class to control the behavior of SSA maximization. The class
/// exposes overridable filter functions to dynamically select which blocks,
/// block arguments, operations, and operation results should be put into
/// maximal SSA form. All filter functions should return true whenever the
/// entity they operate on should be considered for SSA maximization. By
/// default, all filter functions always return true.
class SSAMaximizationStrategy {
public:
/// Determines whether a block should have the values it defines (i.e., block
/// arguments and operation results within the block) SSA maximized.
virtual bool maximizeBlock(Block *block);
/// Determines whether a block argument should be SSA maximized.
virtual bool maximizeArgument(BlockArgument arg);
/// Determines whether an operation should have its results SSA maximized.
virtual bool maximizeOp(Operation *op);
/// Determines whether an operation's result should be SSA maximized.
virtual bool maximizeResult(OpResult res);
virtual ~SSAMaximizationStrategy() = default;
};
/// Converts a single value within a function into maximal SSA form. This
/// removes any implicit dataflow of this specific value within the enclosing
/// function. The function adds new block arguments wherever necessary to carry
/// the value explicitly between blocks.
/// Succeeds when it was possible to convert the value into maximal SSA form.
LogicalResult maximizeSSA(Value value, PatternRewriter &rewriter);
/// Considers all of an operation's results for SSA maximization, following a
/// provided strategy. This removes any implicit dataflow of the selected
/// operation's results within the enclosing function. The function adds new
/// block arguments wherever necessary to carry the results explicitly between
/// blocks. Succeeds when it was possible to convert the selected operation's
/// results into maximal SSA form.
LogicalResult maximizeSSA(Operation *op, SSAMaximizationStrategy &strategy,
PatternRewriter &rewriter);
/// Considers all values defined by a block (i.e., block arguments and operation
/// results within the block) for SSA maximization, following a provided
/// strategy. This removes any implicit dataflow of the selected values within
/// the enclosing function. The function adds new block arguments wherever
/// necessary to carry the values explicitly between blocks. Succeeds when it
/// was possible to convert the selected values defined by the block into
/// maximal SSA form.
LogicalResult maximizeSSA(Block *block, SSAMaximizationStrategy &strategy,
PatternRewriter &rewriter);
/// Considers all blocks within a region for SSA maximization, following a
/// provided strategy. This removes any implicit dataflow of the values defined
/// by selected blocks within the region. The function adds new block arguments
/// wherever necessary to carry the region's values explicitly between blocks.
/// Succeeds when it was possible to convert all of the values defined by
/// selected blocks into maximal SSA form.
LogicalResult maximizeSSA(Region &region, SSAMaximizationStrategy &strategy,
PatternRewriter &rewriter);
/// Manually run merge block insertion on a region.
///
/// This transformation does treat loops like a single block and thus does not
/// affect them.
LogicalResult insertMergeBlocks(mlir::Region &r,
mlir::ConversionPatternRewriter &rewriter);
//===----------------------------------------------------------------------===//
// Registration
//===----------------------------------------------------------------------===//

View File

@ -70,4 +70,34 @@ def MapArithToCombPass : InterfacePass<"map-arith-to-comb", "circt::hw::HWModule
let dependentDialects = ["circt::hw::HWDialect, mlir::arith::ArithDialect, circt::comb::CombDialect"];
}
def InsertMergeBlocks : Pass<"insert-merge-blocks", "::mlir::ModuleOp"> {
let summary = "Insert explicit merge blocks";
let description = [{
This pass inserts additional merge blocks for each block with more than
two successors. A merge block is a block that only contains one operation,
a terminator, and has two predecessors.
The order successors are merged together mirrors the order different control
paths are created. Thus, each block with two successors will have a corresponding
merge block.
This pass brings the CFG into a canonical form for further transformations.
Treats loops and sub-CFGs with irregular control flow like single blocks.
}];
let constructor = "circt::createInsertMergeBlocksPass()";
let dependentDialects = ["mlir::cf::ControlFlowDialect", "mlir::func::FuncDialect"];
}
def MaximizeSSA : Pass<"maximize-ssa", "::mlir::ModuleOp"> {
let summary = "Convert every function in the module into maximal SSA form";
let description = [{
Convert the region within every function into maximal SSA form. This
ensures that every value used within a block is also defined within the
block, making dataflow explicit and removing block dominance-based dataflow
semantics. The pass achieves this by adding block arguments wherever
necessary to forward values to the block(s) where they are used.
}];
let constructor = "circt::createMaximizeSSAPass()";
}
#endif // CIRCT_TRANSFORMS_PASSES

View File

@ -1,7 +1,5 @@
add_circt_library(CIRCTCFToHandshake
CFToHandshake.cpp
InsertMergeBlocks.cpp
MaximizeSSA.cpp
ADDITIONAL_HEADER_DIRS
${MLIR_MAIN_INCLUDE_DIR}/mlir/Conversion/CFToHandshake
@ -22,4 +20,4 @@ add_circt_library(CIRCTCFToHandshake
MLIRSupport
MLIRTransforms
MLIRAffineToStandard
)
)

View File

@ -2,6 +2,8 @@ add_circt_library(CIRCTTransforms
FlattenMemRefs.cpp
StripDebugInfoWithPred.cpp
MapArithToComb.cpp
MaximizeSSA.cpp
InsertMergeBlocks.cpp
ADDITIONAL_HEADER_DIRS
${CIRCT_MAIN_INCLUDE_DIR}/circt/Transforms

View File

@ -6,8 +6,8 @@
//
//===----------------------------------------------------------------------===//
#include "../PassDetail.h"
#include "circt/Conversion/CFToHandshake.h"
#include "PassDetail.h"
#include "circt/Transforms/Passes.h"
#include "mlir/Analysis/CFGLoopInfo.h"
#include "mlir/Conversion/LLVMCommon/ConversionTarget.h"
#include "mlir/Conversion/LLVMCommon/Pattern.h"

View File

@ -11,8 +11,7 @@
//
//===----------------------------------------------------------------------===//
#include "../PassDetail.h"
#include "circt/Conversion/CFToHandshake.h"
#include "PassDetail.h"
#include "circt/Transforms/Passes.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"
#include "mlir/IR/MLIRContext.h"