Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DOT output format #48

Merged
merged 3 commits into from
Aug 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ The list of arguments for `hls`-mode is presented below:
* `--out-sv-lib <PATH>`: *optional* filesystem-path option; used to specify the output SystemVerilog file for generated operations library.
* `--out-dfcir <PATH>`: *optional* filesystem-path option; used to specify the output DFCIR file.
* `--out-firrtl <PATH>`: *optional* filesystem-path option; used to specify the output FIRRTL file.
* `--out-dot <PATH>`: *optional* filesystem-path option; used to specify the output DOT file.
* `-a` or `-l`: *required* flag; used to specify the chosen scheduling strategy - either as-soon-as-possible or linear programming. **Exactly one of these flags has to be specified**.

**At least one of the `out-*` options has to be specified.**
Expand Down
3 changes: 2 additions & 1 deletion config.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"out_sv" : "",
"out_sv_lib" : "",
"out_dfcir" : "",
"out_firrtl" : ""
"out_firrtl" : "",
"out_dot" : ""
}
}
2 changes: 1 addition & 1 deletion src/model/dfcxx/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.20 FATAL_ERROR)
project(DFCXX LANGUAGES C CXX)
set(CMAKE_CXX_STANDARD 17)

find_package(CTemplate REQUIRED COMPONENTS nothreads)
add_subdirectory(include)
add_subdirectory(includeDev)
add_subdirectory(lib)
8 changes: 8 additions & 0 deletions src/model/dfcxx/include/dfcxx/kernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@
#include <string_view>
#include <vector>

// This forward declaration is needed to avoid
// users having to include LLVM headers.
namespace llvm {
class raw_fd_ostream;
}

