#include "toy/Parser.h"
#include "toy/Passes.h"
+#include "mlir/Dialect/Affine/Passes.h"
#include "mlir/IR/AsmState.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/MLIRContext.h"
// Add optimizations if enabled.
if (enableOpt) {
optPM.addPass(mlir::createLoopFusionPass());
- optPM.addPass(mlir::createMemRefDataFlowOptPass());
+ optPM.addPass(mlir::createAffineScalarReplacementPass());
}
}
#include "toy/Parser.h"
#include "toy/Passes.h"
+#include "mlir/Dialect/Affine/Passes.h"
#include "mlir/ExecutionEngine/ExecutionEngine.h"
#include "mlir/ExecutionEngine/OptUtils.h"
#include "mlir/IR/AsmState.h"
// Add optimizations if enabled.
if (enableOpt) {
optPM.addPass(mlir::createLoopFusionPass());
- optPM.addPass(mlir::createMemRefDataFlowOptPass());
+ optPM.addPass(mlir::createAffineScalarReplacementPass());
}
}
#include "toy/Parser.h"
#include "toy/Passes.h"
+#include "mlir/Dialect/Affine/Passes.h"
#include "mlir/ExecutionEngine/ExecutionEngine.h"
#include "mlir/ExecutionEngine/OptUtils.h"
#include "mlir/IR/AsmState.h"
// Add optimizations if enabled.
if (enableOpt) {
optPM.addPass(mlir::createLoopFusionPass());
- optPM.addPass(mlir::createMemRefDataFlowOptPass());
+ optPM.addPass(mlir::createAffineScalarReplacementPass());
}
}
/// Overload relying on pass options for initialization.
std::unique_ptr<OperationPass<FuncOp>> 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<FuncOp>> createAffineScalarReplacementPass();
+
/// Creates a pass to perform tiling on loop nests.
std::unique_ptr<OperationPass<FuncOp>>
createLoopTilingPass(uint64_t cacheSizeBytes);
];
}
+def AffineScalarReplacement : FunctionPass<"affine-scalrep"> {
+ let summary = "Replace affine memref acceses by scalars by forwarding stores "
+ "to loads and eliminating redundant loads";
+ let description = [{
+ This pass performs store to load forwarding and redundant load elimination
+ for affine memref accesses and potentially eliminates the entire memref
+ if all its accesses are forwarded.
+
+ Input
+
+ ```mlir
+ func @store_load_affine_apply() -> memref<10x10xf32> {
+ %cf7 = constant 7.0 : f32
+ %m = alloc() : memref<10x10xf32>
+ affine.for %i0 = 0 to 10 {
+ affine.for %i1 = 0 to 10 {
+ affine.store %cf7, %m[%i0, %i1] : memref<10x10xf32>
+ %v0 = affine.load %m[%i0, %i1] : memref<10x10xf32>
+ %v1 = addf %v0, %v0 : f32
+ }
+ }
+ return %m : memref<10x10xf32>
+ }
+ ```
+
+ Output
+
+ ```mlir
+ module {
+ func @store_load_affine_apply() -> memref<10x10xf32> {
+ %cst = constant 7.000000e+00 : f32
+ %0 = alloc() : memref<10x10xf32>
+ affine.for %arg0 = 0 to 10 {
+ affine.for %arg1 = 0 to 10 {
+ affine.store %cst, %0[%arg0, %arg1] : memref<10x10xf32>
+ %1 = addf %cst, %cst : f32
+ }
+ }
+ return %0 : memref<10x10xf32>
+ }
+ }
+ ```
+ }];
+ let constructor = "mlir::createAffineScalarReplacementPass()";
+}
+
def AffineVectorize : FunctionPass<"affine-super-vectorize"> {
let summary = "Vectorize to a target independent n-D vector abstraction";
let constructor = "mlir::createSuperVectorizePass()";
/// variables into another ParallelLoop over less than N induction variables.
std::unique_ptr<Pass> createParallelLoopCollapsingPass();
-/// Creates a pass to perform optimizations relying on memref dataflow such as
-/// store to load forwarding, elimination of dead stores, and dead allocs.
-std::unique_ptr<OperationPass<FuncOp>> createMemRefDataFlowOptPass();
-
/// Creates a pass to strip debug information from a function.
std::unique_ptr<Pass> createStripDebugInfoPass();
let constructor = "mlir::createLoopInvariantCodeMotionPass()";
}
-def MemRefDataFlowOpt : FunctionPass<"memref-dataflow-opt"> {
- let summary = "Perform store/load forwarding for memrefs";
- let description = [{
- This pass performs store to load forwarding for memref's to eliminate memory
- accesses and potentially the entire memref if all its accesses are
- forwarded.
-
- Input
-
- ```mlir
- func @store_load_affine_apply() -> memref<10x10xf32> {
- %cf7 = constant 7.0 : f32
- %m = alloc() : memref<10x10xf32>
- affine.for %i0 = 0 to 10 {
- affine.for %i1 = 0 to 10 {
- affine.store %cf7, %m[%i0, %i1] : memref<10x10xf32>
- %v0 = affine.load %m[%i0, %i1] : memref<10x10xf32>
- %v1 = addf %v0, %v0 : f32
- }
- }
- return %m : memref<10x10xf32>
- }
- ```
-
- Output
-
- ```mlir
- module {
- func @store_load_affine_apply() -> memref<10x10xf32> {
- %cst = constant 7.000000e+00 : f32
- %0 = alloc() : memref<10x10xf32>
- affine.for %arg0 = 0 to 10 {
- affine.for %arg1 = 0 to 10 {
- affine.store %cst, %0[%arg0, %arg1] : memref<10x10xf32>
- %1 = addf %cst, %cst : f32
- }
- }
- return %0 : memref<10x10xf32>
- }
- }
- ```
- }];
- let constructor = "mlir::createMemRefDataFlowOptPass()";
-}
-
def NormalizeMemRefs : Pass<"normalize-memrefs", "ModuleOp"> {
let summary = "Normalize memrefs";
let description = [{
-//===- MemRefDataFlowOpt.cpp - MemRef DataFlow Optimization pass ------ -*-===//
+//===- AffineScalarReplacement.cpp - Affine scalar replacement pass -------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
//
//===----------------------------------------------------------------------===//
//
-// This file implements a pass to forward memref stores to loads, thereby
-// potentially getting rid of intermediate memref's entirely. It also removes
+// This file implements a pass to forward affine memref stores to loads, thereby
+// potentially getting rid of intermediate memrefs entirely. It also removes
// redundant loads.
// TODO: In the future, similar techniques could be used to eliminate
// dead memref store's and perform more complex forwarding when support for
#include "mlir/Analysis/AffineAnalysis.h"
#include "mlir/Analysis/Utils.h"
#include "mlir/Dialect/Affine/IR/AffineOps.h"
+#include "mlir/Dialect/Affine/Passes.h"
#include "mlir/Dialect/MemRef/IR/MemRef.h"
#include "mlir/Dialect/StandardOps/IR/Ops.h"
#include "mlir/IR/Dominance.h"
#include "mlir/Support/LogicalResult.h"
-#include "mlir/Transforms/Passes.h"
#include "llvm/ADT/SmallPtrSet.h"
#include <algorithm>
// currently only eliminates the stores only if no other loads/uses (other
// than dealloc) remain.
//
-struct MemRefDataFlowOpt : public MemRefDataFlowOptBase<MemRefDataFlowOpt> {
+struct AffineScalarReplacement
+ : public AffineScalarReplacementBase<AffineScalarReplacement> {
void runOnFunction() override;
LogicalResult forwardStoreToLoad(AffineReadOpInterface loadOp);
/// Creates a pass to perform optimizations relying on memref dataflow such as
/// store to load forwarding, elimination of dead stores, and dead allocs.
-std::unique_ptr<OperationPass<FuncOp>> mlir::createMemRefDataFlowOptPass() {
- return std::make_unique<MemRefDataFlowOpt>();
+std::unique_ptr<OperationPass<FuncOp>>
+mlir::createAffineScalarReplacementPass() {
+ return std::make_unique<AffineScalarReplacement>();
}
// Check if the store may be reaching the load.
// This is a straightforward implementation not optimized for speed. Optimize
// if needed.
LogicalResult
-MemRefDataFlowOpt::forwardStoreToLoad(AffineReadOpInterface loadOp) {
+AffineScalarReplacement::forwardStoreToLoad(AffineReadOpInterface loadOp) {
// First pass over the use list to get the minimum number of surrounding
// loops common between the load op and the store op, with min taken across
// all store ops.
// 1) loadA and loadB have mathematically equivalent affine access functions.
// 2) loadB dominates loadA.
// 3) loadB postdominates all the store op's that have a dependence into loadA.
-void MemRefDataFlowOpt::loadCSE(AffineReadOpInterface loadOp) {
+void AffineScalarReplacement::loadCSE(AffineReadOpInterface loadOp) {
// The list of load op candidates for forwarding that satisfy conditions
// (1) and (2) above - they will be filtered later when checking (3).
SmallVector<Operation *, 8> fwdingCandidates;
loadOpsToErase.push_back(loadOp);
}
-void MemRefDataFlowOpt::runOnFunction() {
+void AffineScalarReplacement::runOnFunction() {
// Only supports single block functions at the moment.
FuncOp f = getFunction();
if (!llvm::hasSingleElement(f)) {
AffineLoopInvariantCodeMotion.cpp
AffineLoopNormalize.cpp
AffineParallelize.cpp
+ AffineScalarReplacement.cpp
LoopTiling.cpp
LoopUnroll.cpp
LoopUnrollAndJam.cpp
LoopCoalescing.cpp
LoopFusion.cpp
LoopInvariantCodeMotion.cpp
- MemRefDataFlowOpt.cpp
NormalizeMemRefs.cpp
OpStats.cpp
ParallelLoopCollapsing.cpp
-// RUN: mlir-opt -allow-unregistered-dialect %s -memref-dataflow-opt | FileCheck %s
+// RUN: mlir-opt -allow-unregistered-dialect %s -affine-scalrep | FileCheck %s
// CHECK-DAG: [[$MAP0:#map[0-9]+]] = affine_map<(d0, d1) -> (d1 + 1)>
// CHECK-DAG: [[$MAP1:#map[0-9]+]] = affine_map<(d0, d1) -> (d0)>