Add "autoname" pass and use it in "synth_ice40"

Signed-off-by: Clifford Wolf <clifford@clifford.at>
diff --git a/passes/cmds/Makefile.inc b/passes/cmds/Makefile.inc
index cf9663d..c7edc30 100644
--- a/passes/cmds/Makefile.inc
+++ b/passes/cmds/Makefile.inc
@@ -5,6 +5,7 @@
 OBJS += passes/cmds/select.o
 OBJS += passes/cmds/show.o
 OBJS += passes/cmds/rename.o
+OBJS += passes/cmds/autoname.o
 OBJS += passes/cmds/connect.o
 OBJS += passes/cmds/scatter.o
 OBJS += passes/cmds/setundef.o
diff --git a/passes/cmds/autoname.cc b/passes/cmds/autoname.cc
new file mode 100644
index 0000000..4614a81
--- /dev/null
+++ b/passes/cmds/autoname.cc
@@ -0,0 +1,134 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+int autoname_worker(Module *module)
+{
+	dict<Cell*, pair<int, IdString>> proposed_cell_names;
+	dict<Wire*, pair<int, IdString>> proposed_wire_names;
+	dict<Wire*, int> wire_score;
+	int best_score = -1;
+
+	for (auto cell : module->selected_cells())
+	for (auto &conn : cell->connections())
+	for (auto bit : conn.second)
+		if (bit.wire != nullptr)
+			wire_score[bit.wire]++;
+
+	for (auto cell : module->selected_cells()) {
+		if (cell->name[0] == '$') {
+			for (auto &conn : cell->connections()) {
+				string suffix = stringf("_%s_%s", log_id(cell->type), log_id(conn.first));
+				for (auto bit : conn.second)
+					if (bit.wire != nullptr && bit.wire->name[0] != '$') {
+						IdString new_name(bit.wire->name.str() + suffix);
+						int score = wire_score.at(bit.wire);
+						if (cell->output(conn.first)) score = 0;
+						score = 10000*score + new_name.size();
+						if (!proposed_cell_names.count(cell) || score < proposed_cell_names.at(cell).first) {
+							if (best_score < 0 || score < best_score)
+								best_score = score;
+							proposed_cell_names[cell] = make_pair(score, new_name);
+						}
+					}
+			}
+		} else {
+			for (auto &conn : cell->connections()) {
+				string suffix = stringf("_%s", log_id(conn.first));
+				for (auto bit : conn.second)
+					if (bit.wire != nullptr && bit.wire->name[0] == '$') {
+						IdString new_name(cell->name.str() + suffix);
+						int score = wire_score.at(bit.wire);
+						if (cell->output(conn.first)) score = 0;
+						score = 10000*score + new_name.size();
+						if (!proposed_wire_names.count(bit.wire) || score < proposed_wire_names.at(bit.wire).first) {
+							if (best_score < 0 || score < best_score)
+								best_score = score;
+							proposed_wire_names[bit.wire] = make_pair(score, new_name);
+						}
+					}
+			}
+		}
+	}
+
+	for (auto &it : proposed_cell_names) {
+		if (best_score*2 < it.second.first)
+			continue;
+		IdString n = module->uniquify(it.second.second);
+		log_debug("Rename cell %s in %s to %s.\n", log_id(it.first), log_id(module), log_id(n));
+		module->rename(it.first, n);
+	}
+
+	for (auto &it : proposed_wire_names) {
+		if (best_score*2 < it.second.first)
+			continue;
+		IdString n = module->uniquify(it.second.second);
+		log_debug("Rename wire %s in %s to %s.\n", log_id(it.first), log_id(module), log_id(n));
+		module->rename(it.first, n);
+	}
+
+	return proposed_cell_names.size() + proposed_wire_names.size();
+}
+
+struct AutonamePass : public Pass {
+	AutonamePass() : Pass("autoname", "automatically assign names to objects") { }
+	void help() YS_OVERRIDE
+	{
+		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+		log("\n");
+		log("    autoname [selection]\n");
+		log("\n");
+		log("Assign auto-generated public names to objects with private names (the ones\n");
+		log("with $-prefix).\n");
+		log("\n");
+	}
+	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+	{
+		size_t argidx;
+		for (argidx = 1; argidx < args.size(); argidx++)
+		{
+			// if (args[argidx] == "-foo") {
+			// 	foo = true;
+			// 	continue;
+			// }
+			break;
+		}
+
+		log_header(design, "Executing AUTONAME pass.\n");
+
+		for (auto module : design->selected_modules())
+		{
+			int count = 0, iter = 0;
+			while (1) {
+				iter++;
+				int n = autoname_worker(module);
+				if (!n) break;
+				count += n;
+			}
+			if (count > 0)
+				log("Renamed %d objects in module %s (%d iterations).\n", count, log_id(module), iter);
+		}
+	}
+} AutonamePass;
+
+PRIVATE_NAMESPACE_END
diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc
index c942126..901194b 100644
--- a/techlibs/ice40/synth_ice40.cc
+++ b/techlibs/ice40/synth_ice40.cc
@@ -380,6 +380,7 @@
 
 		if (check_label("check"))
 		{
+			run("autoname");
 			run("hierarchy -check");
 			run("stat");
 			run("check -noinit");