From b549051e33f5cb6b1adc60e64cbd2fc2bf0a7365 Mon Sep 17 00:00:00 2001 From: Lenny Truong <leonardtruong@fb.com> Date: Thu, 13 Feb 2020 17:06:24 -0800 Subject: [PATCH 1/6] Special handling of wire inlining to preserve intermediates --- CMakeLists.txt | 4 + include/coreir/passes/analysis/verilog.h | 3 + src/passes/analysis/verilog.cpp | 102 +++++++++++++++-------- tests/gtest/golds/arr_tuple.v | 11 +++ tests/gtest/golds/bit_wire.v | 6 ++ tests/gtest/golds/bits_instance.v | 9 ++ tests/gtest/golds/bits_wire.v | 6 ++ tests/gtest/golds/fanout.v | 7 ++ tests/gtest/golds/nested_array_wire.v | 10 +++ tests/gtest/golds/tuple.v | 7 ++ tests/gtest/srcs/arr_tuple.json | 37 ++++++++ tests/gtest/srcs/bit_wire.json | 23 +++++ tests/gtest/srcs/bits_instance.json | 34 ++++++++ tests/gtest/srcs/bits_wire.json | 24 ++++++ tests/gtest/srcs/fanout.json | 25 ++++++ tests/gtest/srcs/fanout.v | 25 ++++++ tests/gtest/srcs/nested_array_wire.json | 72 ++++++++++++++++ tests/gtest/srcs/tuple.json | 34 ++++++++ tests/gtest/test_inline_wires.cpp | 93 +++++++++++++++++++++ 19 files changed, 498 insertions(+), 34 deletions(-) create mode 100644 tests/gtest/golds/arr_tuple.v create mode 100644 tests/gtest/golds/bit_wire.v create mode 100644 tests/gtest/golds/bits_instance.v create mode 100644 tests/gtest/golds/bits_wire.v create mode 100644 tests/gtest/golds/fanout.v create mode 100644 tests/gtest/golds/nested_array_wire.v create mode 100644 tests/gtest/golds/tuple.v create mode 100644 tests/gtest/srcs/arr_tuple.json create mode 100644 tests/gtest/srcs/bit_wire.json create mode 100644 tests/gtest/srcs/bits_instance.json create mode 100644 tests/gtest/srcs/bits_wire.json create mode 100644 tests/gtest/srcs/fanout.json create mode 100644 tests/gtest/srcs/fanout.v create mode 100644 tests/gtest/srcs/nested_array_wire.json create mode 100644 tests/gtest/srcs/tuple.json create mode 100644 tests/gtest/test_inline_wires.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 48686f1b8..9864793b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,3 +74,7 @@ enable_testing() add_executable(test_verilog tests/gtest/test_verilog.cpp) target_link_libraries(test_verilog gtest_main coreir coreir-commonlib) add_test(NAME test_verilog COMMAND test_verilog WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests/gtest) + +add_executable(test_inline_wires tests/gtest/test_inline_wires.cpp) +target_link_libraries(test_inline_wires gtest_main coreir coreir-commonlib) +add_test(NAME test_inline_wires COMMAND test_inline_wires WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests/gtest) diff --git a/include/coreir/passes/analysis/verilog.h b/include/coreir/passes/analysis/verilog.h index 06f56d985..ce91f5784 100644 --- a/include/coreir/passes/analysis/verilog.h +++ b/include/coreir/passes/analysis/verilog.h @@ -28,6 +28,9 @@ class Verilog : public InstanceGraphPass { // modules. These parametrized modules have been instanced to create coreir // modules, but we only need to compile the verilog definition once std::set<Generator *> verilog_generators_seen; + + // Keep track of wire primitive instances, we do not inline these + std::set<std::string> wires; void compileModule(Module *module); diff --git a/src/passes/analysis/verilog.cpp b/src/passes/analysis/verilog.cpp index 2f5a552ac..d519d39c3 100644 --- a/src/passes/analysis/verilog.cpp +++ b/src/passes/analysis/verilog.cpp @@ -151,11 +151,16 @@ bool can_inline_unary_op(CoreIR::Module *module, bool _inline) { std::unique_ptr<vAST::StructuralStatement> inline_unary_op( std::pair<std::string, CoreIR::Instance *> instance, - std::map<std::string, std::unique_ptr<vAST::Expression>> verilog_connections - ) { + std::map<std::string, std::unique_ptr<vAST::Expression>> + verilog_connections, + bool is_wire) { UnaryOpReplacer transformer(std::move(verilog_connections["in"])); + std::string wire_name = instance.first; + if (!is_wire) { + wire_name += "_out"; + } return std::make_unique<vAST::ContinuousAssign>( - std::make_unique<vAST::Identifier>(instance.first + "_out"), + std::make_unique<vAST::Identifier>(wire_name), transformer.visit(get_primitive_expr(instance.second))); } @@ -321,33 +326,49 @@ process_decl(std::unique_ptr<vAST::Identifier> id, Type *type) { return std::move(id); } +void make_wire_decl( + std::string name, Type *type, + std::vector<std::variant<std::unique_ptr<vAST::StructuralStatement>, + std::unique_ptr<vAST::Declaration>>> + &wire_declarations) { + std::unique_ptr<vAST::Identifier> id = + std::make_unique<vAST::Identifier>(name); + // Can't find a simple way to "convert" a variant type to a + // superset, so we just manually unpack it to call the Wire + // constructor + std::visit( + [&](auto &&arg) -> void { + wire_declarations.push_back( + std::make_unique<vAST::Wire>(std::move(arg))); + }, + process_decl(std::move(id), type)); +} + // Given a map of instances, return a vector of containing declarations for all // the output ports of each instance. We return a vector of a variant type for // compatibility with the module AST node constructor, even though we only ever // create Wire nodes. std::vector<std::variant<std::unique_ptr<vAST::StructuralStatement>, std::unique_ptr<vAST::Declaration>>> -declare_connections(std::map<std::string, Instance *> instances) { +declare_connections(std::map<std::string, Instance *> instances, bool _inline) { std::vector<std::variant<std::unique_ptr<vAST::StructuralStatement>, std::unique_ptr<vAST::Declaration>>> wire_declarations; for (auto instance : instances) { + if (instance.second->getModuleRef()->getName() == "wire" && _inline) { + // Emit inline wire + Type *type = + cast<RecordType>(instance.second->getModuleRef()->getType()) + ->getRecord().at("in"); + make_wire_decl(instance.first, type, wire_declarations); + continue; + } for (auto port : cast<RecordType>(instance.second->getModuleRef()->getType()) ->getRecord()) { if (!port.second->isInput()) { - std::unique_ptr<vAST::Identifier> id = - std::make_unique<vAST::Identifier>(instance.first + "_" + - port.first); - // Can't find a simple way to "convert" a variant type to a - // superset, so we just manually unpack it to call the Wire - // constructor - std::visit( - [&](auto &&arg) -> void { - wire_declarations.push_back( - std::make_unique<vAST::Wire>(std::move(arg))); - }, - process_decl(std::move(id), port.second)); + make_wire_decl(instance.first + "_" + port.first, port.second, + wire_declarations); } } } @@ -575,11 +596,18 @@ build_connection_map(CoreIR::ModuleDef *definition, // Join select path fields by "_" (ignoring intial self if present) std::variant<std::unique_ptr<vAST::Identifier>, std::unique_ptr<vAST::Index>> -convert_to_verilog_connection(Wireable *value) { +convert_to_verilog_connection(Wireable *value, bool _inline) { SelectPath select_path = value->getSelectPath(); if (select_path.front() == "self") { select_path.pop_front(); } + Wireable *parent = value->getTopParent(); + if (_inline && parent->getKind() == Wireable::WK_Instance && + cast<Instance>(parent)->getModuleRef()->getName() == "wire") { + // Use instance name as wire name + select_path.pop_front(); + select_path[0] = parent->toString(); + } std::string connection_name = ""; for (uint i = 0; i < select_path.size(); i++) { auto item = select_path[i]; @@ -618,12 +646,12 @@ std::unique_ptr<vAST::Concat> convert_non_bulk_connection_to_concat(std::vector<ConnMapEntry> entries, std::vector<std::variant<std::unique_ptr<vAST::StructuralStatement>, std::unique_ptr<vAST::Declaration>>> &body, - std::string debug_prefix) { + std::string debug_prefix, bool _inline) { std::vector<std::unique_ptr<vAST::Expression>> args; args.resize(entries.size()); for (auto entry : entries) { std::unique_ptr<vAST::Expression> verilog_conn = - convert_to_expression(convert_to_verilog_connection(entry.source)); + convert_to_expression(convert_to_verilog_connection(entry.source, _inline)); process_connection_debug_metadata(entry, verilog_conn->toString(), body, debug_prefix + "[" + std::to_string(entry.index) + "]"); args[entry.index] = std::move(verilog_conn); @@ -638,7 +666,7 @@ void assign_module_outputs( RecordType *record_type, std::vector<std::variant<std::unique_ptr<vAST::StructuralStatement>, std::unique_ptr<vAST::Declaration>>> &body, - std::map<ConnMapKey, std::vector<ConnMapEntry>> connection_map) { + std::map<ConnMapKey, std::vector<ConnMapEntry>> connection_map, bool _inline) { for (auto port : record_type->getRecord()) { if (port.second->isInput()) { continue; @@ -648,12 +676,12 @@ void assign_module_outputs( continue; } else if (entries.size() > 1) { std::unique_ptr<vAST::Concat> concat = - convert_non_bulk_connection_to_concat(entries, body, port.first); + convert_non_bulk_connection_to_concat(entries, body, port.first, _inline); body.push_back(std::make_unique<vAST::ContinuousAssign>( std::make_unique<vAST::Identifier>(port.first), std::move(concat))); } else { std::unique_ptr<vAST::Expression> verilog_conn = - convert_to_expression(convert_to_verilog_connection(entries[0].source)); + convert_to_expression(convert_to_verilog_connection(entries[0].source, _inline)); process_connection_debug_metadata(entries[0], verilog_conn->toString(), body, port.first); // Regular (possibly bulk) connection @@ -669,13 +697,14 @@ void assign_module_outputs( void assign_inouts( std::vector<Connection> connections, std::vector<std::variant<std::unique_ptr<vAST::StructuralStatement>, - std::unique_ptr<vAST::Declaration>>> &body) { + std::unique_ptr<vAST::Declaration>>> &body, + bool _inline) { for (auto connection : connections) { if (connection.first->getType()->isInOut() || connection.second->getType()->isInOut()) { body.push_back(std::make_unique<vAST::ContinuousAssign>( - convert_to_assign_target(convert_to_verilog_connection(connection.first)), - convert_to_expression(convert_to_verilog_connection(connection.second)) + convert_to_assign_target(convert_to_verilog_connection(connection.first, _inline)), + convert_to_expression(convert_to_verilog_connection(connection.second, _inline)) )); }; }; @@ -688,12 +717,12 @@ std::vector<std::variant<std::unique_ptr<vAST::StructuralStatement>, std::unique_ptr<vAST::Declaration>>> compile_module_body(RecordType *module_type, CoreIR::ModuleDef *definition, - bool _inline) { + bool _inline, std::set<std::string> &wires) { std::map<std::string, Instance *> instances = definition->getInstances(); std::vector<std::variant<std::unique_ptr<vAST::StructuralStatement>, std::unique_ptr<vAST::Declaration>>> - body = declare_connections(instances); + body = declare_connections(instances, _inline); std::map<ConnMapKey, std::vector<ConnMapEntry>> connection_map = build_connection_map(definition, instances); @@ -741,13 +770,13 @@ compile_module_body(RecordType *module_type, } else if (entries.size() > 1) { std::unique_ptr<vAST::Concat> concat = convert_non_bulk_connection_to_concat(entries, body, - instance_name + "." + port.first); + instance_name + "." + port.first, _inline); verilog_connections.insert( std::make_pair(port.first, std::move(concat))); // Otherwise we just use the entry in the connection map } else { std::unique_ptr<vAST::Expression> verilog_conn = - convert_to_expression(convert_to_verilog_connection(entries[0].source)); + convert_to_expression(convert_to_verilog_connection(entries[0].source, _inline)); process_connection_debug_metadata(entries[0], verilog_conn->toString(), body, instance_name + "." + port.first); verilog_connections.insert(std::make_pair(port.first, std::move(verilog_conn))); @@ -776,7 +805,12 @@ compile_module_body(RecordType *module_type, if (can_inline_binary_op(instance_module, _inline)) { statement = inline_binary_op(instance, std::move(verilog_connections)); } else if (can_inline_unary_op(instance_module, _inline)) { - statement = inline_unary_op(instance, std::move(verilog_connections)); + bool is_wire = instance_module->getName() == "wire"; + if (is_wire) { + wires.insert(instance.first); + } + statement = inline_unary_op(instance, std::move(verilog_connections), + is_wire); } else if (can_inline_mux_op(instance_module, _inline)) { statement = inline_mux_op(instance, std::move(verilog_connections)); } else if (can_inline_const_op(instance_module, _inline)) { @@ -809,8 +843,8 @@ compile_module_body(RecordType *module_type, body.push_back(std::move(statement)); } // Wire the outputs of the module and inout connections - assign_module_outputs(module_type, body, connection_map); - assign_inouts(definition->getSortedConnections(), body); + assign_module_outputs(module_type, body, connection_map, _inline); + assign_inouts(definition->getSortedConnections(), body, _inline); return body; } @@ -899,7 +933,7 @@ void Passes::Verilog::compileModule(Module *module) { body; if (module->hasDef()) { body = compile_module_body(module->getType(), definition, - this->_inline); + this->_inline, this->wires); } if (module->getMetaData().count("filename") > 0) { @@ -929,7 +963,7 @@ void Passes::Verilog::compileModule(Module *module) { std::move(parameters)); if (this->_inline) { - vAST::AssignInliner transformer; + vAST::AssignInliner transformer(this->wires); verilog_module = transformer.visit(std::move(verilog_module)); } modules.push_back(std::make_pair(name, std::move(verilog_module))); diff --git a/tests/gtest/golds/arr_tuple.v b/tests/gtest/golds/arr_tuple.v new file mode 100644 index 000000000..57aeed117 --- /dev/null +++ b/tests/gtest/golds/arr_tuple.v @@ -0,0 +1,11 @@ +// Module `Foo` defined externally +module Main (input z_0_x, output z_0_y, input z_1_x, output z_1_y); +wire Foo_inst0_z_0_y; +wire a_x; +wire a_y; +Foo Foo_inst0(.z_0_x(a_y), .z_0_y(Foo_inst0_z_0_y), .z_1_x(z_0_x), .z_1_y(z_1_y)); +assign a_x = Foo_inst0_z_0_y; +assign a_y = z_0_x; +assign z_0_y = a_x; +endmodule + diff --git a/tests/gtest/golds/bit_wire.v b/tests/gtest/golds/bit_wire.v new file mode 100644 index 000000000..74f4b9e43 --- /dev/null +++ b/tests/gtest/golds/bit_wire.v @@ -0,0 +1,6 @@ +module Main (input I, output O); +wire x; +assign x = I; +assign O = x; +endmodule + diff --git a/tests/gtest/golds/bits_instance.v b/tests/gtest/golds/bits_instance.v new file mode 100644 index 000000000..a88ece5cc --- /dev/null +++ b/tests/gtest/golds/bits_instance.v @@ -0,0 +1,9 @@ +// Module `Foo` defined externally +module Main (input [4:0] I, output [4:0] O); +wire [4:0] Foo_inst0_O; +wire [4:0] x; +Foo Foo_inst0(.I(I), .O(Foo_inst0_O)); +assign x = Foo_inst0_O; +assign O = x; +endmodule + diff --git a/tests/gtest/golds/bits_wire.v b/tests/gtest/golds/bits_wire.v new file mode 100644 index 000000000..133f73bca --- /dev/null +++ b/tests/gtest/golds/bits_wire.v @@ -0,0 +1,6 @@ +module Main (input [4:0] I, output [4:0] O); +wire [4:0] x; +assign x = I; +assign O = x; +endmodule + diff --git a/tests/gtest/golds/fanout.v b/tests/gtest/golds/fanout.v new file mode 100644 index 000000000..1d6249ca0 --- /dev/null +++ b/tests/gtest/golds/fanout.v @@ -0,0 +1,7 @@ +module Main (input I, output O0, output O1); +wire x; +assign x = I; +assign O0 = x; +assign O1 = x; +endmodule + diff --git a/tests/gtest/golds/nested_array_wire.v b/tests/gtest/golds/nested_array_wire.v new file mode 100644 index 000000000..e8fdb040b --- /dev/null +++ b/tests/gtest/golds/nested_array_wire.v @@ -0,0 +1,10 @@ +module Main (input [4:0] I_0, input [4:0] I_1, input [4:0] I_2, input [4:0] I_3, input [4:0] I_4, output [4:0] O_0, output [4:0] O_1, output [4:0] O_2, output [4:0] O_3, output [4:0] O_4); +wire [24:0] x; +assign x = {I_4[4],I_4[3],I_4[2],I_4[1],I_4[0],I_3[4],I_3[3],I_3[2],I_3[1],I_3[0],I_2[4],I_2[3],I_2[2],I_2[1],I_2[0],I_1[4],I_1[3],I_1[2],I_1[1],I_1[0],I_0[4],I_0[3],I_0[2],I_0[1],I_0[0]}; +assign O_0 = {x[4],x[3],x[2],x[1],x[0]}; +assign O_1 = {x[9],x[8],x[7],x[6],x[5]}; +assign O_2 = {x[14],x[13],x[12],x[11],x[10]}; +assign O_3 = {x[19],x[18],x[17],x[16],x[15]}; +assign O_4 = {x[24],x[23],x[22],x[21],x[20]}; +endmodule + diff --git a/tests/gtest/golds/tuple.v b/tests/gtest/golds/tuple.v new file mode 100644 index 000000000..793efe59d --- /dev/null +++ b/tests/gtest/golds/tuple.v @@ -0,0 +1,7 @@ +module Main (input [4:0] I__0, input I__1, output [4:0] O__0, output O__1); +wire [5:0] x; +assign x = {I__1,I__0[4],I__0[3],I__0[2],I__0[1],I__0[0]}; +assign O__0 = {x[4],x[3],x[2],x[1],x[0]}; +assign O__1 = x[5]; +endmodule + diff --git a/tests/gtest/srcs/arr_tuple.json b/tests/gtest/srcs/arr_tuple.json new file mode 100644 index 000000000..aff4d1d65 --- /dev/null +++ b/tests/gtest/srcs/arr_tuple.json @@ -0,0 +1,37 @@ +{"top":"global.Main", +"namespaces":{ + "global":{ + "modules":{ + "Foo":{ + "type":["Record",[ + ["z",["Array",2,["Record",[["x","BitIn"],["y","Bit"]]]]] + ]] + }, + "Main":{ + "type":["Record",[ + ["z",["Array",2,["Record",[["x","BitIn"],["y","Bit"]]]]] + ]], + "instances":{ + "Foo_inst0":{ + "modref":"global.Foo" + }, + "a_x":{ + "modref":"corebit.wire" + }, + "a_y":{ + "modref":"corebit.wire" + } + }, + "connections":[ + ["a_y.out","Foo_inst0.z.0.x"], + ["a_x.in","Foo_inst0.z.0.y"], + ["self.z.0.x","Foo_inst0.z.1.x"], + ["self.z.1.y","Foo_inst0.z.1.y"], + ["self.z.0.y","a_x.out"], + ["self.z.0.x","a_y.in"] + ] + } + } + } +} +} diff --git a/tests/gtest/srcs/bit_wire.json b/tests/gtest/srcs/bit_wire.json new file mode 100644 index 000000000..6ef52e97f --- /dev/null +++ b/tests/gtest/srcs/bit_wire.json @@ -0,0 +1,23 @@ +{"top":"global.Main", +"namespaces":{ + "global":{ + "modules":{ + "Main":{ + "type":["Record",[ + ["I","BitIn"], + ["O","Bit"] + ]], + "instances":{ + "x":{ + "modref":"corebit.wire" + } + }, + "connections":[ + ["x.in","self.I"], + ["x.out","self.O"] + ] + } + } + } +} +} diff --git a/tests/gtest/srcs/bits_instance.json b/tests/gtest/srcs/bits_instance.json new file mode 100644 index 000000000..4b08abe2f --- /dev/null +++ b/tests/gtest/srcs/bits_instance.json @@ -0,0 +1,34 @@ +{"top":"global.Main", +"namespaces":{ + "global":{ + "modules":{ + "Foo":{ + "type":["Record",[ + ["I",["Array",5,"BitIn"]], + ["O",["Array",5,"Bit"]] + ]] + }, + "Main":{ + "type":["Record",[ + ["I",["Array",5,"BitIn"]], + ["O",["Array",5,"Bit"]] + ]], + "instances":{ + "Foo_inst0":{ + "modref":"global.Foo" + }, + "x":{ + "genref":"coreir.wire", + "genargs":{"width":["Int",5]} + } + }, + "connections":[ + ["self.I","Foo_inst0.I"], + ["x.in","Foo_inst0.O"], + ["x.out","self.O"] + ] + } + } + } +} +} diff --git a/tests/gtest/srcs/bits_wire.json b/tests/gtest/srcs/bits_wire.json new file mode 100644 index 000000000..cb1eebe24 --- /dev/null +++ b/tests/gtest/srcs/bits_wire.json @@ -0,0 +1,24 @@ +{"top":"global.Main", +"namespaces":{ + "global":{ + "modules":{ + "Main":{ + "type":["Record",[ + ["I",["Array",5,"BitIn"]], + ["O",["Array",5,"Bit"]] + ]], + "instances":{ + "x":{ + "genref":"coreir.wire", + "genargs":{"width":["Int",5]} + } + }, + "connections":[ + ["x.in","self.I"], + ["x.out","self.O"] + ] + } + } + } +} +} diff --git a/tests/gtest/srcs/fanout.json b/tests/gtest/srcs/fanout.json new file mode 100644 index 000000000..3519dae23 --- /dev/null +++ b/tests/gtest/srcs/fanout.json @@ -0,0 +1,25 @@ +{"top":"global.Main", +"namespaces":{ + "global":{ + "modules":{ + "Main":{ + "type":["Record",[ + ["I","BitIn"], + ["O0","Bit"], + ["O1","Bit"] + ]], + "instances":{ + "x":{ + "modref":"corebit.wire" + } + }, + "connections":[ + ["x.in","self.I"], + ["x.out","self.O0"], + ["x.out","self.O1"] + ] + } + } + } +} +} diff --git a/tests/gtest/srcs/fanout.v b/tests/gtest/srcs/fanout.v new file mode 100644 index 000000000..3519dae23 --- /dev/null +++ b/tests/gtest/srcs/fanout.v @@ -0,0 +1,25 @@ +{"top":"global.Main", +"namespaces":{ + "global":{ + "modules":{ + "Main":{ + "type":["Record",[ + ["I","BitIn"], + ["O0","Bit"], + ["O1","Bit"] + ]], + "instances":{ + "x":{ + "modref":"corebit.wire" + } + }, + "connections":[ + ["x.in","self.I"], + ["x.out","self.O0"], + ["x.out","self.O1"] + ] + } + } + } +} +} diff --git a/tests/gtest/srcs/nested_array_wire.json b/tests/gtest/srcs/nested_array_wire.json new file mode 100644 index 000000000..36e2bccee --- /dev/null +++ b/tests/gtest/srcs/nested_array_wire.json @@ -0,0 +1,72 @@ +{"top":"global.Main", +"namespaces":{ + "global":{ + "modules":{ + "Main":{ + "type":["Record",[ + ["I",["Array",5,["Array",5,"BitIn"]]], + ["O",["Array",5,["Array",5,"Bit"]]] + ]], + "instances":{ + "x":{ + "genref":"coreir.wire", + "genargs":{"width":["Int",25]} + } + }, + "connections":[ + ["x.in.0","self.I.0.0"], + ["x.in.1","self.I.0.1"], + ["x.in.2","self.I.0.2"], + ["x.in.3","self.I.0.3"], + ["x.in.4","self.I.0.4"], + ["x.in.5","self.I.1.0"], + ["x.in.6","self.I.1.1"], + ["x.in.7","self.I.1.2"], + ["x.in.8","self.I.1.3"], + ["x.in.9","self.I.1.4"], + ["x.in.10","self.I.2.0"], + ["x.in.11","self.I.2.1"], + ["x.in.12","self.I.2.2"], + ["x.in.13","self.I.2.3"], + ["x.in.14","self.I.2.4"], + ["x.in.15","self.I.3.0"], + ["x.in.16","self.I.3.1"], + ["x.in.17","self.I.3.2"], + ["x.in.18","self.I.3.3"], + ["x.in.19","self.I.3.4"], + ["x.in.20","self.I.4.0"], + ["x.in.21","self.I.4.1"], + ["x.in.22","self.I.4.2"], + ["x.in.23","self.I.4.3"], + ["x.in.24","self.I.4.4"], + ["x.out.0","self.O.0.0"], + ["x.out.1","self.O.0.1"], + ["x.out.2","self.O.0.2"], + ["x.out.3","self.O.0.3"], + ["x.out.4","self.O.0.4"], + ["x.out.5","self.O.1.0"], + ["x.out.6","self.O.1.1"], + ["x.out.7","self.O.1.2"], + ["x.out.8","self.O.1.3"], + ["x.out.9","self.O.1.4"], + ["x.out.10","self.O.2.0"], + ["x.out.11","self.O.2.1"], + ["x.out.12","self.O.2.2"], + ["x.out.13","self.O.2.3"], + ["x.out.14","self.O.2.4"], + ["x.out.15","self.O.3.0"], + ["x.out.16","self.O.3.1"], + ["x.out.17","self.O.3.2"], + ["x.out.18","self.O.3.3"], + ["x.out.19","self.O.3.4"], + ["x.out.20","self.O.4.0"], + ["x.out.21","self.O.4.1"], + ["x.out.22","self.O.4.2"], + ["x.out.23","self.O.4.3"], + ["x.out.24","self.O.4.4"] + ] + } + } + } +} +} diff --git a/tests/gtest/srcs/tuple.json b/tests/gtest/srcs/tuple.json new file mode 100644 index 000000000..ae8bd507e --- /dev/null +++ b/tests/gtest/srcs/tuple.json @@ -0,0 +1,34 @@ +{"top":"global.Main", +"namespaces":{ + "global":{ + "modules":{ + "Main":{ + "type":["Record",[ + ["I",["Record",[["_0",["Array",5,"BitIn"]],["_1","BitIn"]]]], + ["O",["Record",[["_0",["Array",5,"Bit"]],["_1","Bit"]]]] + ]], + "instances":{ + "x":{ + "genref":"coreir.wire", + "genargs":{"width":["Int",6]} + } + }, + "connections":[ + ["x.in.0","self.I._0.0"], + ["x.in.1","self.I._0.1"], + ["x.in.2","self.I._0.2"], + ["x.in.3","self.I._0.3"], + ["x.in.4","self.I._0.4"], + ["x.in.5","self.I._1"], + ["x.out.0","self.O._0.0"], + ["x.out.1","self.O._0.1"], + ["x.out.2","self.O._0.2"], + ["x.out.3","self.O._0.3"], + ["x.out.4","self.O._0.4"], + ["x.out.5","self.O._1"] + ] + } + } + } +} +} diff --git a/tests/gtest/test_inline_wires.cpp b/tests/gtest/test_inline_wires.cpp new file mode 100644 index 000000000..fda51f2d0 --- /dev/null +++ b/tests/gtest/test_inline_wires.cpp @@ -0,0 +1,93 @@ +#include <gtest/gtest.h> +#include "assert_pass.h" +#include "coreir.h" +#include "coreir/definitions/coreVerilog.hpp" +#include "coreir/definitions/corebitVerilog.hpp" + +using namespace CoreIR; + +namespace { + +void load_file(Context *context, std::string file_name) { + Module *top; + bool result = loadFromFile(context, file_name, &top); + ASSERT_TRUE(result); + ASSERT_NE(top, nullptr); + context->setTop(top->getRefName()); +} + +void check_verilog(Context *context, std::string gold_file) { + context->runPasses({"flattentypes", "verilog --inline"}, {}); + assertPassEq<Passes::Verilog>(context, gold_file); +} + +TEST(VerilogInlineWireTest, TestBitWire) { + Context *c = newContext(); + CoreIRLoadVerilog_corebit(c); + load_file(c, "srcs/bit_wire.json"); + + check_verilog(c, "golds/bit_wire.v"); + deleteContext(c); +} + +TEST(VerilogInlineWireTest, TestBitsWire) { + Context *c = newContext(); + CoreIRLoadVerilog_coreir(c); + load_file(c, "srcs/bits_wire.json"); + + check_verilog(c, "golds/bits_wire.v"); + deleteContext(c); +} + +TEST(VerilogInlineWireTest, TestNestedArraysWire) { + Context *c = newContext(); + CoreIRLoadVerilog_coreir(c); + load_file(c, "srcs/nested_array_wire.json"); + + check_verilog(c, "golds/nested_array_wire.v"); + deleteContext(c); +} + +TEST(VerilogInlineWireTest, TestTupleWire) { + Context *c = newContext(); + CoreIRLoadVerilog_coreir(c); + load_file(c, "srcs/tuple.json"); + + check_verilog(c, "golds/tuple.v"); + deleteContext(c); +} + +TEST(VerilogInlineWireTest, TestArrTupleWire) { + Context *c = newContext(); + CoreIRLoadVerilog_corebit(c); + CoreIRLoadVerilog_coreir(c); + load_file(c, "srcs/arr_tuple.json"); + + check_verilog(c, "golds/arr_tuple.v"); + deleteContext(c); +} + +TEST(VerilogInlineWireTest, TestFanOut) { + Context *c = newContext(); + CoreIRLoadVerilog_corebit(c); + load_file(c, "srcs/fanout.json"); + + check_verilog(c, "golds/fanout.v"); + deleteContext(c); +} + +TEST(VerilogInlineWireTest, TestInstance) { + Context *c = newContext(); + CoreIRLoadVerilog_coreir(c); + load_file(c, "srcs/bits_instance.json"); + + check_verilog(c, "golds/bits_instance.v"); + deleteContext(c); +} + +} // namespace + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} From 3f972f4457be8a60753b401cd4c2f97eff393122 Mon Sep 17 00:00:00 2001 From: Lenny Truong <leonardtruong@fb.com> Date: Thu, 13 Feb 2020 17:14:09 -0800 Subject: [PATCH 2/6] Check verilogAST branch --- CMakeLists.txt.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt.in b/CMakeLists.txt.in index 98d3d225e..13b3d6802 100644 --- a/CMakeLists.txt.in +++ b/CMakeLists.txt.in @@ -7,7 +7,7 @@ project(verilogAST-download NONE) include(ExternalProject) ExternalProject_Add(verilogAST GIT_REPOSITORY https://github.com/leonardt/verilogAST-cpp.git - GIT_TAG master + GIT_TAG inline-wire-blacklist SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/verilogAST-src" BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/verilogAST-build" CONFIGURE_COMMAND "" From 0d73963f253dc0e3e9989f7901da1f3f617d257c Mon Sep 17 00:00:00 2001 From: Lenny Truong <leonardtruong@fb.com> Date: Fri, 21 Feb 2020 15:42:33 -0800 Subject: [PATCH 3/6] Add todo --- src/passes/analysis/verilog.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/passes/analysis/verilog.cpp b/src/passes/analysis/verilog.cpp index 3ba157b86..092369758 100644 --- a/src/passes/analysis/verilog.cpp +++ b/src/passes/analysis/verilog.cpp @@ -840,6 +840,8 @@ compile_module_body(RecordType *module_type, body.push_back(std::move(statement)); } // Wire the outputs of the module and inout connections + // TODO: Make these object methods so we don't have to pass things aorund so + // much (e.g. _inline flag) assign_module_outputs(module_type, body, connection_map, _inline); assign_inouts(definition->getSortedConnections(), body, _inline); return body; From a0b59f910ca29e516f43e11654998827e3b91dc7 Mon Sep 17 00:00:00 2001 From: Lenny Truong <leonardtruong@fb.com> Date: Fri, 21 Feb 2020 15:52:55 -0800 Subject: [PATCH 4/6] Fix copy elision --- src/passes/analysis/verilog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/passes/analysis/verilog.cpp b/src/passes/analysis/verilog.cpp index 092369758..1e3c6e6d8 100644 --- a/src/passes/analysis/verilog.cpp +++ b/src/passes/analysis/verilog.cpp @@ -151,7 +151,7 @@ std::unique_ptr<vAST::StructuralStatement> inline_unary_op( std::pair<std::string, CoreIR::Instance *> instance, std::unique_ptr<vAST::Connections> verilog_connections, bool is_wire) { - UnaryOpReplacer transformer(std::move(verilog_connections->at("in"))); + UnaryOpReplacer transformer(verilog_connections->at("in")); std::string wire_name = instance.first; if (!is_wire) { wire_name += "_out"; From c25251ec47299a77395b42eb0eaac332e900fa90 Mon Sep 17 00:00:00 2001 From: Lenny Truong <leonardtruong@fb.com> Date: Mon, 24 Feb 2020 15:39:31 -0800 Subject: [PATCH 5/6] Update golds for linebreaks --- tests/gtest/golds/arr_tuple.v | 14 ++++++++++++-- tests/gtest/golds/bit_wire.v | 5 ++++- tests/gtest/golds/bits_instance.v | 10 ++++++++-- tests/gtest/golds/bits_wire.v | 5 ++++- tests/gtest/golds/fanout.v | 6 +++++- tests/gtest/golds/nested_array_wire.v | 13 ++++++++++++- tests/gtest/golds/tuple.v | 7 ++++++- 7 files changed, 51 insertions(+), 9 deletions(-) diff --git a/tests/gtest/golds/arr_tuple.v b/tests/gtest/golds/arr_tuple.v index 57aeed117..e8f80c4b3 100644 --- a/tests/gtest/golds/arr_tuple.v +++ b/tests/gtest/golds/arr_tuple.v @@ -1,9 +1,19 @@ // Module `Foo` defined externally -module Main (input z_0_x, output z_0_y, input z_1_x, output z_1_y); +module Main ( + input z_0_x, + output z_0_y, + input z_1_x, + output z_1_y +); wire Foo_inst0_z_0_y; wire a_x; wire a_y; -Foo Foo_inst0(.z_0_x(a_y), .z_0_y(Foo_inst0_z_0_y), .z_1_x(z_0_x), .z_1_y(z_1_y)); +Foo Foo_inst0 ( + .z_0_x(a_y), + .z_0_y(Foo_inst0_z_0_y), + .z_1_x(z_0_x), + .z_1_y(z_1_y) +); assign a_x = Foo_inst0_z_0_y; assign a_y = z_0_x; assign z_0_y = a_x; diff --git a/tests/gtest/golds/bit_wire.v b/tests/gtest/golds/bit_wire.v index 74f4b9e43..f4d32abd7 100644 --- a/tests/gtest/golds/bit_wire.v +++ b/tests/gtest/golds/bit_wire.v @@ -1,4 +1,7 @@ -module Main (input I, output O); +module Main ( + input I, + output O +); wire x; assign x = I; assign O = x; diff --git a/tests/gtest/golds/bits_instance.v b/tests/gtest/golds/bits_instance.v index a88ece5cc..d7d5a5b1c 100644 --- a/tests/gtest/golds/bits_instance.v +++ b/tests/gtest/golds/bits_instance.v @@ -1,8 +1,14 @@ // Module `Foo` defined externally -module Main (input [4:0] I, output [4:0] O); +module Main ( + input [4:0] I, + output [4:0] O +); wire [4:0] Foo_inst0_O; wire [4:0] x; -Foo Foo_inst0(.I(I), .O(Foo_inst0_O)); +Foo Foo_inst0 ( + .I(I), + .O(Foo_inst0_O) +); assign x = Foo_inst0_O; assign O = x; endmodule diff --git a/tests/gtest/golds/bits_wire.v b/tests/gtest/golds/bits_wire.v index 133f73bca..42a9c2abe 100644 --- a/tests/gtest/golds/bits_wire.v +++ b/tests/gtest/golds/bits_wire.v @@ -1,4 +1,7 @@ -module Main (input [4:0] I, output [4:0] O); +module Main ( + input [4:0] I, + output [4:0] O +); wire [4:0] x; assign x = I; assign O = x; diff --git a/tests/gtest/golds/fanout.v b/tests/gtest/golds/fanout.v index 1d6249ca0..fd96f4892 100644 --- a/tests/gtest/golds/fanout.v +++ b/tests/gtest/golds/fanout.v @@ -1,4 +1,8 @@ -module Main (input I, output O0, output O1); +module Main ( + input I, + output O0, + output O1 +); wire x; assign x = I; assign O0 = x; diff --git a/tests/gtest/golds/nested_array_wire.v b/tests/gtest/golds/nested_array_wire.v index e8fdb040b..9d3372f6f 100644 --- a/tests/gtest/golds/nested_array_wire.v +++ b/tests/gtest/golds/nested_array_wire.v @@ -1,4 +1,15 @@ -module Main (input [4:0] I_0, input [4:0] I_1, input [4:0] I_2, input [4:0] I_3, input [4:0] I_4, output [4:0] O_0, output [4:0] O_1, output [4:0] O_2, output [4:0] O_3, output [4:0] O_4); +module Main ( + input [4:0] I_0, + input [4:0] I_1, + input [4:0] I_2, + input [4:0] I_3, + input [4:0] I_4, + output [4:0] O_0, + output [4:0] O_1, + output [4:0] O_2, + output [4:0] O_3, + output [4:0] O_4 +); wire [24:0] x; assign x = {I_4[4],I_4[3],I_4[2],I_4[1],I_4[0],I_3[4],I_3[3],I_3[2],I_3[1],I_3[0],I_2[4],I_2[3],I_2[2],I_2[1],I_2[0],I_1[4],I_1[3],I_1[2],I_1[1],I_1[0],I_0[4],I_0[3],I_0[2],I_0[1],I_0[0]}; assign O_0 = {x[4],x[3],x[2],x[1],x[0]}; diff --git a/tests/gtest/golds/tuple.v b/tests/gtest/golds/tuple.v index 793efe59d..c224e7ef8 100644 --- a/tests/gtest/golds/tuple.v +++ b/tests/gtest/golds/tuple.v @@ -1,4 +1,9 @@ -module Main (input [4:0] I__0, input I__1, output [4:0] O__0, output O__1); +module Main ( + input [4:0] I__0, + input I__1, + output [4:0] O__0, + output O__1 +); wire [5:0] x; assign x = {I__1,I__0[4],I__0[3],I__0[2],I__0[1],I__0[0]}; assign O__0 = {x[4],x[3],x[2],x[1],x[0]}; From c2445b6790c2e237f4989d64546de8c66d3734f7 Mon Sep 17 00:00:00 2001 From: Lenny Truong <leonardtruong@fb.com> Date: Mon, 24 Feb 2020 16:04:18 -0800 Subject: [PATCH 6/6] Use master branch --- CMakeLists.txt.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt.in b/CMakeLists.txt.in index 13b3d6802..98d3d225e 100644 --- a/CMakeLists.txt.in +++ b/CMakeLists.txt.in @@ -7,7 +7,7 @@ project(verilogAST-download NONE) include(ExternalProject) ExternalProject_Add(verilogAST GIT_REPOSITORY https://github.com/leonardt/verilogAST-cpp.git - GIT_TAG inline-wire-blacklist + GIT_TAG master SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/verilogAST-src" BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/verilogAST-build" CONFIGURE_COMMAND ""