Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions mlir/include/mlir/Analysis/DataFlow/DeadCodeAnalysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,10 @@ class DeadCodeAnalysis : public DataFlowAnalysis {
/// Get the constant values of the operands of the operation. Returns
/// std::nullopt if any of the operand lattices are uninitialized.
std::optional<SmallVector<Attribute>> getOperandValues(Operation *op);

/// Get the constant values of the operands of the operation.
/// If the operand lattices are uninitialized, add a null attribute for those.
SmallVector<Attribute> getOperandValuesBestEffort(Operation *op);

/// The top-level operation the analysis is running on. This is used to detect
/// if a callable is outside the scope of the analysis and thus must be
Expand Down
10 changes: 10 additions & 0 deletions mlir/include/mlir/Dialect/Affine/IR/AffineMemoryOpInterfaces.td
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,16 @@ def AffineWriteOpInterface : OpInterface<"AffineWriteOpInterface"> {
return $_op.getOperand($_op.getStoredValOperandIndex());
}]
>,
InterfaceMethod<
/*desc=*/"Returns the value to store.",
/*retTy=*/"::mlir::OpOperand&",
/*methodName=*/"getValueToStoreMutable",
/*args=*/(ins),
/*methodBody=*/[{}],
/*defaultImplementation=*/[{
return $_op->getOpOperand($_op.getStoredValOperandIndex());
}]
>,
];
}

