diff --git a/include/Analysis/Utils.h b/include/Analysis/Utils.h index 8bcdf2d..aaf0248 100644 --- a/include/Analysis/Utils.h +++ b/include/Analysis/Utils.h @@ -88,9 +88,9 @@ public: //===----------------------------------------------------------------------===// // For storing all affine memory access operations (including AffineLoadOp and -// AffineStoreOp) indexed by the array (ArrayOp). +// AffineStoreOp) indexed by the corresponding memref. using LoadStores = SmallVector; -using LoadStoresMap = DenseMap; +using LoadStoresMap = DenseMap; // Check if the lhsOp and rhsOp is at the same scheduling level. In this check, // AffineIfOp is transparent. @@ -101,7 +101,9 @@ Optional> checkSameLevel(Operation *lhsOp, // level with dstOp's any parent loop. Operation *getSameLevelDstOp(Operation *srcOp, Operation *dstOp); -/// Get the definition ArrayOp given any memory access operation. +/// Get the definition ArrayOp given any memref or memory access operation. +hlscpp::ArrayOp getArrayOp(Value memref); + hlscpp::ArrayOp getArrayOp(Operation *op); /// Collect all load and store operations in the block. diff --git a/include/Transforms/Passes.h b/include/Transforms/Passes.h index 0d98b3e..b0242de 100644 --- a/include/Transforms/Passes.h +++ b/include/Transforms/Passes.h @@ -31,7 +31,10 @@ std::unique_ptr createLegalizeDataflowPass(); /// Bufferization passes. std::unique_ptr createHLSKernelBufferizePass(); + +/// MemRef Optimization Passes. std::unique_ptr createStoreOpForwardPass(); +std::unique_ptr createSimplifyMemRefAccessPass(); void registerTransformsPasses(); diff --git a/include/Transforms/Passes.td b/include/Transforms/Passes.td index 1103944..2c9d239 100644 --- a/include/Transforms/Passes.td +++ b/include/Transforms/Passes.td @@ -136,6 +136,10 @@ def HLSKernelBufferize : Pass<"hlskernel-bufferize", "FuncOp"> { let constructor = "mlir::scalehls::createHLSKernelBufferizePass()"; } +//===----------------------------------------------------------------------===// +// MemRef Optimization Passes +//===----------------------------------------------------------------------===// + def StoreOpForward : Pass<"store-op-forward", "FuncOp"> { let summary = "Forward store to load, including conditional stores"; let description = [{ @@ -146,4 +150,14 @@ def StoreOpForward : Pass<"store-op-forward", "FuncOp"> { let constructor = "mlir::scalehls::createStoreOpForwardPass()"; } +def SimplifyMemRefAccess : Pass<"simplify-memref-access", "FuncOp"> { + let summary = "Forward store to load, including conditional stores"; + let description = [{ + This simplify-memref-access pass will eliminate the known redundant load and + store operations for simplifying the memref access. + }]; + + let constructor = "mlir::scalehls::createSimplifyMemRefAccessPass()"; +} + #endif // SCALEHLS_TRANSFORMS_PASSES_TD diff --git a/lib/Analysis/QoREstimation.cpp b/lib/Analysis/QoREstimation.cpp index a066646..eb44b7a 100644 --- a/lib/Analysis/QoREstimation.cpp +++ b/lib/Analysis/QoREstimation.cpp @@ -329,7 +329,7 @@ unsigned HLSCppEstimator::getResMinII(LoadStoresMap &map) { unsigned II = 1; for (auto &pair : map) { - auto arrayOp = pair.first; + auto arrayOp = getArrayOp(pair.first); // Partition number should at least be 1. auto partitionNum = max((unsigned)1, getUIntAttrValue(arrayOp, "partition_num")); diff --git a/lib/Analysis/Utils.cpp b/lib/Analysis/Utils.cpp index 471b819..5873492 100644 --- a/lib/Analysis/Utils.cpp +++ b/lib/Analysis/Utils.cpp @@ -85,9 +85,11 @@ Operation *scalehls::getSameLevelDstOp(Operation *srcOp, Operation *dstOp) { return nullptr; } -/// Get the definition ArrayOp given any memory access operation. -hlscpp::ArrayOp scalehls::getArrayOp(Operation *op) { - auto defOp = MemRefAccess(op).memref.getDefiningOp(); +/// Get the definition ArrayOp given any memref or memory access operation. +hlscpp::ArrayOp scalehls::getArrayOp(Value memref) { + assert(memref.getType().isa() && "isn't a MemRef type value"); + + auto defOp = memref.getDefiningOp(); assert(defOp && "MemRef is block argument"); auto arrayOp = dyn_cast(defOp); @@ -96,11 +98,15 @@ hlscpp::ArrayOp scalehls::getArrayOp(Operation *op) { return arrayOp; } +hlscpp::ArrayOp scalehls::getArrayOp(Operation *op) { + return getArrayOp(MemRefAccess(op).memref); +} + /// Collect all load and store operations in the block. void scalehls::getLoadStoresMap(Block &block, LoadStoresMap &map) { for (auto &op : block) { if (isa(op)) - map[getArrayOp(&op)].push_back(&op); + map[MemRefAccess(&op).memref].push_back(&op); else if (op.getNumRegions()) { for (auto ®ion : op.getRegions()) for (auto &block : region) diff --git a/lib/Transforms/ArrayPartition.cpp b/lib/Transforms/ArrayPartition.cpp index e16586e..d00bb7c 100644 --- a/lib/Transforms/ArrayPartition.cpp +++ b/lib/Transforms/ArrayPartition.cpp @@ -34,7 +34,7 @@ static mlir::AffineForOp getPipelineLoop(mlir::AffineForOp root) { template static void applyArrayPartition(LoadStoresMap &map, OpBuilder &builder) { for (auto pair : map) { - auto arrayOp = cast(pair.first); + auto arrayOp = getArrayOp(pair.first); auto arrayShape = arrayOp.getShapedType().getShape(); auto arrayAccesses = pair.second; @@ -120,14 +120,12 @@ void ArrayPartition::runOnOperation() { // Collect memory access information. LoadStoresMap loadMap; outermost.walk([&](mlir::AffineLoadOp loadOp) { - auto arrayOp = loadOp.getMemRef().getDefiningOp(); - loadMap[arrayOp].push_back(loadOp); + loadMap[loadOp.getMemRef()].push_back(loadOp); }); LoadStoresMap storeMap; outermost.walk([&](mlir::AffineStoreOp storeOp) { - auto arrayOp = storeOp.getMemRef().getDefiningOp(); - storeMap[arrayOp].push_back(storeOp); + storeMap[storeOp.getMemRef()].push_back(storeOp); }); // Apply array partition pragma. diff --git a/lib/Transforms/SimplifyMemRefAccess.cpp b/lib/Transforms/SimplifyMemRefAccess.cpp new file mode 100644 index 0000000..20416ca --- /dev/null +++ b/lib/Transforms/SimplifyMemRefAccess.cpp @@ -0,0 +1,31 @@ +//===------------------------------------------------------------*- C++ -*-===// +// +//===----------------------------------------------------------------------===// + +#include "Analysis/Utils.h" +#include "Transforms/Passes.h" +#include "mlir/Analysis/AffineAnalysis.h" +#include "mlir/Analysis/Utils.h" +#include "mlir/Dialect/Affine/IR/AffineOps.h" +#include "mlir/Dialect/StandardOps/IR/Ops.h" +#include "mlir/IR/Dominance.h" +#include "mlir/IR/IntegerSet.h" +#include "llvm/ADT/SmallPtrSet.h" +#include + +using namespace mlir; +using namespace scalehls; + +namespace { +struct SimplifyMemRefAccess + : public SimplifyMemRefAccessBase { + void runOnOperation() override; +}; + +} // end anonymous namespace + +void SimplifyMemRefAccess::runOnOperation() {} + +std::unique_ptr scalehls::createSimplifyMemRefAccessPass() { + return std::make_unique(); +} diff --git a/test/Transforms/test_simplify_memref_access.mlir b/test/Transforms/test_simplify_memref_access.mlir new file mode 100644 index 0000000..2217b97 --- /dev/null +++ b/test/Transforms/test_simplify_memref_access.mlir @@ -0,0 +1,6 @@ +// RUN: scalehls-opt -simplify-memref-access %s | FileCheck %s + +// CHECK-LABEL: func @test_for +func @test_for() { + return +}