Skip to content

Commit

Permalink
Merge pull request #53 from leonardt/inline-slice-id
Browse files Browse the repository at this point in the history
Add support for inlining slice/index when just an ID
  • Loading branch information
leonardt committed Jul 28, 2020
2 parents 45ff717 + 3ef4f85 commit 311b34e
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 55 deletions.
46 changes: 28 additions & 18 deletions include/verilogAST/assign_inliner.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,42 +61,51 @@ class WireReadCounter : public Transformer {
virtual std::unique_ptr<Declaration> visit(std::unique_ptr<Declaration> node);
};

class SliceBlacklister : public Transformer {
class Blacklister : public Transformer {
std::set<std::string> &wire_blacklist;
std::map<std::string, std::unique_ptr<Expression>> &assign_map;

protected:
bool blacklist = false;

public:
Blacklister(std::set<std::string> &wire_blacklist,
std::map<std::string, std::unique_ptr<Expression>> &assign_map)
: wire_blacklist(wire_blacklist), assign_map(assign_map){};
using Transformer::visit;
virtual std::unique_ptr<Identifier> visit(std::unique_ptr<Identifier> node);
};

class SliceBlacklister : public Blacklister {
// Prevent inling wires into slice nodes, e.g.
// wire [7:0] x;
// assign x = y + z;
// assign w = x[4:0];
//
// Verilog does not support (y + z)[4:0]
std::set<std::string> &wire_blacklist;
bool inside_slice = false;

public:
SliceBlacklister(std::set<std::string> &wire_blacklist)
: wire_blacklist(wire_blacklist){};

using Transformer::visit;
SliceBlacklister(
std::set<std::string> &wire_blacklist,
std::map<std::string, std::unique_ptr<Expression>> &assign_map)
: Blacklister(wire_blacklist, assign_map){};
using Blacklister::visit;
virtual std::unique_ptr<Slice> visit(std::unique_ptr<Slice> node);
virtual std::unique_ptr<Identifier> visit(std::unique_ptr<Identifier> node);
};

class IndexBlacklister : public Transformer {
class IndexBlacklister : public Blacklister {
// Prevent inling wires into index nodes, e.g.
// wire x;
// assign x = y + z;
// assign w = x[0];
//
// Verilog does not support (y + z)[0]
std::set<std::string> &wire_blacklist;
bool inside_index = false;

public:
IndexBlacklister(std::set<std::string> &wire_blacklist)
: wire_blacklist(wire_blacklist){};

using Transformer::visit;
IndexBlacklister(
std::set<std::string> &wire_blacklist,
std::map<std::string, std::unique_ptr<Expression>> &assign_map)
: Blacklister(wire_blacklist, assign_map){};
using Blacklister::visit;
virtual std::unique_ptr<Index> visit(std::unique_ptr<Index> node);
virtual std::unique_ptr<Identifier> visit(std::unique_ptr<Identifier> node);
};

class AssignInliner : public Transformer {
Expand Down Expand Up @@ -126,6 +135,7 @@ class AssignInliner : public Transformer {
: wire_blacklist(wire_blacklist){};
using Transformer::visit;
virtual std::unique_ptr<Expression> visit(std::unique_ptr<Expression> node);
virtual std::unique_ptr<Index> visit(std::unique_ptr<Index> node);
virtual std::unique_ptr<ContinuousAssign> visit(
std::unique_ptr<ContinuousAssign> node);
virtual std::unique_ptr<BlockingAssign> visit(
Expand Down
57 changes: 37 additions & 20 deletions src/assign_inliner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,34 @@

namespace verilogAST {

std::unique_ptr<Slice> SliceBlacklister::visit(std::unique_ptr<Slice> node) {
bool prev = this->inside_slice;
this->inside_slice = true;
node = Transformer::visit(std::move(node));
// Restore prev value, since we could be nested inside an slice
this->inside_slice = prev;
std::unique_ptr<Identifier> Blacklister::visit(
std::unique_ptr<Identifier> node) {
if (this->blacklist) {
auto it = assign_map.find(node->toString());
bool assigned_to_id =
it != assign_map.end() && dynamic_cast<Identifier*>(it->second.get());
if (!assigned_to_id) {
this->wire_blacklist.insert(node->value);
}
}
return node;
}

std::unique_ptr<Identifier> SliceBlacklister::visit(
std::unique_ptr<Identifier> node) {
if (this->inside_slice) this->wire_blacklist.insert(node->value);
std::unique_ptr<Slice> SliceBlacklister::visit(std::unique_ptr<Slice> node) {
bool prev = this->blacklist;
this->blacklist = true;
node = Transformer::visit(std::move(node));
// Restore prev value, since we could be nested inside an slice
this->blacklist = prev;
return node;
}

std::unique_ptr<Index> IndexBlacklister::visit(std::unique_ptr<Index> node) {
bool prev = this->inside_index;
this->inside_index = true;
bool prev = this->blacklist;
this->blacklist = true;
node = Transformer::visit(std::move(node));
// Restore prev value, since we could be nested inside an index
this->inside_index = prev;
return node;
}

std::unique_ptr<Identifier> IndexBlacklister::visit(
std::unique_ptr<Identifier> node) {
if (this->inside_index) this->wire_blacklist.insert(node->value);
this->blacklist = prev;
return node;
}

Expand Down Expand Up @@ -114,6 +115,22 @@ bool AssignInliner::can_inline(std::string key) {
dynamic_cast<NumericLiteral*>(it->second.get()));
}

std::unique_ptr<Index> AssignInliner::visit(std::unique_ptr<Index> node) {
if (std::holds_alternative<std::unique_ptr<Identifier>>(node->value)) {
std::string key =
std::get<std::unique_ptr<Identifier>>(node->value)->toString();
if (this->can_inline(key)) {
std::unique_ptr<Expression> value = this->visit(assign_map[key]->clone());
if (auto ptr = dynamic_cast<Identifier*>(value.get())) {
value.release();
node->value = std::unique_ptr<Identifier>(ptr);
}
}
return node;
}
return Transformer::visit(std::move(node));
}

std::unique_ptr<Expression> AssignInliner::visit(
std::unique_ptr<Expression> node) {
if (auto ptr = dynamic_cast<Identifier*>(node.get())) {
Expand Down Expand Up @@ -219,10 +236,10 @@ std::unique_ptr<Module> AssignInliner::visit(std::unique_ptr<Module> node) {
WireReadCounter counter(this->read_count);
node = counter.visit(std::move(node));

IndexBlacklister index_blacklist(this->wire_blacklist);
IndexBlacklister index_blacklist(this->wire_blacklist, this->assign_map);
node = index_blacklist.visit(std::move(node));

SliceBlacklister slice_blacklist(this->wire_blacklist);
SliceBlacklister slice_blacklist(this->wire_blacklist, this->assign_map);
node = slice_blacklist.visit(std::move(node));

std::vector<std::unique_ptr<AbstractPort>> new_ports;
Expand Down
97 changes: 80 additions & 17 deletions tests/assign_inliner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -716,8 +716,10 @@ TEST(InlineAssignTests, TestNoInlineIndex) {
std::make_unique<vAST::Vector>(vAST::make_id("i2"), vAST::make_num("1"),
vAST::make_num("0")),
vAST::INPUT, vAST::WIRE));
ports.push_back(std::make_unique<vAST::Port>(vAST::make_id("o"), vAST::OUTPUT,
vAST::WIRE));
ports.push_back(std::make_unique<vAST::Port>(vAST::make_id("o0"),
vAST::OUTPUT, vAST::WIRE));
ports.push_back(std::make_unique<vAST::Port>(vAST::make_id("o1"),
vAST::OUTPUT, vAST::WIRE));

std::vector<std::variant<std::unique_ptr<vAST::StructuralStatement>,
std::unique_ptr<vAST::Declaration>>>
Expand All @@ -726,47 +728,80 @@ TEST(InlineAssignTests, TestNoInlineIndex) {
body.push_back(
std::make_unique<vAST::Wire>(std::make_unique<vAST::Identifier>("x")));

body.push_back(
std::make_unique<vAST::Wire>(std::make_unique<vAST::Identifier>("y")));

body.push_back(std::make_unique<vAST::ContinuousAssign>(
vAST::make_id("x"),
std::make_unique<vAST::BinaryOp>(vAST::make_id("i1"), vAST::BinOp::ADD,
vAST::make_id("i2"))));

body.push_back(std::make_unique<vAST::ContinuousAssign>(
vAST::make_id("o"),
vAST::make_id("o0"),
std::make_unique<vAST::Index>(vAST::make_id("x"), vAST::make_num("0"))));

body.push_back(std::make_unique<vAST::ContinuousAssign>(vAST::make_id("y"),
vAST::make_id("i1")));

body.push_back(std::make_unique<vAST::ContinuousAssign>(
vAST::make_id("o1"),
std::make_unique<vAST::Index>(vAST::make_id("y"), vAST::make_num("0"))));

std::unique_ptr<vAST::AbstractModule> module = std::make_unique<vAST::Module>(
"test_module", std::move(ports), std::move(body));

std::string raw_str =
"module test_module (\n"
" input [1:0] i1,\n"
" input [1:0] i2,\n"
" output o\n"
" output o0,\n"
" output o1\n"
");\n"
"wire x;\n"
"wire y;\n"
"assign x = i1 + i2;\n"
"assign o = x[0];\n"
"assign o0 = x[0];\n"
"assign y = i1;\n"
"assign o1 = y[0];\n"
"endmodule\n";

EXPECT_EQ(module->toString(), raw_str);

std::string expected_str =
"module test_module (\n"
" input [1:0] i1,\n"
" input [1:0] i2,\n"
" output o0,\n"
" output o1\n"
");\n"
"wire x;\n"
"assign x = i1 + i2;\n"
"assign o0 = x[0];\n"
"assign o1 = i1[0];\n"
"endmodule\n";

vAST::AssignInliner transformer;
EXPECT_EQ(transformer.visit(std::move(module))->toString(), raw_str);
EXPECT_EQ(transformer.visit(std::move(module))->toString(), expected_str);
}

TEST(InlineAssignTests, TestNoInlineSlice) {
TEST(InlineAssignTests, TestNoInlineSliceUnlessID) {
std::vector<std::unique_ptr<vAST::AbstractPort>> ports;
ports.push_back(std::make_unique<vAST::Port>(
std::make_unique<vAST::Vector>(vAST::make_id("i1"), vAST::make_num("1"),
std::make_unique<vAST::Vector>(vAST::make_id("i1"), vAST::make_num("4"),
vAST::make_num("0")),
vAST::INPUT, vAST::WIRE));
ports.push_back(std::make_unique<vAST::Port>(
std::make_unique<vAST::Vector>(vAST::make_id("i2"), vAST::make_num("1"),
std::make_unique<vAST::Vector>(vAST::make_id("i2"), vAST::make_num("4"),
vAST::make_num("0")),
vAST::INPUT, vAST::WIRE));
ports.push_back(std::make_unique<vAST::Port>(vAST::make_id("o"), vAST::OUTPUT,
vAST::WIRE));
ports.push_back(std::make_unique<vAST::Port>(
std::make_unique<vAST::Vector>(vAST::make_id("o0"), vAST::make_num("3"),
vAST::make_num("0")),
vAST::OUTPUT, vAST::WIRE));
ports.push_back(std::make_unique<vAST::Port>(
std::make_unique<vAST::Vector>(vAST::make_id("o1"), vAST::make_num("3"),
vAST::make_num("0")),
vAST::OUTPUT, vAST::WIRE));

std::vector<std::variant<std::unique_ptr<vAST::StructuralStatement>,
std::unique_ptr<vAST::Declaration>>>
Expand All @@ -775,34 +810,62 @@ TEST(InlineAssignTests, TestNoInlineSlice) {
body.push_back(
std::make_unique<vAST::Wire>(std::make_unique<vAST::Identifier>("x")));

body.push_back(
std::make_unique<vAST::Wire>(std::make_unique<vAST::Identifier>("y")));

body.push_back(std::make_unique<vAST::ContinuousAssign>(
vAST::make_id("x"),
std::make_unique<vAST::BinaryOp>(vAST::make_id("i1"), vAST::BinOp::ADD,
vAST::make_id("i2"))));

body.push_back(std::make_unique<vAST::ContinuousAssign>(
vAST::make_id("o"),
vAST::make_id("o0"),
std::make_unique<vAST::Slice>(vAST::make_id("x"), vAST::make_num("3"),
vAST::make_num("0"))));

body.push_back(std::make_unique<vAST::ContinuousAssign>(vAST::make_id("y"),
vAST::make_id("i1")));

body.push_back(std::make_unique<vAST::ContinuousAssign>(
vAST::make_id("o1"),
std::make_unique<vAST::Slice>(vAST::make_id("y"), vAST::make_num("3"),
vAST::make_num("0"))));

std::unique_ptr<vAST::AbstractModule> module = std::make_unique<vAST::Module>(
"test_module", std::move(ports), std::move(body));

std::string raw_str =
"module test_module (\n"
" input [1:0] i1,\n"
" input [1:0] i2,\n"
" output o\n"
" input [4:0] i1,\n"
" input [4:0] i2,\n"
" output [3:0] o0,\n"
" output [3:0] o1\n"
");\n"
"wire x;\n"
"wire y;\n"
"assign x = i1 + i2;\n"
"assign o = x[3:0];\n"
"assign o0 = x[3:0];\n"
"assign y = i1;\n"
"assign o1 = y[3:0];\n"
"endmodule\n";

EXPECT_EQ(module->toString(), raw_str);

std::string expected_str =
"module test_module (\n"
" input [4:0] i1,\n"
" input [4:0] i2,\n"
" output [3:0] o0,\n"
" output [3:0] o1\n"
");\n"
"wire x;\n"
"assign x = i1 + i2;\n"
"assign o0 = x[3:0];\n"
"assign o1 = i1[3:0];\n"
"endmodule\n";

vAST::AssignInliner transformer;
EXPECT_EQ(transformer.visit(std::move(module))->toString(), raw_str);
EXPECT_EQ(transformer.visit(std::move(module))->toString(), expected_str);
}

} // namespace
Expand Down

0 comments on commit 311b34e

Please sign in to comment.