namespace dfcxx {

class DFCIRBuilder;
Expand All @@ -36,6 +42,8 @@ class Kernel {
TypeBuilder typeBuilder;
VarBuilder varBuilder;
Graph graph;

bool compileDot(llvm::raw_fd_ostream *stream);

protected:
IO io;
Expand Down
1 change: 1 addition & 0 deletions src/model/dfcxx/include/dfcxx/typedefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ enum class OutputFormatID : uint8_t {
SVLibrary,
DFCIR,
FIRRTL,
DOT,
// Utility value. Constains the number of elements in the enum.
COUNT
};
Expand Down
1 change: 1 addition & 0 deletions src/model/dfcxx/includeDev/dfcxx/converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "dfcxx/typedefs.h"

#include "dfcir/conversions/DFCIRPasses.h"
#include "llvm/Support/raw_ostream.h"
#include "mlir/IR/BuiltinOps.h"

#include <string>
Expand Down
9 changes: 9 additions & 0 deletions src/model/dfcxx/lib/dfcxx/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ target_include_directories(DFCXX
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/includeDev>
)

set(TEMPLATES_PATH "${PROJECT_SOURCE_DIR}/templates")

add_compile_definitions(
TEMPLATES_PATH="${TEMPLATES_PATH}"
DOT_TEMPLATE_PATH="${TEMPLATES_PATH}/dot.tpl"
)

## MLIRDFCIR is ensured to be compiled beforehand.
target_link_libraries(DFCXX
PRIVATE $<LINK_ONLY:MLIRPass>
Expand All @@ -49,6 +56,8 @@ target_link_libraries(DFCXX
PRIVATE $<LINK_ONLY:CIRCTFIRRTLToHW>
PRIVATE $<LINK_ONLY:CIRCTSeqToSV>
PRIVATE $<LINK_ONLY:CIRCTExportVerilog>
PRIVATE $<LINK_ONLY:CTemplate::nothreads>
PRIVATE $<LINK_ONLY:LLVMSupport>
)

add_library(Utopia::DFCXX ALIAS DFCXX)
108 changes: 105 additions & 3 deletions src/model/dfcxx/lib/dfcxx/kernel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,15 @@
#include "dfcxx/converter.h"
#include "dfcxx/IRbuilders/builder.h"
#include "dfcxx/kernel.h"
#include "dfcxx/vars/constant.h"

#include "ctemplate/template.h"
#include "llvm/Support/raw_ostream.h"

#include <ctime>
#include <iostream>
#include <string>
#include <unordered_map>

namespace dfcxx {

Expand Down Expand Up @@ -40,6 +47,94 @@ DFType Kernel::dfBool() {
return DFType(storage.addType(type));
}

bool Kernel::compileDot(llvm::raw_fd_ostream *stream) {
using ctemplate::TemplateDictionary;

uint64_t counter = 0;
std::unordered_map<Node, std::string> idMapping;
auto getName = [&idMapping, &counter] (const Node &node) -> std::string {
// If the node is named - just return the name.
auto name = DFVariable(node.var).getName();
if (!name.empty()) {
return name.data();
}
// If the mapping contains the node name - return it.
auto it = idMapping.find(node);
if (it != idMapping.end()) {
return it->second;
}
// Otherwise create and return the new node name mapping.
return (idMapping[node] = "node" + std::to_string(counter++));
};

std::string result;
TemplateDictionary *dict = new TemplateDictionary("dot");
dict->SetValue("KERNEL_NAME", this->getName().data());
auto time = std::time(nullptr);
auto *localTime = std::localtime(&time);
dict->SetFormattedValue("GEN_TIME",
"%d-%d-%d %d:%d:%d",
localTime->tm_mday,
localTime->tm_mon + 1,
localTime->tm_year + 1900,
localTime->tm_hour,
localTime->tm_min,
localTime->tm_sec);

for (Node node : graph.nodes) {
TemplateDictionary *elem = dict->AddSectionDictionary("ELEMENTS");
auto name = getName(node);
elem->SetValue("NAME", name);
std::string shape = "box";
std::string label = name;
auto data = node.data;
switch (node.type) {
case OFFSET:
shape = "diamond";
label = std::to_string(data.offset);
break;
case IN: shape = "invtriangle"; break;
case OUT: shape = "triangle"; break;
case MUX: shape = "invtrapezium"; break;
case ADD: label = "+"; break;
case SUB: label = "-"; break;
case MUL: label = "*"; break;
case DIV: label = "/"; break;
case AND: label = "&"; break;
case OR: label = "|"; break;
case XOR: label = "^"; break;
case NOT: label = "!"; break;
case NEG: label = "-"; break;
case LESS: label = "<"; break;
case LESSEQ: label = "<="; break;
case GREATER: label = ">"; break;
case GREATEREQ: label = ">="; break;
case EQ: label = "=="; break;
case NEQ: label = "!="; break;
case SHL: label = "<< " + std::to_string(data.bitShift); break;
case SHR: label = ">> " + std::to_string(data.bitShift); break;
default: break; // Silences -Wswitch warning for "CONST".
}

elem->SetValue("SHAPE", shape);
elem->SetValue("LABEL", label);

unsigned i = 0;
for (Channel chan : graph.inputs[node]) {
TemplateDictionary *conn = elem->AddSectionDictionary("CONNECTIONS");
conn->SetValue("SRC_NAME", getName(chan.source));
conn->SetValue("TRG_NAME", name);
conn->SetValue("CON_LABEL", std::to_string(i++));
}
}

ctemplate::ExpandTemplate(DOT_TEMPLATE_PATH, ctemplate::DO_NOT_STRIP,
dict, &result);
delete dict;

*stream << result;
return true;
}

bool Kernel::compile(const DFLatencyConfig &config,
const std::vector<std::string> &outputPaths,
Expand All @@ -55,9 +150,16 @@ bool Kernel::compile(const DFLatencyConfig &config,
? new llvm::raw_fd_ostream(outputPaths[i], ec)
: nullptr;
}
bool result = DFCIRConverter(config).convertAndPrint(compiled,
outputStreams,
sched);
bool result = true;
// Compile the kernel to DOT if such stream is specified.
if (auto *stream = outputStreams[OUT_FORMAT_ID_INT(DOT)]) {
result &= compileDot(stream);
}
if (result) {
result &= DFCIRConverter(config).convertAndPrint(compiled,
outputStreams,
sched);
}
// Every created output stream has to be closed explicitly.
for (llvm::raw_fd_ostream *stream : outputStreams) {
if (stream) {
Expand Down
15 changes: 15 additions & 0 deletions src/model/dfcxx/templates/dot.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{{#LICENSE}}
{{!===---------------------------------------------------------------------===}}
{{! }}
{{! Part of the Utopia HLS Project, under the Apache License v2.0 }}
{{! SPDX-License-Identifier: Apache-2.0 }}
{{! Copyright 2024 ISP RAS (http://www.ispras.ru) }}
{{! }}
{{!===---------------------------------------------------------------------===}}
{{/LICENSE}}// This file has been automatically generated by Utopia HLS at {{GEN_TIME}}.
digraph {{KERNEL_NAME}} {
{{#ELEMENTS}}{{NAME}} [shape={{SHAPE}}, label="{{LABEL}}"]
{{#CONNECTIONS}}{{SRC_NAME}} -> {{TRG_NAME}} [label="{{CON_LABEL}}"]
{{/CONNECTIONS}}
{{/ELEMENTS}}
}
6 changes: 6 additions & 0 deletions src/options.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#define OUT_SV_LIB_JSON "out_sv_lib"
#define OUT_DFCIR_JSON "out_dfcir"
#define OUT_FIRRTL_JSON "out_firrtl"
#define OUT_DOT_JSON "out_dot"

//===----------------------------------------------------------------------===//
// CLI args/flags definitions
Expand All @@ -53,6 +54,7 @@
#define OUT_SV_LIB_ARG CLI_ARG("out-sv-lib")
#define OUT_DFCIR_ARG CLI_ARG("out-dfcir")
#define OUT_FIRRTL_ARG CLI_ARG("out-firrtl")
#define OUT_DOT_ARG CLI_ARG("out-dot")

//===----------------------------------------------------------------------===//

Expand Down Expand Up @@ -195,6 +197,9 @@ struct HlsOptions final : public AppOptions {
outputGroup->add_option(OUT_FIRRTL_ARG,
outNames[OUT_FORMAT_ID_INT(FIRRTL)],
"Path to output scheduled FIRRTL");
outputGroup->add_option(OUT_DOT_ARG,
outNames[OUT_FORMAT_ID_INT(DOT)],
"Path to output a DFCxx kernel in DOT format.");
outputGroup->require_option();
}

Expand All @@ -206,6 +211,7 @@ struct HlsOptions final : public AppOptions {
get(json, OUT_SV_LIB_JSON, outNames[OUT_FORMAT_ID_INT(SVLibrary)]);
get(json, OUT_DFCIR_JSON, outNames[OUT_FORMAT_ID_INT(DFCIR)]);
get(json, OUT_FIRRTL_JSON, outNames[OUT_FORMAT_ID_INT(FIRRTL)]);
get(json, OUT_DOT_JSON, outNames[OUT_FORMAT_ID_INT(DOT)]);
}

std::string latConfigFile;
Expand Down
11 changes: 10 additions & 1 deletion test/model/dfcxx/output_formats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,22 @@ TEST(DFCxxOutputFormats, FIRRTL) {
EXPECT_EQ(kernel.compile(config, paths, dfcxx::ASAP), true);
}

TEST(DFCxxOutputFormats, DOT) {
Polynomial2 kernel;
DFOutputPaths paths = {
{dfcxx::OutputFormatID::DOT, NULLDEVICE}
};
EXPECT_EQ(kernel.compile(config, paths, dfcxx::ASAP), true);
}

TEST(DFCxxOutputFormats, All) {
Polynomial2 kernel;
DFOutputPaths paths = {
{dfcxx::OutputFormatID::SystemVerilog, NULLDEVICE},
{dfcxx::OutputFormatID::SVLibrary, NULLDEVICE},
{dfcxx::OutputFormatID::DFCIR, NULLDEVICE},
{dfcxx::OutputFormatID::FIRRTL, NULLDEVICE}
{dfcxx::OutputFormatID::FIRRTL, NULLDEVICE},
{dfcxx::OutputFormatID::DOT, NULLDEVICE}
};
EXPECT_EQ(kernel.compile(config, paths, dfcxx::ASAP), true);
}