[HLSCppDialect] pragma operations come back... eventually I found the analysis+estimate 2-step approach in COMBA is misleading, basically you can't clearly partition the task into two passes (StaticAnalysis and QoREstimation), so that I decide to merge the two into one QoREstimation pass. In this case, there's no need to move around estimated or extracted parameters between different passes, which means we can create an internal data structure in QoREstimation pass for decently holding all parameters, and pragma information will continue to be represented as pragma operation
This commit is contained in:
parent
e06ba37001
commit
9b7c1c1c69
|
@ -24,10 +24,9 @@ class HLSCppOp<string mnemonic, list<OpTrait> traits = []> :
|
||||||
Op<HLSCppDialect, mnemonic, traits>;
|
Op<HLSCppDialect, mnemonic, traits>;
|
||||||
|
|
||||||
include "Interfaces.td"
|
include "Interfaces.td"
|
||||||
|
|
||||||
include "Attributes.td"
|
include "Attributes.td"
|
||||||
|
|
||||||
include "ParamOps.td"
|
include "PragmaOps.td"
|
||||||
include "StructureOps.td"
|
include "StructureOps.td"
|
||||||
|
|
||||||
#endif // SCALEHLS_DIALECT_HLSCPP_HLSCPP_TD
|
#endif // SCALEHLS_DIALECT_HLSCPP_HLSCPP_TD
|
||||||
|
|
|
@ -14,11 +14,4 @@ def PragmaOpInterface : OpInterface<"PragmaOpInterface"> {
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
def ParamOpInterface : OpInterface<"ParamOpInterface"> {
|
|
||||||
let description = [{
|
|
||||||
This interface indicates the operation represents a group of parameters of
|
|
||||||
its parent region.
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // SCALEHLS_DIALECT_HLSCPP_INTERFACES_TD
|
#endif // SCALEHLS_DIALECT_HLSCPP_INTERFACES_TD
|
||||||
|
|
|
@ -1,144 +0,0 @@
|
||||||
//===-------------------------------------------------------*- tablegen -*-===//
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef SCALEHLS_DIALECT_HLSCPP_PARAMOPS_TD
|
|
||||||
#define SCALEHLS_DIALECT_HLSCPP_PARAMOPS_TD
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// FuncParamOp
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
def FuncParamOp : HLSCppOp<"func_param", [
|
|
||||||
ParamOpInterface,
|
|
||||||
HasParent<"FuncOp">
|
|
||||||
]> {
|
|
||||||
let summary = "Hold function parameters";
|
|
||||||
let description = [{
|
|
||||||
This hlscpp.func_param operation holds parameters for function region.
|
|
||||||
}];
|
|
||||||
|
|
||||||
let arguments = (ins
|
|
||||||
// Pragma configuration parameters
|
|
||||||
// BoolAttr : $enable_pipeline,
|
|
||||||
// PositiveUI32Attr : $initial_interval,
|
|
||||||
|
|
||||||
// Resource utilization parameters
|
|
||||||
UI32Attr : $lut,
|
|
||||||
UI32Attr : $dsp,
|
|
||||||
UI32Attr : $bram
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// LoopParamOp
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
def LoopParamOp : HLSCppOp<"loop_param", [
|
|
||||||
ParamOpInterface,
|
|
||||||
HasParent<"AffineForOp">
|
|
||||||
]> {
|
|
||||||
let summary = "Hold loop parameters";
|
|
||||||
let description = [{
|
|
||||||
This hlscpp.loop_param operation holds parameters for loop region.
|
|
||||||
}];
|
|
||||||
|
|
||||||
let arguments = (ins
|
|
||||||
// Pragma configuration parameters
|
|
||||||
BoolAttr : $enable_pipeline,
|
|
||||||
PositiveUI32Attr : $initial_interval,
|
|
||||||
PositiveUI32Attr : $unroll_factor,
|
|
||||||
|
|
||||||
// Performance parameters
|
|
||||||
UI32Attr : $loop_bound,
|
|
||||||
UI32Attr : $nonproc_latency,
|
|
||||||
UI32Attr : $iteration_latency,
|
|
||||||
UI32Attr : $latency,
|
|
||||||
|
|
||||||
// Resource utilization parameters
|
|
||||||
UI32Attr : $lut,
|
|
||||||
UI32Attr : $dsp,
|
|
||||||
UI32Attr : $bram
|
|
||||||
);
|
|
||||||
|
|
||||||
let extraClassDeclaration = [{
|
|
||||||
unsigned getUnrollFactor() {
|
|
||||||
return getAttrOfType<IntegerAttr>("unroll_factor").getUInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned getLoopBound() {
|
|
||||||
return getAttrOfType<IntegerAttr>("loop_bound").getUInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned getNonprocLatency() {
|
|
||||||
return getAttrOfType<IntegerAttr>("nonproc_latency").getUInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned getIterationLatency() {
|
|
||||||
return getAttrOfType<IntegerAttr>("iteration_latency").getUInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned getLatency() {
|
|
||||||
return getAttrOfType<IntegerAttr>("latency").getUInt();
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// IfParamOp
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
def IfParamOp : HLSCppOp<"if_param", [
|
|
||||||
ParamOpInterface,
|
|
||||||
HasParent<"AffineIfOp">
|
|
||||||
]> {
|
|
||||||
let summary = "Hold if region parameters";
|
|
||||||
let description = [{
|
|
||||||
This hlscpp.if_param operation holds parameters for if regions, including
|
|
||||||
then region and else region (if applicable).
|
|
||||||
}];
|
|
||||||
|
|
||||||
let arguments = (ins
|
|
||||||
// Performance parameters
|
|
||||||
UI32Attr : $latency,
|
|
||||||
|
|
||||||
// Resource utilization parameters
|
|
||||||
UI32Attr : $lut,
|
|
||||||
UI32Attr : $dsp,
|
|
||||||
UI32Attr : $bram
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// ArrayParamOp
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
def ArrayParamOp : HLSCppOp<"array_param", [
|
|
||||||
ParamOpInterface
|
|
||||||
]> {
|
|
||||||
let summary = "Hold array parameters";
|
|
||||||
let description = [{
|
|
||||||
This hlscpp.array_param operation holds parameters for arrays.
|
|
||||||
}];
|
|
||||||
|
|
||||||
let arguments = (ins
|
|
||||||
// Pragma configuration parameters
|
|
||||||
StorageTypeAttr : $storage_type,
|
|
||||||
PartitionTypeAttr : $partition_type,
|
|
||||||
PositiveUI32ArrayAttr : $partition_factor,
|
|
||||||
|
|
||||||
// Performance parameters
|
|
||||||
UI32Attr : $reads,
|
|
||||||
UI32Attr : $writes,
|
|
||||||
PositiveUI32Attr : $read_ports,
|
|
||||||
PositiveUI32Attr : $write_ports,
|
|
||||||
UI32Attr : $dependency_latency,
|
|
||||||
UI32Attr : $dependency_distance,
|
|
||||||
|
|
||||||
// Resource utilization parameters
|
|
||||||
UI32Attr : $lut,
|
|
||||||
UI32Attr : $bram
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // SCALEHLS_DIALECT_HLSCPP_PARAMOPS_TD
|
|
|
@ -16,7 +16,6 @@ namespace mlir {
|
||||||
namespace scalehls {
|
namespace scalehls {
|
||||||
namespace hlscpp {
|
namespace hlscpp {
|
||||||
|
|
||||||
std::unique_ptr<mlir::Pass> createStaticAnalysisPass();
|
|
||||||
std::unique_ptr<mlir::Pass> createQoREstimationPass();
|
std::unique_ptr<mlir::Pass> createQoREstimationPass();
|
||||||
std::unique_ptr<mlir::Pass> createPragmaDSEPass();
|
std::unique_ptr<mlir::Pass> createPragmaDSEPass();
|
||||||
|
|
||||||
|
|
|
@ -7,24 +7,12 @@
|
||||||
|
|
||||||
include "mlir/Pass/PassBase.td"
|
include "mlir/Pass/PassBase.td"
|
||||||
|
|
||||||
def StaticAnalysis : Pass<"hlscpp-static-analysis", "ModuleOp"> {
|
|
||||||
let summary = "Analyze CDFG and generate parameters for QoR estimation";
|
|
||||||
let description = [{
|
|
||||||
This hlscpp-static-analysis pass will analyze the input CDFG and insert
|
|
||||||
HLSCpp parameter operations for each function, loop, and other regions. The
|
|
||||||
extracted parameters will then be passed to QoREstimation for estimating
|
|
||||||
quality of results.
|
|
||||||
}];
|
|
||||||
|
|
||||||
let constructor = "mlir::scalehls::hlscpp::createStaticAnalysisPass()";
|
|
||||||
}
|
|
||||||
|
|
||||||
def QoREstimation : Pass<"hlscpp-qor-estimation", "ModuleOp"> {
|
def QoREstimation : Pass<"hlscpp-qor-estimation", "ModuleOp"> {
|
||||||
let summary = "Estimate the performance and resource utilization";
|
let summary = "Estimate the performance and resource utilization";
|
||||||
let description = [{
|
let description = [{
|
||||||
This hlscpp-qor-estimation pass will take HLSCpp parameter operations inside
|
This hlscpp-qor-estimation pass will analyze the input CDFG and pragma
|
||||||
of each function, loop, and other regions into consideration and estimate
|
operations (if applied) for estimating performance and resource utilization
|
||||||
performance and resource utilization of the HLS results.
|
of the HLS results.
|
||||||
}];
|
}];
|
||||||
|
|
||||||
let constructor = "mlir::scalehls::hlscpp::createQoREstimationPass()";
|
let constructor = "mlir::scalehls::hlscpp::createQoREstimationPass()";
|
||||||
|
@ -42,8 +30,8 @@ def QoREstimation : Pass<"hlscpp-qor-estimation", "ModuleOp"> {
|
||||||
def PragmaDSE : Pass<"hlscpp-pragma-dse", "ModuleOp"> {
|
def PragmaDSE : Pass<"hlscpp-pragma-dse", "ModuleOp"> {
|
||||||
let summary = "Optimize pragma configuration of each optimizable region";
|
let summary = "Optimize pragma configuration of each optimizable region";
|
||||||
let description = [{
|
let description = [{
|
||||||
This hlscpp-pragma-dse pass will automatically tune HLS pragma optimization
|
This hlscpp-pragma-dse pass will automatically tune HLS pragma insertion and
|
||||||
of each optimizable region for performance and area opt. By calling methods
|
configuration for performance and area optimization. By calling methods
|
||||||
provided by hlscpp-qor-estimation, this pass is able to rapidly obtain the
|
provided by hlscpp-qor-estimation, this pass is able to rapidly obtain the
|
||||||
QoR estimation of the current design point, and feed it back to the design
|
QoR estimation of the current design point, and feed it back to the design
|
||||||
space exploration engine for an efficient convergence.
|
space exploration engine for an efficient convergence.
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
/// This file is deprecated and will be removed in the future.
|
|
||||||
|
|
||||||
#ifndef SCALEHLS_DIALECT_HLSCPP_PRAGMAOPS_TD
|
#ifndef SCALEHLS_DIALECT_HLSCPP_PRAGMAOPS_TD
|
||||||
#define SCALEHLS_DIALECT_HLSCPP_PRAGMAOPS_TD
|
#define SCALEHLS_DIALECT_HLSCPP_PRAGMAOPS_TD
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ using namespace mlir;
|
||||||
using namespace scalehls;
|
using namespace scalehls;
|
||||||
using namespace hlscpp;
|
using namespace hlscpp;
|
||||||
|
|
||||||
|
/*
|
||||||
namespace {
|
namespace {
|
||||||
class QoREstimator {
|
class QoREstimator {
|
||||||
public:
|
public:
|
||||||
|
@ -104,10 +105,12 @@ void QoREstimator::estimateModule(ModuleOp module) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
struct QoREstimation : public QoREstimationBase<QoREstimation> {
|
struct QoREstimation : public QoREstimationBase<QoREstimation> {
|
||||||
void runOnOperation() override {
|
void runOnOperation() override {
|
||||||
QoREstimator(toolConfig, opLatency).estimateModule(getOperation());
|
// QoREstimator(toolConfig, opLatency).estimateModule(getOperation());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
//===------------------------------------------------------------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "Dialect/HLSCpp/HLSCpp.h"
|
|
||||||
#include "Dialect/HLSCpp/Passes.h"
|
|
||||||
|
|
||||||
using namespace mlir;
|
|
||||||
using namespace scalehls;
|
|
||||||
using namespace hlscpp;
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
struct StaticAnalysis : public StaticAnalysisBase<StaticAnalysis> {
|
|
||||||
void runOnOperation() {}
|
|
||||||
};
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
std::unique_ptr<mlir::Pass> hlscpp::createStaticAnalysisPass() {
|
|
||||||
return std::make_unique<StaticAnalysis>();
|
|
||||||
}
|
|
|
@ -164,10 +164,12 @@ public:
|
||||||
AddCFOp, SubCFOp, ImOp, ReOp, CreateComplexOp,
|
AddCFOp, SubCFOp, ImOp, ReOp, CreateComplexOp,
|
||||||
// Special operations.
|
// Special operations.
|
||||||
SelectOp, ConstantOp, CopySignOp, TruncateIOp, ZeroExtendIOp,
|
SelectOp, ConstantOp, CopySignOp, TruncateIOp, ZeroExtendIOp,
|
||||||
SignExtendIOp, IndexCastOp, CallOp, ReturnOp, AssignOp, EndOp>(
|
SignExtendIOp, IndexCastOp, CallOp, ReturnOp, AssignOp, EndOp,
|
||||||
[&](auto opNode) -> ResultType {
|
// Pragma operations.
|
||||||
return thisCast->visitOp(opNode, args...);
|
ApplyPragmasOp, PragmaPipelineOp, PragmaUnrollOp,
|
||||||
})
|
PragmaArrayPartitionOp>([&](auto opNode) -> ResultType {
|
||||||
|
return thisCast->visitOp(opNode, args...);
|
||||||
|
})
|
||||||
.Default([&](auto opNode) -> ResultType {
|
.Default([&](auto opNode) -> ResultType {
|
||||||
return thisCast->visitInvalidOp(op, args...);
|
return thisCast->visitInvalidOp(op, args...);
|
||||||
});
|
});
|
||||||
|
@ -288,6 +290,12 @@ public:
|
||||||
HANDLE(ReturnOp);
|
HANDLE(ReturnOp);
|
||||||
HANDLE(AssignOp);
|
HANDLE(AssignOp);
|
||||||
HANDLE(EndOp);
|
HANDLE(EndOp);
|
||||||
|
|
||||||
|
// Pragma operations.
|
||||||
|
HANDLE(ApplyPragmasOp);
|
||||||
|
HANDLE(PragmaPipelineOp);
|
||||||
|
HANDLE(PragmaUnrollOp);
|
||||||
|
HANDLE(PragmaArrayPartitionOp);
|
||||||
#undef HANDLE
|
#undef HANDLE
|
||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -341,6 +349,12 @@ public:
|
||||||
void emitCall(CallOp *op);
|
void emitCall(CallOp *op);
|
||||||
void emitAssign(AssignOp *op);
|
void emitAssign(AssignOp *op);
|
||||||
|
|
||||||
|
/// Pragma operation emitters.
|
||||||
|
void emitApplyPragmas(ApplyPragmasOp *op);
|
||||||
|
void emitPragmaPipeline(PragmaPipelineOp *op);
|
||||||
|
void emitPragmaUnroll(PragmaUnrollOp *op);
|
||||||
|
void emitPragmaArrayPartition(PragmaArrayPartitionOp *op);
|
||||||
|
|
||||||
/// Top-level MLIR module emitter.
|
/// Top-level MLIR module emitter.
|
||||||
void emitModule(ModuleOp module);
|
void emitModule(ModuleOp module);
|
||||||
|
|
||||||
|
@ -621,6 +635,20 @@ public:
|
||||||
|
|
||||||
using HLSCppVisitorBase::visitOp;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ModuleEmitter &emitter;
|
ModuleEmitter &emitter;
|
||||||
};
|
};
|
||||||
|
@ -1173,6 +1201,51 @@ void ModuleEmitter::emitAssign(AssignOp *op) {
|
||||||
emitNestedLoopTail(rank);
|
emitNestedLoopTail(rank);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Pragma operation emitters.
|
||||||
|
void ModuleEmitter::emitApplyPragmas(ApplyPragmasOp *op) {
|
||||||
|
emitBlock(*op->getBody());
|
||||||
|
os << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModuleEmitter::emitPragmaPipeline(PragmaPipelineOp *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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
indent();
|
||||||
|
os << "#pragma HLS array_partition";
|
||||||
|
os << " variable=";
|
||||||
|
emitValue(op->getOperand());
|
||||||
|
os << " " << op->getPartitionType();
|
||||||
|
if (op->getPartitionType() != "complete")
|
||||||
|
os << " factor=" << op->getFactor();
|
||||||
|
os << " dim=" << op->getDim();
|
||||||
|
os << "\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
/// C++ component emitters.
|
/// C++ component emitters.
|
||||||
void ModuleEmitter::emitValue(Value val, unsigned rank, bool isPtr) {
|
void ModuleEmitter::emitValue(Value val, unsigned rank, bool isPtr) {
|
||||||
assert(!(rank && isPtr) && "should be either an array or a pointer.");
|
assert(!(rank && isPtr) && "should be either an array or a pointer.");
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// RUN: scalehls-opt -hlscpp-static-analysis -hlscpp-pragma-dse %s | FileCheck %s
|
// RUN: scalehls-opt -hlscpp-pragma-dse %s | FileCheck %s
|
||||||
|
|
||||||
// CHECK-LABEL: func @test_pragma()
|
// CHECK-LABEL: func @test_pragma()
|
||||||
func @test_pragma() {
|
func @test_pragma() {
|
||||||
|
|
Loading…
Reference in New Issue