Expand Down
3 changes: 2 additions & 1 deletion mlir/include/mlir/Dialect/Affine/IR/AffineOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ def AffineForOp : Affine_Op<"for",
ImplicitAffineTerminator, ConditionallySpeculatable,
RecursiveMemoryEffects, DeclareOpInterfaceMethods<LoopLikeOpInterface,
["getLoopInductionVars", "getLoopLowerBounds", "getLoopSteps",
"getLoopUpperBounds", "getYieldedValuesMutable",
"getLoopUpperBounds", "getYieldedValuesMutable", "getLoopResults",
"getInitsMutable", "getYieldedValuesMutable",
"replaceWithAdditionalYields"]>,
DeclareOpInterfaceMethods<RegionBranchOpInterface,
["getEntrySuccessorOperands"]>]> {
Expand Down
5 changes: 3 additions & 2 deletions mlir/include/mlir/Dialect/Affine/LoopUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#define MLIR_DIALECT_AFFINE_LOOPUTILS_H

#include "mlir/IR/Block.h"
#include "mlir/IR/Operation.h"
#include "mlir/Support/LLVM.h"
#include "mlir/Transforms/RegionUtils.h"
#include <optional>
Expand Down Expand Up @@ -101,7 +102,7 @@ LogicalResult affineForOpBodySkew(AffineForOp forOp, ArrayRef<uint64_t> shifts,
/// Identify valid and profitable bands of loops to tile. This is currently just
/// a temporary placeholder to test the mechanics of tiled code generation.
/// Returns all maximal outermost perfect loop nests to tile.
void getTileableBands(func::FuncOp f,
void getTileableBands(Operation *f,
std::vector<SmallVector<AffineForOp, 6>> *bands);

/// Tiles the specified band of perfectly nested loops creating tile-space loops
Expand Down Expand Up @@ -272,7 +273,7 @@ void mapLoopToProcessorIds(scf::ForOp forOp, ArrayRef<Value> processorId,
ArrayRef<Value> numProcessors);

/// Gathers all AffineForOps in 'func.func' grouped by loop depth.
void gatherLoops(func::FuncOp func,
void gatherLoops(Operation* func,
std::vector<SmallVector<AffineForOp, 2>> &depthToLoops);

/// Creates an AffineForOp while ensuring that the lower and upper bounds are
Expand Down
51 changes: 38 additions & 13 deletions mlir/include/mlir/Dialect/Affine/Passes.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,38 @@
#ifndef MLIR_DIALECT_AFFINE_PASSES_H
#define MLIR_DIALECT_AFFINE_PASSES_H

#include "mlir/IR/BuiltinOps.h"
#include "mlir/Interfaces/FunctionInterfaces.h"
#include "mlir/Pass/Pass.h"
#include <limits>
#include <llvm/ADT/StringRef.h>

namespace mlir {

namespace func {
class FuncOp;
} // namespace func
namespace memref {
class MemRefDialect;
} // namespace memref

namespace affine {
class AffineForOp;


class AffineScopePassBase : public OperationPass<> {
using OperationPass<>::OperationPass;

bool canScheduleOn(RegisteredOperationName opInfo) const final {
return opInfo.hasTrait<OpTrait::AffineScope>() &&
opInfo.getStringRef() != ModuleOp::getOperationName();
}

bool shouldImplicitlyNestOn(llvm::StringRef anchorName) const final {
return anchorName == ModuleOp::getOperationName();
}
};

/// Fusion mode to attempt. The default mode `Greedy` does both
/// producer-consumer and sibling fusion.
enum FusionMode { Greedy, ProducerConsumer, Sibling };
Expand All @@ -37,40 +56,46 @@ enum FusionMode { Greedy, ProducerConsumer, Sibling };
/// Creates a simplification pass for affine structures (maps and sets). In
/// addition, this pass also normalizes memrefs to have the trivial (identity)
/// layout map.
std::unique_ptr<OperationPass<func::FuncOp>>
std::unique_ptr<AffineScopePassBase>
createSimplifyAffineStructuresPass();

/// Creates a loop invariant code motion pass that hoists loop invariant
/// operations out of affine loops.
std::unique_ptr<OperationPass<func::FuncOp>>
std::unique_ptr<AffineScopePassBase>
createAffineLoopInvariantCodeMotionPass();

/// Creates a pass to convert all parallel affine.for's into 1-d affine.parallel
/// ops.
std::unique_ptr<AffineScopePassBase> createAffineParallelizePass();

/// Creates a pass that converts some memref operators to affine operators.
std::unique_ptr<AffineScopePassBase> createRaiseMemrefToAffine();

/// Apply normalization transformations to affine loop-like ops. If
/// `promoteSingleIter` is true, single iteration loops are promoted (i.e., the
/// loop is replaced by its loop body).
std::unique_ptr<OperationPass<func::FuncOp>>
std::unique_ptr<AffineScopePassBase>
createAffineLoopNormalizePass(bool promoteSingleIter = false);

/// Performs packing (or explicit copying) of accessed memref regions into
/// buffers in the specified faster memory space through either pointwise copies
/// or DMA operations.
std::unique_ptr<OperationPass<func::FuncOp>> createAffineDataCopyGenerationPass(
std::unique_ptr<AffineScopePassBase> createAffineDataCopyGenerationPass(
unsigned slowMemorySpace, unsigned fastMemorySpace,
unsigned tagMemorySpace = 0, int minDmaTransferSize = 1024,
uint64_t fastMemCapacityBytes = std::numeric_limits<uint64_t>::max());
/// Overload relying on pass options for initialization.
std::unique_ptr<OperationPass<func::FuncOp>>
std::unique_ptr<AffineScopePassBase>
createAffineDataCopyGenerationPass();

/// Creates a pass to replace affine memref accesses by scalars using store to
/// load forwarding and redundant load elimination; consequently also eliminate
/// dead allocs.
std::unique_ptr<OperationPass<func::FuncOp>>
createAffineScalarReplacementPass();
std::unique_ptr<AffineScopePassBase> createAffineScalarReplacementPass();

/// Creates a pass that transforms perfectly nested loops with independent
/// bounds into a single loop.
std::unique_ptr<OperationPass<func::FuncOp>> createLoopCoalescingPass();
std::unique_ptr<AffineScopePassBase> createLoopCoalescingPass();

/// Creates a loop fusion pass which fuses affine loop nests at the top-level of
/// the operation the pass is created on according to the type of fusion
Expand All @@ -83,31 +108,31 @@ createLoopFusionPass(unsigned fastMemorySpace = 0,
enum FusionMode fusionMode = FusionMode::Greedy);

/// Creates a pass to perform tiling on loop nests.
std::unique_ptr<OperationPass<func::FuncOp>>
std::unique_ptr<AffineScopePassBase>
createLoopTilingPass(uint64_t cacheSizeBytes);
/// Overload relying on pass options for initialization.
std::unique_ptr<OperationPass<func::FuncOp>> createLoopTilingPass();
std::unique_ptr<AffineScopePassBase> createLoopTilingPass();

/// Creates a loop unrolling pass with the provided parameters.
/// 'getUnrollFactor' is a function callback for clients to supply a function
/// that computes an unroll factor - the callback takes precedence over unroll
/// factors supplied through other means. If -1 is passed as the unrollFactor
/// and no callback is provided, anything passed from the command-line (if at
/// all) or the default unroll factor is used (LoopUnroll:kDefaultUnrollFactor).
std::unique_ptr<InterfacePass<FunctionOpInterface>> createLoopUnrollPass(
std::unique_ptr<AffineScopePassBase> createLoopUnrollPass(
int unrollFactor = -1, bool unrollUpToFactor = false,
bool unrollFull = false,
const std::function<unsigned(AffineForOp)> &getUnrollFactor = nullptr);

/// Creates a loop unroll jam pass to unroll jam by the specified factor. A
/// factor of -1 lets the pass use the default factor or the one on the command
/// line if provided.
std::unique_ptr<InterfacePass<FunctionOpInterface>>
std::unique_ptr<AffineScopePassBase>
createLoopUnrollAndJamPass(int unrollJamFactor = -1);

/// Creates a pass to pipeline explicit movement of data across levels of the
/// memory hierarchy.
std::unique_ptr<OperationPass<func::FuncOp>> createPipelineDataTransferPass();
std::unique_ptr<AffineScopePassBase> createPipelineDataTransferPass();

/// Creates a pass to expand affine index operations into more fundamental
/// operations (not necessarily restricted to Affine dialect).
Expand Down
41 changes: 28 additions & 13 deletions mlir/include/mlir/Dialect/Affine/Passes.td
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@

include "mlir/Pass/PassBase.td"

def AffineDataCopyGeneration : Pass<"affine-data-copy-generate", "func::FuncOp"> {
class AffineScopePass<string name>
: PassBase<name, "::mlir::affine::AffineScopePassBase">;

def AffineDataCopyGeneration : AffineScopePass<"affine-data-copy-generate"> {
let summary = "Generate explicit copying for affine memory operations";
let constructor = "mlir::affine::createAffineDataCopyGenerationPass()";
let dependentDialects = ["memref::MemRefDialect"];
Expand Down Expand Up @@ -43,7 +46,7 @@ def AffineDataCopyGeneration : Pass<"affine-data-copy-generate", "func::FuncOp">
];
}

def AffineLoopFusion : Pass<"affine-loop-fusion"> {
def AffineLoopFusion : AffineScopePass<"affine-loop-fusion"> {
let summary = "Fuse affine loop nests";
let description = [{
This pass performs fusion of loop nests using a slicing-based approach. The
Expand Down Expand Up @@ -178,12 +181,12 @@ def AffineLoopFusion : Pass<"affine-loop-fusion"> {
}

def AffineLoopInvariantCodeMotion
: Pass<"affine-loop-invariant-code-motion", "func::FuncOp"> {
: AffineScopePass<"affine-loop-invariant-code-motion"> {
let summary = "Hoist loop invariant instructions outside of affine loops";
let constructor = "mlir::affine::createAffineLoopInvariantCodeMotionPass()";
}

def AffineLoopTiling : Pass<"affine-loop-tile", "func::FuncOp"> {
def AffineLoopTiling : AffineScopePass<"affine-loop-tile"> {
let summary = "Tile affine loop nests";
let constructor = "mlir::affine::createLoopTilingPass()";
let options = [
Expand All @@ -199,7 +202,7 @@ def AffineLoopTiling : Pass<"affine-loop-tile", "func::FuncOp"> {
];
}

def AffineLoopUnroll : InterfacePass<"affine-loop-unroll", "FunctionOpInterface"> {
def AffineLoopUnroll : AffineScopePass<"affine-loop-unroll"> {
let summary = "Unroll affine loops";
let constructor = "mlir::affine::createLoopUnrollPass()";
let options = [
Expand All @@ -219,7 +222,7 @@ def AffineLoopUnroll : InterfacePass<"affine-loop-unroll", "FunctionOpInterface"
];
}

def AffineLoopUnrollAndJam : InterfacePass<"affine-loop-unroll-jam", "FunctionOpInterface"> {
def AffineLoopUnrollAndJam : AffineScopePass<"affine-loop-unroll-jam"> {
let summary = "Unroll and jam affine loops";
let constructor = "mlir::affine::createLoopUnrollAndJamPass()";
let options = [
Expand All @@ -230,7 +233,7 @@ def AffineLoopUnrollAndJam : InterfacePass<"affine-loop-unroll-jam", "FunctionOp
}

def AffinePipelineDataTransfer
: Pass<"affine-pipeline-data-transfer", "func::FuncOp"> {
: AffineScopePass<"affine-pipeline-data-transfer"> {
let summary = "Pipeline non-blocking data transfers between explicitly "
"managed levels of the memory hierarchy";
let description = [{
Expand Down Expand Up @@ -298,7 +301,7 @@ def AffinePipelineDataTransfer
let constructor = "mlir::affine::createPipelineDataTransferPass()";
}

def AffineScalarReplacement : Pass<"affine-scalrep", "func::FuncOp"> {
def AffineScalarReplacement : AffineScopePass<"affine-scalrep"> {
let summary = "Replace affine memref accesses by scalars by forwarding stores "
"to loads and eliminating redundant loads";
let description = [{
Expand Down Expand Up @@ -344,7 +347,7 @@ def AffineScalarReplacement : Pass<"affine-scalrep", "func::FuncOp"> {
let constructor = "mlir::affine::createAffineScalarReplacementPass()";
}

def AffineVectorize : Pass<"affine-super-vectorize", "func::FuncOp"> {
def AffineVectorize : AffineScopePass<"affine-super-vectorize"> {
let summary = "Vectorize to a target independent n-D vector abstraction";
let dependentDialects = ["vector::VectorDialect"];
let options = [
Expand All @@ -368,7 +371,7 @@ def AffineVectorize : Pass<"affine-super-vectorize", "func::FuncOp"> {
];
}

def AffineParallelize : Pass<"affine-parallelize", "func::FuncOp"> {
def AffineParallelize : AffineScopePass<"affine-parallelize"> {
let summary = "Convert affine.for ops into 1-D affine.parallel";
let options = [
Option<"maxNested", "max-nested", "unsigned", /*default=*/"-1u",
Expand All @@ -380,7 +383,7 @@ def AffineParallelize : Pass<"affine-parallelize", "func::FuncOp"> {
];
}

def AffineLoopNormalize : Pass<"affine-loop-normalize", "func::FuncOp"> {
def AffineLoopNormalize : AffineScopePass<"affine-loop-normalize"> {
let summary = "Apply normalization transformations to affine loop-like ops";
let constructor = "mlir::affine::createAffineLoopNormalizePass()";
let options = [
Expand All @@ -389,14 +392,26 @@ def AffineLoopNormalize : Pass<"affine-loop-normalize", "func::FuncOp"> {
];
}

def LoopCoalescing : Pass<"affine-loop-coalescing", "func::FuncOp"> {
def LoopCoalescing : AffineScopePass<"affine-loop-coalescing"> {
let summary = "Coalesce nested loops with independent bounds into a single "
"loop";
let constructor = "mlir::affine::createLoopCoalescingPass()";
let dependentDialects = ["affine::AffineDialect","arith::ArithDialect"];
}

def SimplifyAffineStructures : Pass<"affine-simplify-structures", "func::FuncOp"> {
def RaiseMemrefDialect : AffineScopePass<"affine-raise-from-memref"> {
let summary = "Turn some memref operators to affine operators where supported";
let description = [{
Raise memref.load and memref.store to affine.store and affine.load, inferring
the affine map of those operators if needed. This allows passes like --affine-scalrep
to optimize those loads and stores (forwarding them or eliminating them).
They can be turned back to memref dialect ops with --lower-affine.
}];
let constructor = "mlir::affine::createRaiseMemrefToAffine()";
let dependentDialects = ["affine::AffineDialect"];
}

def SimplifyAffineStructures : AffineScopePass<"affine-simplify-structures"> {
let summary = "Simplify affine expressions in maps/sets and normalize "
"memrefs";
let constructor = "mlir::affine::createSimplifyAffineStructuresPass()";
Expand Down
18 changes: 17 additions & 1 deletion mlir/include/mlir/Dialect/Affine/Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#include "mlir/Dialect/Affine/Analysis/AffineAnalysis.h"
#include "mlir/Dialect/Affine/IR/AffineOps.h"
#include "mlir/IR/OpDefinition.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/LogicalResult.h"
#include <optional>

namespace mlir {
Expand Down Expand Up @@ -105,7 +107,7 @@ struct VectorizationStrategy {
/// Replace affine store and load accesses by scalars by forwarding stores to
/// loads and eliminate invariant affine loads; consequently, eliminate dead
/// allocs.
void affineScalarReplace(func::FuncOp f, DominanceInfo &domInfo,
void affineScalarReplace(Operation *parentOp, DominanceInfo &domInfo,
PostDominanceInfo &postDomInfo,
AliasAnalysis &analysis);

Expand Down Expand Up @@ -338,6 +340,20 @@ OpFoldResult linearizeIndex(OpBuilder &builder, Location loc,
ArrayRef<OpFoldResult> multiIndex,
ArrayRef<OpFoldResult> basis);

/// Given a set of indices into a memref which may be computed using
/// arith ops, try to compute each value to an affine expr. This is
/// only possible if the indices are an expression of valid dims and
/// args. If this succeeds, the affine map is populated, along with
/// the map arguments (concrete bindings for dims and symbols).
LogicalResult
convertValuesToAffineMapAndArgs(MLIRContext *ctx, ValueRange indices,
AffineMap &map,
llvm::SmallVectorImpl<Value> &mapArgs);
LogicalResult
convertValuesToAffineMapAndArgs(MLIRContext *ctx,
ArrayRef<OpFoldResult> indices, AffineMap &map,
llvm::SmallVectorImpl<OpFoldResult> &mapArgs);

/// Ensure that all operations that could be executed after `start`
/// (noninclusive) and prior to `memOp` (e.g. on a control flow/op path
/// between the operations) do not have the potential memory effect
Expand Down
16 changes: 16 additions & 0 deletions mlir/include/mlir/Dialect/Bufferization/Transforms/Passes.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#include "mlir/Dialect/Bufferization/IR/BufferDeallocationOpInterface.h"
#include "mlir/Dialect/MemRef/IR/MemRef.h"
#include "mlir/Pass/Pass.h"
#include <mlir/IR/BuiltinOps.h>
#include <mlir/IR/OpDefinition.h>

namespace mlir {
class FunctionOpInterface;
Expand All @@ -23,6 +25,20 @@ struct OneShotBufferizationOptions;
/// Maps from symbol table to its corresponding dealloc helper function.
using DeallocHelperMap = llvm::DenseMap<Operation *, func::FuncOp>;


class BufferScopePassBase : public OperationPass<> {
using OperationPass<>::OperationPass;

bool canScheduleOn(RegisteredOperationName opInfo) const final {
return opInfo.hasTrait<OpTrait::AutomaticAllocationScope>() &&
opInfo.getStringRef() != ModuleOp::getOperationName();
}

bool shouldImplicitlyNestOn(llvm::StringRef anchorName) const final {
return anchorName == ModuleOp::getOperationName();
}
};

//===----------------------------------------------------------------------===//
// Passes
//===----------------------------------------------------------------------===//
Expand Down
Loading