[AffineStoreForward] factor out applyAffineStoreForward() method; [SimplifyMemrefAccess] factor out applySimplifyMemrefAccess() method

This commit is contained in:
Hanchen Ye 2021-01-08 01:13:41 -06:00
parent 07d77f7193
commit 9f31dd663d
3 changed files with 59 additions and 31 deletions

View File

@ -33,6 +33,10 @@ bool applyLoopPipelining(AffineForOp loop, OpBuilder &builder);
bool applyArrayPartition(FuncOp func, OpBuilder &builder); bool applyArrayPartition(FuncOp func, OpBuilder &builder);
bool applyAffineStoreForward(FuncOp func, OpBuilder &builder);
bool applySimplifyMemrefAccess(FuncOp func);
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Optimization Pass Entries // Optimization Pass Entries
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

View File

@ -19,6 +19,23 @@ using namespace scalehls;
// The difference between this pass and built-in memref-dataflow-opt is this // The difference between this pass and built-in memref-dataflow-opt is this
// pass support to forward the StoreOps that are conditionally executed. // pass support to forward the StoreOps that are conditionally executed.
namespace {
struct AffineStoreForward : public AffineStoreForwardBase<AffineStoreForward> {
void runOnOperation() override {
// Only supports single block functions at the moment.
FuncOp func = getOperation();
auto builder = OpBuilder(func);
if (!llvm::hasSingleElement(func)) {
markAllAnalysesPreserved();
return;
}
applyAffineStoreForward(func, builder);
}
};
} // namespace
namespace { namespace {
// The store to load forwarding relies on three conditions: // The store to load forwarding relies on three conditions:
// //
@ -52,29 +69,30 @@ namespace {
// currently only eliminates the stores only if no other loads/uses (other // currently only eliminates the stores only if no other loads/uses (other
// than dealloc) remain. // than dealloc) remain.
// //
struct AffineStoreForward : public AffineStoreForwardBase<AffineStoreForward> { class AffineStoreForwardImpl {
void runOnOperation() override; public:
explicit AffineStoreForwardImpl(SmallPtrSet<Value, 4> &memrefsToErase,
DominanceInfo *domInfo,
PostDominanceInfo *postDomInfo,
OpBuilder &builder)
: memrefsToErase(memrefsToErase), domInfo(domInfo),
postDomInfo(postDomInfo), builder(builder) {}
void forwardStoreToLoad(AffineReadOpInterface loadOp); void forwardStoreToLoad(AffineReadOpInterface loadOp);
// A list of memref's that are potentially dead / could be eliminated. // A list of memref's that are potentially dead / could be eliminated.
SmallPtrSet<Value, 4> memrefsToErase; SmallPtrSet<Value, 4> &memrefsToErase;
DominanceInfo *domInfo = nullptr; DominanceInfo *domInfo = nullptr;
PostDominanceInfo *postDomInfo = nullptr; PostDominanceInfo *postDomInfo = nullptr;
OpBuilder &builder;
}; };
} // namespace
} // end anonymous namespace
/// 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<Pass> scalehls::createAffineStoreForwardPass() {
return std::make_unique<AffineStoreForward>();
}
// This is a straightforward implementation not optimized for speed. Optimize // This is a straightforward implementation not optimized for speed. Optimize
// if needed. // if needed.
void AffineStoreForward::forwardStoreToLoad(AffineReadOpInterface loadOp) { void AffineStoreForwardImpl::forwardStoreToLoad(AffineReadOpInterface loadOp) {
// First pass over the use list to get the minimum number of surrounding // 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 // loops common between the load op and the store op, with min taken across
// all store ops. // all store ops.
@ -188,7 +206,6 @@ void AffineStoreForward::forwardStoreToLoad(AffineReadOpInterface loadOp) {
return; return;
// Create a new if operation before the loadOp. // Create a new if operation before the loadOp.
OpBuilder builder(loadOp);
builder.setInsertionPointAfter(loadOp); builder.setInsertionPointAfter(loadOp);
auto newIfOp = builder.create<mlir::AffineIfOp>( auto newIfOp = builder.create<mlir::AffineIfOp>(
loadOp.getLoc(), loadOp.getValue().getType(), ifOp.getIntegerSet(), loadOp.getLoc(), loadOp.getValue().getType(), ifOp.getIntegerSet(),
@ -214,21 +231,21 @@ void AffineStoreForward::forwardStoreToLoad(AffineReadOpInterface loadOp) {
memrefsToErase.insert(loadOp.getMemRef()); memrefsToErase.insert(loadOp.getMemRef());
} }
void AffineStoreForward::runOnOperation() { bool scalehls::applyAffineStoreForward(FuncOp func, OpBuilder &builder) {
// Only supports single block functions at the moment. SmallPtrSet<Value, 4> memrefsToErase;
FuncOp f = getOperation();
if (!llvm::hasSingleElement(f)) {
markAllAnalysesPreserved();
return;
}
domInfo = &getAnalysis<DominanceInfo>();
postDomInfo = &getAnalysis<PostDominanceInfo>();
memrefsToErase.clear(); memrefsToErase.clear();
auto domInfo = DominanceInfo(func);
auto postDomInfo = PostDominanceInfo(func);
// Instantiate the pass implementation.
auto implement =
AffineStoreForwardImpl(memrefsToErase, &domInfo, &postDomInfo, builder);
// Walk all load's and perform store to load forwarding. // Walk all load's and perform store to load forwarding.
f.walk([&](AffineReadOpInterface loadOp) { forwardStoreToLoad(loadOp); }); func.walk([&](AffineReadOpInterface loadOp) {
implement.forwardStoreToLoad(loadOp);
});
// Check if the store fwd'ed memrefs are now left with only stores and can // Check if the store fwd'ed memrefs are now left with only stores and can
// thus be completely deleted. Note: the canonicalize pass should be able // thus be completely deleted. Note: the canonicalize pass should be able
@ -250,4 +267,12 @@ void AffineStoreForward::runOnOperation() {
user->erase(); user->erase();
defOp->erase(); defOp->erase();
} }
return true;
}
/// 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<Pass> scalehls::createAffineStoreForwardPass() {
return std::make_unique<AffineStoreForward>();
} }

View File

@ -15,14 +15,11 @@ using namespace scalehls;
namespace { namespace {
struct SimplifyMemrefAccess struct SimplifyMemrefAccess
: public SimplifyMemrefAccessBase<SimplifyMemrefAccess> { : public SimplifyMemrefAccessBase<SimplifyMemrefAccess> {
void runOnOperation() override; void runOnOperation() override { applySimplifyMemrefAccess(getOperation()); }
}; };
} // namespace
} // end anonymous namespace bool scalehls::applySimplifyMemrefAccess(FuncOp func) {
void SimplifyMemrefAccess::runOnOperation() {
auto func = getOperation();
// Collect all load and store operations in the function block. // Collect all load and store operations in the function block.
MemAccessesMap map; MemAccessesMap map;
getMemAccessesMap(func.front(), map); getMemAccessesMap(func.front(), map);
@ -115,6 +112,8 @@ void SimplifyMemrefAccess::runOnOperation() {
opIndex++; opIndex++;
} }
} }
return true;
} }
std::unique_ptr<Pass> scalehls::createSimplifyMemrefAccessPass() { std::unique_ptr<Pass> scalehls::createSimplifyMemrefAccessPass() {