Skip to content

Commit

Permalink
Fix handling of multiple assignments in inlining
Browse files Browse the repository at this point in the history
  • Loading branch information
leonardt committed Aug 27, 2020
1 parent 8ed0645 commit a9da412
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 1 deletion.
7 changes: 7 additions & 0 deletions include/verilogAST.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,13 @@ class If : public BehavioralStatement {
else_ifs(std::move(else_ifs)),
else_body(std::move(else_body)){};

If(std::unique_ptr<Expression> cond,
std::vector<std::unique_ptr<BehavioralStatement>> true_body,
std::vector<std::unique_ptr<BehavioralStatement>> else_body)
: cond(std::move(cond)),
true_body(std::move(true_body)),
else_body(std::move(else_body)){};

std::string toString();
~If(){};
};
Expand Down
13 changes: 12 additions & 1 deletion src/assign_inliner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
namespace verilogAST {

void Blacklister::blacklist_invalid_driver(std::unique_ptr<Identifier> node) {
if (this->wire_blacklist.count(node->value)) {
// Already blacklisted
return;
}
if (!assign_map.count(node->toString())) {
// Not in assign map, means it's a module input, don't need to do anything
// because it won't be inlined
Expand Down Expand Up @@ -136,7 +140,7 @@ bool AssignInliner::can_inline(std::string key) {
return false;
}
auto it = assign_map.find(key);
return it != assign_map.end() && (this->assign_count[key] == 1) &&
return it != assign_map.end() &&
(this->read_count[key] == 1 ||
dynamic_cast<Identifier*>(it->second.get()) ||
dynamic_cast<NumericLiteral*>(it->second.get()));
Expand Down Expand Up @@ -259,6 +263,13 @@ std::unique_ptr<Module> AssignInliner::visit(std::unique_ptr<Module> node) {
this->non_input_ports, this->output_ports,
this->input_ports);
node = builder.visit(std::move(node));
for (auto entry : assign_count) {
if (entry.second > 1) {
// Do not inline things assigned more than once, e.g. a reg inside
// if/else statements
this->wire_blacklist.insert(entry.first);
}
}

WireReadCounter counter(this->read_count);
node = counter.visit(std::move(node));
Expand Down
116 changes: 116 additions & 0 deletions tests/assign_inliner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -961,6 +961,122 @@ TEST(InlineAssignTests, TestInlineSliceOfIndex) {
EXPECT_EQ(transformer.visit(std::move(module))->toString(), expected_str);
}

TEST(InlineAssignTests, TestInlineMultipleAssign) {
std::vector<std::unique_ptr<vAST::AbstractPort>> ports;
ports.push_back(std::make_unique<vAST::Port>(
std::make_unique<vAST::Vector>(vAST::make_id("i0"), 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("i1"), vAST::make_num("4"),
vAST::make_num("0")),
vAST::INPUT, vAST::WIRE));
ports.push_back(std::make_unique<vAST::Port>(vAST::make_id("s"), vAST::INPUT,
vAST::WIRE));
ports.push_back(std::make_unique<vAST::Port>(
std::make_unique<vAST::Vector>(vAST::make_id("o"), 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>>>
body;

body.push_back(std::make_unique<vAST::Wire>(std::make_unique<vAST::Vector>(
vAST::make_id("x"), vAST::make_num("4"), vAST::make_num("0"))));

body.push_back(std::make_unique<vAST::Wire>(std::make_unique<vAST::Vector>(
vAST::make_id("y"), vAST::make_num("4"), vAST::make_num("0"))));

body.push_back(std::make_unique<vAST::Wire>(std::make_unique<vAST::Vector>(
vAST::make_id("z"), vAST::make_num("4"), vAST::make_num("0"))));

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

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

std::vector<std::variant<
std::unique_ptr<vAST::Identifier>, std::unique_ptr<vAST::PosEdge>,
std::unique_ptr<vAST::NegEdge>, std::unique_ptr<vAST::Star>>>
sensitivity_list;
sensitivity_list.push_back(std::make_unique<vAST::Star>());

std::vector<std::unique_ptr<vAST::BehavioralStatement>> always_body;

std::vector<std::unique_ptr<vAST::BehavioralStatement>> true_body;
true_body.push_back(std::make_unique<vAST::BlockingAssign>(
std::make_unique<vAST::Identifier>("z"),
std::make_unique<vAST::Identifier>("x")));

std::vector<std::unique_ptr<vAST::BehavioralStatement>> else_body;
else_body.push_back(std::make_unique<vAST::BlockingAssign>(
std::make_unique<vAST::Identifier>("z"),
std::make_unique<vAST::Identifier>("y")));

always_body.push_back(std::make_unique<vAST::If>(
vAST::make_id("s"), std::move(true_body), std::move(else_body)));

body.push_back(std::make_unique<vAST::Always>(std::move(sensitivity_list),
std::move(always_body)));

body.push_back(std::make_unique<vAST::ContinuousAssign>(
vAST::make_id("o"),
std::make_unique<vAST::Slice>(vAST::make_id("z"), 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 [4:0] i0,\n"
" input [4:0] i1,\n"
" input s,\n"
" output [3:0] o\n"
");\n"
"wire [4:0] x;\n"
"wire [4:0] y;\n"
"wire [4:0] z;\n"
"assign x = i0;\n"
"assign y = i1;\n"
"always @(*) begin\n"
"if (s) begin\n"
" z = x;\n"
"end else begin\n"
" z = y;\n"
"end\n"
"end\n"
"\n"
"assign o = z[3:0];\n"
"endmodule\n";

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

std::string expected_str =
"module test_module (\n"
" input [4:0] i0,\n"
" input [4:0] i1,\n"
" input s,\n"
" output [3:0] o\n"
");\n"
"wire [4:0] z;\n"
"always @(*) begin\n"
"if (s) begin\n"
" z = i0;\n"
"end else begin\n"
" z = i1;\n"
"end\n"
"end\n"
"\n"
"assign o = z[3:0];\n"
"endmodule\n";

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

} // namespace

int main(int argc, char **argv) {
Expand Down

0 comments on commit a9da412

Please sign in to comment.