[ConvertToHLSCpp] support to recursively convert for loop body

This commit is contained in:
Hanchen Ye 2020-10-05 23:52:43 -05:00
parent f3c40918e3
commit a2934a09a9
2 changed files with 72 additions and 57 deletions

View File

@ -19,13 +19,69 @@ public:
};
} // namespace
static void convertBlock(Block &block) {
for (auto &op : block) {
if (isa<ArrayOp>(op))
continue;
auto b = OpBuilder(&op);
// ArrayOp will be inserted after each ShapedType value from declaration
// or function signature.
for (auto operand : op.getOperands()) {
if (auto arrayType = operand.getType().dyn_cast<ShapedType>()) {
bool insertArrayOp = false;
if (operand.getKind() == Value::Kind::BlockArgument)
insertArrayOp = true;
else if (!isa<ArrayOp>(operand.getDefiningOp())) {
insertArrayOp = true;
if (!arrayType.hasStaticShape())
operand.getDefiningOp()->emitError(
"is unranked or has dynamic shape which is illegal.");
}
if (insertArrayOp) {
// Insert array operation and set attributes.
b.setInsertionPointAfterValue(operand);
auto arrayOp =
b.create<ArrayOp>(op.getLoc(), operand.getType(), operand);
operand.replaceAllUsesExcept(arrayOp.getResult(),
SmallPtrSet<Operation *, 1>{arrayOp});
// Set array pragma attributes, default array instance is ram_1p
// bram. Other attributes are not set here since they requires more
// analysis to be determined.
arrayOp.setAttr("interface", b.getBoolAttr(false));
arrayOp.setAttr("storage_type", b.getStringAttr("ram_1p"));
arrayOp.setAttr("storage_impl", b.getStringAttr("bram"));
arrayOp.setAttr("partition", b.getBoolAttr(false));
}
}
}
if (auto forOp = dyn_cast<AffineForOp>(op)) {
if (forOp.getLoopBody().getBlocks().size() != 1)
forOp.emitError("has zero or more than one basic blocks");
// Set loop pragma attributes.
forOp.setAttr("pipeline", b.getBoolAttr(false));
forOp.setAttr("pipeline_II", b.getUI32IntegerAttr(1));
forOp.setAttr("unroll_factor", b.getUI32IntegerAttr(1));
convertBlock(forOp.getLoopBody().front());
}
}
}
void ConvertToHLSCppPass::runOnOperation() {
for (auto func : getOperation().getOps<FuncOp>()) {
if (func.getBlocks().size() != 1)
func.emitError("has zero or more than one basic blocks");
auto b = OpBuilder(func);
if (func.getBlocks().size() != 1)
func.emitError("has zero or more than one basic blocks.");
// Set function pragma attributes.
func.setAttr("dataflow", b.getBoolAttr(false));
// Insert AssignOp.
if (auto returnOp = dyn_cast<ReturnOp>(func.front().getTerminator())) {
b.setInsertionPoint(returnOp);
@ -45,51 +101,8 @@ void ConvertToHLSCppPass::runOnOperation() {
} else
func.emitError("doesn't have a return as terminator.");
// Set function pragma attributes.
func.setAttr("dataflow", b.getBoolAttr(false));
for (auto &op : func.front()) {
if (auto forOp = dyn_cast<AffineForOp>(op)) {
if (forOp.getLoopBody().getBlocks().size() != 1)
forOp.emitError("has zero or more than one basic blocks");
// Set loop pragma attributes.
forOp.setAttr("pipeline", b.getBoolAttr(false));
forOp.setAttr("pipeline_II", b.getUI32IntegerAttr(1));
forOp.setAttr("unroll_factor", b.getUI32IntegerAttr(1));
}
for (auto operand : op.getOperands()) {
if (auto arrayType = operand.getType().dyn_cast<ShapedType>()) {
bool insertArrayOp = false;
if (operand.getKind() == Value::Kind::BlockArgument)
insertArrayOp = true;
else if (!isa<ArrayOp>(operand.getDefiningOp())) {
insertArrayOp = true;
if (!arrayType.hasStaticShape())
operand.getDefiningOp()->emitError(
"is unranked or has dynamic shape which is illegal.");
}
if (insertArrayOp) {
// Insert array operation and set attributes.
b.setInsertionPointAfterValue(operand);
auto arrayOp =
b.create<ArrayOp>(op.getLoc(), operand.getType(), operand);
operand.replaceAllUsesExcept(arrayOp.getResult(),
SmallPtrSet<Operation *, 1>{arrayOp});
// Set array pragma attributes, default array instance is ram_1p
// bram. Other attributes are not set here since they requires more
// analysis to be determined.
arrayOp.setAttr("interface", b.getBoolAttr(false));
arrayOp.setAttr("storage_type", b.getStringAttr("ram_1p"));
arrayOp.setAttr("storage_impl", b.getStringAttr("bram"));
arrayOp.setAttr("partition", b.getBoolAttr(false));
}
}
}
}
// Recursively convert every for loop body blocks.
convertBlock(func.front());
}
}

View File

@ -1,18 +1,20 @@
// RUN: scalehls-opt -qor-estimation %s | FileCheck %s
// CHECK-LABEL: func @test_for
func @test_for(%arg0: memref<16x4x4xindex>, %arg1: memref<16x4x4xindex>) {
"hlscpp.array_pragma" (%arg0) {partition=true, partition_type=["cyclic", "cyclic", "cyclic"], partition_factor=[4 : ui32, 2 : ui32, 4 : ui32], storage_type="ram_2p", interface=true, interface_mode="bram"} : (memref<16x4x4xindex>) -> ()
"hlscpp.array_pragma" (%arg1) {partition=true, partition_type=["cyclic", "cyclic", "cyclic"], partition_factor=[4 : ui32, 2 : ui32, 4 : ui32], storage_type="ram_2p", interface=true, interface_mode="bram"} : (memref<16x4x4xindex>) -> ()
func @test_for(%arg0: memref<16x4x4xindex>, %arg1: memref<16x4x4xindex>) attributes {dataflow = false} {
%array0 = "hlscpp.array"(%arg0) {interface = false, partition = false, storage_impl = "bram", storage_type = "ram_1p"} : (memref<16x4x4xindex>) -> memref<16x4x4xindex>
%array1 = "hlscpp.array"(%arg1) {interface = false, partition = false, storage_impl = "bram", storage_type = "ram_1p"} : (memref<16x4x4xindex>) -> memref<16x4x4xindex>
//"hlscpp.array_pragma" (%arg0) {partition=true, partition_type=["cyclic", "cyclic", "cyclic"], partition_factor=[4 : ui32, 2 : ui32, 4 : ui32], storage_type="ram_2p", interface=true, interface_mode="bram"} : (memref<16x4x4xindex>) -> ()
//"hlscpp.array_pragma" (%arg1) {partition=true, partition_type=["cyclic", "cyclic", "cyclic"], partition_factor=[4 : ui32, 2 : ui32, 4 : ui32], storage_type="ram_2p", interface=true, interface_mode="bram"} : (memref<16x4x4xindex>) -> ()
affine.for %i = 0 to 16 {
affine.for %j = 0 to 4 {
affine.for %k = 0 to 4 {
%0 = affine.load %arg0[%i, %j, %k] : memref<16x4x4xindex>
%1 = affine.load %arg1[%i, %j, %k] : memref<16x4x4xindex>
%0 = affine.load %array0[%i, %j, %k] : memref<16x4x4xindex>
%1 = affine.load %array1[%i, %j, %k] : memref<16x4x4xindex>
%2 = muli %0, %1 : index
affine.store %2, %arg0[%i, %j, %k] : memref<16x4x4xindex>
}
}
}
affine.store %2, %array1[%i, %j, %k] : memref<16x4x4xindex>
} {pipeline = false, pipeline_II = 1 : ui32, unroll_factor = 1 : ui32}
} {pipeline = false, pipeline_II = 1 : ui32, unroll_factor = 1 : ui32}
} {pipeline = false, pipeline_II = 1 : ui32, unroll_factor = 1 : ui32}
return
}