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

slang-reflect: Add support to reflect Unions #1173

Merged
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
3 changes: 3 additions & 0 deletions include/slang/ast/types/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ class SLANG_EXPORT Type : public Symbol {
/// Indicates whether this is a dynamic array, associative array, or a queue.
bool isDynamicallySizedArray() const;

/// Indicates whether this is a packed or unpacked union.
bool isUnion() const;

/// Indicates whether this is a tagged union, packed or unpacked.
bool isTaggedUnion() const;

Expand Down
11 changes: 11 additions & 0 deletions source/ast/types/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,17 @@ bool Type::isHandleType() const {
}
}

bool Type::isUnion() const {
const Type& ct = getCanonicalType();
switch (ct.kind) {
case SymbolKind::UnpackedUnionType:
case SymbolKind::PackedUnionType:
return true;
default:
return false;
}
}

bool Type::isTaggedUnion() const {
auto& ct = getCanonicalType();
switch (ct.kind) {
Expand Down
5 changes: 3 additions & 2 deletions tools/reflect/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
# ~~~

add_library(
slang_reflect_obj_lib OBJECT src/SvStruct.cpp src/SvType.cpp src/SvEnum.cpp
src/SvTypeReflector.cpp src/SvLocalParam.cpp)
slang_reflect_obj_lib OBJECT
src/SvStruct.cpp src/SvType.cpp src/SvEnum.cpp src/SvTypeReflector.cpp
src/SvLocalParam.cpp src/SvUnion.cpp)

target_include_directories(slang_reflect_obj_lib PUBLIC include ../../include)
target_link_libraries(slang_reflect_obj_lib PUBLIC slang::slang)
Expand Down
16 changes: 8 additions & 8 deletions tools/reflect/include/ASTVisitors.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,25 @@

#pragma once

#include <iostream>
#include <ranges>

#include "slang/ast/ASTVisitor.h"
#include "slang/ast/Compilation.h"
#include "slang/syntax/SyntaxVisitor.h"

class PublicDirectiveVisitor : public slang::syntax::SyntaxVisitor<PublicDirectiveVisitor> {
public:
explicit PublicDirectiveVisitor(slang::parsing::TokenKind tokenKind) : tokenKind(tokenKind) {}
explicit PublicDirectiveVisitor(const slang::parsing::TokenKind tokenKind) :
tokenKind(tokenKind) {}

void visitToken(slang::parsing::Token token) {
void visitToken(const slang::parsing::Token token) {
if (token.kind == tokenKind) {
auto blockComments = token.trivia() | std::views::filter([](auto& v) {
return v.kind == slang::parsing::TriviaKind::BlockComment;
});

for (auto& blockComment : blockComments) {
isPublic = std::find(publicDirectives.begin(), publicDirectives.end(),
blockComment.getRawText()) != publicDirectives.end();
isPublic = std::ranges::find(publicDirectives, blockComment.getRawText()) !=
publicDirectives.end();
}
}
}
Expand All @@ -38,6 +37,7 @@ class PublicDirectiveVisitor : public slang::syntax::SyntaxVisitor<PublicDirecti
bool isPublic{false};
slang::parsing::TokenKind tokenKind;

constexpr static const std::array<std::string_view, 3> publicDirectives = {
"/* public */", "/*verilator public*/", "/* verilator public */"};
constexpr static std::array<std::string_view, 3> publicDirectives = {"/* public */",
"/*verilator public*/",
"/* verilator public */"};
};
22 changes: 11 additions & 11 deletions tools/reflect/include/CppEmitter.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@
#include <sstream>
#include <vector>

#include "slang/util/SmallVector.h"
#include "slang/util/Util.h"

namespace fs = std::filesystem;

class HppFile {
public:
explicit HppFile(std::string_view name, bool noSystemC) : fileName(std::string(name) + ".h") {
explicit HppFile(const std::string_view name, const bool noSystemC) :
fileName(std::string(name) + ".h") {
includes.emplace_back("ostream");
includes.emplace_back("cstddef");
includes.emplace_back("cstdint");
Expand All @@ -35,11 +35,11 @@ class HppFile {

void add(std::string&& code) { hpp << code; }
void addInclude(std::string&& code) {
if (std::find(includes.begin(), includes.end(), code) == includes.end())
if (std::ranges::find(includes, code) == includes.end())
includes.emplace_back(code);
}
void addIncludeHeader(std::string_view code) {
if (std::find(headers.begin(), headers.end(), code) == headers.end())
if (std::ranges::find(headers, code) == headers.end())
headers.emplace_back(code);
}
void addWithIndent(std::string&& code) { hpp << indent(currentIndent) << code; }
Expand All @@ -49,7 +49,7 @@ class HppFile {
currentIndent--;
}

std::string emit() {
std::string emit() const {
auto includesTransform = std::views::transform(includes, [](const auto& inc) {
return fmt::format("#include <{}>", inc);
});
Expand All @@ -61,7 +61,7 @@ class HppFile {
hpp.str());
}

void emitToFile(const fs::path& path) {
void emitToFile(const fs::path& path) const {
auto outFile = std::ofstream(path / fileName);
outFile << emit();
}
Expand All @@ -73,7 +73,7 @@ class HppFile {
std::string fileName;
uint32_t currentIndent{0};

std::string indent(uint64_t blocks) {
static std::string indent(const uint64_t blocks) {
std::string ret;
for (auto i = 0; i < blocks * 4; i++)
ret += " ";
Expand All @@ -83,21 +83,21 @@ class HppFile {

class CppEmitter {
public:
explicit CppEmitter(bool noSystemC) : noSystemC(noSystemC) {}
explicit CppEmitter(const bool noSystemC) : noSystemC(noSystemC) {}

[[nodiscard]] HppFile& newNamespace(std::string_view name) {
[[nodiscard]] HppFile& newNamespace(const std::string_view name) {
hppFiles.push_back(HppFile(name, noSystemC));
return hppFiles.back();
}

std::string emit() {
std::string emit() const {
std::stringstream ret;
for (auto& hpp : hppFiles)
ret << hpp.emit();
return std::move(ret.str());
}

void emitToFile(const fs::path& path) {
void emitToFile(const fs::path& path) const {
for (auto& hpp : hppFiles)
hpp.emitToFile(path);
}
Expand Down
7 changes: 3 additions & 4 deletions tools/reflect/include/SvEnum.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,11 @@

#include "slang/ast/types/AllTypes.h"

class SvEnum : public SvGeneric {
class SvEnum final : public SvGeneric {
public:
explicit SvEnum(const slang::ast::TypeAliasType& type) :
SvGeneric(SvGeneric::Kind::Enum), type(type) {}
explicit SvEnum(const slang::ast::TypeAliasType& type) : SvGeneric(Kind::Enum), type(type) {}

void toCpp(HppFile& hppFile, std::string_view, const SvAliases&, bool noSystemC) const override;
void toCpp(HppFile& hppFile, std::string_view, const SvAliases&, bool) const override;

private:
const slang::ast::TypeAliasType& type;
Expand Down
24 changes: 12 additions & 12 deletions tools/reflect/include/SvGeneric.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,36 +9,36 @@
#pragma once

#include "CppEmitter.h"

#include "slang/ast/types/AllTypes.h"
#include <unordered_map>

using SvAliases = std::unordered_map<std::string_view, std::string_view>;

class SvGeneric {
public:
enum class Kind { Struct, Enum, LocalParam };
explicit SvGeneric(Kind kind) : kind(kind) {}
enum class Kind { Struct, Enum, LocalParam, Union };
explicit SvGeneric(const Kind kind) : kind(kind) {}

virtual void toCpp(HppFile&, std::string_view, const SvAliases&, bool noSystemC) const = 0;

bool isStruct() const { return kind == Kind::Struct; }
bool isEnum() const { return kind == Kind::Enum; }
bool isLocalParam() const { return kind == Kind::LocalParam; }
[[nodiscard]] bool isStruct() const { return kind == Kind::Struct; }
[[nodiscard]] bool isEnum() const { return kind == Kind::Enum; }
[[nodiscard]] bool isLocalParam() const { return kind == Kind::LocalParam; }
[[nodiscard]] bool isUnion() const { return kind == Kind::Union; }

virtual ~SvGeneric() = default;

protected:
Kind kind;

static std::string_view resolveAlias(std::string_view typeName, const SvAliases& aliases) {
if (auto alias = aliases.find(typeName); alias != aliases.end())
[[nodiscard]] static std::string_view resolveAlias(const std::string_view& typeName,
const SvAliases& aliases) {
if (const auto& alias = aliases.find(typeName); alias != aliases.end())
return alias->second;
return typeName;
}

static bool isCppReserved(std::string_view name) {
return std::find(cppReservedKeywords.begin(), cppReservedKeywords.end(), name) !=
cppReservedKeywords.end();
[[nodiscard]] static bool isCppReserved(const std::string_view name) {
return std::ranges::find(cppReservedKeywords, name) != cppReservedKeywords.end();
}

static constexpr std::array cppReservedKeywords = {"alignas",
Expand Down
5 changes: 2 additions & 3 deletions tools/reflect/include/SvLocalParam.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,14 @@
#pragma once

#include "SvGeneric.h"
#include "SvType.h"
#include <fmt/format.h>

#include "slang/ast/symbols/ParameterSymbols.h"

class SvLocalParam : public SvGeneric {
class SvLocalParam final : public SvGeneric {
public:
explicit SvLocalParam(const slang::ast::ParameterSymbol& parameter) :
SvGeneric(SvGeneric::Kind::LocalParam), parameter(parameter) {}
SvGeneric(Kind::LocalParam), parameter(parameter) {}

void toCpp(HppFile& hppFile, std::string_view, const SvAliases&, bool) const override;

Expand Down
5 changes: 3 additions & 2 deletions tools/reflect/include/SvStruct.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@
#include "CppEmitter.h"
#include "SvGeneric.h"
#include "fmt/format.h"
#include <slang/ast/types/AllTypes.h>

class SvStruct : public SvGeneric {
class SvStruct final : public SvGeneric {
public:
explicit SvStruct(const slang::ast::TypeAliasType& type) :
SvGeneric(SvGeneric::Kind::Struct), type(type) {}
SvGeneric(Kind::Struct), type(type) {}

void toCpp(HppFile& hppFile, std::string_view _namespace, const SvAliases& aliases,
bool noSystemC) const override;
Expand Down
17 changes: 9 additions & 8 deletions tools/reflect/include/SvType.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,10 @@

#pragma once

#include <ostream>

#include "slang/ast/types/Type.h"

namespace CppType {
enum Type { BOOL, U32, U64, SC_BV, STRUCT, ENUM };
enum Type { BOOL, U32, U64, SC_BV, STRUCT, ENUM, UNION };

std::string toString(const Type& cppType);
Type fromSize(size_t size);
Expand All @@ -22,15 +20,18 @@ Type fromSize(size_t size);
class SvType {
public:
explicit SvType(const slang::ast::Type& type);
explicit SvType(const slang::ast::Type& type, std::string_view name) : SvType(type) {
explicit SvType(const slang::ast::Type& type, const std::string_view name) : SvType(type) {
this->name = name;
}

bool isStruct() const { return cppType == CppType::STRUCT; }
bool isEnum() const { return cppType == CppType::ENUM; }
bool isStructOrEnum() const { return this->isStruct() || this->isEnum(); }
[[nodiscard]] bool isStruct() const { return cppType == CppType::STRUCT; }
[[nodiscard]] bool isEnum() const { return cppType == CppType::ENUM; }
[[nodiscard]] bool isUnion() const { return cppType == CppType::UNION; }
[[nodiscard]] bool isStructEnumOrUnion() const {
return this->isStruct() || this->isEnum() || this->isUnion();
}

std::string toString() const;
[[nodiscard]] std::string toString() const;
friend std::ostream& operator<<(std::ostream& os, const SvType& type);

CppType::Type cppType;
Expand Down
12 changes: 6 additions & 6 deletions tools/reflect/include/SvTypeReflector.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@

class SvTypeReflector {
public:
explicit SvTypeReflector(std::unique_ptr<slang::ast::Compilation> compilation, bool verbose,
bool noSystemC) :
compilation(std::move(compilation)), verbose(verbose), noSystemC(noSystemC),
cppEmitter(noSystemC) {}
explicit SvTypeReflector(std::unique_ptr<slang::ast::Compilation> compilation,
const bool verbose, const bool noSystemC) :
verbose(verbose), noSystemC(noSystemC), cppEmitter(noSystemC),
compilation(std::move(compilation)) {}

void reflect();

std::string emit() { return cppEmitter.emit(); }
void emitToFile(const fs::path& path) { cppEmitter.emitToFile(path); }
std::string emit() const { return cppEmitter.emit(); }
void emitToFile(const fs::path& path) const { cppEmitter.emitToFile(path); }

private:
bool verbose;
Expand Down
23 changes: 23 additions & 0 deletions tools/reflect/include/SvUnion.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//------------------------------------------------------------------------------
//! @file SvEnum.h
//! @brief Handles with SystemVerilog Enums
//
// SPDX-FileCopyrightText: Michael Popoloski
// SPDX-License-Identifier: MIT
//------------------------------------------------------------------------------

#pragma once

#include "SvGeneric.h"

#include "slang/ast/types/AllTypes.h"

class SvUnion final : public SvGeneric {
public:
explicit SvUnion(const slang::ast::TypeAliasType& type) : SvGeneric(Kind::Union), type(type) {}

void toCpp(HppFile& hppFile, std::string_view, const SvAliases&, bool noSystemC) const override;

private:
const slang::ast::TypeAliasType& type;
};
20 changes: 7 additions & 13 deletions tools/reflect/src/SvEnum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@
#include "SvEnum.h"

#include <fmt/format.h>
#include <iostream>

void SvEnum::toCpp(HppFile& hppFile, std::string_view, const SvAliases&, bool) const {
auto underlyingType = [&]() {
auto underlyingType = [&] {
if (type.getBitstreamWidth() <= 8)
return "uint8_t"sv;
if (type.getBitstreamWidth() <= 16)
Expand All @@ -16,9 +15,8 @@ void SvEnum::toCpp(HppFile& hppFile, std::string_view, const SvAliases&, bool) c
return "uint32_t"sv;
if (type.getBitstreamWidth() <= 64)
return "uint64_t"sv;
else
SLANG_THROW(
std::runtime_error("Enum with $bits size bigger than 64 bits are not supported"));
SLANG_THROW(
std::runtime_error("Enum with $bits size bigger than 64 bits are not supported"));
};
//** STRUCT (ENUM) DECLARATION **//
hppFile.addWithIndent(fmt::format("struct {} {{\n", type.name));
Expand Down Expand Up @@ -62,12 +60,8 @@ void SvEnum::toCpp(HppFile& hppFile, std::string_view, const SvAliases&, bool) c
hppFile.increaseIndent();
hppFile.addWithIndent("switch (__data) {\n");
hppFile.increaseIndent();
for (const auto& member : members)
hppFile.addWithIndent(
fmt::format("case {}: type = Type::{}; break;\n", member.second, member.first));
hppFile.addWithIndent(fmt::format(
"default: throw std::runtime_error(\"Can not create {} from provided value\");\n",
type.name));
for (const auto& [name, value] : members)
hppFile.addWithIndent(fmt::format("case {}: type = Type::{}; break;\n", value, name));
hppFile.decreaseIndent();
hppFile.addWithIndent("}\n");
hppFile.decreaseIndent();
Expand All @@ -82,8 +76,8 @@ void SvEnum::toCpp(HppFile& hppFile, std::string_view, const SvAliases&, bool) c
hppFile.increaseIndent();
hppFile.addWithIndent("switch (__data.type) {\n");
hppFile.increaseIndent();
for (const auto& member : members)
hppFile.addWithIndent(fmt::format("case Type::{0}: os << \"{0}\"; break;\n", member.first));
for (const auto& name : members | std::views::keys)
hppFile.addWithIndent(fmt::format("case Type::{0}: os << \"{0}\"; break;\n", name));
hppFile.decreaseIndent();
hppFile.addWithIndent("}\n");
hppFile.addWithIndent("return os;\n");
Expand Down
Loading