[HLSCppDialect] update pragma operations definition, update corresponding emitters

This commit is contained in:
Hanchen Ye 2020-09-25 23:19:24 -05:00
parent 4470f6c232
commit 77eaacd030
4 changed files with 109 additions and 123 deletions

View File

@ -5,115 +5,107 @@
#ifndef SCALEHLS_DIALECT_HLSCPP_PRAGMAOPS_TD
#define SCALEHLS_DIALECT_HLSCPP_PRAGMAOPS_TD
def ApplyPragmasOp : HLSCppOp<"apply_pragmas", [
def LoopPragmaOp : HLSCppOp<"loop_pragma", [
PragmaOpInterface,
SingleBlockImplicitTerminator<"EndOp">
HasParent<"AffineForOp">
]> {
let summary = "Apply pragmas to the parent operation";
let summary = "Apply loop pragmas";
let description = [{
This hlscpp.apply_pragmas operation owns one region containing one or more
concrete pragmas, and applies all of them to its parent operation (e.g.,
functions, loops, or other regions). This operation should always be
inserted to the front of its parent operation. For detailed description of
each concrete pragma, please refer to:
https://www.xilinx.com/html_docs/xilinx2020_1/vitis_doc/hlspragmas.html
}];
let regions = (region SizedRegion<1> : $pragmaRegion);
let skipDefaultBuilders = 1;
let builders = [OpBuilder<"OpBuilder &builder, OperationState &state", [{
auto &pragmaRegion = *state.addRegion();
ApplyPragmasOp::ensureTerminator(pragmaRegion, builder, state.location);
}]>];
// TODO: verifier for this op:
// (1) is in the front of its parent operation.
// (2) only contains hlscpp pragma operation.
let extraClassDeclaration = [{
OpBuilder getBodyBuilder() {
assert(!pragmaRegion().empty() && "Unexpected empty pragma region.");
Block &body = pragmaRegion().front();
return OpBuilder(&body, std::prev(body.end()));
}
}];
}
def PragmaPipelineOp : HLSCppOp<"pragma_pipeline", [
PragmaOpInterface,
HasParent<"ApplyPragmasOp">
]> {
let summary = "Apply PIPELINE HLS pragma";
let description = [{
This hlscpp.pragma_pipeline operation represent the "#pragma HLS PIPELINE"
directive in HLS C++.
This hlscpp.loop_pragma operation represent pragmas for loops, such as
pipeline, and unroll pragma.
}];
let arguments = (ins
// Pipeline pragma-related attributes.
Confined<UI32Attr, [IntPositive]> : $II,
BoolAttr : $enable_flush,
BoolAttr : $rewind,
BoolAttr : $off
);
BoolAttr : $off,
let extraClassDeclaration = [{
unsigned getII() {
return getAttrOfType<IntegerAttr>("II").getUInt();
}
bool isEnableFlush() {
return getAttrOfType<BoolAttr>("enable_flush").getValue();
}
bool isRewind() {
return getAttrOfType<BoolAttr>("rewind").getValue();
}
bool isOff() {
return getAttrOfType<BoolAttr>("off").getValue();
}
}];
}
def PragmaUnrollOp : HLSCppOp<"pragma_unroll", [
PragmaOpInterface,
HasParent<"ApplyPragmasOp">
]> {
let summary = "Apply UNROLL HLS pragma";
let description = [{
This hlscpp.pragma_unroll operation represent the "#pragma HLS UNROLL"
directive in HLS C++.
}];
let arguments = (ins
// Unroll pragma-related attributes.
Confined<UI32Attr, [IntPositive]> : $factor,
BoolAttr : $region,
BoolAttr : $skip_exit_check
);
let extraClassDeclaration = [{
// Pipeline pragma-related methods.
unsigned getII() {
return getAttrOfType<IntegerAttr>("II").getUInt();
}
bool isEnableFlush() {
return getAttrOfType<BoolAttr>("enable_flush").getValue();
}
bool isRewind() {
return getAttrOfType<BoolAttr>("rewind").getValue();
}
bool isOff() {
return getAttrOfType<BoolAttr>("off").getValue();
}
// Unroll pragma-related methods.
unsigned getFactor() {
return getAttrOfType<IntegerAttr>("factor").getUInt();
}
bool isRegion() {
return getAttrOfType<BoolAttr>("region").getValue();
}
bool isSkipExitCheck() {
return getAttrOfType<BoolAttr>("skip_exit_check").getValue();
}
}];
}
def PragmaArrayPartitionOp : HLSCppOp<"pragma_array_partition", [
def FuncPragmaOp : HLSCppOp<"func_pragma", [
PragmaOpInterface,
HasParent<"FuncOp">
]> {
let summary = "Apply function pragmas";
let description = [{
This hlscpp.func_pragma operation represent pragmas for functions, such as
pipeline, and dataflow pragma.
}];
let arguments = (ins
// Pipeline pragma-related attributes.
Confined<UI32Attr, [IntPositive]> : $II,
BoolAttr : $enable_flush,
BoolAttr : $rewind,
BoolAttr : $off,
// Dataflow pragma-related attributes.
BoolAttr : $dataflow
);
let extraClassDeclaration = [{
// Pipeline pragma-related methods.
unsigned getII() {
return getAttrOfType<IntegerAttr>("II").getUInt();
}
bool isEnableFlush() {
return getAttrOfType<BoolAttr>("enable_flush").getValue();
}
bool isRewind() {
return getAttrOfType<BoolAttr>("rewind").getValue();
}
bool isOff() {
return getAttrOfType<BoolAttr>("off").getValue();
}
// Dataflow pragma-related methods.
bool isDataflow() {
return getAttrOfType<BoolAttr>("dataflow").getValue();
}
}];
}
def ArrayPragmaOp : HLSCppOp<"array_pragma", [
PragmaOpInterface
]> {
let summary = "Apply ARRAY_PARTITION HLS pragma to the input value";
let summary = "Apply array pragmas";
let description = [{
This hlscpp.pragma_array_partition operation represent the "#pragma HLS
ARRAY_PARTITION" directive in HLS C++.
This hlscpp.func_pragma operation represent pragmas for arrays, such as
array partition, interface, and bind storage pragma.
}];
let arguments = (ins
@ -131,11 +123,9 @@ def PragmaArrayPartitionOp : HLSCppOp<"pragma_array_partition", [
StringRef getPartitionType() {
return getAttrOfType<StringAttr>("type").getValue();
}
unsigned getFactor() {
return getAttrOfType<IntegerAttr>("factor").getUInt();
}
unsigned getDim() {
return getAttrOfType<IntegerAttr>("dim").getUInt();
}

View File

@ -49,8 +49,8 @@ public:
SelectOp, ConstantOp, CopySignOp, TruncateIOp, ZeroExtendIOp,
SignExtendIOp, IndexCastOp, CallOp, ReturnOp, AssignOp, EndOp,
// Pragma operations.
ApplyPragmasOp, PragmaPipelineOp, PragmaUnrollOp,
PragmaArrayPartitionOp>([&](auto opNode) -> ResultType {
LoopPragmaOp, FuncPragmaOp, ArrayPragmaOp>(
[&](auto opNode) -> ResultType {
return thisCast->visitOp(opNode, args...);
})
.Default([&](auto opNode) -> ResultType {
@ -175,10 +175,9 @@ public:
HANDLE(EndOp);
// Pragma operations.
HANDLE(ApplyPragmasOp);
HANDLE(PragmaPipelineOp);
HANDLE(PragmaUnrollOp);
HANDLE(PragmaArrayPartitionOp);
HANDLE(LoopPragmaOp);
HANDLE(FuncPragmaOp);
HANDLE(ArrayPragmaOp);
#undef HANDLE
};
} // namespace scalehls

View File

@ -86,9 +86,7 @@ bool QoREstimator::visitOp(AffineForOp op) {
// Recursively estimate latency of sub-elements, including functions and
// loops. These sub-elements will be considered as a normal node in the CDFG
// for function latency estimzation.
for (auto &op : body.front()) {
estimateOperation(&op);
}
estimateBlock(body.front());
// Estimate iteration latency.
unsigned iterLatency = searchLongestPath(body.front());

View File

@ -178,10 +178,9 @@ public:
void emitAssign(AssignOp *op);
/// Pragma operation emitters.
void emitApplyPragmas(ApplyPragmasOp *op);
void emitPragmaPipeline(PragmaPipelineOp *op);
void emitPragmaUnroll(PragmaUnrollOp *op);
void emitPragmaArrayPartition(PragmaArrayPartitionOp *op);
void emitLoopPragma(LoopPragmaOp *op);
void emitFuncPragma(FuncPragmaOp *op);
void emitArrayPragma(ArrayPragmaOp *op);
/// Top-level MLIR module emitter.
void emitModule(ModuleOp module);
@ -464,18 +463,9 @@ public:
using HLSCppVisitorBase::visitOp;
/// Pragma operations.
bool visitOp(ApplyPragmasOp op) {
return emitter.emitApplyPragmas(&op), true;
}
bool visitOp(PragmaPipelineOp op) {
return emitter.emitPragmaPipeline(&op), true;
}
bool visitOp(PragmaUnrollOp op) {
return emitter.emitPragmaUnroll(&op), true;
}
bool visitOp(PragmaArrayPartitionOp op) {
return emitter.emitPragmaArrayPartition(&op), true;
}
bool visitOp(LoopPragmaOp op) { return emitter.emitLoopPragma(&op), true; }
bool visitOp(FuncPragmaOp op) { return emitter.emitFuncPragma(&op), true; }
bool visitOp(ArrayPragmaOp op) { return emitter.emitArrayPragma(&op), true; }
private:
ModuleEmitter &emitter;
@ -1030,12 +1020,33 @@ void ModuleEmitter::emitAssign(AssignOp *op) {
}
/// Pragma operation emitters.
void ModuleEmitter::emitApplyPragmas(ApplyPragmasOp *op) {
emitBlock(*op->getBody());
void ModuleEmitter::emitLoopPragma(LoopPragmaOp *op) {
indent();
os << "#pragma HLS pipeline";
if (op->isOff())
os << " off\n";
else {
os << " II=" << op->getII();
if (op->isRewind())
os << " rewind";
if (op->isEnableFlush())
os << " enable_flush";
os << "\n";
}
indent();
os << "#pragma HLS unroll";
// TODO: default factor.
os << " factor=" << op->getFactor();
if (op->isRegion())
os << " region";
if (op->isSkipExitCheck())
os << " skip_exit_check";
os << "\n";
}
void ModuleEmitter::emitPragmaPipeline(PragmaPipelineOp *op) {
void ModuleEmitter::emitFuncPragma(FuncPragmaOp *op) {
indent();
os << "#pragma HLS pipeline";
if (op->isOff())
@ -1050,19 +1061,7 @@ void ModuleEmitter::emitPragmaPipeline(PragmaPipelineOp *op) {
}
}
void ModuleEmitter::emitPragmaUnroll(PragmaUnrollOp *op) {
indent();
os << "#pragma HLS unroll";
// TODO: default factor.
os << " factor=" << op->getFactor();
if (op->isRegion())
os << " region";
if (op->isSkipExitCheck())
os << " skip_exit_check";
os << "\n";
}
void ModuleEmitter::emitPragmaArrayPartition(PragmaArrayPartitionOp *op) {
void ModuleEmitter::emitArrayPragma(ArrayPragmaOp *op) {
indent();
os << "#pragma HLS array_partition";
os << " variable=";