diff --git a/include/verilogAST.hpp b/include/verilogAST.hpp index a5d83dd..4cdfe02 100644 --- a/include/verilogAST.hpp +++ b/include/verilogAST.hpp @@ -807,6 +807,13 @@ class If : public BehavioralStatement { else_ifs(std::move(else_ifs)), else_body(std::move(else_body)){}; + If(std::unique_ptr cond, + std::vector> true_body, + std::vector> else_body) + : cond(std::move(cond)), + true_body(std::move(true_body)), + else_body(std::move(else_body)){}; + std::string toString(); ~If(){}; }; diff --git a/src/assign_inliner.cpp b/src/assign_inliner.cpp index feef28d..7493a89 100644 --- a/src/assign_inliner.cpp +++ b/src/assign_inliner.cpp @@ -4,6 +4,10 @@ namespace verilogAST { void Blacklister::blacklist_invalid_driver(std::unique_ptr 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 @@ -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(it->second.get()) || dynamic_cast(it->second.get())); @@ -259,6 +263,13 @@ std::unique_ptr AssignInliner::visit(std::unique_ptr 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)); diff --git a/tests/assign_inliner.cpp b/tests/assign_inliner.cpp index 36d2f46..8d2d229 100644 --- a/tests/assign_inliner.cpp +++ b/tests/assign_inliner.cpp @@ -961,6 +961,122 @@ TEST(InlineAssignTests, TestInlineSliceOfIndex) { EXPECT_EQ(transformer.visit(std::move(module))->toString(), expected_str); } +TEST(InlineAssignTests, TestInlineMultipleAssign) { + std::vector> ports; + ports.push_back(std::make_unique( + std::make_unique(vAST::make_id("i0"), vAST::make_num("4"), + vAST::make_num("0")), + vAST::INPUT, vAST::WIRE)); + ports.push_back(std::make_unique( + std::make_unique(vAST::make_id("i1"), vAST::make_num("4"), + vAST::make_num("0")), + vAST::INPUT, vAST::WIRE)); + ports.push_back(std::make_unique(vAST::make_id("s"), vAST::INPUT, + vAST::WIRE)); + ports.push_back(std::make_unique( + std::make_unique(vAST::make_id("o"), vAST::make_num("3"), + vAST::make_num("0")), + vAST::OUTPUT, vAST::WIRE)); + + std::vector, + std::unique_ptr>> + body; + + body.push_back(std::make_unique(std::make_unique( + vAST::make_id("x"), vAST::make_num("4"), vAST::make_num("0")))); + + body.push_back(std::make_unique(std::make_unique( + vAST::make_id("y"), vAST::make_num("4"), vAST::make_num("0")))); + + body.push_back(std::make_unique(std::make_unique( + vAST::make_id("z"), vAST::make_num("4"), vAST::make_num("0")))); + + body.push_back(std::make_unique(vAST::make_id("x"), + vAST::make_id("i0"))); + + body.push_back(std::make_unique(vAST::make_id("y"), + vAST::make_id("i1"))); + + std::vector, std::unique_ptr, + std::unique_ptr, std::unique_ptr>> + sensitivity_list; + sensitivity_list.push_back(std::make_unique()); + + std::vector> always_body; + + std::vector> true_body; + true_body.push_back(std::make_unique( + std::make_unique("z"), + std::make_unique("x"))); + + std::vector> else_body; + else_body.push_back(std::make_unique( + std::make_unique("z"), + std::make_unique("y"))); + + always_body.push_back(std::make_unique( + vAST::make_id("s"), std::move(true_body), std::move(else_body))); + + body.push_back(std::make_unique(std::move(sensitivity_list), + std::move(always_body))); + + body.push_back(std::make_unique( + vAST::make_id("o"), + std::make_unique(vAST::make_id("z"), vAST::make_num("3"), + vAST::make_num("0")))); + + std::unique_ptr module = std::make_unique( + "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) {