hanchenye-scalehls/lib/Transforms/Memory/SimplifyMemrefAccess.cpp

125 lines
4.0 KiB
C++

//===----------------------------------------------------------------------===//
//
// Copyright 2020-2021 The ScaleHLS Authors.
//
//===----------------------------------------------------------------------===//
#include "scalehls/Support/Utils.h"
#include "scalehls/Transforms/Passes.h"
using namespace mlir;
using namespace scalehls;
static bool applySimplifyMemrefAccess(FuncOp func) {
SmallPtrSet<Operation *, 16> opsToErase;
MemAccessesMap memAccessesMap;
getMemAccessesMap(func.front(), memAccessesMap);
for (auto memAccessesPair : memAccessesMap) {
auto loadOrStoreOps = memAccessesPair.second;
// Collect all load operations that share the same memref access.
ReverseOpIteratorsMap loadsMap;
for (auto it = loadOrStoreOps.rbegin(); it != loadOrStoreOps.rend(); ++it) {
if (isa<AffineReadOpInterface>(*it))
loadsMap[PtrLikeMemRefAccess(*it)].push_back(it);
}
// Traverse each {MemRefAccess, Load operation iterator vector} element.
for (auto loadsPair : loadsMap) {
auto loadOps = loadsPair.second;
for (unsigned i = 0, e = loadOps.size() - 1; i < e; ++i) {
auto loadOpIt = loadOps[i];
auto domLoadOpIt = loadOps[i + 1];
auto loadOp = *loadOpIt;
auto domLoadOp = *domLoadOpIt;
// The two load operations must locate in the same basic block.
if (loadOp->getBlock() != domLoadOp->getBlock())
continue;
// Traverse all store operations between the current two load operations
// that share the same memref access.
auto it = std::next(loadOpIt);
for (; it != domLoadOpIt; ++it) {
if (isa<AffineWriteOpInterface>(*it))
if (checkDependence(*it, loadOp))
break;
}
// We need to make sure there is no dependency exists in between.
if (it != domLoadOpIt)
continue;
// Now we know loadOp can be eliminated.
loadOp->getResult(0).replaceAllUsesWith(domLoadOp->getResult(0));
opsToErase.insert(loadOp);
}
}
// Find all store operations that share the same memref access.
OpIteratorsMap storesMap;
for (auto it = loadOrStoreOps.begin(); it != loadOrStoreOps.end(); ++it) {
if (isa<AffineWriteOpInterface>(*it))
storesMap[PtrLikeMemRefAccess(*it)].push_back(it);
}
// Traverse each {MemRefAccess, Store operation iterator vector} element.
for (auto storesPair : storesMap) {
auto storeOps = storesPair.second;
for (unsigned i = 0, e = storeOps.size() - 1; i < e; ++i) {
auto storeOpIt = storeOps[i];
auto postDomStoreOpIt = storeOps[i + 1];
auto storeOp = *storeOpIt;
auto postDomStoreOp = *postDomStoreOpIt;
// The two store operations must locate in the same loop level.
auto sameLevelOps = checkSameLevel(storeOp, postDomStoreOp);
if (!sameLevelOps)
continue;
// The second store operation must always be executed.
if (sameLevelOps.getValue().second != postDomStoreOp)
continue;
// Traverse all load operations between the current two load operations
// that share the same memref access.
auto it = std::next(storeOpIt);
for (; it != postDomStoreOpIt; ++it) {
if (isa<AffineReadOpInterface>(*it))
if (checkDependence(storeOp, *it))
break;
}
// We need to make sure there is no dependency exists in between.
if (it != postDomStoreOpIt)
continue;
// Now we know storeOp can be eliminated.
opsToErase.insert(storeOp);
}
}
}
for (auto op : opsToErase)
op->erase();
return true;
}
namespace {
struct SimplifyMemrefAccess
: public SimplifyMemrefAccessBase<SimplifyMemrefAccess> {
void runOnOperation() override { applySimplifyMemrefAccess(getOperation()); }
};
} // namespace
std::unique_ptr<Pass> scalehls::createSimplifyMemrefAccessPass() {
return std::make_unique<SimplifyMemrefAccess>();
}