Skip to content

Commit

Permalink
Use namespace-level const string for magic attr names
Browse files Browse the repository at this point in the history
  • Loading branch information
hanchenye committed Apr 14, 2024
1 parent f176352 commit f339435
Show file tree
Hide file tree
Showing 8 changed files with 95 additions and 58 deletions.
9 changes: 9 additions & 0 deletions include/scalehls/Dialect/HLS/IR/HLS.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,15 @@ namespace mlir {
namespace scalehls {
namespace hls {

const std::string kTopAttrName = "hls.__top__";
const std::string kEntryAttrName = "hls.__entry__";
const std::string kPipelineAttrName = "hls.__pipeline__";
const std::string kDataflowAttrName = "hls.__dataflow__";
const std::string kPartitionAttrName = "hls.__partition__";
const std::string kStableAttrName = "hls.__stable__";
const std::string kLocationAttrName = "hls.__location__";
const std::string kCopyAttrName = "hls.__copy__";

/// Get or check the memory kind of a type.
MemoryKind getMemoryKind(MemRefType type);

Expand Down
10 changes: 5 additions & 5 deletions lib/Dialect/HLS/Transforms/ApplyDirectives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ struct ApplyDirectives
SmallVector<affine::AffineForOp> loopsToPipeline;
SmallVector<affine::AffineForOp> loopsToDataflow;
func.walk([&](affine::AffineForOp loop) {
if (loop->hasAttr("__pipeline__"))
if (loop->hasAttr(kPipelineAttrName))
loopsToPipeline.push_back(loop);
else if (loop->hasAttr("__dataflow__"))
else if (loop->hasAttr(kDataflowAttrName))
loopsToDataflow.push_back(loop);
});

Expand All @@ -64,17 +64,17 @@ struct ApplyDirectives
auto band = getLoopBandFromInnermostLoop(loop);
if (affine::isPerfectlyNested(band) &&
succeeded(affine::coalesceLoops(band)))
band.front()->setAttr("__dataflow__", builder.getUnitAttr());
band.front()->setAttr(kDataflowAttrName, builder.getUnitAttr());
}

// Apply partition layout to all buffers.
func.walk([](hls::BufferOp buffer) {
if (auto layoutAttr =
buffer->getAttrOfType<PartitionLayoutAttr>("__partition__")) {
buffer->getAttrOfType<PartitionLayoutAttr>(kPartitionAttrName)) {
buffer.getResult().setType(
MemRefType::get(buffer.getType().getShape(),
buffer.getType().getElementType(), layoutAttr));
buffer->removeAttr("__partition__");
buffer->removeAttr(kPartitionAttrName);
}
});
}
Expand Down
3 changes: 2 additions & 1 deletion lib/Dialect/HLS/Transforms/ComprehensiveBufferize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ static Operation *createLinalgCopyOp(OpBuilder &b, Location loc, Value from,
utils::IteratorType::parallel);

SmallVector<NamedAttribute> linalgAttributes(attributes);
linalgAttributes.emplace_back(b.getStringAttr("__copy__"), b.getUnitAttr());
linalgAttributes.emplace_back(b.getStringAttr(kCopyAttrName),
b.getUnitAttr());

return b.create<linalg::GenericOp>(
loc, from, to, llvm::ArrayRef({id, id}), iteratorTypes,
Expand Down
21 changes: 19 additions & 2 deletions lib/Dialect/HLS/Transforms/ConvertDataflowToFunc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ struct ConvertTaskToFunc : public OpRewritePattern<TaskOp> {
// Collect all live-ins of the task.
rewriter.setInsertionPointToStart(&task.getBody().front());
SmallVector<Value, 8> operands;
SmallVector<int64_t> stableIndices;
unsigned index = 0;
auto liveins = task.getLiveIns();
for (auto livein : liveins) {
if (auto constLivein = livein.getDefiningOp<arith::ConstantOp>()) {
Expand All @@ -46,8 +48,17 @@ struct ConvertTaskToFunc : public OpRewritePattern<TaskOp> {
rewriter.replaceUsesWithIf(livein, cloneLivein, [&](OpOperand &use) {
return task->isAncestor(use.getOwner());
});
} else
} else {
operands.push_back(livein);
if (livein.getDefiningOp<memref::GetGlobalOp>())
stableIndices.push_back(index);
else if (auto arg = dyn_cast<BlockArgument>(livein))
if (auto func = arg.getDefiningOp<func::FuncOp>())
if (func.getArgAttrOfType<UnitAttr>(arg.getArgNumber(),
kStableAttrName))
stableIndices.push_back(index);
index++;
}
}

// Create a new sub-function.
Expand All @@ -56,12 +67,18 @@ struct ConvertTaskToFunc : public OpRewritePattern<TaskOp> {
task.getLoc(), task.getNameAttr(),
rewriter.getFunctionType(TypeRange(operands), TypeRange()));
if (task.getLocation())
subFunc->setAttr("__location__", task.getLocationAttr());
subFunc->setAttr(kLocationAttrName, task.getLocationAttr());

// Apply all attributes from the task to the sub-function.
for (auto attr : task->getAttrs())
if (attr.getName() != task.getLocationAttrName() &&
attr.getName() != task.getNameAttrName())
subFunc->setAttr(attr.getName(), attr.getValue());

// Mark stable arguments.
for (auto index : stableIndices)
subFunc.setArgAttr(index, kStableAttrName, rewriter.getUnitAttr());

// Construct the body and arguments of the sub-function.
auto subFuncBlock = rewriter.createBlock(&subFunc.getBody());
auto subFuncArgs = subFuncBlock->addArguments(
Expand Down
10 changes: 5 additions & 5 deletions lib/Dialect/HLS/Transforms/GenerateDirectives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,22 +57,22 @@ struct GenerateDirectives

// Set dataflow directive for the function if it contains any task.
if (!func.getOps<hls::TaskOp>().empty())
func->setAttr("__dataflow__", builder.getUnitAttr());
func->setAttr(kDataflowAttrName, builder.getUnitAttr());

func.walk([&](hls::TaskOp task) {
// Set dataflow directive for the task if it contains any task.
if (!task.getOps<hls::TaskOp>().empty())
task->setAttr("__dataflow__", builder.getUnitAttr());
task->setAttr(kDataflowAttrName, builder.getUnitAttr());
});

llvm::SmallDenseMap<BufferOp, SmallVector<Partition>> partitionsMap;
func.walk([&](scf::ForOp loop) {
// Set dataflow directive if the loop contains any task. Otherwise, set
// pipeline directive if the loop is leaf loop.
if (!loop.getOps<hls::TaskOp>().empty())
loop->setAttr("__dataflow__", builder.getUnitAttr());
loop->setAttr(kDataflowAttrName, builder.getUnitAttr());
else if (isLeafLoop(loop)) {
loop->setAttr("__pipeline__", builder.getUnitAttr());
loop->setAttr(kPipelineAttrName, builder.getUnitAttr());

for (auto subview : loop.getOps<memref::SubViewOp>()) {
auto buffer = subview.getSource().getDefiningOp<BufferOp>();
Expand Down Expand Up @@ -111,7 +111,7 @@ struct GenerateDirectives

auto layoutAttr =
hls::PartitionLayoutAttr::get(builder.getContext(), kinds, factors);
buffer->setAttr("__partition__", layoutAttr);
buffer->setAttr(kPartitionAttrName, layoutAttr);
}
}
};
Expand Down
4 changes: 2 additions & 2 deletions lib/Dialect/HLS/Transforms/ScheduleDataflow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,9 +204,9 @@ struct ScheduleDataflow
continue;
auto taskName = func.getName().str() + "_top_" + std::to_string(taskId++);
auto task = wrapOpsIntoTask(ops, taskName, location, builder);
task->setAttr("__top__", builder.getUnitAttr());
task->setAttr(kTopAttrName, builder.getUnitAttr());
}
func->setAttr("__entry__", builder.getUnitAttr());
func->setAttr(kEntryAttrName, builder.getUnitAttr());
}

/// Infer and apply the locations of tensor/itensor instance ops based on the
Expand Down
39 changes: 19 additions & 20 deletions lib/Translation/EmitHLSCpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -673,9 +673,7 @@ bool ExprVisitor::visitOp(arith::CmpIOp op) {
//===----------------------------------------------------------------------===//

/// HLS dialect operation emitters.
void ModuleEmitter::emitBuffer(BufferOp op) {
emitAlloc(op);
}
void ModuleEmitter::emitBuffer(BufferOp op) { emitAlloc(op); }

void ModuleEmitter::emitStreamChannel(StreamOp op) {
indent();
Expand Down Expand Up @@ -1644,13 +1642,9 @@ void ModuleEmitter::emitLoopDirectives(Operation *loop) {
if (!emitDirectives())
return;

if (loop->hasAttr("__pipeline__")) {
indent() << "#pragma HLS pipeline";
if (auto ii = loop->getAttrOfType<IntegerAttr>("__ii__"))
os << " II=" << cast<IntegerAttr>(ii).getInt() << "\n";
else
os << "\n";
} else if (loop->hasAttr("__dataflow__"))
if (loop->hasAttr(kPipelineAttrName)) {
indent() << "#pragma HLS pipeline\n";
} else if (loop->hasAttr(kDataflowAttrName))
indent() << "#pragma HLS dataflow\n";
}

Expand Down Expand Up @@ -1709,12 +1703,13 @@ void ModuleEmitter::emitFunctionDirectives(func::FuncOp func,
// Only top function should emit interface pragmas.
if (isTopFunc) {
indent() << "#pragma HLS interface s_axilite port=return\n";
for (auto &port : portList) {
if (isa<MemRefType>(port.getType())) {
for (auto port : portList) {
if (auto memrefType = dyn_cast<MemRefType>(port.getType())) {
indent() << "#pragma HLS interface m_axi offset=slave port=";
emitValue(port);
os << " bundle=";
emitValue(port);
os << " depth=" << memrefType.getNumElements();
os << " max_widen_bitwidth=" << axiMaxWidenBitwidth();
os << "\n";
emitArrayDirectives(cast<TypedValue<MemRefType>>(port), true);
Expand All @@ -1735,29 +1730,33 @@ void ModuleEmitter::emitFunctionDirectives(func::FuncOp func,
}
}

if (func->getAttr("__inline__"))
indent() << "#pragma HLS inline\n";
for (auto arg : func.getArguments())
if (func.getArgAttr(arg.getArgNumber(), kStableAttrName)) {
indent() << "#pragma HLS stable variable=";
emitValue(arg);
os << "\n";
}

if (func->hasAttr("__pipeline__")) {
if (func->hasAttr(kPipelineAttrName)) {
indent() << "#pragma HLS pipeline\n";
// An empty line.
os << "\n";
} else if (func->hasAttr("__dataflow__")) {
} else if (func->hasAttr(kDataflowAttrName)) {
indent() << "#pragma HLS dataflow\n";
// An empty line.
os << "\n";
}
}

void ModuleEmitter::emitFunction(func::FuncOp func) {
if (auto location = func->getAttrOfType<StringAttr>("__location__"))
if (auto location = func->getAttrOfType<StringAttr>(kLocationAttrName))
if (location == "pl") {
if (func->hasAttr("__top__"))
if (func->hasAttr(kTopAttrName))
os << "/// Top PL function.\n";
setEmitDirectives();
}

if (func->hasAttr("__entry__"))
if (func->hasAttr(kEntryAttrName))
os << "/// Entry function.\n";

if (func.getBlocks().size() != 1)
Expand Down Expand Up @@ -1809,7 +1808,7 @@ void ModuleEmitter::emitFunction(func::FuncOp func) {
// Emit function body.
addIndent();

emitFunctionDirectives(func, portList, func->hasAttr("__top__"));
emitFunctionDirectives(func, portList, func->hasAttr(kTopAttrName));
emitBlock(func.front());
reduceIndent();
os << "}\n";
Expand Down
57 changes: 34 additions & 23 deletions python/scalehls/transforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,7 @@ def verify(self):
# ===----------------------------------------------------------------------=== #


k_linalg_dsg_id_name = "__linalg_dsg_id__"
k_linalg_dsg_id_attr_name = "hls.__linalg_dsg_id__"


class LinalgDesignSpaceGraph(BaseDesignSpaceGraph):
Expand All @@ -675,7 +675,7 @@ def __init__(self, module: Module, entry: str = "forward"):
self.add_node(op, name=op.name, id=id,
parent=self.top, children=[])
self.nodes[self.top]["children"].append(op)
op.attributes[k_linalg_dsg_id_name] = i64_attr(id)
op.attributes[k_linalg_dsg_id_attr_name] = i64_attr(id)
for operand in op.operands:
if not isinstance(operand.owner, Block):
prev = operand.owner
Expand Down Expand Up @@ -790,7 +790,7 @@ def construct_linalg_transform_sequence(target: BlockArgument,
"""
for node, data in graph.nodes(data=True):
node_handle = match(target, [data["name"]], {
k_linalg_dsg_id_name: i64_attr(data["id"])})
k_linalg_dsg_id_attr_name: i64_attr(data["id"])})

if isinstance(node, linalg.GenericOp):
if "parallel_tile_sizes" not in data:
Expand All @@ -809,7 +809,7 @@ def construct_linalg_transform_sequence(target: BlockArgument,
data["unroll_sizes"],
data["permutation"],
len(node.inputs) > 0)
annotate(linalg_op_handle, k_linalg_dsg_id_name,
annotate(linalg_op_handle, k_linalg_dsg_id_attr_name,
i64_param(data["id"]))

if isinstance(node, tensor.ExpandShapeOp):
Expand All @@ -823,7 +823,7 @@ def construct_linalg_transform_sequence(target: BlockArgument,
data["source_tile_sizes"],
data["result_tile_sizes"])
annotate(convert_op.itensor_reassociate,
k_linalg_dsg_id_name, i64_param(data["id"]))
k_linalg_dsg_id_attr_name, i64_param(data["id"]))

if isinstance(node, tensor.CollapseShapeOp):
if "source_tile_sizes" not in data:
Expand All @@ -836,7 +836,7 @@ def construct_linalg_transform_sequence(target: BlockArgument,
data["source_tile_sizes"],
data["result_tile_sizes"])
annotate(convert_op.itensor_reassociate,
k_linalg_dsg_id_name, i64_param(data["id"]))
k_linalg_dsg_id_attr_name, i64_param(data["id"]))
return []


Expand All @@ -846,14 +846,14 @@ def apply_linalg_design_space(graph: LinalgDesignSpaceGraph,
graph.module,
construct_linalg_transform_sequence(graph.module, graph),
delete_sequence)
apply_strip_annotations(graph.module, k_linalg_dsg_id_name)
apply_strip_annotations(graph.module, k_linalg_dsg_id_attr_name)

# ===----------------------------------------------------------------------=== #
# DataflowDesignSpaceGraph Class
# ===----------------------------------------------------------------------=== #


k_dataflow_dsg_id_name = "__dataflow_dsg_id__"
k_dataflow_dsg_id_attr_name = "hls.__dataflow_dsg_id__"


class DataflowDesignSpaceGraph(BaseDesignSpaceGraph):
Expand All @@ -868,7 +868,7 @@ def add_task_node(op: OpView):
self.add_node(op, name=op.name,
id=id[0], parent=parent, children=[])
self.nodes[parent]["children"].append(op)
op.attributes[k_dataflow_dsg_id_name] = i64_attr(id[0])
op.attributes[k_dataflow_dsg_id_attr_name] = i64_attr(id[0])
id[0] += 1

for operand in hls.get_live_ins(op):
Expand Down Expand Up @@ -1001,20 +1001,28 @@ def generate_testbench(self,
def generate_config(self,
hls_top: str,
file_paths: List[str],
tb_file_path: List[str]):
tb_file_path: List[str],
dataflow_profiling: bool = False,
fifo_sizing: bool = False):
config_path = f"{self.work_path}/{hls_top}_config.ini"
lines = [
f"part={self.part}\n\n",
f"[hls]\n",
f"clock={self.clock_period}\n",
f"clock_uncertainty=15%\n",
f"flow_target=vitis\n",
*[f"syn.file={file_path}\n" for file_path in file_paths],
f"syn.top={hls_top}\n",
*[f"tb.file={file_path}\n" for file_path in tb_file_path]
]
if dataflow_profiling:
lines.append(
"cosim.enable_dataflow_profiling=true\n")
if fifo_sizing:
lines.append("cosim.enable_fifo_sizing=true\n")

with open(config_path, "w") as config_file:
config_file.writelines([
f"part={self.part}\n\n",
f"[hls]\n",
f"clock={self.clock_period}\n",
f"clock_uncertainty=15%\n",
f"flow_target=vitis\n",
*[f"syn.file={file_path}\n" for file_path in file_paths],
f"syn.top={hls_top}\n",
*[f"tb.file={file_path}\n" for file_path in tb_file_path],
f"syn.dataflow.default_channel=pingpong\n"
])
config_file.writelines(lines)
return config_file, config_path

def run(self,
Expand All @@ -1025,7 +1033,9 @@ def run(self,
output: Tensor,
csim: bool = True,
csynth: bool = True,
cosim: bool = False):
cosim: bool = False,
dataflow_profiling: bool = False,
fifo_sizing: bool = False):
design_path = f"{self.work_path}/{entry}.cpp"
with open(design_path, "w") as design_file:
emit_hlscpp(module, design_file, omit_global_constants=False)
Expand All @@ -1034,7 +1044,8 @@ def run(self,
entry, [design_path], input, output)

config_file, config_path = self.generate_config(
hls_top, [design_path], testbench_paths)
hls_top, [design_path], testbench_paths, dataflow_profiling,
fifo_sizing)

work_path = f"{self.work_path}/{entry}_{hls_top}"
if csim:
Expand Down

0 comments on commit f339435

Please sign in to comment.