From 4a594c93030acc78bf2c5b8183b1af730c3bf154 Mon Sep 17 00:00:00 2001 From: Hanchen Ye Date: Mon, 18 Jan 2021 17:27:24 -0600 Subject: [PATCH] [LoopPipelining] recursively fully unroll all inner loops until no failure are met --- README.md | 6 +++--- include/Conversion/Passes.td | 2 +- include/Transforms/Passes.td | 2 +- lib/Conversion/LegalizeToHLSCpp.cpp | 2 +- lib/Transforms/FuncPipelining.cpp | 11 +++++++++-- lib/Transforms/LoopPipelining.cpp | 13 +++++++++---- test/Conversion/LegalizeToHLSCpp/test_assign.mlir | 2 +- 7 files changed, 25 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index be66d39..7e08e8a 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ $ # Loop and pragma-level optimizations, performance estimation, and C++ code ge $ scalehls-opt samples/polybench/syrk.mlir \ -affine-loop-perfection -remove-variable-bound -affine-loop-normalize \ -partial-affine-loop-tile="tile-level=1 tile-size=4" \ - -legalize-to-hlscpp="top-function=test_syrk" -loop-pipelining="pipeline-level=1" \ + -legalize-to-hlscpp="top-func=test_syrk" -loop-pipelining="pipeline-level=1" \ -affine-store-forward -simplify-memref-access -array-partition -cse -canonicalize \ -qor-estimation="target-spec=config/target-spec.ini" \ | scalehls-translate -emit-hlscpp @@ -55,7 +55,7 @@ $ benchmark-gen -type "cnn" -config "config/cnn-config.ini" -number 1 \ | scalehls-opt -legalize-dataflow -split-function \ -hlskernel-bufferize -hlskernel-to-affine -func-bufferize \ -affine-loop-perfection -affine-loop-normalize \ - -legalize-to-hlscpp="top-function=auto_gen_cnn" \ + -legalize-to-hlscpp="top-func=auto_gen_cnn" \ -affine-store-forward -simplify-memref-access -cse -canonicalize \ -qor-estimation="target-spec=config/target-spec.ini" \ | scalehls-translate -emit-hlscpp @@ -85,7 +85,7 @@ $ # Legalize the output of ONNX-MLIR, optimize and emit C++ code. $ scalehls-opt resnet18.mlir -legalize-onnx -affine-loop-normalize -canonicalize \ -legalize-dataflow="min-gran=2 insert-copy=false" -split-function \ -convert-linalg-to-affine-loops -affine-loop-fusion \ - -legalize-to-hlscpp="top-function=main_graph" \ + -legalize-to-hlscpp="top-func=main_graph" \ | scalehls-translate -emit-hlscpp ``` diff --git a/include/Conversion/Passes.td b/include/Conversion/Passes.td index 964c196..30e569f 100644 --- a/include/Conversion/Passes.td +++ b/include/Conversion/Passes.td @@ -22,7 +22,7 @@ def LegalizeToHLSCpp : Pass<"legalize-to-hlscpp", "FuncOp"> { let constructor = "mlir::scalehls::createLegalizeToHLSCppPass()"; let options = [ - Option<"topFunction", "top-function", "std::string", /*default=*/"\"main\"", + Option<"topFunc", "top-func", "std::string", /*default=*/"\"main\"", "The top function for HLS synthesis">, ]; } diff --git a/include/Transforms/Passes.td b/include/Transforms/Passes.td index 20aaee8..1573c23 100644 --- a/include/Transforms/Passes.td +++ b/include/Transforms/Passes.td @@ -66,7 +66,7 @@ def FuncPipelining : Pass<"func-pipelining", "FuncOp"> { let constructor = "mlir::scalehls::createFuncPipeliningPass()"; let options = [ - Option<"targetFunction", "target-function", "std::string", + Option<"targetFunc", "target-func", "std::string", /*default=*/"\"main\"", "The target function to be pipelined"> ]; } diff --git a/lib/Conversion/LegalizeToHLSCpp.cpp b/lib/Conversion/LegalizeToHLSCpp.cpp index 3d4fc02..504cf0f 100644 --- a/lib/Conversion/LegalizeToHLSCpp.cpp +++ b/lib/Conversion/LegalizeToHLSCpp.cpp @@ -29,7 +29,7 @@ void LegalizeToHLSCpp::runOnOperation() { if (!func->getAttr("dataflow")) func->setAttr("dataflow", builder.getBoolAttr(false)); - if (func.getName() == topFunction) + if (func.getName() == topFunc) func->setAttr("top_function", builder.getBoolAttr(true)); else func->setAttr("top_function", builder.getBoolAttr(false)); diff --git a/lib/Transforms/FuncPipelining.cpp b/lib/Transforms/FuncPipelining.cpp index 2a16544..7895aab 100644 --- a/lib/Transforms/FuncPipelining.cpp +++ b/lib/Transforms/FuncPipelining.cpp @@ -18,7 +18,7 @@ struct FuncPipelining : public FuncPipeliningBase { auto func = getOperation(); auto builder = OpBuilder(func); - if (func.getName() == targetFunction) { + if (func.getName() == targetFunc) { applyFuncPipelining(func, builder); // Canonicalize the IR after function pipelining. @@ -35,7 +35,14 @@ struct FuncPipelining : public FuncPipeliningBase { /// Apply function pipelining to the input function, all contained loops are /// automatically fully unrolled. bool scalehls::applyFuncPipelining(FuncOp func, OpBuilder &builder) { - func.walk([&](AffineForOp loop) { loopUnrollFull(loop); }); + bool hasFullyUnrolled = false; + while (hasFullyUnrolled == false) { + hasFullyUnrolled = true; + func.walk([&](AffineForOp loop) { + if (failed(loopUnrollFull(loop))) + hasFullyUnrolled = false; + }); + } func->setAttr("pipeline", builder.getBoolAttr(true)); func->setAttr("dataflow", builder.getBoolAttr(false)); diff --git a/lib/Transforms/LoopPipelining.cpp b/lib/Transforms/LoopPipelining.cpp index 9a2ea53..f565f80 100644 --- a/lib/Transforms/LoopPipelining.cpp +++ b/lib/Transforms/LoopPipelining.cpp @@ -63,10 +63,15 @@ bool scalehls::applyLoopPipelining(AffineForOp targetLoop, OpBuilder &builder) { targetLoop->setAttr("pipeline", builder.getBoolAttr(true)); // All inner loops of the pipelined loop are automatically unrolled. - targetLoop.walk([&](AffineForOp loop) { - if (loop != targetLoop) - loopUnrollFull(loop); - }); + bool hasFullyUnrolled = false; + while (hasFullyUnrolled == false) { + hasFullyUnrolled = true; + targetLoop.walk([&](AffineForOp loop) { + if (loop != targetLoop) + if (failed(loopUnrollFull(loop))) + hasFullyUnrolled = false; + }); + } // All outer loops that perfect nest the pipelined loop can be flattened. SmallVector flattenedLoops; diff --git a/test/Conversion/LegalizeToHLSCpp/test_assign.mlir b/test/Conversion/LegalizeToHLSCpp/test_assign.mlir index 2df877e..3f15c4a 100644 --- a/test/Conversion/LegalizeToHLSCpp/test_assign.mlir +++ b/test/Conversion/LegalizeToHLSCpp/test_assign.mlir @@ -1,4 +1,4 @@ -// RUN: scalehls-opt -legalize-to-hlscpp="top-function=test_assign" %s | FileCheck %s +// RUN: scalehls-opt -legalize-to-hlscpp="top-func=test_assign" %s | FileCheck %s // CHECK-LABEL: func @test_assign( // CHECK-SAME: %arg0: f32, %arg1: memref<16xf32, 1>) -> (f32, memref<16xf32, 1>, i32, memref<2x2xi32, 1>) attributes {dataflow = false, top_function = true} {