From 07c4a7d4388cdacaa15512dd2f6f0f9e9fcb31f5 Mon Sep 17 00:00:00 2001
From: Bogdan Vukobratovic <bogdan.vukobratovic@gmail.com>
Date: Fri, 26 Jul 2019 11:36:48 +0200
Subject: [PATCH 01/20] Implement opt_share

This pass identifies arithmetic operators that share an operand and whose
results are used in mutually exclusive cases controlled by a multiplexer, and
merges them together by multiplexing the other operands
---
 passes/opt/Makefile.inc         |   2 +-
 passes/opt/opt_share.cc         | 329 ++++++++++++++++++++++++++++++++
 tests/opt/opt_share_cat.v       |  15 ++
 tests/opt/opt_share_cat.ys      |   9 +
 tests/opt/opt_share_mux_tree.v  |  19 ++
 tests/opt/opt_share_mux_tree.ys |  10 +
 6 files changed, 383 insertions(+), 1 deletion(-)
 create mode 100644 passes/opt/opt_share.cc
 create mode 100644 tests/opt/opt_share_cat.v
 create mode 100644 tests/opt/opt_share_cat.ys
 create mode 100644 tests/opt/opt_share_mux_tree.v
 create mode 100644 tests/opt/opt_share_mux_tree.ys

diff --git a/passes/opt/Makefile.inc b/passes/opt/Makefile.inc
index ea3646330..eb07e9452 100644
--- a/passes/opt/Makefile.inc
+++ b/passes/opt/Makefile.inc
@@ -4,6 +4,7 @@ OBJS += passes/opt/opt_merge.o
 OBJS += passes/opt/opt_muxtree.o
 OBJS += passes/opt/opt_reduce.o
 OBJS += passes/opt/opt_rmdff.o
+OBJS += passes/opt/opt_share.o
 OBJS += passes/opt/opt_clean.o
 OBJS += passes/opt/opt_expr.o
 
@@ -16,4 +17,3 @@ OBJS += passes/opt/opt_lut.o
 OBJS += passes/opt/pmux2shiftx.o
 OBJS += passes/opt/muxpack.o
 endif
-
diff --git a/passes/opt/opt_share.cc b/passes/opt/opt_share.cc
new file mode 100644
index 000000000..9f6f59b64
--- /dev/null
+++ b/passes/opt/opt_share.cc
@@ -0,0 +1,329 @@
+/*
+ *  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/log.h"
+#include "kernel/register.h"
+#include "kernel/rtlil.h"
+#include "kernel/sigtools.h"
+#include <algorithm>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+SigMap assign_map;
+
+// Helper class that to track whether a SigSpec is signed and whether it is
+// connected to the \\B port of the $sub cell, which makes its sign prefix
+// negative.
+struct ExtSigSpec {
+	RTLIL::SigSpec sig;
+	bool sign;
+	bool is_signed;
+
+	ExtSigSpec() {}
+
+	ExtSigSpec(RTLIL::SigSpec s, bool sign = false, bool is_signed = false) : sig(s), sign(sign), is_signed(is_signed) {}
+
+	ExtSigSpec(RTLIL::Cell *cell, RTLIL::IdString port_name, SigMap *sigmap)
+	{
+		sign = (cell->type == "$sub") && (port_name == "\\B");
+		sig = (*sigmap)(cell->getPort(port_name));
+
+		is_signed = false;
+		if (cell->hasParam(port_name.str() + "_SIGNED")) {
+			is_signed = cell->getParam(port_name.str() + "_SIGNED").as_bool();
+		}
+	}
+
+	bool empty() const { return sig.empty(); }
+
+	bool operator<(const ExtSigSpec &other) const
+	{
+		if (sig != other.sig)
+			return sig < other.sig;
+
+		if (sign != other.sign)
+			return sign < other.sign;
+
+		return is_signed < other.is_signed;
+	}
+
+	bool operator==(const RTLIL::SigSpec &other) const { return sign ? false : sig == other; }
+	bool operator==(const ExtSigSpec &other) const { return is_signed == other.is_signed && sign == other.sign && sig == other.sig; }
+};
+
+void merge_operators(RTLIL::Module *module, RTLIL::Cell *mux, const std::vector<RTLIL::Cell *> &operators, int offset, int width,
+		     const ExtSigSpec &operand)
+{
+
+	std::vector<ExtSigSpec> muxed_operands;
+	int max_width = 0;
+	for (auto op : operators) {
+		for (auto &conn : op->connections()) {
+			if (op->output(conn.first))
+				continue;
+
+			if (conn.second != operand.sig) {
+				auto operand = ExtSigSpec(op, conn.first, &assign_map);
+				if (operand.sig.size() > max_width) {
+					max_width = operand.sig.size();
+				}
+
+				muxed_operands.push_back(operand);
+			}
+		}
+	}
+
+	for (auto &operand : muxed_operands) {
+		operand.sig.extend_u0(max_width, operand.is_signed);
+	}
+
+	auto shared_op = operators[0];
+
+	for (auto op : operators) {
+		if (op == shared_op)
+			continue;
+		module->remove(op);
+	}
+
+	RTLIL::SigSpec mux_out = mux->getPort("\\Y");
+
+	if (muxed_operands[0].sign != muxed_operands[1].sign) {
+		muxed_operands[1] = ExtSigSpec(module->Neg(NEW_ID, muxed_operands[1].sig, muxed_operands[1].is_signed));
+	}
+
+	auto mux_to_oper = module->Mux(NEW_ID, muxed_operands[0].sig, muxed_operands[1].sig, mux->getPort("\\S"));
+
+	shared_op->setPort("\\Y", mux_out.extract(offset, width));
+	shared_op->setParam("\\Y_WIDTH", width);
+
+	auto dummy = module->addWire(NEW_ID, width);
+
+	mux_out.replace(offset, dummy);
+	mux->setPort("\\Y", mux_out);
+
+	if (shared_op->getPort("\\A") == operand.sig) {
+		shared_op->setPort("\\B", mux_to_oper);
+		shared_op->setParam("\\B_WIDTH", max_width);
+	} else {
+		shared_op->setPort("\\A", mux_to_oper);
+		shared_op->setParam("\\A_WIDTH", max_width);
+	}
+}
+
+typedef struct {
+	RTLIL::Cell *mux;
+	std::vector<RTLIL::Cell *> operators;
+	int offset;
+	int width;
+	ExtSigSpec shared_operand;
+} shared_op_t;
+
+bool find_op_res_width(int offset, int &width, RTLIL::SigSpec porta, RTLIL::SigSpec portb,
+		       const dict<RTLIL::SigBit, RTLIL::SigSpec> &op_outbit_to_outsig, const dict<RTLIL::SigBit, int> &op_outbit_user_cnt)
+{
+
+	std::array<RTLIL::SigSpec, 2> op_outsigs{op_outbit_to_outsig.at(porta[offset]), op_outbit_to_outsig.at(portb[offset])};
+
+	width = 0;
+	bool multi_user = false;
+
+	while (true) {
+		for (const auto &op_outsig : op_outsigs)
+			if (op_outbit_user_cnt.at(op_outsig[width]) > 1)
+				multi_user = true;
+
+		++offset;
+		++width;
+
+		if ((offset >= porta.size()) || (width >= op_outsigs[0].size()) || (width >= op_outsigs[1].size()))
+			break;
+
+		if ((porta[offset] != op_outsigs[0][width]) || (portb[offset] != op_outsigs[1][width]))
+			break;
+	}
+
+	if (multi_user)
+		return false;
+
+	for (const auto &outsig : op_outsigs)
+		for (int i = width; i < outsig.size(); i++)
+			if (op_outbit_user_cnt.count(outsig[i]))
+				return false;
+
+	return true;
+}
+
+ExtSigSpec find_shared_operand(const std::vector<RTLIL::Cell *> &operators, const std::map<ExtSigSpec, std::set<RTLIL::Cell *>> &operand_to_users)
+{
+
+	std::set<RTLIL::Cell *> operators_set(operators.begin(), operators.end());
+	ExtSigSpec oper;
+
+	auto op_a = operators[0];
+	for (auto &conn : op_a->connections()) {
+		if (op_a->output(conn.first))
+			continue;
+
+		oper = ExtSigSpec(op_a, conn.first, &assign_map);
+		auto bundle = operand_to_users.at(oper);
+
+		if (std::includes(bundle.begin(), bundle.end(), operators_set.begin(), operators_set.end()))
+			break;
+	}
+
+	return oper;
+}
+
+dict<RTLIL::SigBit, int> find_op_outbit_user_cnt(RTLIL::Module *module, const dict<RTLIL::SigBit, RTLIL::SigSpec> &op_outbit_to_outsig)
+{
+	dict<RTLIL::SigBit, int> op_outbit_user_cnt;
+
+	std::function<void(SigSpec)> update_op_outbit_user_cnt = [&](SigSpec sig) {
+		auto outsig = assign_map(sig);
+		for (auto outbit : outsig)
+			if (op_outbit_to_outsig.count(outbit))
+				op_outbit_user_cnt[outbit]++;
+	};
+
+	for (auto cell : module->cells())
+		for (auto &conn : cell->connections())
+			if (cell->input(conn.first))
+				update_op_outbit_user_cnt(conn.second);
+
+	for (auto w : module->wires()) {
+		if (!w->port_output)
+			continue;
+
+		update_op_outbit_user_cnt(w);
+	}
+
+	return op_outbit_user_cnt;
+}
+
+struct OptRmdffPass : public Pass {
+	OptRmdffPass() : Pass("opt_share", "merge arithmetic operators that share an operand") {}
+	void help() YS_OVERRIDE
+	{
+		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+		log("\n");
+		log("    opt_share [selection]\n");
+		log("\n");
+		log("This pass identifies arithmetic operators that share an operand and whose\n");
+		log("results are used in mutually exclusive cases controlled by a multiplexer,\n");
+		log("and merges them together by multiplexing the other operands.\n");
+		log("\n");
+	}
+	void execute(std::vector<std::string>, RTLIL::Design *design) YS_OVERRIDE
+	{
+
+		log_header(design, "Executing OPT_SHARE pass.\n");
+
+		for (auto module : design->selected_modules()) {
+			assign_map.clear();
+			assign_map.set(module);
+
+			std::map<ExtSigSpec, std::set<RTLIL::Cell *>> operand_to_users;
+			dict<RTLIL::SigSpec, RTLIL::Cell *> outsig_to_operator;
+			dict<RTLIL::SigBit, RTLIL::SigSpec> op_outbit_to_outsig;
+			bool any_shared_operands = false;
+
+			for (auto cell : module->cells()) {
+				if (!cell->type.in("$add", "$sub"))
+					continue;
+
+				for (auto &conn : cell->connections()) {
+					if (cell->output(conn.first)) {
+						auto outsig = assign_map(conn.second);
+						for (auto outbit : outsig)
+							op_outbit_to_outsig[outbit] = outsig;
+
+						outsig_to_operator[outsig] = cell;
+					} else {
+						auto op_insig = ExtSigSpec(cell, conn.first, &assign_map);
+						operand_to_users[op_insig].insert(cell);
+						if (operand_to_users[op_insig].size() > 1)
+							any_shared_operands = true;
+					}
+				}
+			}
+
+			if (!any_shared_operands)
+				continue;
+
+			// Operator outputs need to be exclusively connected to the $mux inputs in order to be mergeable. Hence we count to
+			// how many points are operator output bits connected.
+			dict<RTLIL::SigBit, int> op_outbit_user_cnt = find_op_outbit_user_cnt(module, op_outbit_to_outsig);
+			std::vector<shared_op_t> shared_ops;
+			for (auto cell : module->cells()) {
+				if (!cell->type.in("$mux", "$_MUX_"))
+					continue;
+
+				auto porta = assign_map(cell->getPort("\\A"));
+				auto portb = assign_map(cell->getPort("\\B"));
+
+				// Look through the bits of the $mux inputs and see which of them are connected to the operator
+				// results. Operator results can be concatenated with other signals before led to the $mux.
+				for (int i = 0; i < porta.size(); ++i) {
+					std::array<RTLIL::SigBit, 2> mux_inbits{porta[i], portb[i]};
+
+					// Are the results of an $add or $sub operators connected to both of this $mux inputs?
+					if (!op_outbit_to_outsig.count(mux_inbits[0]) or !op_outbit_to_outsig.count(mux_inbits[1]))
+						continue;
+
+					std::vector<RTLIL::Cell *> operators;
+					for (const auto &b : mux_inbits)
+						operators.push_back(outsig_to_operator.at(op_outbit_to_outsig.at(b)));
+
+					// Do these operators share an operand?
+					auto shared_operand = find_shared_operand(operators, operand_to_users);
+					if (shared_operand.empty())
+						continue;
+
+					// Some bits of the operator results might be unconnected. Calculate the number of conneted
+					// bits.
+					int width;
+
+					if (find_op_res_width(i, width, porta, portb, op_outbit_to_outsig, op_outbit_user_cnt))
+						shared_ops.push_back(shared_op_t{cell, operators, i, width, shared_operand});
+
+					i += width - 1;
+				}
+			}
+
+			for (auto &shared : shared_ops) {
+				log("    Found arithmetic cells that share an operand and can be merged by moving the %s %s in front "
+				    "of "
+				    "them:\n",
+				    log_id(shared.mux->type), log_id(shared.mux));
+				for (auto op : shared.operators)
+					log("        %s\n", log_id(op));
+				log("\n");
+
+				merge_operators(module, shared.mux, shared.operators, shared.offset, shared.width, shared.shared_operand);
+			}
+		}
+	}
+
+} OptRmdffPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/tests/opt/opt_share_cat.v b/tests/opt/opt_share_cat.v
new file mode 100644
index 000000000..c32073360
--- /dev/null
+++ b/tests/opt/opt_share_cat.v
@@ -0,0 +1,15 @@
+module add_sub(
+               input [15:0]  a,
+               input [15:0]  b,
+               input [15:0]  c,
+               input [15:0]  d,
+               input 				 sel,
+               output [63:0] res,
+               );
+
+  reg [31: 0] 							 cat1 = {a+b, c+d};
+  reg [31: 0] 							 cat2 = {a-b, c-d};
+
+  assign res = {b, sel ? cat1 : cat2, a};
+
+endmodule
diff --git a/tests/opt/opt_share_cat.ys b/tests/opt/opt_share_cat.ys
new file mode 100644
index 000000000..c3f2f5a2f
--- /dev/null
+++ b/tests/opt/opt_share_cat.ys
@@ -0,0 +1,9 @@
+read_verilog opt_share_cat.v
+prep -flatten
+opt
+pmuxtree
+opt_share
+opt_clean
+
+select -assert-count 2 t:$sub
+select -assert-count 0 t:$add
diff --git a/tests/opt/opt_share_mux_tree.v b/tests/opt/opt_share_mux_tree.v
new file mode 100644
index 000000000..807ed2978
--- /dev/null
+++ b/tests/opt/opt_share_mux_tree.v
@@ -0,0 +1,19 @@
+module add_sub(
+               input [15:0] 		 a,
+               input [15:0] 		 b,
+               input [15:0] 		 c,
+               input [1:0] 			 sel,
+               output reg [15:0] res
+               );
+
+
+  always @* begin
+    case(sel)
+      0: res = a + b;
+      1: res = a - b;
+      2: res = a + c;
+      default: res = 16'bx;
+    endcase
+  end
+
+endmodule
diff --git a/tests/opt/opt_share_mux_tree.ys b/tests/opt/opt_share_mux_tree.ys
new file mode 100644
index 000000000..94d6aa7d2
--- /dev/null
+++ b/tests/opt/opt_share_mux_tree.ys
@@ -0,0 +1,10 @@
+read_verilog opt_share_mux_tree.v
+prep -flatten
+opt
+pmuxtree
+opt_share;
+opt_share;
+opt_clean
+
+select -assert-count 1 t:$add
+select -assert-count 0 t:$sub

From c075486c59155d16ed278922a3752366a95246ff Mon Sep 17 00:00:00 2001
From: Bogdan Vukobratovic <bogdan.vukobratovic@gmail.com>
Date: Sun, 28 Jul 2019 16:03:54 +0200
Subject: [PATCH 02/20] Reimplement opt_share to work on $alu and $pmux

---
 passes/opt/opt_share.cc                       | 322 ++++++++++++------
 tests/opt/opt_share_add_sub.v                 |  10 +
 tests/opt/opt_share_add_sub.ys                |  13 +
 tests/opt/opt_share_cat.v                     |   2 +-
 tests/opt/opt_share_cat.ys                    |  18 +-
 tests/opt/opt_share_cat_multiuser.v           |  22 ++
 tests/opt/opt_share_cat_multiuser.ys          |  13 +
 tests/opt/opt_share_diff_port_widths.v        |  21 ++
 tests/opt/opt_share_diff_port_widths.ys       |  13 +
 tests/opt/opt_share_extend.v                  |  19 ++
 tests/opt/opt_share_extend.ys                 |  13 +
 tests/opt/opt_share_large_pmux_cat.v          |  22 ++
 tests/opt/opt_share_large_pmux_cat.ys         |  13 +
 .../opt/opt_share_large_pmux_cat_multipart.v  |  25 ++
 .../opt/opt_share_large_pmux_cat_multipart.ys |  15 +
 tests/opt/opt_share_large_pmux_multipart.v    |  24 ++
 tests/opt/opt_share_large_pmux_multipart.ys   |  13 +
 tests/opt/opt_share_large_pmux_part.v         |  22 ++
 tests/opt/opt_share_large_pmux_part.ys        |  13 +
 tests/opt/opt_share_mux_tree.v                |   2 +-
 tests/opt/opt_share_mux_tree.ys               |  19 +-
 21 files changed, 521 insertions(+), 113 deletions(-)
 create mode 100644 tests/opt/opt_share_add_sub.v
 create mode 100644 tests/opt/opt_share_add_sub.ys
 create mode 100644 tests/opt/opt_share_cat_multiuser.v
 create mode 100644 tests/opt/opt_share_cat_multiuser.ys
 create mode 100644 tests/opt/opt_share_diff_port_widths.v
 create mode 100644 tests/opt/opt_share_diff_port_widths.ys
 create mode 100644 tests/opt/opt_share_extend.v
 create mode 100644 tests/opt/opt_share_extend.ys
 create mode 100644 tests/opt/opt_share_large_pmux_cat.v
 create mode 100644 tests/opt/opt_share_large_pmux_cat.ys
 create mode 100644 tests/opt/opt_share_large_pmux_cat_multipart.v
 create mode 100644 tests/opt/opt_share_large_pmux_cat_multipart.ys
 create mode 100644 tests/opt/opt_share_large_pmux_multipart.v
 create mode 100644 tests/opt/opt_share_large_pmux_multipart.ys
 create mode 100644 tests/opt/opt_share_large_pmux_part.v
 create mode 100644 tests/opt/opt_share_large_pmux_part.ys

diff --git a/passes/opt/opt_share.cc b/passes/opt/opt_share.cc
index 9f6f59b64..e9a2f05f9 100644
--- a/passes/opt/opt_share.cc
+++ b/passes/opt/opt_share.cc
@@ -31,12 +31,21 @@ PRIVATE_NAMESPACE_BEGIN
 
 SigMap assign_map;
 
+struct InPort {
+	RTLIL::SigSpec sig;
+	RTLIL::Cell *pmux;
+	int port_id;
+	RTLIL::Cell *alu;
+
+	InPort(RTLIL::SigSpec s, RTLIL::Cell *c, int p, RTLIL::Cell *a = NULL) : sig(s), pmux(c), port_id(p), alu(a) {}
+};
+
 // Helper class that to track whether a SigSpec is signed and whether it is
 // connected to the \\B port of the $sub cell, which makes its sign prefix
 // negative.
 struct ExtSigSpec {
 	RTLIL::SigSpec sig;
-	bool sign;
+	RTLIL::SigSpec sign;
 	bool is_signed;
 
 	ExtSigSpec() {}
@@ -45,7 +54,7 @@ struct ExtSigSpec {
 
 	ExtSigSpec(RTLIL::Cell *cell, RTLIL::IdString port_name, SigMap *sigmap)
 	{
-		sign = (cell->type == "$sub") && (port_name == "\\B");
+		sign = (port_name == "\\B") ? cell->getPort("\\BI") : RTLIL::Const(0, 1);
 		sig = (*sigmap)(cell->getPort(port_name));
 
 		is_signed = false;
@@ -67,23 +76,22 @@ struct ExtSigSpec {
 		return is_signed < other.is_signed;
 	}
 
-	bool operator==(const RTLIL::SigSpec &other) const { return sign ? false : sig == other; }
+	bool operator==(const RTLIL::SigSpec &other) const { return (sign != RTLIL::Const(0, 1)) ? false : sig == other; }
 	bool operator==(const ExtSigSpec &other) const { return is_signed == other.is_signed && sign == other.sign && sig == other.sig; }
 };
 
-void merge_operators(RTLIL::Module *module, RTLIL::Cell *mux, const std::vector<RTLIL::Cell *> &operators, int offset, int width,
+void merge_operators(RTLIL::Module *module, RTLIL::Cell *mux, const std::vector<InPort> &ports, int offset, int width,
 		     const ExtSigSpec &operand)
 {
 
 	std::vector<ExtSigSpec> muxed_operands;
 	int max_width = 0;
-	for (auto op : operators) {
-		for (auto &conn : op->connections()) {
-			if (op->output(conn.first))
-				continue;
+	for (const auto& p : ports) {
+		auto op = p.alu;
 
-			if (conn.second != operand.sig) {
-				auto operand = ExtSigSpec(op, conn.first, &assign_map);
+		for (RTLIL::IdString port_name : {"\\A", "\\B"}) {
+			if (op->getPort(port_name) != operand.sig) {
+				auto operand = ExtSigSpec(op, port_name, &assign_map);
 				if (operand.sig.size() > max_width) {
 					max_width = operand.sig.size();
 				}
@@ -97,30 +105,61 @@ void merge_operators(RTLIL::Module *module, RTLIL::Cell *mux, const std::vector<
 		operand.sig.extend_u0(max_width, operand.is_signed);
 	}
 
-	auto shared_op = operators[0];
+	auto shared_op = ports[0].alu;
 
-	for (auto op : operators) {
+	for (const auto& p : ports) {
+		auto op = p.alu;
 		if (op == shared_op)
 			continue;
 		module->remove(op);
 	}
 
-	RTLIL::SigSpec mux_out = mux->getPort("\\Y");
-
-	if (muxed_operands[0].sign != muxed_operands[1].sign) {
-		muxed_operands[1] = ExtSigSpec(module->Neg(NEW_ID, muxed_operands[1].sig, muxed_operands[1].is_signed));
+	for (auto &muxed_op : muxed_operands) {
+		if (muxed_op.sign != muxed_operands[0].sign) {
+			muxed_op = ExtSigSpec(module->Neg(NEW_ID, muxed_op.sig, muxed_op.is_signed));
+		}
 	}
 
-	auto mux_to_oper = module->Mux(NEW_ID, muxed_operands[0].sig, muxed_operands[1].sig, mux->getPort("\\S"));
+	RTLIL::SigSpec mux_y = mux->getPort("\\Y");
+	RTLIL::SigSpec mux_a = mux->getPort("\\A");
+	RTLIL::SigSpec mux_b = mux->getPort("\\B");
+	RTLIL::SigSpec mux_s = mux->getPort("\\S");
 
-	shared_op->setPort("\\Y", mux_out.extract(offset, width));
+	RTLIL::SigSpec alu_x = shared_op->getPort("\\X");
+	RTLIL::SigSpec alu_co = shared_op->getPort("\\CO");
+
+	RTLIL::SigSpec shared_pmux_a = RTLIL::Const(RTLIL::State::Sx, max_width);
+	RTLIL::SigSpec shared_pmux_b;
+	RTLIL::SigSpec shared_pmux_s;
+
+	shared_op->setPort("\\Y", shared_op->getPort("\\Y").extract(0, width));
+
+	if (mux->type == "$pmux") {
+		shared_pmux_s = RTLIL::SigSpec();
+
+		for (const auto&p: ports) {
+			shared_pmux_s.append(mux_s[p.port_id]);
+			mux_b.replace(p.port_id * mux_a.size() + offset, shared_op->getPort("\\Y"));
+		}
+	} else {
+		shared_pmux_s = RTLIL::SigSpec{mux_s, module->Not(NEW_ID, mux_s)};
+		mux_a.replace(offset, shared_op->getPort("\\Y"));
+		mux_b.replace(offset, shared_op->getPort("\\Y"));
+	}
+
+	mux->setPort("\\Y", mux_y);
+	mux->setPort("\\S", mux_s);
+	mux->setPort("\\B", mux_b);
+
+	for (const auto &op : muxed_operands)
+		shared_pmux_b.append(op.sig);
+
+	auto mux_to_oper = module->Pmux(NEW_ID, shared_pmux_a, shared_pmux_b, shared_pmux_s);
+
+	shared_op->setPort("\\X", alu_x.extract(0, width));
+	shared_op->setPort("\\CO", alu_co.extract(0, width));
 	shared_op->setParam("\\Y_WIDTH", width);
 
-	auto dummy = module->addWire(NEW_ID, width);
-
-	mux_out.replace(offset, dummy);
-	mux->setPort("\\Y", mux_out);
-
 	if (shared_op->getPort("\\A") == operand.sig) {
 		shared_op->setPort("\\B", mux_to_oper);
 		shared_op->setParam("\\B_WIDTH", max_width);
@@ -128,81 +167,132 @@ void merge_operators(RTLIL::Module *module, RTLIL::Cell *mux, const std::vector<
 		shared_op->setPort("\\A", mux_to_oper);
 		shared_op->setParam("\\A_WIDTH", max_width);
 	}
+
 }
 
 typedef struct {
 	RTLIL::Cell *mux;
-	std::vector<RTLIL::Cell *> operators;
+	std::vector<InPort> ports;
 	int offset;
 	int width;
 	ExtSigSpec shared_operand;
 } shared_op_t;
 
-bool find_op_res_width(int offset, int &width, RTLIL::SigSpec porta, RTLIL::SigSpec portb,
-		       const dict<RTLIL::SigBit, RTLIL::SigSpec> &op_outbit_to_outsig, const dict<RTLIL::SigBit, int> &op_outbit_user_cnt)
+
+template <typename T> void remove_val(std::vector<T> &v, const std::vector<T> &vals)
+{
+	auto val_iter = vals.rbegin();
+	for (auto i = v.rbegin(); i != v.rend(); ++i)
+		if ((val_iter != vals.rend()) && (*i == *val_iter)) {
+			v.erase(i.base() - 1);
+			++val_iter;
+		}
+}
+
+bool find_op_res_width(int offset, int &width, std::vector<InPort*>& ports, const dict<RTLIL::SigBit, RTLIL::SigSpec> &op_outbit_to_outsig)
 {
 
-	std::array<RTLIL::SigSpec, 2> op_outsigs{op_outbit_to_outsig.at(porta[offset]), op_outbit_to_outsig.at(portb[offset])};
+	std::vector<RTLIL::SigSpec> op_outsigs;
+	dict<int, std::set<InPort*>> op_outsig_span;
+
+	std::transform(ports.begin(), ports.end(), std::back_inserter(op_outsigs), [&](InPort *p) { return op_outbit_to_outsig.at(p->sig[offset]); });
+
+	std::vector<bool> finished(ports.size(), false);
 
 	width = 0;
-	bool multi_user = false;
 
-	while (true) {
-		for (const auto &op_outsig : op_outsigs)
-			if (op_outbit_user_cnt.at(op_outsig[width]) > 1)
-				multi_user = true;
+	std::function<bool()> all_finished = [&] { return std::find(std::begin(finished), std::end(finished), false) == end(finished);};
 
+	while (!all_finished())
+	{
 		++offset;
 		++width;
 
-		if ((offset >= porta.size()) || (width >= op_outsigs[0].size()) || (width >= op_outsigs[1].size()))
-			break;
+		if (offset >= ports[0]->sig.size()) {
+			for (size_t i = 0; i < op_outsigs.size(); ++i) {
+				if (finished[i])
+					continue;
+
+				op_outsig_span[width].insert(ports[i]);
+				finished[i] = true;
+			}
 
-		if ((porta[offset] != op_outsigs[0][width]) || (portb[offset] != op_outsigs[1][width]))
 			break;
+		}
+
+		for (size_t i = 0; i < op_outsigs.size(); ++i) {
+			if (finished[i])
+				continue;
+
+			if ((width >= op_outsigs[i].size()) || (ports[i]->sig[offset] != op_outsigs[i][width])) {
+				op_outsig_span[width].insert(ports[i]);
+				finished[i] = true;
+			}
+		}
 	}
 
-	if (multi_user)
-		return false;
+	for (auto w: op_outsig_span) {
+		if (w.second.size() > 1) {
+			width = w.first;
 
-	for (const auto &outsig : op_outsigs)
-		for (int i = width; i < outsig.size(); i++)
-			if (op_outbit_user_cnt.count(outsig[i]))
-				return false;
+			ports.erase(std::remove_if(ports.begin(), ports.end(), [&](InPort *p) { return !w.second.count(p); }), ports.end());
 
-	return true;
+			return true;
+		}
+	}
+
+	return false;
 }
 
-ExtSigSpec find_shared_operand(const std::vector<RTLIL::Cell *> &operators, const std::map<ExtSigSpec, std::set<RTLIL::Cell *>> &operand_to_users)
+ExtSigSpec find_shared_operand(InPort* seed, std::vector<InPort *> &ports, const std::map<ExtSigSpec, std::set<RTLIL::Cell *>> &operand_to_users)
 {
+	std::set<RTLIL::Cell *> alus_using_operand;
+	std::set<RTLIL::Cell *> alus_set;
+	for(const auto& p: ports)
+		alus_set.insert(p->alu);
 
-	std::set<RTLIL::Cell *> operators_set(operators.begin(), operators.end());
 	ExtSigSpec oper;
 
-	auto op_a = operators[0];
-	for (auto &conn : op_a->connections()) {
-		if (op_a->output(conn.first))
+	auto op_a = seed->alu;
+
+	for (RTLIL::IdString port_name : {"\\A", "\\B"}) {
+		oper = ExtSigSpec(op_a, port_name, &assign_map);
+		auto operand_users = operand_to_users.at(oper);
+
+		if (operand_users.size() == 1)
 			continue;
 
-		oper = ExtSigSpec(op_a, conn.first, &assign_map);
-		auto bundle = operand_to_users.at(oper);
+		alus_using_operand.clear();
+		std::set_intersection(operand_users.begin(), operand_users.end(), alus_set.begin(), alus_set.end(),
+				      std::inserter(alus_using_operand, alus_using_operand.begin()));
 
-		if (std::includes(bundle.begin(), bundle.end(), operators_set.begin(), operators_set.end()))
-			break;
+		if (alus_using_operand.size() > 1) {
+			ports.erase(std::remove_if(ports.begin(), ports.end(), [&](InPort *p) { return !alus_using_operand.count(p->alu); }),
+				    ports.end());
+			return oper;
+		}
 	}
 
-	return oper;
+	return ExtSigSpec();
 }
 
-dict<RTLIL::SigBit, int> find_op_outbit_user_cnt(RTLIL::Module *module, const dict<RTLIL::SigBit, RTLIL::SigSpec> &op_outbit_to_outsig)
+void remove_multi_user_outbits(RTLIL::Module *module, dict<RTLIL::SigBit, RTLIL::SigSpec> &op_outbit_to_outsig)
 {
 	dict<RTLIL::SigBit, int> op_outbit_user_cnt;
 
 	std::function<void(SigSpec)> update_op_outbit_user_cnt = [&](SigSpec sig) {
 		auto outsig = assign_map(sig);
-		for (auto outbit : outsig)
-			if (op_outbit_to_outsig.count(outbit))
-				op_outbit_user_cnt[outbit]++;
+		for (auto outbit : outsig) {
+			if (!op_outbit_to_outsig.count(outbit))
+				continue;
+
+			if (++op_outbit_user_cnt[outbit] > 1) {
+				auto alu_outsig = op_outbit_to_outsig.at(outbit);
+
+				for (auto outbit : alu_outsig)
+					op_outbit_to_outsig.erase(outbit);
+			}
+		}
 	};
 
 	for (auto cell : module->cells())
@@ -216,8 +306,6 @@ dict<RTLIL::SigBit, int> find_op_outbit_user_cnt(RTLIL::Module *module, const di
 
 		update_op_outbit_user_cnt(w);
 	}
-
-	return op_outbit_user_cnt;
 }
 
 struct OptRmdffPass : public Pass {
@@ -246,24 +334,31 @@ struct OptRmdffPass : public Pass {
 			dict<RTLIL::SigSpec, RTLIL::Cell *> outsig_to_operator;
 			dict<RTLIL::SigBit, RTLIL::SigSpec> op_outbit_to_outsig;
 			bool any_shared_operands = false;
+			std::vector<ExtSigSpec> op_insigs;
 
 			for (auto cell : module->cells()) {
-				if (!cell->type.in("$add", "$sub"))
+				if (!cell->type.in("$alu"))
 					continue;
 
-				for (auto &conn : cell->connections()) {
-					if (cell->output(conn.first)) {
-						auto outsig = assign_map(conn.second);
-						for (auto outbit : outsig)
-							op_outbit_to_outsig[outbit] = outsig;
+				RTLIL::SigSpec sig_bi = cell->getPort("\\BI");
+				RTLIL::SigSpec sig_ci = cell->getPort("\\CI");
 
-						outsig_to_operator[outsig] = cell;
-					} else {
-						auto op_insig = ExtSigSpec(cell, conn.first, &assign_map);
-						operand_to_users[op_insig].insert(cell);
-						if (operand_to_users[op_insig].size() > 1)
-							any_shared_operands = true;
-					}
+				if ((!sig_bi.is_fully_const()) || (!sig_ci.is_fully_const()) || (sig_bi != sig_ci))
+					continue;
+
+				RTLIL::SigSpec sig_y = cell->getPort("\\A");
+
+				auto outsig = assign_map(cell->getPort("\\Y"));
+				outsig_to_operator[outsig] = cell;
+				for (auto outbit : outsig)
+					op_outbit_to_outsig[outbit] = outsig;
+
+				for (RTLIL::IdString port_name : {"\\A", "\\B"}) {
+					auto op_insig = ExtSigSpec(cell, port_name, &assign_map);
+					op_insigs.push_back(op_insig);
+					operand_to_users[op_insig].insert(cell);
+					if (operand_to_users[op_insig].size() > 1)
+						any_shared_operands = true;
 				}
 			}
 
@@ -272,42 +367,77 @@ struct OptRmdffPass : public Pass {
 
 			// Operator outputs need to be exclusively connected to the $mux inputs in order to be mergeable. Hence we count to
 			// how many points are operator output bits connected.
-			dict<RTLIL::SigBit, int> op_outbit_user_cnt = find_op_outbit_user_cnt(module, op_outbit_to_outsig);
+			remove_multi_user_outbits(module, op_outbit_to_outsig);
+
 			std::vector<shared_op_t> shared_ops;
 			for (auto cell : module->cells()) {
-				if (!cell->type.in("$mux", "$_MUX_"))
+				if (!cell->type.in("$mux", "$_MUX_", "$pmux"))
 					continue;
 
-				auto porta = assign_map(cell->getPort("\\A"));
-				auto portb = assign_map(cell->getPort("\\B"));
+				RTLIL::SigSpec sig_a = cell->getPort("\\A");
+				RTLIL::SigSpec sig_b = cell->getPort("\\B");
+				RTLIL::SigSpec sig_s = cell->getPort("\\S");
+
+				std::vector<InPort> ports;
+
+				if (cell->type.in("$mux", "$_MUX_")) {
+					ports.push_back(InPort(assign_map(sig_a), cell, 0));
+					ports.push_back(InPort(assign_map(sig_b), cell, 1));
+				} else {
+					RTLIL::SigSpec sig_s = cell->getPort("\\S");
+					for (int i = 0; i < sig_s.size(); i++) {
+						auto inp = sig_b.extract(i * sig_a.size(), sig_a.size());
+						ports.push_back(InPort(assign_map(inp), cell, i));
+					}
+				}
 
 				// Look through the bits of the $mux inputs and see which of them are connected to the operator
 				// results. Operator results can be concatenated with other signals before led to the $mux.
-				for (int i = 0; i < porta.size(); ++i) {
-					std::array<RTLIL::SigBit, 2> mux_inbits{porta[i], portb[i]};
+				for (int i = 0; i < sig_a.size(); ++i) {
+					std::vector<InPort*> alu_ports;
+					for (auto& p: ports)
+						if (op_outbit_to_outsig.count(p.sig[i])) {
+							p.alu = outsig_to_operator.at(op_outbit_to_outsig.at(p.sig[i]));
+							alu_ports.push_back(&p);
+						}
 
-					// Are the results of an $add or $sub operators connected to both of this $mux inputs?
-					if (!op_outbit_to_outsig.count(mux_inbits[0]) or !op_outbit_to_outsig.count(mux_inbits[1]))
-						continue;
+					int alu_port_width = 0;
 
-					std::vector<RTLIL::Cell *> operators;
-					for (const auto &b : mux_inbits)
-						operators.push_back(outsig_to_operator.at(op_outbit_to_outsig.at(b)));
+					while (alu_ports.size() > 1) {
+						std::vector<InPort*> shared_ports(alu_ports);
 
-					// Do these operators share an operand?
-					auto shared_operand = find_shared_operand(operators, operand_to_users);
-					if (shared_operand.empty())
-						continue;
+						auto seed = alu_ports[0];
+						alu_ports.erase(alu_ports.begin());
 
-					// Some bits of the operator results might be unconnected. Calculate the number of conneted
-					// bits.
-					int width;
+						// Find ports whose $alu-s share an operand with $alu connected to the seed port
+						auto shared_operand = find_shared_operand(seed, shared_ports, operand_to_users);
 
-					if (find_op_res_width(i, width, porta, portb, op_outbit_to_outsig, op_outbit_user_cnt))
-						shared_ops.push_back(shared_op_t{cell, operators, i, width, shared_operand});
+						if (shared_operand.empty())
+							continue;
 
-					i += width - 1;
+						// Some bits of the operator results might be unconnected. Calculate the number of conneted
+						// bits.
+						if (!find_op_res_width(i, alu_port_width, shared_ports, op_outbit_to_outsig))
+							break;
+
+						if (shared_ports.size() < 2)
+							break;
+
+						// Remember the combination for the merger
+						std::vector<InPort> shared_p;
+						for (auto p: shared_ports)
+							shared_p.push_back(*p);
+
+						shared_ops.push_back(shared_op_t{cell, shared_p, i, alu_port_width, shared_operand});
+
+						// Remove merged ports from the list and try to find other mergers for the mux
+						remove_val(alu_ports, shared_ports);
+					}
+
+					if (alu_port_width)
+						i += alu_port_width - 1;
 				}
+
 			}
 
 			for (auto &shared : shared_ops) {
@@ -315,11 +445,11 @@ struct OptRmdffPass : public Pass {
 				    "of "
 				    "them:\n",
 				    log_id(shared.mux->type), log_id(shared.mux));
-				for (auto op : shared.operators)
-					log("        %s\n", log_id(op));
+				for (const auto& op : shared.ports)
+					log("        %s\n", log_id(op.alu));
 				log("\n");
 
-				merge_operators(module, shared.mux, shared.operators, shared.offset, shared.width, shared.shared_operand);
+				merge_operators(module, shared.mux, shared.ports, shared.offset, shared.width, shared.shared_operand);
 			}
 		}
 	}
diff --git a/tests/opt/opt_share_add_sub.v b/tests/opt/opt_share_add_sub.v
new file mode 100644
index 000000000..30e093a39
--- /dev/null
+++ b/tests/opt/opt_share_add_sub.v
@@ -0,0 +1,10 @@
+module opt_share_test(
+               input [15:0]  a,
+               input [15:0]  b,
+               input 				 sel,
+               output [15:0] res,
+               );
+
+  assign res = {sel ? a + b : a - b};
+
+endmodule
diff --git a/tests/opt/opt_share_add_sub.ys b/tests/opt/opt_share_add_sub.ys
new file mode 100644
index 000000000..4a5406791
--- /dev/null
+++ b/tests/opt/opt_share_add_sub.ys
@@ -0,0 +1,13 @@
+read_verilog opt_share_add_sub.v
+proc;;
+copy opt_share_test merged
+
+alumacc merged
+opt merged
+opt_share merged
+opt_clean merged
+
+miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp opt_share_test merged miter
+sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter
+
+select -assert-count 1 -module merged t:$alu
diff --git a/tests/opt/opt_share_cat.v b/tests/opt/opt_share_cat.v
index c32073360..605dcfe59 100644
--- a/tests/opt/opt_share_cat.v
+++ b/tests/opt/opt_share_cat.v
@@ -1,4 +1,4 @@
-module add_sub(
+module opt_share_test(
                input [15:0]  a,
                input [15:0]  b,
                input [15:0]  c,
diff --git a/tests/opt/opt_share_cat.ys b/tests/opt/opt_share_cat.ys
index c3f2f5a2f..7de69bfde 100644
--- a/tests/opt/opt_share_cat.ys
+++ b/tests/opt/opt_share_cat.ys
@@ -1,9 +1,13 @@
 read_verilog opt_share_cat.v
-prep -flatten
-opt
-pmuxtree
-opt_share
-opt_clean
+proc;;
+copy opt_share_test merged
 
-select -assert-count 2 t:$sub
-select -assert-count 0 t:$add
+alumacc merged
+opt merged
+opt_share merged
+opt_clean merged
+
+miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp opt_share_test merged miter
+sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter
+
+select -assert-count 2 -module merged t:$alu
diff --git a/tests/opt/opt_share_cat_multiuser.v b/tests/opt/opt_share_cat_multiuser.v
new file mode 100644
index 000000000..9ac0ceec8
--- /dev/null
+++ b/tests/opt/opt_share_cat_multiuser.v
@@ -0,0 +1,22 @@
+module opt_share_test(
+               input [15:0] 		 a,
+               input [15:0] 		 b,
+               input [15:0] 		 c,
+               input [15:0] 		 d,
+               input 						 sel,
+               output reg [47:0] res,
+               );
+
+  wire [15:0] 									 add_res = a+b;
+  wire [15:0] 									 sub_res = a-b;
+  wire [31: 0] 									 cat1 = {add_res, c+d};
+  wire [31: 0] 									 cat2 = {sub_res, c-d};
+
+  always @* begin
+    case(sel)
+      0: res = {cat1, add_res};
+      1: res = {cat2, add_res};
+    endcase
+  end
+
+endmodule
diff --git a/tests/opt/opt_share_cat_multiuser.ys b/tests/opt/opt_share_cat_multiuser.ys
new file mode 100644
index 000000000..6a82fbd79
--- /dev/null
+++ b/tests/opt/opt_share_cat_multiuser.ys
@@ -0,0 +1,13 @@
+read_verilog opt_share_cat_multiuser.v
+proc;;
+copy opt_share_test merged
+
+alumacc merged
+opt merged
+opt_share merged
+opt_clean merged
+
+miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp opt_share_test merged miter
+sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter
+
+select -assert-count 3 -module merged t:$alu
diff --git a/tests/opt/opt_share_diff_port_widths.v b/tests/opt/opt_share_diff_port_widths.v
new file mode 100644
index 000000000..5e2971e30
--- /dev/null
+++ b/tests/opt/opt_share_diff_port_widths.v
@@ -0,0 +1,21 @@
+module opt_share_test(
+               input [15:0] 		 a,
+               input [15:0] 		 b,
+							 input [15:0] 		 c,
+							 input [1:0] 			 sel,
+							 output reg [15:0] res
+               );
+
+  wire [15:0] 							 add0_res = a+b;
+  wire [15:0] 							 add1_res = a+c;
+
+  always @* begin
+    case(sel)
+      0: res = add0_res[10:0];
+      1: res = add1_res[10:0];
+      2: res = a - b;
+      default: res = 32'bx;
+    endcase
+  end
+
+endmodule
diff --git a/tests/opt/opt_share_diff_port_widths.ys b/tests/opt/opt_share_diff_port_widths.ys
new file mode 100644
index 000000000..ec5e9f7b0
--- /dev/null
+++ b/tests/opt/opt_share_diff_port_widths.ys
@@ -0,0 +1,13 @@
+read_verilog opt_share_diff_port_widths.v
+proc;;
+copy opt_share_test merged
+
+alumacc merged
+opt merged
+opt_share merged
+opt_clean merged
+
+miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp opt_share_test merged miter
+sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter
+
+select -assert-count 2 -module merged t:$alu
diff --git a/tests/opt/opt_share_extend.v b/tests/opt/opt_share_extend.v
new file mode 100644
index 000000000..5ed6bde6f
--- /dev/null
+++ b/tests/opt/opt_share_extend.v
@@ -0,0 +1,19 @@
+module opt_share_test(
+											input signed [7:0] 			 a,
+											input signed [10:0] 		 b,
+											input signed [15:0] 		 c,
+											input [1:0] 						 sel,
+											output reg signed [15:0] res
+											);
+
+
+  always @* begin
+    case(sel)
+      0: res = a + b;
+      1: res = a - b;
+      2: res = a + c;
+      default: res = 16'bx;
+    endcase
+  end
+
+endmodule
diff --git a/tests/opt/opt_share_extend.ys b/tests/opt/opt_share_extend.ys
new file mode 100644
index 000000000..c553ee0fb
--- /dev/null
+++ b/tests/opt/opt_share_extend.ys
@@ -0,0 +1,13 @@
+read_verilog opt_share_extend.v
+proc;;
+copy opt_share_test merged
+
+alumacc merged
+opt merged
+opt_share merged
+opt_clean merged
+
+miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp opt_share_test merged miter
+sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter
+
+select -assert-count 1 -module merged t:$alu
diff --git a/tests/opt/opt_share_large_pmux_cat.v b/tests/opt/opt_share_large_pmux_cat.v
new file mode 100644
index 000000000..6208c796b
--- /dev/null
+++ b/tests/opt/opt_share_large_pmux_cat.v
@@ -0,0 +1,22 @@
+module opt_share_test(
+											input [15:0] 			a,
+											input [15:0] 			b,
+											input [15:0] 			c,
+											input [2:0] 			sel,
+											output reg [31:0] res
+											);
+
+
+  always @* begin
+    case(sel)
+      0: res = {a + b, a};
+      1: res = {a - b, b};
+      2: res = {a + c, c};
+      3: res = {a - c, a};
+      4: res = {b, b};
+      5: res = {c, c};
+      default: res = 32'bx;
+    endcase
+  end
+
+endmodule
diff --git a/tests/opt/opt_share_large_pmux_cat.ys b/tests/opt/opt_share_large_pmux_cat.ys
new file mode 100644
index 000000000..4186ca52e
--- /dev/null
+++ b/tests/opt/opt_share_large_pmux_cat.ys
@@ -0,0 +1,13 @@
+read_verilog opt_share_large_pmux_cat.v
+proc;;
+copy opt_share_test merged
+
+alumacc merged
+opt merged
+opt_share merged
+opt_clean merged
+
+miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp opt_share_test merged miter
+sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter
+
+select -assert-count 1 -module merged t:$alu
diff --git a/tests/opt/opt_share_large_pmux_cat_multipart.v b/tests/opt/opt_share_large_pmux_cat_multipart.v
new file mode 100644
index 000000000..f97971bf6
--- /dev/null
+++ b/tests/opt/opt_share_large_pmux_cat_multipart.v
@@ -0,0 +1,25 @@
+module opt_share_test(
+											input [15:0] 			a,
+											input [15:0] 			b,
+											input [15:0] 			c,
+											input [15:0] 			d,
+											input [2:0] 			sel,
+											output reg [31:0] res
+											);
+
+  wire [15:0] 													add0_res = a+d;
+
+  always @* begin
+    case(sel)
+      0: res = {add0_res, a};
+      1: res = {a - b, add0_res[7], 15'b0};
+      2: res = {b-a, b};
+      3: res = {d, b - c};
+      4: res = {d, b - a};
+      5: res = {c, d};
+      6: res = {a - c, b-d};
+      default: res = 32'bx;
+    endcase
+  end
+
+endmodule
diff --git a/tests/opt/opt_share_large_pmux_cat_multipart.ys b/tests/opt/opt_share_large_pmux_cat_multipart.ys
new file mode 100644
index 000000000..54d200dc7
--- /dev/null
+++ b/tests/opt/opt_share_large_pmux_cat_multipart.ys
@@ -0,0 +1,15 @@
+read_verilog opt_share_large_pmux_cat_multipart.v
+proc;;
+copy opt_share_test merged
+
+alumacc merged
+opt merged
+
+opt_share merged
+opt_clean merged
+opt -full
+
+miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp opt_share_test merged miter
+sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter
+
+select -assert-count 4 -module merged t:$alu
diff --git a/tests/opt/opt_share_large_pmux_multipart.v b/tests/opt/opt_share_large_pmux_multipart.v
new file mode 100644
index 000000000..e7ba318ef
--- /dev/null
+++ b/tests/opt/opt_share_large_pmux_multipart.v
@@ -0,0 +1,24 @@
+module opt_share_test(
+											input [15:0] 			a,
+											input [15:0] 			b,
+											input [15:0] 			c,
+											input [15:0] 			d,
+											input [2:0] 			sel,
+											output reg [15:0] res
+											);
+
+
+  always @* begin
+    case(sel)
+      0: res = a + d;
+      1: res = a - b;
+      2: res = b;
+      3: res = b - c;
+      4: res = b - a;
+      5: res = c;
+      6: res = a - c;
+      default: res = 16'bx;
+    endcase
+  end
+
+endmodule
diff --git a/tests/opt/opt_share_large_pmux_multipart.ys b/tests/opt/opt_share_large_pmux_multipart.ys
new file mode 100644
index 000000000..11182df1a
--- /dev/null
+++ b/tests/opt/opt_share_large_pmux_multipart.ys
@@ -0,0 +1,13 @@
+read_verilog opt_share_large_pmux_multipart.v
+proc;;
+copy opt_share_test merged
+
+alumacc merged
+opt merged
+opt_share merged
+opt_clean merged
+
+miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp opt_share_test merged miter
+sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter
+
+select -assert-count 2 -module merged t:$alu
diff --git a/tests/opt/opt_share_large_pmux_part.v b/tests/opt/opt_share_large_pmux_part.v
new file mode 100644
index 000000000..138be0cd6
--- /dev/null
+++ b/tests/opt/opt_share_large_pmux_part.v
@@ -0,0 +1,22 @@
+module opt_share_test(
+											input [15:0] 			a,
+											input [15:0] 			b,
+											input [15:0] 			c,
+											input [2:0] 			sel,
+											output reg [15:0] res
+											);
+
+
+  always @* begin
+    case(sel)
+      0: res = a + b;
+      1: res = a - b;
+      2: res = a + c;
+      3: res = a - c;
+      4: res = b;
+      5: res = c;
+      default: res = 16'bx;
+    endcase
+  end
+
+endmodule
diff --git a/tests/opt/opt_share_large_pmux_part.ys b/tests/opt/opt_share_large_pmux_part.ys
new file mode 100644
index 000000000..6b594a3d6
--- /dev/null
+++ b/tests/opt/opt_share_large_pmux_part.ys
@@ -0,0 +1,13 @@
+read_verilog opt_share_large_pmux_part.v
+proc;;
+copy opt_share_test merged
+
+alumacc merged
+opt merged
+opt_share merged
+opt_clean merged
+
+miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp opt_share_test merged miter
+sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter
+
+select -assert-count 1 -module merged t:$alu
diff --git a/tests/opt/opt_share_mux_tree.v b/tests/opt/opt_share_mux_tree.v
index 807ed2978..c90826204 100644
--- a/tests/opt/opt_share_mux_tree.v
+++ b/tests/opt/opt_share_mux_tree.v
@@ -1,4 +1,4 @@
-module add_sub(
+module opt_share_test(
                input [15:0] 		 a,
                input [15:0] 		 b,
                input [15:0] 		 c,
diff --git a/tests/opt/opt_share_mux_tree.ys b/tests/opt/opt_share_mux_tree.ys
index 94d6aa7d2..58473039f 100644
--- a/tests/opt/opt_share_mux_tree.ys
+++ b/tests/opt/opt_share_mux_tree.ys
@@ -1,10 +1,13 @@
 read_verilog opt_share_mux_tree.v
-prep -flatten
-opt
-pmuxtree
-opt_share;
-opt_share;
-opt_clean
+proc;;
+copy opt_share_test merged
 
-select -assert-count 1 t:$add
-select -assert-count 0 t:$sub
+alumacc merged
+opt merged
+opt_share merged
+opt_clean merged
+
+miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp opt_share_test merged miter
+sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter
+
+select -assert-count 1 -module merged t:$alu

From 280c4e7794543e99244aafffc62a2dd4454bcb06 Mon Sep 17 00:00:00 2001
From: Bogdan Vukobratovic <bogdan.vukobratovic@gmail.com>
Date: Sat, 3 Aug 2019 12:28:46 +0200
Subject: [PATCH 03/20] Fix spacing in opt_share tests, change wording in
 opt_share help

---
 passes/opt/opt_share.cc                       | 16 +++++---
 tests/opt/opt_share_add_sub.v                 | 12 +++---
 tests/opt/opt_share_cat.v                     | 20 +++++-----
 tests/opt/opt_share_cat_multiuser.v           | 34 ++++++++--------
 tests/opt/opt_share_diff_port_widths.v        | 32 +++++++--------
 tests/opt/opt_share_extend.v                  | 29 +++++++-------
 tests/opt/opt_share_large_pmux_cat.v          | 35 ++++++++--------
 .../opt/opt_share_large_pmux_cat_multipart.v  | 40 +++++++++----------
 tests/opt/opt_share_large_pmux_multipart.v    | 39 +++++++++---------
 tests/opt/opt_share_large_pmux_part.v         | 35 ++++++++--------
 tests/opt/opt_share_mux_tree.v                | 29 +++++++-------
 11 files changed, 160 insertions(+), 161 deletions(-)

diff --git a/passes/opt/opt_share.cc b/passes/opt/opt_share.cc
index e9a2f05f9..25b07cbbd 100644
--- a/passes/opt/opt_share.cc
+++ b/passes/opt/opt_share.cc
@@ -2,6 +2,7 @@
  *  yosys -- Yosys Open SYnthesis Suite
  *
  *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *                2019  Bogdan Vukobratovic <bogdan.vukobratovic@gmail.com>
  *
  *  Permission to use, copy, modify, and/or distribute this software for any
  *  purpose with or without fee is hereby granted, provided that the above
@@ -308,17 +309,20 @@ void remove_multi_user_outbits(RTLIL::Module *module, dict<RTLIL::SigBit, RTLIL:
 	}
 }
 
-struct OptRmdffPass : public Pass {
-	OptRmdffPass() : Pass("opt_share", "merge arithmetic operators that share an operand") {}
+struct OptSharePass : public Pass {
+	OptSharePass() : Pass("opt_share", "merge arithmetic operators that share an operand") {}
 	void help() YS_OVERRIDE
 	{
 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 		log("\n");
 		log("    opt_share [selection]\n");
 		log("\n");
-		log("This pass identifies arithmetic operators that share an operand and whose\n");
-		log("results are used in mutually exclusive cases controlled by a multiplexer,\n");
-		log("and merges them together by multiplexing the other operands.\n");
+
+		log("This pass identifies mutually exclusive $alu arithmetic cells that:\n");
+		log("    (a) share an input operand\n");
+		log("    (b) drive the same $mux, $_MUX_, or $pmux multiplexing cell allowing\n");
+		log("        the $alu cell to be merged and the multiplexer to be moved from\n");
+		log("        multiplexing its output to multiplexing the non-shared input operands.\n");
 		log("\n");
 	}
 	void execute(std::vector<std::string>, RTLIL::Design *design) YS_OVERRIDE
@@ -454,6 +458,6 @@ struct OptRmdffPass : public Pass {
 		}
 	}
 
-} OptRmdffPass;
+} OptSharePass;
 
 PRIVATE_NAMESPACE_END
diff --git a/tests/opt/opt_share_add_sub.v b/tests/opt/opt_share_add_sub.v
index 30e093a39..1c2665cf0 100644
--- a/tests/opt/opt_share_add_sub.v
+++ b/tests/opt/opt_share_add_sub.v
@@ -1,10 +1,10 @@
 module opt_share_test(
-               input [15:0]  a,
-               input [15:0]  b,
-               input 				 sel,
-               output [15:0] res,
-               );
+	input [15:0] 	a,
+	input [15:0] 	b,
+	input 				sel,
+	output [15:0] res,
+	);
 
-  assign res = {sel ? a + b : a - b};
+	assign res = {sel ? a + b : a - b};
 
 endmodule
diff --git a/tests/opt/opt_share_cat.v b/tests/opt/opt_share_cat.v
index 605dcfe59..7b6f626b9 100644
--- a/tests/opt/opt_share_cat.v
+++ b/tests/opt/opt_share_cat.v
@@ -1,15 +1,15 @@
 module opt_share_test(
-               input [15:0]  a,
-               input [15:0]  b,
-               input [15:0]  c,
-               input [15:0]  d,
-               input 				 sel,
-               output [63:0] res,
-               );
+	input [15:0] 	a,
+	input [15:0] 	b,
+	input [15:0] 	c,
+	input [15:0] 	d,
+	input 				sel,
+	output [63:0] res,
+	);
 
-  reg [31: 0] 							 cat1 = {a+b, c+d};
-  reg [31: 0] 							 cat2 = {a-b, c-d};
+	reg [31: 0] 	cat1 = {a+b, c+d};
+	reg [31: 0] 	cat2 = {a-b, c-d};
 
-  assign res = {b, sel ? cat1 : cat2, a};
+	assign res = {b, sel ? cat1 : cat2, a};
 
 endmodule
diff --git a/tests/opt/opt_share_cat_multiuser.v b/tests/opt/opt_share_cat_multiuser.v
index 9ac0ceec8..f77f912e9 100644
--- a/tests/opt/opt_share_cat_multiuser.v
+++ b/tests/opt/opt_share_cat_multiuser.v
@@ -1,22 +1,22 @@
 module opt_share_test(
-               input [15:0] 		 a,
-               input [15:0] 		 b,
-               input [15:0] 		 c,
-               input [15:0] 		 d,
-               input 						 sel,
-               output reg [47:0] res,
-               );
+	input [15:0] 			a,
+	input [15:0] 			b,
+	input [15:0] 			c,
+	input [15:0] 			d,
+	input 						sel,
+	output reg [47:0] res,
+	);
 
-  wire [15:0] 									 add_res = a+b;
-  wire [15:0] 									 sub_res = a-b;
-  wire [31: 0] 									 cat1 = {add_res, c+d};
-  wire [31: 0] 									 cat2 = {sub_res, c-d};
+	wire [15:0] 			add_res = a+b;
+	wire [15:0] 			sub_res = a-b;
+	wire [31: 0] 			cat1 = {add_res, c+d};
+	wire [31: 0] 			cat2 = {sub_res, c-d};
 
-  always @* begin
-    case(sel)
-      0: res = {cat1, add_res};
-      1: res = {cat2, add_res};
-    endcase
-  end
+	always @* begin
+		case(sel)
+			0: res = {cat1, add_res};
+			1: res = {cat2, add_res};
+		endcase
+	end
 
 endmodule
diff --git a/tests/opt/opt_share_diff_port_widths.v b/tests/opt/opt_share_diff_port_widths.v
index 5e2971e30..e57ab7a83 100644
--- a/tests/opt/opt_share_diff_port_widths.v
+++ b/tests/opt/opt_share_diff_port_widths.v
@@ -1,21 +1,21 @@
 module opt_share_test(
-               input [15:0] 		 a,
-               input [15:0] 		 b,
-							 input [15:0] 		 c,
-							 input [1:0] 			 sel,
-							 output reg [15:0] res
-               );
+	input [15:0]			 a,
+	input [15:0]			 b,
+	input [15:0]			 c,
+	input [1:0]			 sel,
+	output reg [15:0] res
+	);
 
-  wire [15:0] 							 add0_res = a+b;
-  wire [15:0] 							 add1_res = a+c;
+	wire [15:0] 			add0_res = a+b;
+	wire [15:0] 			add1_res = a+c;
 
-  always @* begin
-    case(sel)
-      0: res = add0_res[10:0];
-      1: res = add1_res[10:0];
-      2: res = a - b;
-      default: res = 32'bx;
-    endcase
-  end
+	always @* begin
+		case(sel)
+			0: res = add0_res[10:0];
+			1: res = add1_res[10:0];
+			2: res = a - b;
+			default: res = 32'bx;
+		endcase
+	end
 
 endmodule
diff --git a/tests/opt/opt_share_extend.v b/tests/opt/opt_share_extend.v
index 5ed6bde6f..60ce1a2f3 100644
--- a/tests/opt/opt_share_extend.v
+++ b/tests/opt/opt_share_extend.v
@@ -1,19 +1,18 @@
 module opt_share_test(
-											input signed [7:0] 			 a,
-											input signed [10:0] 		 b,
-											input signed [15:0] 		 c,
-											input [1:0] 						 sel,
-											output reg signed [15:0] res
-											);
+	input signed [7:0]			 a,
+	input signed [10:0]			 b,
+	input signed [15:0]			 c,
+	input [1:0]							 sel,
+	output reg signed [15:0] res
+	);
 
-
-  always @* begin
-    case(sel)
-      0: res = a + b;
-      1: res = a - b;
-      2: res = a + c;
-      default: res = 16'bx;
-    endcase
-  end
+	always @* begin
+		case(sel)
+			0: res = a + b;
+			1: res = a - b;
+			2: res = a + c;
+			default: res = 16'bx;
+		endcase
+	end
 
 endmodule
diff --git a/tests/opt/opt_share_large_pmux_cat.v b/tests/opt/opt_share_large_pmux_cat.v
index 6208c796b..0667e6080 100644
--- a/tests/opt/opt_share_large_pmux_cat.v
+++ b/tests/opt/opt_share_large_pmux_cat.v
@@ -1,22 +1,21 @@
 module opt_share_test(
-											input [15:0] 			a,
-											input [15:0] 			b,
-											input [15:0] 			c,
-											input [2:0] 			sel,
-											output reg [31:0] res
-											);
+	input [15:0]			a,
+	input [15:0]			b,
+	input [15:0]			c,
+	input [2:0]				sel,
+	output reg [31:0] res
+	);
 
-
-  always @* begin
-    case(sel)
-      0: res = {a + b, a};
-      1: res = {a - b, b};
-      2: res = {a + c, c};
-      3: res = {a - c, a};
-      4: res = {b, b};
-      5: res = {c, c};
-      default: res = 32'bx;
-    endcase
-  end
+	always @* begin
+		case(sel)
+			0: res = {a + b, a};
+			1: res = {a - b, b};
+			2: res = {a + c, c};
+			3: res = {a - c, a};
+			4: res = {b, b};
+			5: res = {c, c};
+			default: res = 32'bx;
+		endcase
+	end
 
 endmodule
diff --git a/tests/opt/opt_share_large_pmux_cat_multipart.v b/tests/opt/opt_share_large_pmux_cat_multipart.v
index f97971bf6..f26505d3a 100644
--- a/tests/opt/opt_share_large_pmux_cat_multipart.v
+++ b/tests/opt/opt_share_large_pmux_cat_multipart.v
@@ -1,25 +1,25 @@
 module opt_share_test(
-											input [15:0] 			a,
-											input [15:0] 			b,
-											input [15:0] 			c,
-											input [15:0] 			d,
-											input [2:0] 			sel,
-											output reg [31:0] res
-											);
+	input [15:0]			a,
+	input [15:0]			b,
+	input [15:0]			c,
+	input [15:0]			d,
+	input [2:0]				sel,
+	output reg [31:0] res
+	);
 
-  wire [15:0] 													add0_res = a+d;
+	wire [15:0] 			add0_res = a+d;
 
-  always @* begin
-    case(sel)
-      0: res = {add0_res, a};
-      1: res = {a - b, add0_res[7], 15'b0};
-      2: res = {b-a, b};
-      3: res = {d, b - c};
-      4: res = {d, b - a};
-      5: res = {c, d};
-      6: res = {a - c, b-d};
-      default: res = 32'bx;
-    endcase
-  end
+	always @* begin
+		case(sel)
+			0: res = {add0_res, a};
+			1: res = {a - b, add0_res[7], 15'b0};
+			2: res = {b-a, b};
+			3: res = {d, b - c};
+			4: res = {d, b - a};
+			5: res = {c, d};
+			6: res = {a - c, b-d};
+			default: res = 32'bx;
+		endcase
+	end
 
 endmodule
diff --git a/tests/opt/opt_share_large_pmux_multipart.v b/tests/opt/opt_share_large_pmux_multipart.v
index e7ba318ef..1c460292f 100644
--- a/tests/opt/opt_share_large_pmux_multipart.v
+++ b/tests/opt/opt_share_large_pmux_multipart.v
@@ -1,24 +1,23 @@
 module opt_share_test(
-											input [15:0] 			a,
-											input [15:0] 			b,
-											input [15:0] 			c,
-											input [15:0] 			d,
-											input [2:0] 			sel,
-											output reg [15:0] res
-											);
+	input [15:0]			a,
+	input [15:0]			b,
+	input [15:0]			c,
+	input [15:0]			d,
+	input [2:0]				sel,
+	output reg [15:0] res
+	);
 
-
-  always @* begin
-    case(sel)
-      0: res = a + d;
-      1: res = a - b;
-      2: res = b;
-      3: res = b - c;
-      4: res = b - a;
-      5: res = c;
-      6: res = a - c;
-      default: res = 16'bx;
-    endcase
-  end
+	always @* begin
+		case(sel)
+			0: res = a + d;
+			1: res = a - b;
+			2: res = b;
+			3: res = b - c;
+			4: res = b - a;
+			5: res = c;
+			6: res = a - c;
+			default: res = 16'bx;
+		endcase
+	end
 
 endmodule
diff --git a/tests/opt/opt_share_large_pmux_part.v b/tests/opt/opt_share_large_pmux_part.v
index 138be0cd6..f9dd17446 100644
--- a/tests/opt/opt_share_large_pmux_part.v
+++ b/tests/opt/opt_share_large_pmux_part.v
@@ -1,22 +1,21 @@
 module opt_share_test(
-											input [15:0] 			a,
-											input [15:0] 			b,
-											input [15:0] 			c,
-											input [2:0] 			sel,
-											output reg [15:0] res
-											);
+	input [15:0]			a,
+	input [15:0]			b,
+	input [15:0]			c,
+	input [2:0]				sel,
+	output reg [15:0] res
+	);
 
-
-  always @* begin
-    case(sel)
-      0: res = a + b;
-      1: res = a - b;
-      2: res = a + c;
-      3: res = a - c;
-      4: res = b;
-      5: res = c;
-      default: res = 16'bx;
-    endcase
-  end
+	always @* begin
+		case(sel)
+			0: res = a + b;
+			1: res = a - b;
+			2: res = a + c;
+			3: res = a - c;
+			4: res = b;
+			5: res = c;
+			default: res = 16'bx;
+		endcase
+	end
 
 endmodule
diff --git a/tests/opt/opt_share_mux_tree.v b/tests/opt/opt_share_mux_tree.v
index c90826204..4a26afb46 100644
--- a/tests/opt/opt_share_mux_tree.v
+++ b/tests/opt/opt_share_mux_tree.v
@@ -1,19 +1,18 @@
 module opt_share_test(
-               input [15:0] 		 a,
-               input [15:0] 		 b,
-               input [15:0] 		 c,
-               input [1:0] 			 sel,
-               output reg [15:0] res
-               );
+	input [15:0] 			a,
+	input [15:0] 			b,
+	input [15:0] 			c,
+	input [1:0] 			sel,
+	output reg [15:0] res
+	);
 
-
-  always @* begin
-    case(sel)
-      0: res = a + b;
-      1: res = a - b;
-      2: res = a + c;
-      default: res = 16'bx;
-    endcase
-  end
+	always @* begin
+		case(sel)
+			0: res = a + b;
+			1: res = a - b;
+			2: res = a + c;
+			default: res = 16'bx;
+		endcase
+	end
 
 endmodule

From d8be5ce6ba11ec78d0f7925d488fad09a3eaba2c Mon Sep 17 00:00:00 2001
From: Bogdan Vukobratovic <bogdan.vukobratovic@gmail.com>
Date: Sat, 3 Aug 2019 12:35:46 +0200
Subject: [PATCH 04/20] Tabs to spaces in opt_share examples

---
 tests/opt/opt_share_add_sub.v                 | 12 +++---
 tests/opt/opt_share_cat.v                     | 20 +++++-----
 tests/opt/opt_share_cat_multiuser.v           | 34 ++++++++--------
 tests/opt/opt_share_diff_port_widths.v        | 32 +++++++--------
 tests/opt/opt_share_extend.v                  | 28 ++++++-------
 tests/opt/opt_share_large_pmux_cat.v          | 34 ++++++++--------
 .../opt/opt_share_large_pmux_cat_multipart.v  | 40 +++++++++----------
 tests/opt/opt_share_large_pmux_multipart.v    | 38 +++++++++---------
 tests/opt/opt_share_large_pmux_part.v         | 34 ++++++++--------
 tests/opt/opt_share_mux_tree.v                | 28 ++++++-------
 10 files changed, 150 insertions(+), 150 deletions(-)

diff --git a/tests/opt/opt_share_add_sub.v b/tests/opt/opt_share_add_sub.v
index 1c2665cf0..d918f27cc 100644
--- a/tests/opt/opt_share_add_sub.v
+++ b/tests/opt/opt_share_add_sub.v
@@ -1,10 +1,10 @@
 module opt_share_test(
-	input [15:0] 	a,
-	input [15:0] 	b,
-	input 				sel,
-	output [15:0] res,
-	);
+  input [15:0]  a,
+  input [15:0]  b,
+  input         sel,
+  output [15:0] res,
+  );
 
-	assign res = {sel ? a + b : a - b};
+  assign res = {sel ? a + b : a - b};
 
 endmodule
diff --git a/tests/opt/opt_share_cat.v b/tests/opt/opt_share_cat.v
index 7b6f626b9..7fb97fef5 100644
--- a/tests/opt/opt_share_cat.v
+++ b/tests/opt/opt_share_cat.v
@@ -1,15 +1,15 @@
 module opt_share_test(
-	input [15:0] 	a,
-	input [15:0] 	b,
-	input [15:0] 	c,
-	input [15:0] 	d,
-	input 				sel,
-	output [63:0] res,
-	);
+  input [15:0]  a,
+  input [15:0]  b,
+  input [15:0]  c,
+  input [15:0]  d,
+  input         sel,
+  output [63:0] res,
+  );
 
-	reg [31: 0] 	cat1 = {a+b, c+d};
-	reg [31: 0] 	cat2 = {a-b, c-d};
+  reg [31: 0]   cat1 = {a+b, c+d};
+  reg [31: 0]   cat2 = {a-b, c-d};
 
-	assign res = {b, sel ? cat1 : cat2, a};
+  assign res = {b, sel ? cat1 : cat2, a};
 
 endmodule
diff --git a/tests/opt/opt_share_cat_multiuser.v b/tests/opt/opt_share_cat_multiuser.v
index f77f912e9..b250689d9 100644
--- a/tests/opt/opt_share_cat_multiuser.v
+++ b/tests/opt/opt_share_cat_multiuser.v
@@ -1,22 +1,22 @@
 module opt_share_test(
-	input [15:0] 			a,
-	input [15:0] 			b,
-	input [15:0] 			c,
-	input [15:0] 			d,
-	input 						sel,
-	output reg [47:0] res,
-	);
+  input [15:0]      a,
+  input [15:0]      b,
+  input [15:0]      c,
+  input [15:0]      d,
+  input             sel,
+  output reg [47:0] res,
+  );
 
-	wire [15:0] 			add_res = a+b;
-	wire [15:0] 			sub_res = a-b;
-	wire [31: 0] 			cat1 = {add_res, c+d};
-	wire [31: 0] 			cat2 = {sub_res, c-d};
+  wire [15:0]       add_res = a+b;
+  wire [15:0]       sub_res = a-b;
+  wire [31: 0]      cat1 = {add_res, c+d};
+  wire [31: 0]      cat2 = {sub_res, c-d};
 
-	always @* begin
-		case(sel)
-			0: res = {cat1, add_res};
-			1: res = {cat2, add_res};
-		endcase
-	end
+  always @* begin
+    case(sel)
+      0: res = {cat1, add_res};
+      1: res = {cat2, add_res};
+    endcase
+  end
 
 endmodule
diff --git a/tests/opt/opt_share_diff_port_widths.v b/tests/opt/opt_share_diff_port_widths.v
index e57ab7a83..1a37c80a6 100644
--- a/tests/opt/opt_share_diff_port_widths.v
+++ b/tests/opt/opt_share_diff_port_widths.v
@@ -1,21 +1,21 @@
 module opt_share_test(
-	input [15:0]			 a,
-	input [15:0]			 b,
-	input [15:0]			 c,
-	input [1:0]			 sel,
-	output reg [15:0] res
-	);
+  input [15:0]       a,
+  input [15:0]       b,
+  input [15:0]       c,
+  input [1:0]      sel,
+  output reg [15:0] res
+  );
 
-	wire [15:0] 			add0_res = a+b;
-	wire [15:0] 			add1_res = a+c;
+  wire [15:0]       add0_res = a+b;
+  wire [15:0]       add1_res = a+c;
 
-	always @* begin
-		case(sel)
-			0: res = add0_res[10:0];
-			1: res = add1_res[10:0];
-			2: res = a - b;
-			default: res = 32'bx;
-		endcase
-	end
+  always @* begin
+    case(sel)
+      0: res = add0_res[10:0];
+      1: res = add1_res[10:0];
+      2: res = a - b;
+      default: res = 32'bx;
+    endcase
+  end
 
 endmodule
diff --git a/tests/opt/opt_share_extend.v b/tests/opt/opt_share_extend.v
index 60ce1a2f3..d39f19069 100644
--- a/tests/opt/opt_share_extend.v
+++ b/tests/opt/opt_share_extend.v
@@ -1,18 +1,18 @@
 module opt_share_test(
-	input signed [7:0]			 a,
-	input signed [10:0]			 b,
-	input signed [15:0]			 c,
-	input [1:0]							 sel,
-	output reg signed [15:0] res
-	);
+  input signed [7:0]       a,
+  input signed [10:0]      b,
+  input signed [15:0]      c,
+  input [1:0]              sel,
+  output reg signed [15:0] res
+  );
 
-	always @* begin
-		case(sel)
-			0: res = a + b;
-			1: res = a - b;
-			2: res = a + c;
-			default: res = 16'bx;
-		endcase
-	end
+  always @* begin
+    case(sel)
+      0: res = a + b;
+      1: res = a - b;
+      2: res = a + c;
+      default: res = 16'bx;
+    endcase
+  end
 
 endmodule
diff --git a/tests/opt/opt_share_large_pmux_cat.v b/tests/opt/opt_share_large_pmux_cat.v
index 0667e6080..416ba3766 100644
--- a/tests/opt/opt_share_large_pmux_cat.v
+++ b/tests/opt/opt_share_large_pmux_cat.v
@@ -1,21 +1,21 @@
 module opt_share_test(
-	input [15:0]			a,
-	input [15:0]			b,
-	input [15:0]			c,
-	input [2:0]				sel,
-	output reg [31:0] res
-	);
+  input [15:0]      a,
+  input [15:0]      b,
+  input [15:0]      c,
+  input [2:0]       sel,
+  output reg [31:0] res
+  );
 
-	always @* begin
-		case(sel)
-			0: res = {a + b, a};
-			1: res = {a - b, b};
-			2: res = {a + c, c};
-			3: res = {a - c, a};
-			4: res = {b, b};
-			5: res = {c, c};
-			default: res = 32'bx;
-		endcase
-	end
+  always @* begin
+    case(sel)
+      0: res = {a + b, a};
+      1: res = {a - b, b};
+      2: res = {a + c, c};
+      3: res = {a - c, a};
+      4: res = {b, b};
+      5: res = {c, c};
+      default: res = 32'bx;
+    endcase
+  end
 
 endmodule
diff --git a/tests/opt/opt_share_large_pmux_cat_multipart.v b/tests/opt/opt_share_large_pmux_cat_multipart.v
index f26505d3a..34d2bd9a8 100644
--- a/tests/opt/opt_share_large_pmux_cat_multipart.v
+++ b/tests/opt/opt_share_large_pmux_cat_multipart.v
@@ -1,25 +1,25 @@
 module opt_share_test(
-	input [15:0]			a,
-	input [15:0]			b,
-	input [15:0]			c,
-	input [15:0]			d,
-	input [2:0]				sel,
-	output reg [31:0] res
-	);
+  input [15:0]      a,
+  input [15:0]      b,
+  input [15:0]      c,
+  input [15:0]      d,
+  input [2:0]       sel,
+  output reg [31:0] res
+  );
 
-	wire [15:0] 			add0_res = a+d;
+  wire [15:0]       add0_res = a+d;
 
-	always @* begin
-		case(sel)
-			0: res = {add0_res, a};
-			1: res = {a - b, add0_res[7], 15'b0};
-			2: res = {b-a, b};
-			3: res = {d, b - c};
-			4: res = {d, b - a};
-			5: res = {c, d};
-			6: res = {a - c, b-d};
-			default: res = 32'bx;
-		endcase
-	end
+  always @* begin
+    case(sel)
+      0: res = {add0_res, a};
+      1: res = {a - b, add0_res[7], 15'b0};
+      2: res = {b-a, b};
+      3: res = {d, b - c};
+      4: res = {d, b - a};
+      5: res = {c, d};
+      6: res = {a - c, b-d};
+      default: res = 32'bx;
+    endcase
+  end
 
 endmodule
diff --git a/tests/opt/opt_share_large_pmux_multipart.v b/tests/opt/opt_share_large_pmux_multipart.v
index 1c460292f..535adf96f 100644
--- a/tests/opt/opt_share_large_pmux_multipart.v
+++ b/tests/opt/opt_share_large_pmux_multipart.v
@@ -1,23 +1,23 @@
 module opt_share_test(
-	input [15:0]			a,
-	input [15:0]			b,
-	input [15:0]			c,
-	input [15:0]			d,
-	input [2:0]				sel,
-	output reg [15:0] res
-	);
+  input [15:0]      a,
+  input [15:0]      b,
+  input [15:0]      c,
+  input [15:0]      d,
+  input [2:0]       sel,
+  output reg [15:0] res
+  );
 
-	always @* begin
-		case(sel)
-			0: res = a + d;
-			1: res = a - b;
-			2: res = b;
-			3: res = b - c;
-			4: res = b - a;
-			5: res = c;
-			6: res = a - c;
-			default: res = 16'bx;
-		endcase
-	end
+  always @* begin
+    case(sel)
+      0: res = a + d;
+      1: res = a - b;
+      2: res = b;
+      3: res = b - c;
+      4: res = b - a;
+      5: res = c;
+      6: res = a - c;
+      default: res = 16'bx;
+    endcase
+  end
 
 endmodule
diff --git a/tests/opt/opt_share_large_pmux_part.v b/tests/opt/opt_share_large_pmux_part.v
index f9dd17446..a9008fb5a 100644
--- a/tests/opt/opt_share_large_pmux_part.v
+++ b/tests/opt/opt_share_large_pmux_part.v
@@ -1,21 +1,21 @@
 module opt_share_test(
-	input [15:0]			a,
-	input [15:0]			b,
-	input [15:0]			c,
-	input [2:0]				sel,
-	output reg [15:0] res
-	);
+  input [15:0]      a,
+  input [15:0]      b,
+  input [15:0]      c,
+  input [2:0]       sel,
+  output reg [15:0] res
+  );
 
-	always @* begin
-		case(sel)
-			0: res = a + b;
-			1: res = a - b;
-			2: res = a + c;
-			3: res = a - c;
-			4: res = b;
-			5: res = c;
-			default: res = 16'bx;
-		endcase
-	end
+  always @* begin
+    case(sel)
+      0: res = a + b;
+      1: res = a - b;
+      2: res = a + c;
+      3: res = a - c;
+      4: res = b;
+      5: res = c;
+      default: res = 16'bx;
+    endcase
+  end
 
 endmodule
diff --git a/tests/opt/opt_share_mux_tree.v b/tests/opt/opt_share_mux_tree.v
index 4a26afb46..cc5ae4eb9 100644
--- a/tests/opt/opt_share_mux_tree.v
+++ b/tests/opt/opt_share_mux_tree.v
@@ -1,18 +1,18 @@
 module opt_share_test(
-	input [15:0] 			a,
-	input [15:0] 			b,
-	input [15:0] 			c,
-	input [1:0] 			sel,
-	output reg [15:0] res
-	);
+  input [15:0]      a,
+  input [15:0]      b,
+  input [15:0]      c,
+  input [1:0]       sel,
+  output reg [15:0] res
+  );
 
-	always @* begin
-		case(sel)
-			0: res = a + b;
-			1: res = a - b;
-			2: res = a + c;
-			default: res = 16'bx;
-		endcase
-	end
+  always @* begin
+    case(sel)
+      0: res = a + b;
+      1: res = a - b;
+      2: res = a + c;
+      default: res = 16'bx;
+    endcase
+  end
 
 endmodule

From 6a796accc09bc2c8ef98c068185de13d3e01890a Mon Sep 17 00:00:00 2001
From: Bogdan Vukobratovic <bogdan.vukobratovic@gmail.com>
Date: Sun, 4 Aug 2019 19:06:38 +0200
Subject: [PATCH 05/20] Support various binary operators in opt_share

---
 Makefile                    |   1 +
 passes/opt/opt_share.cc     | 610 ++++++++++++++++++++++++------------
 tests/opt_share/.gitignore  |   1 +
 tests/opt_share/generate.py |  86 +++++
 tests/opt_share/run-test.sh |  39 +++
 5 files changed, 531 insertions(+), 206 deletions(-)
 create mode 100644 tests/opt_share/.gitignore
 create mode 100644 tests/opt_share/generate.py
 create mode 100755 tests/opt_share/run-test.sh

diff --git a/Makefile b/Makefile
index 3bc119800..d06c7ab3d 100644
--- a/Makefile
+++ b/Makefile
@@ -678,6 +678,7 @@ test: $(TARGETS) $(EXTRA_TARGETS)
 	+cd tests/asicworld && bash run-test.sh $(SEEDOPT)
 	# +cd tests/realmath && bash run-test.sh $(SEEDOPT)
 	+cd tests/share && bash run-test.sh $(SEEDOPT)
+	+cd tests/opt_share && bash run-test.sh $(SEEDOPT)
 	+cd tests/fsm && bash run-test.sh $(SEEDOPT)
 	+cd tests/techmap && bash run-test.sh
 	+cd tests/memories && bash run-test.sh $(ABCOPT) $(SEEDOPT)
diff --git a/passes/opt/opt_share.cc b/passes/opt/opt_share.cc
index 25b07cbbd..e8f44749a 100644
--- a/passes/opt/opt_share.cc
+++ b/passes/opt/opt_share.cc
@@ -32,37 +32,36 @@ PRIVATE_NAMESPACE_BEGIN
 
 SigMap assign_map;
 
-struct InPort {
+struct OpMuxConn {
 	RTLIL::SigSpec sig;
-	RTLIL::Cell *pmux;
-	int port_id;
-	RTLIL::Cell *alu;
+	RTLIL::Cell *mux;
+	RTLIL::Cell *op;
+	int mux_port_id;
+	int mux_port_offset;
+	int op_outsig_offset;
 
-	InPort(RTLIL::SigSpec s, RTLIL::Cell *c, int p, RTLIL::Cell *a = NULL) : sig(s), pmux(c), port_id(p), alu(a) {}
+	bool operator<(const OpMuxConn &other) const
+	{
+		if (mux != other.mux)
+			return mux < other.mux;
+
+		if (mux_port_id != other.mux_port_id)
+			return mux_port_id < other.mux_port_id;
+
+		return mux_port_offset < other.mux_port_offset;
+	}
 };
 
-// Helper class that to track whether a SigSpec is signed and whether it is
-// connected to the \\B port of the $sub cell, which makes its sign prefix
-// negative.
+// Helper class to track additiona information about a SigSpec, like whether it is signed and the semantics of the port it is connected to
 struct ExtSigSpec {
 	RTLIL::SigSpec sig;
 	RTLIL::SigSpec sign;
 	bool is_signed;
+	RTLIL::IdString semantics;
 
 	ExtSigSpec() {}
 
-	ExtSigSpec(RTLIL::SigSpec s, bool sign = false, bool is_signed = false) : sig(s), sign(sign), is_signed(is_signed) {}
-
-	ExtSigSpec(RTLIL::Cell *cell, RTLIL::IdString port_name, SigMap *sigmap)
-	{
-		sign = (port_name == "\\B") ? cell->getPort("\\BI") : RTLIL::Const(0, 1);
-		sig = (*sigmap)(cell->getPort(port_name));
-
-		is_signed = false;
-		if (cell->hasParam(port_name.str() + "_SIGNED")) {
-			is_signed = cell->getParam(port_name.str() + "_SIGNED").as_bool();
-		}
-	}
+	ExtSigSpec(RTLIL::SigSpec s, RTLIL::SigSpec sign = RTLIL::Const(0, 1), bool is_signed = false, RTLIL::IdString semantics = RTLIL::IdString()) : sig(s), sign(sign), is_signed(is_signed), semantics(semantics) {}
 
 	bool empty() const { return sig.empty(); }
 
@@ -74,42 +73,136 @@ struct ExtSigSpec {
 		if (sign != other.sign)
 			return sign < other.sign;
 
-		return is_signed < other.is_signed;
+		if (is_signed != other.is_signed)
+			return is_signed < other.is_signed;
+
+		return semantics < other.semantics;
 	}
 
 	bool operator==(const RTLIL::SigSpec &other) const { return (sign != RTLIL::Const(0, 1)) ? false : sig == other; }
-	bool operator==(const ExtSigSpec &other) const { return is_signed == other.is_signed && sign == other.sign && sig == other.sig; }
+	bool operator==(const ExtSigSpec &other) const { return is_signed == other.is_signed && sign == other.sign && sig == other.sig && semantics == other.semantics; }
 };
 
-void merge_operators(RTLIL::Module *module, RTLIL::Cell *mux, const std::vector<InPort> &ports, int offset, int width,
-		     const ExtSigSpec &operand)
+#define BITWISE_OPS "$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_", "$and", "$or", "$xor", "$xnor"
+
+#define REDUCTION_OPS "$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool", "$reduce_nand"
+
+#define LOGICAL_OPS "$logic_and", "$logic_or"
+
+#define SHIFT_OPS "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx"
+
+#define RELATIONAL_OPS "$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt"
+
+bool cell_supported(RTLIL::Cell *cell)
+{
+
+	if (cell->type.in("$alu")) {
+		RTLIL::SigSpec sig_bi = cell->getPort("\\BI");
+		RTLIL::SigSpec sig_ci = cell->getPort("\\CI");
+
+		if (sig_bi.is_fully_const() && sig_ci.is_fully_const() && sig_bi == sig_ci)
+			return true;
+	} else if (cell->type.in(LOGICAL_OPS, SHIFT_OPS, BITWISE_OPS, RELATIONAL_OPS, "$add", "$sub", "$mul", "$div", "$mod", "$concat")) {
+		return true;
+	}
+
+	return false;
+}
+
+std::map<std::string, std::string> mergeable_type_map{
+  {"$sub", "$add"},
+};
+
+bool mergeable(RTLIL::Cell *a, RTLIL::Cell *b)
+{
+	auto a_type = a->type;
+	if (mergeable_type_map.count(a_type.str()))
+		a_type = mergeable_type_map.at(a_type.str());
+
+	auto b_type = b->type;
+	if (mergeable_type_map.count(b_type.str()))
+		b_type = mergeable_type_map.at(b_type.str());
+
+	return a_type == b_type;
+}
+
+RTLIL::IdString decode_port_semantics(RTLIL::Cell *cell, RTLIL::IdString port_name)
+{
+	if (cell->type.in("$lt", "$le", "$ge", "$gt", "$div", "$mod", "$concat", SHIFT_OPS) && port_name == "\\B")
+		return port_name;
+
+	return "";
+}
+
+RTLIL::SigSpec decode_port_sign(RTLIL::Cell *cell, RTLIL::IdString port_name) {
+
+	if (cell->type == "$alu" && port_name == "\\B")
+		return cell->getPort("\\BI");
+	else if	(cell->type == "$sub" && port_name == "\\B")
+		return RTLIL::Const(1, 1);
+
+	return RTLIL::Const(0, 1);
+}
+
+bool decode_port_signed(RTLIL::Cell *cell, RTLIL::IdString port_name)
+{
+	if (cell->type.in(BITWISE_OPS, LOGICAL_OPS))
+		return false;
+
+	if (cell->hasParam(port_name.str() + "_SIGNED"))
+		return cell->getParam(port_name.str() + "_SIGNED").as_bool();
+
+	return false;
+
+}
+
+ExtSigSpec decode_port(RTLIL::Cell *cell, RTLIL::IdString port_name, SigMap *sigmap)
+{
+	auto sig = (*sigmap)(cell->getPort(port_name));
+
+	RTLIL::SigSpec sign = decode_port_sign(cell, port_name);
+	RTLIL::IdString semantics = decode_port_semantics(cell, port_name);
+
+	bool is_signed = decode_port_signed(cell, port_name);
+
+	return ExtSigSpec(sig, sign, is_signed, semantics);
+}
+
+void merge_operators(RTLIL::Module *module, RTLIL::Cell *mux, const std::vector<OpMuxConn> &ports, const ExtSigSpec &operand)
 {
 
 	std::vector<ExtSigSpec> muxed_operands;
 	int max_width = 0;
 	for (const auto& p : ports) {
-		auto op = p.alu;
+		auto op = p.op;
 
-		for (RTLIL::IdString port_name : {"\\A", "\\B"}) {
-			if (op->getPort(port_name) != operand.sig) {
-				auto operand = ExtSigSpec(op, port_name, &assign_map);
-				if (operand.sig.size() > max_width) {
-					max_width = operand.sig.size();
-				}
-
-				muxed_operands.push_back(operand);
-			}
+		RTLIL::IdString muxed_port_name = "\\A";
+		if (op->getPort("\\A") == operand.sig) {
+			muxed_port_name = "\\B";
 		}
+
+		auto operand = decode_port(op, muxed_port_name, &assign_map);
+		if (operand.sig.size() > max_width) {
+			max_width = operand.sig.size();
+		}
+
+		muxed_operands.push_back(operand);
 	}
 
+	auto shared_op = ports[0].op;
+
+	if (std::any_of(muxed_operands.begin(), muxed_operands.end(), [&](ExtSigSpec &op) { return op.sign != muxed_operands[0].sign; }))
+		if (max_width < shared_op->getParam("\\Y_WIDTH").as_int())
+			max_width = shared_op->getParam("\\Y_WIDTH").as_int();
+
+
 	for (auto &operand : muxed_operands) {
 		operand.sig.extend_u0(max_width, operand.is_signed);
 	}
 
-	auto shared_op = ports[0].alu;
 
 	for (const auto& p : ports) {
-		auto op = p.alu;
+		auto op = p.op;
 		if (op == shared_op)
 			continue;
 		module->remove(op);
@@ -126,40 +219,47 @@ void merge_operators(RTLIL::Module *module, RTLIL::Cell *mux, const std::vector<
 	RTLIL::SigSpec mux_b = mux->getPort("\\B");
 	RTLIL::SigSpec mux_s = mux->getPort("\\S");
 
-	RTLIL::SigSpec alu_x = shared_op->getPort("\\X");
-	RTLIL::SigSpec alu_co = shared_op->getPort("\\CO");
-
 	RTLIL::SigSpec shared_pmux_a = RTLIL::Const(RTLIL::State::Sx, max_width);
 	RTLIL::SigSpec shared_pmux_b;
 	RTLIL::SigSpec shared_pmux_s;
 
-	shared_op->setPort("\\Y", shared_op->getPort("\\Y").extract(0, width));
+	int conn_width = ports[0].sig.size();
+	int conn_offset = ports[0].mux_port_offset;
+
+	shared_op->setPort("\\Y", shared_op->getPort("\\Y").extract(0, conn_width));
 
 	if (mux->type == "$pmux") {
 		shared_pmux_s = RTLIL::SigSpec();
 
-		for (const auto&p: ports) {
-			shared_pmux_s.append(mux_s[p.port_id]);
-			mux_b.replace(p.port_id * mux_a.size() + offset, shared_op->getPort("\\Y"));
+		for (const auto &p : ports) {
+			shared_pmux_s.append(mux_s[p.mux_port_id]);
+			mux_b.replace(p.mux_port_id * mux_a.size() + conn_offset, shared_op->getPort("\\Y"));
 		}
 	} else {
 		shared_pmux_s = RTLIL::SigSpec{mux_s, module->Not(NEW_ID, mux_s)};
-		mux_a.replace(offset, shared_op->getPort("\\Y"));
-		mux_b.replace(offset, shared_op->getPort("\\Y"));
+		mux_a.replace(conn_offset, shared_op->getPort("\\Y"));
+		mux_b.replace(conn_offset, shared_op->getPort("\\Y"));
 	}
 
+	mux->setPort("\\A", mux_a);
+	mux->setPort("\\B", mux_b);
 	mux->setPort("\\Y", mux_y);
 	mux->setPort("\\S", mux_s);
-	mux->setPort("\\B", mux_b);
 
 	for (const auto &op : muxed_operands)
 		shared_pmux_b.append(op.sig);
 
 	auto mux_to_oper = module->Pmux(NEW_ID, shared_pmux_a, shared_pmux_b, shared_pmux_s);
 
-	shared_op->setPort("\\X", alu_x.extract(0, width));
-	shared_op->setPort("\\CO", alu_co.extract(0, width));
-	shared_op->setParam("\\Y_WIDTH", width);
+	if (shared_op->type.in("$alu")) {
+		RTLIL::SigSpec alu_x = shared_op->getPort("\\X");
+		RTLIL::SigSpec alu_co = shared_op->getPort("\\CO");
+
+		shared_op->setPort("\\X", alu_x.extract(0, conn_width));
+		shared_op->setPort("\\CO", alu_co.extract(0, conn_width));
+	}
+
+	shared_op->setParam("\\Y_WIDTH", conn_width);
 
 	if (shared_op->getPort("\\A") == operand.sig) {
 		shared_op->setPort("\\B", mux_to_oper);
@@ -173,11 +273,9 @@ void merge_operators(RTLIL::Module *module, RTLIL::Cell *mux, const std::vector<
 
 typedef struct {
 	RTLIL::Cell *mux;
-	std::vector<InPort> ports;
-	int offset;
-	int width;
+	std::vector<OpMuxConn> ports;
 	ExtSigSpec shared_operand;
-} shared_op_t;
+} merged_op_t;
 
 
 template <typename T> void remove_val(std::vector<T> &v, const std::vector<T> &vals)
@@ -190,86 +288,60 @@ template <typename T> void remove_val(std::vector<T> &v, const std::vector<T> &v
 		}
 }
 
-bool find_op_res_width(int offset, int &width, std::vector<InPort*>& ports, const dict<RTLIL::SigBit, RTLIL::SigSpec> &op_outbit_to_outsig)
+void check_muxed_operands(std::vector<const OpMuxConn *> &ports, const ExtSigSpec &shared_operand)
 {
 
-	std::vector<RTLIL::SigSpec> op_outsigs;
-	dict<int, std::set<InPort*>> op_outsig_span;
+	auto it = ports.begin();
+	ExtSigSpec seed;
 
-	std::transform(ports.begin(), ports.end(), std::back_inserter(op_outsigs), [&](InPort *p) { return op_outbit_to_outsig.at(p->sig[offset]); });
+	while (it != ports.end()) {
+		auto p = *it;
+		auto op = p->op;
 
-	std::vector<bool> finished(ports.size(), false);
-
-	width = 0;
-
-	std::function<bool()> all_finished = [&] { return std::find(std::begin(finished), std::end(finished), false) == end(finished);};
-
-	while (!all_finished())
-	{
-		++offset;
-		++width;
-
-		if (offset >= ports[0]->sig.size()) {
-			for (size_t i = 0; i < op_outsigs.size(); ++i) {
-				if (finished[i])
-					continue;
-
-				op_outsig_span[width].insert(ports[i]);
-				finished[i] = true;
-			}
-
-			break;
+		RTLIL::IdString muxed_port_name = "\\A";
+		if (op->getPort("\\A") == shared_operand.sig) {
+			muxed_port_name = "\\B";
 		}
 
-		for (size_t i = 0; i < op_outsigs.size(); ++i) {
-			if (finished[i])
-				continue;
+		auto operand = decode_port(op, muxed_port_name, &assign_map);
 
-			if ((width >= op_outsigs[i].size()) || (ports[i]->sig[offset] != op_outsigs[i][width])) {
-				op_outsig_span[width].insert(ports[i]);
-				finished[i] = true;
-			}
+		if (seed.empty())
+			seed = operand;
+
+		if (operand.is_signed != seed.is_signed) {
+			ports.erase(it);
+		} else {
+			++it;
 		}
 	}
-
-	for (auto w: op_outsig_span) {
-		if (w.second.size() > 1) {
-			width = w.first;
-
-			ports.erase(std::remove_if(ports.begin(), ports.end(), [&](InPort *p) { return !w.second.count(p); }), ports.end());
-
-			return true;
-		}
-	}
-
-	return false;
 }
 
-ExtSigSpec find_shared_operand(InPort* seed, std::vector<InPort *> &ports, const std::map<ExtSigSpec, std::set<RTLIL::Cell *>> &operand_to_users)
+ExtSigSpec find_shared_operand(const OpMuxConn* seed, std::vector<const OpMuxConn *> &ports, const std::map<ExtSigSpec, std::set<RTLIL::Cell *>> &operand_to_users)
 {
-	std::set<RTLIL::Cell *> alus_using_operand;
-	std::set<RTLIL::Cell *> alus_set;
+	std::set<RTLIL::Cell *> ops_using_operand;
+	std::set<RTLIL::Cell *> ops_set;
 	for(const auto& p: ports)
-		alus_set.insert(p->alu);
+		ops_set.insert(p->op);
 
 	ExtSigSpec oper;
 
-	auto op_a = seed->alu;
+	auto op_a = seed->op;
 
 	for (RTLIL::IdString port_name : {"\\A", "\\B"}) {
-		oper = ExtSigSpec(op_a, port_name, &assign_map);
+		oper = decode_port(op_a, port_name, &assign_map);
 		auto operand_users = operand_to_users.at(oper);
 
 		if (operand_users.size() == 1)
 			continue;
 
-		alus_using_operand.clear();
-		std::set_intersection(operand_users.begin(), operand_users.end(), alus_set.begin(), alus_set.end(),
-				      std::inserter(alus_using_operand, alus_using_operand.begin()));
+		ops_using_operand.clear();
+		for (auto mux_ops: ops_set)
+			if (operand_users.count(mux_ops))
+				ops_using_operand.insert(mux_ops);
 
-		if (alus_using_operand.size() > 1) {
-			ports.erase(std::remove_if(ports.begin(), ports.end(), [&](InPort *p) { return !alus_using_operand.count(p->alu); }),
-				    ports.end());
+		if (ops_using_operand.size() > 1) {
+			ports.erase(std::remove_if(ports.begin(), ports.end(), [&](const OpMuxConn *p) { return !ops_using_operand.count(p->op); }),
+						ports.end());
 			return oper;
 		}
 	}
@@ -277,40 +349,135 @@ ExtSigSpec find_shared_operand(InPort* seed, std::vector<InPort *> &ports, const
 	return ExtSigSpec();
 }
 
-void remove_multi_user_outbits(RTLIL::Module *module, dict<RTLIL::SigBit, RTLIL::SigSpec> &op_outbit_to_outsig)
+dict<RTLIL::SigSpec, OpMuxConn> find_valid_op_mux_conns(RTLIL::Module *module, dict<RTLIL::SigBit, RTLIL::SigSpec> &op_outbit_to_outsig,
+							dict<RTLIL::SigSpec, RTLIL::Cell *> outsig_to_operator,
+							dict<RTLIL::SigBit, RTLIL::SigSpec> &op_aux_to_outsig)
 {
-	dict<RTLIL::SigBit, int> op_outbit_user_cnt;
+	dict<RTLIL::SigSpec, int> op_outsig_user_track;
+	dict<RTLIL::SigSpec, OpMuxConn> op_mux_conn_map;
+
+	std::function<void(RTLIL::SigSpec)> remove_outsig = [&](RTLIL::SigSpec outsig) {
+		for (auto op_outbit : outsig)
+			op_outbit_to_outsig.erase(op_outbit);
+
+		if (op_mux_conn_map.count(outsig))
+			op_mux_conn_map.erase(outsig);
+	};
+
+	std::function<void(RTLIL::SigBit)> remove_outsig_from_aux_bit = [&](RTLIL::SigBit auxbit) {
+		auto aux_outsig = op_aux_to_outsig.at(auxbit);
+		auto op = outsig_to_operator.at(aux_outsig);
+		auto op_outsig = assign_map(op->getPort("\\Y"));
+		remove_outsig(op_outsig);
+
+		for (auto aux_outbit : aux_outsig)
+			op_aux_to_outsig.erase(aux_outbit);
+	};
+
+	std::function<void(RTLIL::Cell *)>
+	  find_op_mux_conns = [&](RTLIL::Cell *mux) {
+		  RTLIL::SigSpec sig;
+		  int mux_port_size;
+
+		  if (mux->type.in("$mux", "$_MUX_")) {
+			  mux_port_size = mux->getPort("\\A").size();
+			  sig = RTLIL::SigSpec{mux->getPort("\\B"), mux->getPort("\\A")};
+		  } else {
+			  mux_port_size = mux->getPort("\\A").size();
+			  sig = mux->getPort("\\B");
+		  }
+
+		  auto mux_insig = assign_map(sig);
+
+		  for (int i = 0; i < mux_insig.size(); ++i) {
+			  if (op_aux_to_outsig.count(mux_insig[i])) {
+				  remove_outsig_from_aux_bit(mux_insig[i]);
+				  continue;
+			  }
+
+			  if (!op_outbit_to_outsig.count(mux_insig[i]))
+				  continue;
+
+			  auto op_outsig = op_outbit_to_outsig.at(mux_insig[i]);
+
+			  if (op_mux_conn_map.count(op_outsig)) {
+					remove_outsig(op_outsig);
+				  continue;
+			  }
+
+			  int mux_port_id = i / mux_port_size;
+			  int mux_port_offset = i % mux_port_size;
+
+			  int op_outsig_offset;
+			  for (op_outsig_offset = 0; op_outsig[op_outsig_offset] != mux_insig[i]; ++op_outsig_offset)
+				  ;
+
+			  int j = op_outsig_offset;
+			  do {
+				  if (!op_outbit_to_outsig.count(mux_insig[i]))
+					  break;
+
+				  if (op_outbit_to_outsig.at(mux_insig[i]) != op_outsig)
+					  break;
+
+				  ++i;
+				  ++j;
+			  } while ((i / mux_port_size == mux_port_id) && (j < op_outsig.size()));
+
+			  int op_conn_width = j - op_outsig_offset;
+			  OpMuxConn inp = {
+			    op_outsig.extract(op_outsig_offset, op_conn_width),
+			    mux,
+			    outsig_to_operator.at(op_outsig),
+			    mux_port_id,
+			    mux_port_offset,
+			    op_outsig_offset,
+			  };
+
+			  op_mux_conn_map[op_outsig] = inp;
+
+			  --i;
+		  }
+	  };
+
+	std::function<void(RTLIL::SigSpec)> remove_connected_ops = [&](RTLIL::SigSpec sig) {
+		auto mux_insig = assign_map(sig);
+		for (auto outbit : mux_insig) {
+			if (op_aux_to_outsig.count(outbit)) {
+				remove_outsig_from_aux_bit(outbit);
+				continue;
+			}
 
-	std::function<void(SigSpec)> update_op_outbit_user_cnt = [&](SigSpec sig) {
-		auto outsig = assign_map(sig);
-		for (auto outbit : outsig) {
 			if (!op_outbit_to_outsig.count(outbit))
 				continue;
 
-			if (++op_outbit_user_cnt[outbit] > 1) {
-				auto alu_outsig = op_outbit_to_outsig.at(outbit);
-
-				for (auto outbit : alu_outsig)
-					op_outbit_to_outsig.erase(outbit);
-			}
+			remove_outsig(op_outbit_to_outsig.at(outbit));
 		}
 	};
 
-	for (auto cell : module->cells())
-		for (auto &conn : cell->connections())
-			if (cell->input(conn.first))
-				update_op_outbit_user_cnt(conn.second);
+	for (auto cell : module->cells()) {
+		if (cell->type.in("$mux", "$_MUX_", "$pmux")) {
+			remove_connected_ops(cell->getPort("\\S"));
+			find_op_mux_conns(cell);
+		} else {
+			for (auto &conn : cell->connections())
+				if (cell->input(conn.first))
+					remove_connected_ops(conn.second);
+		}
+	}
 
 	for (auto w : module->wires()) {
 		if (!w->port_output)
 			continue;
 
-		update_op_outbit_user_cnt(w);
+		remove_connected_ops(w);
 	}
+
+	return op_mux_conn_map;
 }
 
 struct OptSharePass : public Pass {
-	OptSharePass() : Pass("opt_share", "merge arithmetic operators that share an operand") {}
+	OptSharePass() : Pass("opt_share", "merge mutually exclusive cells of the same type that share an input signal") {}
 	void help() YS_OVERRIDE
 	{
 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
@@ -318,18 +485,19 @@ struct OptSharePass : public Pass {
 		log("    opt_share [selection]\n");
 		log("\n");
 
-		log("This pass identifies mutually exclusive $alu arithmetic cells that:\n");
-		log("    (a) share an input operand\n");
+		log("This pass identifies mutually exclusive cells of the same type that:\n");
+		log("    (a) share an input signal\n");
 		log("    (b) drive the same $mux, $_MUX_, or $pmux multiplexing cell allowing\n");
-		log("        the $alu cell to be merged and the multiplexer to be moved from\n");
-		log("        multiplexing its output to multiplexing the non-shared input operands.\n");
+		log("        the cell to be merged and the multiplexer to be moved from\n");
+		log("        multiplexing its output to multiplexing the non-shared input signals.\n");
 		log("\n");
 	}
-	void execute(std::vector<std::string>, RTLIL::Design *design) YS_OVERRIDE
+	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
 	{
 
 		log_header(design, "Executing OPT_SHARE pass.\n");
 
+		extra_args(args, 1, design);
 		for (auto module : design->selected_modules()) {
 			assign_map.clear();
 			assign_map.set(module);
@@ -337,28 +505,30 @@ struct OptSharePass : public Pass {
 			std::map<ExtSigSpec, std::set<RTLIL::Cell *>> operand_to_users;
 			dict<RTLIL::SigSpec, RTLIL::Cell *> outsig_to_operator;
 			dict<RTLIL::SigBit, RTLIL::SigSpec> op_outbit_to_outsig;
+			dict<RTLIL::SigBit, RTLIL::SigSpec> op_aux_to_outsig;
 			bool any_shared_operands = false;
 			std::vector<ExtSigSpec> op_insigs;
 
 			for (auto cell : module->cells()) {
-				if (!cell->type.in("$alu"))
+				if (!cell_supported(cell))
 					continue;
 
-				RTLIL::SigSpec sig_bi = cell->getPort("\\BI");
-				RTLIL::SigSpec sig_ci = cell->getPort("\\CI");
+				if (cell->type == "$alu") {
+					for (RTLIL::IdString port_name : {"\\X", "\\CO"}) {
+						auto mux_insig = assign_map(cell->getPort(port_name));
+						outsig_to_operator[mux_insig] = cell;
+						for (auto outbit : mux_insig)
+							op_aux_to_outsig[outbit] = mux_insig;
+					}
+				}
 
-				if ((!sig_bi.is_fully_const()) || (!sig_ci.is_fully_const()) || (sig_bi != sig_ci))
-					continue;
-
-				RTLIL::SigSpec sig_y = cell->getPort("\\A");
-
-				auto outsig = assign_map(cell->getPort("\\Y"));
-				outsig_to_operator[outsig] = cell;
-				for (auto outbit : outsig)
-					op_outbit_to_outsig[outbit] = outsig;
+				auto mux_insig = assign_map(cell->getPort("\\Y"));
+				outsig_to_operator[mux_insig] = cell;
+				for (auto outbit : mux_insig)
+					op_outbit_to_outsig[outbit] = mux_insig;
 
 				for (RTLIL::IdString port_name : {"\\A", "\\B"}) {
-					auto op_insig = ExtSigSpec(cell, port_name, &assign_map);
+					auto op_insig = decode_port(cell, port_name, &assign_map);
 					op_insigs.push_back(op_insig);
 					operand_to_users[op_insig].insert(cell);
 					if (operand_to_users[op_insig].size() > 1)
@@ -371,89 +541,117 @@ struct OptSharePass : public Pass {
 
 			// Operator outputs need to be exclusively connected to the $mux inputs in order to be mergeable. Hence we count to
 			// how many points are operator output bits connected.
-			remove_multi_user_outbits(module, op_outbit_to_outsig);
+			dict<RTLIL::SigSpec, OpMuxConn> op_mux_conn_map =
+			  find_valid_op_mux_conns(module, op_outbit_to_outsig, outsig_to_operator, op_aux_to_outsig);
 
-			std::vector<shared_op_t> shared_ops;
-			for (auto cell : module->cells()) {
-				if (!cell->type.in("$mux", "$_MUX_", "$pmux"))
-					continue;
+			// Group op connections connected to same ports of the same $mux. Sort them in ascending order of their port offset
+			dict<RTLIL::Cell*, std::vector<std::set<OpMuxConn>>> mux_port_op_conns;
+			for (auto& val: op_mux_conn_map) {
+				OpMuxConn p = val.second;
+				auto& mux_port_conns = mux_port_op_conns[p.mux];
 
-				RTLIL::SigSpec sig_a = cell->getPort("\\A");
-				RTLIL::SigSpec sig_b = cell->getPort("\\B");
-				RTLIL::SigSpec sig_s = cell->getPort("\\S");
+				if (mux_port_conns.size() == 0) {
+					int mux_port_num;
 
-				std::vector<InPort> ports;
+					if (p.mux->type.in("$mux", "$_MUX_"))
+						mux_port_num = 2;
+					else
+						mux_port_num = p.mux->getPort("\\S").size();
 
-				if (cell->type.in("$mux", "$_MUX_")) {
-					ports.push_back(InPort(assign_map(sig_a), cell, 0));
-					ports.push_back(InPort(assign_map(sig_b), cell, 1));
-				} else {
-					RTLIL::SigSpec sig_s = cell->getPort("\\S");
-					for (int i = 0; i < sig_s.size(); i++) {
-						auto inp = sig_b.extract(i * sig_a.size(), sig_a.size());
-						ports.push_back(InPort(assign_map(inp), cell, i));
-					}
+					mux_port_conns.resize(mux_port_num);
 				}
 
+				mux_port_conns[p.mux_port_id].insert(p);
+			}
+
+			std::vector<merged_op_t> merged_ops;
+			for (auto& val: mux_port_op_conns) {
+
+				RTLIL::Cell* cell = val.first;
+				auto &mux_port_conns = val.second;
+
+				const OpMuxConn *seed = NULL;
+
 				// Look through the bits of the $mux inputs and see which of them are connected to the operator
 				// results. Operator results can be concatenated with other signals before led to the $mux.
-				for (int i = 0; i < sig_a.size(); ++i) {
-					std::vector<InPort*> alu_ports;
-					for (auto& p: ports)
-						if (op_outbit_to_outsig.count(p.sig[i])) {
-							p.alu = outsig_to_operator.at(op_outbit_to_outsig.at(p.sig[i]));
-							alu_ports.push_back(&p);
-						}
+				while (true) {
 
-					int alu_port_width = 0;
-
-					while (alu_ports.size() > 1) {
-						std::vector<InPort*> shared_ports(alu_ports);
-
-						auto seed = alu_ports[0];
-						alu_ports.erase(alu_ports.begin());
-
-						// Find ports whose $alu-s share an operand with $alu connected to the seed port
-						auto shared_operand = find_shared_operand(seed, shared_ports, operand_to_users);
-
-						if (shared_operand.empty())
-							continue;
-
-						// Some bits of the operator results might be unconnected. Calculate the number of conneted
-						// bits.
-						if (!find_op_res_width(i, alu_port_width, shared_ports, op_outbit_to_outsig))
-							break;
-
-						if (shared_ports.size() < 2)
-							break;
-
-						// Remember the combination for the merger
-						std::vector<InPort> shared_p;
-						for (auto p: shared_ports)
-							shared_p.push_back(*p);
-
-						shared_ops.push_back(shared_op_t{cell, shared_p, i, alu_port_width, shared_operand});
-
-						// Remove merged ports from the list and try to find other mergers for the mux
-						remove_val(alu_ports, shared_ports);
+					// Remove either the merged ports from the last iteration or the seed that failed to yield a merger
+					if (seed != NULL) {
+						mux_port_conns[seed->mux_port_id].erase(*seed);
+						seed = NULL;
 					}
 
-					if (alu_port_width)
-						i += alu_port_width - 1;
+					// For a new merger, find the seed op connection that starts at lowest port offset among port connections
+					for (auto &port_conns : mux_port_conns) {
+						if (!port_conns.size())
+							continue;
+
+						const OpMuxConn *next_p = &(*port_conns.begin());
+
+						if ((seed == NULL) || (seed->mux_port_offset > next_p->mux_port_offset))
+							seed = next_p;
+					}
+
+					// Cannot find the seed -> nothing to do for this $mux anymore
+					if (seed == NULL)
+						break;
+
+					// Find all other op connections that start from the same port offset, and whose ops can be merged with the seed op
+					std::vector<const OpMuxConn *> mergeable_conns;
+					for (auto &port_conns : mux_port_conns) {
+						if (!port_conns.size())
+							continue;
+
+						const OpMuxConn *next_p = &(*port_conns.begin());
+
+						if ((next_p->op_outsig_offset == seed->op_outsig_offset) &&
+						    (next_p->mux_port_offset == seed->mux_port_offset) && mergeable(next_p->op, seed->op) &&
+						    next_p->sig.size() == seed->sig.size())
+							mergeable_conns.push_back(next_p);
+					}
+
+					// We need at least two mergeable connections for the merger
+					if (mergeable_conns.size() < 2)
+						continue;
+
+					// Filter mergeable connections whose ops share an operand with seed connection's op
+					auto shared_operand = find_shared_operand(seed, mergeable_conns, operand_to_users);
+
+					if (shared_operand.empty())
+						continue;
+
+					check_muxed_operands(mergeable_conns, shared_operand);
+
+					if (mergeable_conns.size() < 2)
+						continue;
+
+					// Remember the combination for the merger
+					std::vector<OpMuxConn> merged_ports;
+					for (auto p : mergeable_conns) {
+						merged_ports.push_back(*p);
+						mux_port_conns[p->mux_port_id].erase(*p);
+					}
+
+					seed = NULL;
+
+					merged_ops.push_back(merged_op_t{cell, merged_ports, shared_operand});
+
+					design->scratchpad_set_bool("opt.did_something", true);
 				}
 
 			}
 
-			for (auto &shared : shared_ops) {
-				log("    Found arithmetic cells that share an operand and can be merged by moving the %s %s in front "
+			for (auto &shared : merged_ops) {
+				log("    Found cells that share an operand and can be merged by moving the %s %s in front "
 				    "of "
 				    "them:\n",
 				    log_id(shared.mux->type), log_id(shared.mux));
 				for (const auto& op : shared.ports)
-					log("        %s\n", log_id(op.alu));
+					log("        %s\n", log_id(op.op));
 				log("\n");
 
-				merge_operators(module, shared.mux, shared.ports, shared.offset, shared.width, shared.shared_operand);
+				merge_operators(module, shared.mux, shared.ports, shared.shared_operand);
 			}
 		}
 	}
diff --git a/tests/opt_share/.gitignore b/tests/opt_share/.gitignore
new file mode 100644
index 000000000..9c595a6fb
--- /dev/null
+++ b/tests/opt_share/.gitignore
@@ -0,0 +1 @@
+temp
diff --git a/tests/opt_share/generate.py b/tests/opt_share/generate.py
new file mode 100644
index 000000000..2ec92f7de
--- /dev/null
+++ b/tests/opt_share/generate.py
@@ -0,0 +1,86 @@
+#!/usr/bin/env python3
+
+import argparse
+import sys
+import random
+from contextlib import contextmanager
+
+
+@contextmanager
+def redirect_stdout(new_target):
+    old_target, sys.stdout = sys.stdout, new_target
+    try:
+        yield new_target
+    finally:
+        sys.stdout = old_target
+
+
+def random_plus_x():
+    return "%s x" % random.choice(['+', '+', '+', '-', '-', '|', '&', '^'])
+
+
+def maybe_plus_x(expr):
+    if random.randint(0, 4) == 0:
+        return "(%s %s)" % (expr, random_plus_x())
+    else:
+        return expr
+
+
+parser = argparse.ArgumentParser(
+    formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+parser.add_argument('-S', '--seed', type=int, help='seed for PRNG')
+parser.add_argument('-c',
+                    '--count',
+                    type=int,
+                    default=100,
+                    help='number of test cases to generate')
+args = parser.parse_args()
+
+if args.seed is not None:
+    print("PRNG seed: %d" % args.seed)
+    random.seed(args.seed)
+
+for idx in range(args.count):
+    with open('temp/uut_%05d.v' % idx, 'w') as f:
+        with redirect_stdout(f):
+            print('module uut_%05d(a, b, c, s, y);' % (idx))
+            op = random.choice([
+                random.choice(['+', '-', '*', '/', '%']),
+                random.choice(['<', '<=', '==', '!=', '===', '!==', '>=',
+                               '>']),
+                random.choice(['<<', '>>', '<<<', '>>>']),
+                random.choice(['|', '&', '^', '~^', '||', '&&']),
+            ])
+            print('  input%s [%d:0] a;' % (random.choice(['', ' signed']), 8))
+            print('  input%s [%d:0] b;' % (random.choice(['', ' signed']), 8))
+            print('  input%s [%d:0] c;' % (random.choice(['', ' signed']), 8))
+            print('  input s;')
+            print('  output [%d:0] y;' % 8)
+            ops1 = ['a', 'b']
+            ops2 = ['a', 'c']
+            random.shuffle(ops1)
+            random.shuffle(ops2)
+            cast1 = random.choice(['', '$signed', '$unsigned'])
+            cast2 = random.choice(['', '$signed', '$unsigned'])
+            print('  assign y = (s ? %s(%s %s %s) : %s(%s %s %s));' %
+                  (cast1, ops1[0], op, ops1[1],
+                   cast2, ops2[0], op, ops2[1]))
+            print('endmodule')
+
+    with open('temp/uut_%05d.ys' % idx, 'w') as f:
+        with redirect_stdout(f):
+            print('read_verilog temp/uut_%05d.v' % idx)
+            print('proc;;')
+            print('copy uut_%05d gold' % idx)
+            print('rename uut_%05d gate' % idx)
+            print('tee -a temp/all_share_log.txt log')
+            print('tee -a temp/all_share_log.txt log #job# uut_%05d' % idx)
+            print('tee -a temp/all_share_log.txt opt gate')
+            print('tee -a temp/all_share_log.txt opt_share gate')
+            print('tee -a temp/all_share_log.txt opt_clean gate')
+            print(
+                'miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp gold gate miter'
+            )
+            print(
+                'sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter'
+            )
diff --git a/tests/opt_share/run-test.sh b/tests/opt_share/run-test.sh
new file mode 100755
index 000000000..e01552646
--- /dev/null
+++ b/tests/opt_share/run-test.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+
+# run this test many times:
+# time bash -c 'for ((i=0; i<100; i++)); do echo "-- $i --"; bash run-test.sh || exit 1; done'
+
+set -e
+
+OPTIND=1
+count=100
+seed=""    # default to no seed specified
+while getopts "c:S:" opt
+do
+  case "$opt" in
+		c) count="$OPTARG" ;;
+		S) seed="-S $OPTARG" ;;
+  esac
+done
+shift "$((OPTIND-1))"
+
+rm -rf temp
+mkdir -p temp
+echo "generating tests.."
+python3 generate.py -c $count $seed
+
+echo "running tests.."
+for i in $( ls temp/*.ys | sed 's,[^0-9],,g; s,^0*\(.\),\1,g;' ); do
+	echo -n "[$i]"
+	idx=$( printf "%05d" $i )
+	../../yosys -ql temp/uut_${idx}.log temp/uut_${idx}.ys
+done
+echo
+
+failed_share=$( echo $( gawk '/^#job#/ { j=$2; db[j]=0; } /^Removing [246] cells/ { delete db[j]; } END { for (j in db) print(j); }' temp/all_share_log.txt ) )
+if [ -n "$failed_share" ]; then
+	echo "Resource sharing failed for the following test cases: $failed_share"
+	false
+fi
+
+exit 0

From 067b44938c1fd3e24fc9478b96a47bac7152c111 Mon Sep 17 00:00:00 2001
From: Bogdan Vukobratovic <bogdan.vukobratovic@gmail.com>
Date: Wed, 7 Aug 2019 09:30:58 +0200
Subject: [PATCH 06/20] Fix wrong results when opt_share called before
 opt_clean

---
 passes/opt/opt_share.cc                       | 32 ++++++++-----------
 .../opt/opt_share_large_pmux_cat_multipart.ys |  1 -
 2 files changed, 14 insertions(+), 19 deletions(-)

diff --git a/passes/opt/opt_share.cc b/passes/opt/opt_share.cc
index e8f44749a..a2ec9cc37 100644
--- a/passes/opt/opt_share.cc
+++ b/passes/opt/opt_share.cc
@@ -138,7 +138,7 @@ RTLIL::SigSpec decode_port_sign(RTLIL::Cell *cell, RTLIL::IdString port_name) {
 
 	if (cell->type == "$alu" && port_name == "\\B")
 		return cell->getPort("\\BI");
-	else if	(cell->type == "$sub" && port_name == "\\B")
+	else if (cell->type == "$sub" && port_name == "\\B")
 		return RTLIL::Const(1, 1);
 
 	return RTLIL::Const(0, 1);
@@ -177,14 +177,12 @@ void merge_operators(RTLIL::Module *module, RTLIL::Cell *mux, const std::vector<
 		auto op = p.op;
 
 		RTLIL::IdString muxed_port_name = "\\A";
-		if (op->getPort("\\A") == operand.sig) {
+		if (decode_port(op, "\\A", &assign_map) == operand)
 			muxed_port_name = "\\B";
-		}
 
 		auto operand = decode_port(op, muxed_port_name, &assign_map);
-		if (operand.sig.size() > max_width) {
+		if (operand.sig.size() > max_width)
 			max_width = operand.sig.size();
-		}
 
 		muxed_operands.push_back(operand);
 	}
@@ -196,10 +194,8 @@ void merge_operators(RTLIL::Module *module, RTLIL::Cell *mux, const std::vector<
 			max_width = shared_op->getParam("\\Y_WIDTH").as_int();
 
 
-	for (auto &operand : muxed_operands) {
+	for (auto &operand : muxed_operands)
 		operand.sig.extend_u0(max_width, operand.is_signed);
-	}
-
 
 	for (const auto& p : ports) {
 		auto op = p.op;
@@ -208,11 +204,10 @@ void merge_operators(RTLIL::Module *module, RTLIL::Cell *mux, const std::vector<
 		module->remove(op);
 	}
 
-	for (auto &muxed_op : muxed_operands) {
-		if (muxed_op.sign != muxed_operands[0].sign) {
+	for (auto &muxed_op : muxed_operands)
+		if (muxed_op.sign != muxed_operands[0].sign)
 			muxed_op = ExtSigSpec(module->Neg(NEW_ID, muxed_op.sig, muxed_op.is_signed));
-		}
-	}
+
 
 	RTLIL::SigSpec mux_y = mux->getPort("\\Y");
 	RTLIL::SigSpec mux_a = mux->getPort("\\A");
@@ -261,7 +256,7 @@ void merge_operators(RTLIL::Module *module, RTLIL::Cell *mux, const std::vector<
 
 	shared_op->setParam("\\Y_WIDTH", conn_width);
 
-	if (shared_op->getPort("\\A") == operand.sig) {
+	if (decode_port(shared_op, "\\A", &assign_map) == operand) {
 		shared_op->setPort("\\B", mux_to_oper);
 		shared_op->setParam("\\B_WIDTH", max_width);
 	} else {
@@ -299,7 +294,7 @@ void check_muxed_operands(std::vector<const OpMuxConn *> &ports, const ExtSigSpe
 		auto op = p->op;
 
 		RTLIL::IdString muxed_port_name = "\\A";
-		if (op->getPort("\\A") == shared_operand.sig) {
+		if (decode_port(op, "\\A", &assign_map) == shared_operand) {
 			muxed_port_name = "\\B";
 		}
 
@@ -486,10 +481,11 @@ struct OptSharePass : public Pass {
 		log("\n");
 
 		log("This pass identifies mutually exclusive cells of the same type that:\n");
-		log("    (a) share an input signal\n");
-		log("    (b) drive the same $mux, $_MUX_, or $pmux multiplexing cell allowing\n");
-		log("        the cell to be merged and the multiplexer to be moved from\n");
-		log("        multiplexing its output to multiplexing the non-shared input signals.\n");
+		log("    (a) share an input signal,\n");
+		log("    (b) drive the same $mux, $_MUX_, or $pmux multiplexing cell,\n");
+		log("\n");
+		log("allowing the cell to be merged and the multiplexer to be moved from\n");
+		log("multiplexing its output to multiplexing the non-shared input signals.\n");
 		log("\n");
 	}
 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
diff --git a/tests/opt/opt_share_large_pmux_cat_multipart.ys b/tests/opt/opt_share_large_pmux_cat_multipart.ys
index 54d200dc7..610bb8c6c 100644
--- a/tests/opt/opt_share_large_pmux_cat_multipart.ys
+++ b/tests/opt/opt_share_large_pmux_cat_multipart.ys
@@ -7,7 +7,6 @@ opt merged
 
 opt_share merged
 opt_clean merged
-opt -full
 
 miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp opt_share_test merged miter
 sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter

From 12c692f6eda7367527fde2a8aad49447a73aa643 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Mon, 12 Aug 2019 12:06:45 -0700
Subject: [PATCH 07/20] Revert "Merge pull request #1280 from
 YosysHQ/revert-1266-eddie/ice40_full_adder"

This reverts commit c851dc13108021834533094a8a3236da6d9e0161, reversing
changes made to f54bf1631ff37a83733c162e6ebd188c1d5ea18f.
---
 CHANGELOG                                     |   2 +
 frontends/ast/ast.cc                          |   2 +-
 passes/pmgen/Makefile.inc                     |  10 ++
 passes/pmgen/ice40_wrapcarry.cc               |  90 +++++++++++++++
 passes/pmgen/ice40_wrapcarry.pmg              |  11 ++
 techlibs/ice40/Makefile.inc                   |   1 -
 techlibs/ice40/arith_map.v                    |  32 ++----
 techlibs/ice40/cells_map.v                    |  23 ++--
 techlibs/ice40/ice40_unlut.cc                 | 106 ------------------
 techlibs/ice40/synth_ice40.cc                 |  13 ++-
 techlibs/ice40/tests/test_arith.ys            |   9 +-
 tests/{various => opt}/opt_expr.ys            |   0
 tests/opt/opt_ff.v                            |  21 ----
 tests/opt/opt_ff.ys                           |   3 -
 tests/opt/opt_lut.ys                          |   4 +-
 tests/{various => opt}/opt_rmdff.v            |   0
 tests/{various => opt}/opt_rmdff.ys           |   0
 tests/opt/{opt_ff_sat.v => opt_rmdff_sat.v}   |   0
 tests/opt/{opt_ff_sat.ys => opt_rmdff_sat.ys} |   2 +-
 tests/various/wreduce.ys                      |  33 +++++-
 20 files changed, 181 insertions(+), 181 deletions(-)
 create mode 100644 passes/pmgen/ice40_wrapcarry.cc
 create mode 100644 passes/pmgen/ice40_wrapcarry.pmg
 delete mode 100644 techlibs/ice40/ice40_unlut.cc
 rename tests/{various => opt}/opt_expr.ys (100%)
 delete mode 100644 tests/opt/opt_ff.v
 delete mode 100644 tests/opt/opt_ff.ys
 rename tests/{various => opt}/opt_rmdff.v (100%)
 rename tests/{various => opt}/opt_rmdff.ys (100%)
 rename tests/opt/{opt_ff_sat.v => opt_rmdff_sat.v} (100%)
 rename tests/opt/{opt_ff_sat.ys => opt_rmdff_sat.ys} (70%)

diff --git a/CHANGELOG b/CHANGELOG
index 638c36121..21fb8a3f5 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -19,6 +19,8 @@ Yosys 0.9 .. Yosys 0.9-dev
     - Added automatic gzip compression (based on filename extension) for backends
     - Improve attribute and parameter encoding in JSON to avoid ambiguities between
       bit vectors and strings containing [01xz]*
+    - Added "ice40_wrapcarry" to encapsulate SB_LUT+SB_CARRY pairs for techmapping
+    - Removed "ice40_unlut"
 
 Yosys 0.8 .. Yosys 0.8-dev
 --------------------------
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index 07ef0a86e..0d6626b19 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -1172,7 +1172,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
 
 			if (design->has((*it)->str)) {
 				RTLIL::Module *existing_mod = design->module((*it)->str);
-				if (!nooverwrite && !overwrite && !existing_mod->get_bool_attribute("\\blackbox")) {
+				if (!nooverwrite && !overwrite && !existing_mod->get_blackbox_attribute()) {
 					log_file_error((*it)->filename, (*it)->linenum, "Re-definition of module `%s'!\n", (*it)->str.c_str());
 				} else if (nooverwrite) {
 					log("Ignoring re-definition of module `%s' at %s:%d.\n",
diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc
index 7911132db..c03606152 100644
--- a/passes/pmgen/Makefile.inc
+++ b/passes/pmgen/Makefile.inc
@@ -1,4 +1,5 @@
 OBJS += passes/pmgen/ice40_dsp.o
+OBJS += passes/pmgen/ice40_wrapcarry.o
 OBJS += passes/pmgen/peepopt.o
 
 # --------------------------------------
@@ -12,6 +13,15 @@ passes/pmgen/ice40_dsp_pm.h: passes/pmgen/pmgen.py passes/pmgen/ice40_dsp.pmg
 
 # --------------------------------------
 
+passes/pmgen/ice40_wrapcarry.o: passes/pmgen/ice40_wrapcarry_pm.h
+EXTRA_OBJS += passes/pmgen/ice40_wrapcarry_pm.h
+.SECONDARY: passes/pmgen/ice40_wrapcarry_pm.h
+
+passes/pmgen/ice40_wrapcarry_pm.h: passes/pmgen/pmgen.py passes/pmgen/ice40_wrapcarry.pmg
+	$(P) mkdir -p passes/pmgen && python3 $< -o $@ -p ice40_wrapcarry $(filter-out $<,$^)
+
+# --------------------------------------
+
 passes/pmgen/peepopt.o: passes/pmgen/peepopt_pm.h
 EXTRA_OBJS += passes/pmgen/peepopt_pm.h
 .SECONDARY: passes/pmgen/peepopt_pm.h
diff --git a/passes/pmgen/ice40_wrapcarry.cc b/passes/pmgen/ice40_wrapcarry.cc
new file mode 100644
index 000000000..69ef3cd82
--- /dev/null
+++ b/passes/pmgen/ice40_wrapcarry.cc
@@ -0,0 +1,90 @@
+/*
+ *  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"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+#include "passes/pmgen/ice40_wrapcarry_pm.h"
+
+void create_ice40_wrapcarry(ice40_wrapcarry_pm &pm)
+{
+	auto &st = pm.st_ice40_wrapcarry;
+
+#if 0
+	log("\n");
+	log("carry: %s\n", log_id(st.carry, "--"));
+	log("lut:   %s\n", log_id(st.lut, "--"));
+#endif
+
+	log("  replacing SB_LUT + SB_CARRY with $__ICE40_CARRY_WRAPPER cell.\n");
+
+	Cell *cell = pm.module->addCell(NEW_ID, "$__ICE40_CARRY_WRAPPER");
+	pm.module->swap_names(cell, st.carry);
+
+	cell->setPort("\\A", st.carry->getPort("\\I0"));
+	cell->setPort("\\B", st.carry->getPort("\\I1"));
+	cell->setPort("\\CI", st.carry->getPort("\\CI"));
+	cell->setPort("\\CO", st.carry->getPort("\\CO"));
+
+	cell->setPort("\\I0", st.lut->getPort("\\I0"));
+	cell->setPort("\\I3", st.lut->getPort("\\I3"));
+	cell->setPort("\\O", st.lut->getPort("\\O"));
+	cell->setParam("\\LUT", st.lut->getParam("\\LUT_INIT"));
+
+	pm.autoremove(st.carry);
+	pm.autoremove(st.lut);
+}
+
+struct Ice40WrapCarryPass : public Pass {
+	Ice40WrapCarryPass() : Pass("ice40_wrapcarry", "iCE40: wrap carries") { }
+	void help() YS_OVERRIDE
+	{
+		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+		log("\n");
+		log("    ice40_wrapcarry [selection]\n");
+		log("\n");
+		log("Wrap manually instantiated SB_CARRY cells, along with their associated SB_LUTs,\n");
+		log("into an internal $__ICE40_CARRY_WRAPPER cell for preservation across technology\n");
+		log("mapping.");
+		log("\n");
+	}
+	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+	{
+		log_header(design, "Executing ICE40_WRAPCARRY pass (wrap carries).\n");
+
+		size_t argidx;
+		for (argidx = 1; argidx < args.size(); argidx++)
+		{
+			// if (args[argidx] == "-singleton") {
+			// 	singleton_mode = true;
+			// 	continue;
+			// }
+			break;
+		}
+		extra_args(args, argidx, design);
+
+		for (auto module : design->selected_modules())
+			ice40_wrapcarry_pm(module, module->selected_cells()).run_ice40_wrapcarry(create_ice40_wrapcarry);
+	}
+} Ice40WrapCarryPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/pmgen/ice40_wrapcarry.pmg b/passes/pmgen/ice40_wrapcarry.pmg
new file mode 100644
index 000000000..9e64c7467
--- /dev/null
+++ b/passes/pmgen/ice40_wrapcarry.pmg
@@ -0,0 +1,11 @@
+pattern ice40_wrapcarry
+
+match carry
+	select carry->type.in(\SB_CARRY)
+endmatch
+
+match lut
+	select lut->type.in(\SB_LUT4)
+	index <SigSpec> port(lut, \I1) === port(carry, \I0)
+	index <SigSpec> port(lut, \I2) === port(carry, \I1)
+endmatch
diff --git a/techlibs/ice40/Makefile.inc b/techlibs/ice40/Makefile.inc
index d258d5a5d..76a89b107 100644
--- a/techlibs/ice40/Makefile.inc
+++ b/techlibs/ice40/Makefile.inc
@@ -4,7 +4,6 @@ OBJS += techlibs/ice40/ice40_braminit.o
 OBJS += techlibs/ice40/ice40_ffssr.o
 OBJS += techlibs/ice40/ice40_ffinit.o
 OBJS += techlibs/ice40/ice40_opt.o
-OBJS += techlibs/ice40/ice40_unlut.o
 
 GENFILES += techlibs/ice40/brams_init1.vh
 GENFILES += techlibs/ice40/brams_init2.vh
diff --git a/techlibs/ice40/arith_map.v b/techlibs/ice40/arith_map.v
index fe83a8e38..26b24db9e 100644
--- a/techlibs/ice40/arith_map.v
+++ b/techlibs/ice40/arith_map.v
@@ -44,35 +44,21 @@ module _80_ice40_alu (A, B, CI, BI, X, Y, CO);
 
 	genvar i;
 	generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice
-`ifdef _ABC
-		\$__ICE40_FULL_ADDER carry (
+		\$__ICE40_CARRY_WRAPPER #(
+			//    A[0]: 1010 1010 1010 1010
+			//    A[1]: 1100 1100 1100 1100
+			//    A[2]: 1111 0000 1111 0000
+			//    A[3]: 1111 1111 0000 0000
+			.LUT(16'b 0110_1001_1001_0110)
+		) fadd (
 			.A(AA[i]),
 			.B(BB[i]),
 			.CI(C[i]),
+			.I0(1'b0),
+			.I3(C[i]),
 			.CO(CO[i]),
 			.O(Y[i])
 		);
-`else
-		SB_CARRY carry (
-			.I0(AA[i]),
-			.I1(BB[i]),
-			.CI(C[i]),
-			.CO(CO[i])
-		);
-		SB_LUT4 #(
-			//         I0: 1010 1010 1010 1010
-			//         I1: 1100 1100 1100 1100
-			//         I2: 1111 0000 1111 0000
-			//         I3: 1111 1111 0000 0000
-			.LUT_INIT(16'b 0110_1001_1001_0110)
-		) adder (
-			.I0(1'b0),
-			.I1(AA[i]),
-			.I2(BB[i]),
-			.I3(C[i]),
-			.O(Y[i])
-		);
-`endif
 	end endgenerate
 
 	assign X = AA ^ BB;
diff --git a/techlibs/ice40/cells_map.v b/techlibs/ice40/cells_map.v
index b4b831165..0c10c9ac4 100644
--- a/techlibs/ice40/cells_map.v
+++ b/techlibs/ice40/cells_map.v
@@ -62,26 +62,21 @@ module \$lut (A, Y);
 endmodule
 `endif
 
-`ifdef _ABC
-module \$__ICE40_FULL_ADDER (output CO, O, input A, B, CI);
+`ifndef NO_ADDER
+module \$__ICE40_CARRY_WRAPPER (output CO, O, input A, B, CI, I0, I3);
+  parameter LUT = 0;
   SB_CARRY carry (
     .I0(A),
     .I1(B),
     .CI(CI),
     .CO(CO)
   );
-  SB_LUT4 #(
-    //         I0: 1010 1010 1010 1010
-    //         I1: 1100 1100 1100 1100
-    //         I2: 1111 0000 1111 0000
-    //         I3: 1111 1111 0000 0000
-    .LUT_INIT(16'b 0110_1001_1001_0110)
-  ) adder (
-    .I0(1'b0),
-    .I1(A),
-    .I2(B),
-    .I3(CI),
-    .O(O)
+  \$lut #(
+    .WIDTH(4),
+    .LUT(LUT)
+  ) lut (
+    .A({I3,B,A,I0}),
+    .Y(O)
   );
 endmodule
 `endif
diff --git a/techlibs/ice40/ice40_unlut.cc b/techlibs/ice40/ice40_unlut.cc
deleted file mode 100644
index f3f70ac1f..000000000
--- a/techlibs/ice40/ice40_unlut.cc
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- *  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"
-#include "kernel/sigtools.h"
-#include <stdlib.h>
-#include <stdio.h>
-
-USING_YOSYS_NAMESPACE
-PRIVATE_NAMESPACE_BEGIN
-
-static SigBit get_bit_or_zero(const SigSpec &sig)
-{
-	if (GetSize(sig) == 0)
-		return State::S0;
-	return sig[0];
-}
-
-static void run_ice40_unlut(Module *module)
-{
-	SigMap sigmap(module);
-
-	for (auto cell : module->selected_cells())
-	{
-		if (cell->type == "\\SB_LUT4")
-		{
-			SigSpec inbits;
-
-			inbits.append(get_bit_or_zero(cell->getPort("\\I0")));
-			inbits.append(get_bit_or_zero(cell->getPort("\\I1")));
-			inbits.append(get_bit_or_zero(cell->getPort("\\I2")));
-			inbits.append(get_bit_or_zero(cell->getPort("\\I3")));
-			sigmap.apply(inbits);
-
-			log("Mapping SB_LUT4 cell %s.%s to $lut.\n", log_id(module), log_id(cell));
-
-			cell->type ="$lut";
-			cell->setParam("\\WIDTH", 4);
-			cell->setParam("\\LUT", cell->getParam("\\LUT_INIT"));
-			cell->unsetParam("\\LUT_INIT");
-
-			cell->setPort("\\A", SigSpec({
-				get_bit_or_zero(cell->getPort("\\I0")),
-				get_bit_or_zero(cell->getPort("\\I1")),
-				get_bit_or_zero(cell->getPort("\\I2")),
-				get_bit_or_zero(cell->getPort("\\I3"))
-			}));
-			cell->setPort("\\Y", cell->getPort("\\O")[0]);
-			cell->unsetPort("\\I0");
-			cell->unsetPort("\\I1");
-			cell->unsetPort("\\I2");
-			cell->unsetPort("\\I3");
-			cell->unsetPort("\\O");
-
-			cell->check();
-		}
-	}
-}
-
-struct Ice40UnlutPass : public Pass {
-	Ice40UnlutPass() : Pass("ice40_unlut", "iCE40: transform SB_LUT4 cells to $lut cells") { }
-	void help() YS_OVERRIDE
-	{
-		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
-		log("\n");
-		log("    ice40_unlut [options] [selection]\n");
-		log("\n");
-		log("This command transforms all SB_LUT4 cells to generic $lut cells.\n");
-		log("\n");
-	}
-	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
-	{
-		log_header(design, "Executing ICE40_UNLUT pass (convert SB_LUT4 to $lut).\n");
-		log_push();
-
-		size_t argidx;
-		for (argidx = 1; argidx < args.size(); argidx++) {
-			// if (args[argidx] == "-???") {
-			//  continue;
-			// }
-			break;
-		}
-		extra_args(args, argidx, design);
-
-		for (auto module : design->selected_modules())
-			run_ice40_unlut(module);
-	}
-} Ice40UnlutPass;
-
-PRIVATE_NAMESPACE_END
diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc
index dc04eed67..c6de81bd9 100644
--- a/techlibs/ice40/synth_ice40.cc
+++ b/techlibs/ice40/synth_ice40.cc
@@ -238,7 +238,7 @@ struct SynthIce40Pass : public ScriptPass
 	{
 		if (check_label("begin"))
 		{
-			run("read_verilog -icells -lib -D_ABC +/ice40/cells_sim.v");
+			run("read_verilog -icells -lib +/ice40/cells_sim.v");
 			run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
 			run("proc");
 		}
@@ -293,8 +293,10 @@ struct SynthIce40Pass : public ScriptPass
 		{
 			if (nocarry)
 				run("techmap");
-			else
-				run("techmap -map +/techmap.v -map +/ice40/arith_map.v" + std::string(abc == "abc9" ? " -D _ABC" : ""));
+			else {
+				run("ice40_wrapcarry");
+				run("techmap -map +/techmap.v -map +/ice40/arith_map.v");
+			}
 			if (retime || help_mode)
 				run(abc + " -dff", "(only if -retime)");
 			run("ice40_opt");
@@ -309,7 +311,7 @@ struct SynthIce40Pass : public ScriptPass
 				run("opt_merge");
 				run(stringf("dff2dffe -unmap-mince %d", min_ce_use));
 			}
-			run("techmap -D NO_LUT -map +/ice40/cells_map.v");
+			run("techmap -D NO_LUT -D NO_ADDER -map +/ice40/cells_map.v");
 			run("opt_expr -mux_undef");
 			run("simplemap");
 			run("ice40_ffinit");
@@ -338,13 +340,12 @@ struct SynthIce40Pass : public ScriptPass
 					else
 						wire_delay = 250;
 					run(abc + stringf(" -W %d -lut +/ice40/abc_%s.lut -box +/ice40/abc_%s.box", wire_delay, device_opt.c_str(), device_opt.c_str()), "(skip if -noabc)");
-					run("techmap -D NO_LUT -D _ABC -map +/ice40/cells_map.v");
 				}
 				else
 					run(abc + " -dress -lut 4", "(skip if -noabc)");
 			}
+			run("techmap -D NO_LUT -map +/ice40/cells_map.v");
 			run("clean");
-			run("ice40_unlut");
 			run("opt_lut -dlogic SB_CARRY:I0=2:I1=1:CI=0");
 		}
 
diff --git a/techlibs/ice40/tests/test_arith.ys b/techlibs/ice40/tests/test_arith.ys
index 160c767fb..ddb80b700 100644
--- a/techlibs/ice40/tests/test_arith.ys
+++ b/techlibs/ice40/tests/test_arith.ys
@@ -1,6 +1,5 @@
 read_verilog test_arith.v
 synth_ice40
-techmap -map ../cells_sim.v
 rename test gate
 
 read_verilog test_arith.v
@@ -8,3 +7,11 @@ rename test gold
 
 miter -equiv -flatten -make_outputs gold gate miter
 sat -verify -prove trigger 0 -show-ports miter
+
+synth_ice40 -top gate
+
+read_verilog test_arith.v
+rename test gold
+
+miter -equiv -flatten -make_outputs gold gate miter
+sat -verify -prove trigger 0 -show-ports miter
diff --git a/tests/various/opt_expr.ys b/tests/opt/opt_expr.ys
similarity index 100%
rename from tests/various/opt_expr.ys
rename to tests/opt/opt_expr.ys
diff --git a/tests/opt/opt_ff.v b/tests/opt/opt_ff.v
deleted file mode 100644
index a01b64b61..000000000
--- a/tests/opt/opt_ff.v
+++ /dev/null
@@ -1,21 +0,0 @@
-module top(
-    input clk,
-    input rst,
-    input [2:0] a,
-    output [1:0] b
-);
-    reg [2:0] b_reg;
-    initial begin
-        b_reg <= 3'b0;
-    end
-
-    assign b = b_reg[1:0];
-    always @(posedge clk or posedge rst) begin
-        if(rst) begin
-            b_reg <= 3'b0;
-        end else begin
-            b_reg <= a;
-        end
-    end
-endmodule
-
diff --git a/tests/opt/opt_ff.ys b/tests/opt/opt_ff.ys
deleted file mode 100644
index 704c7acf3..000000000
--- a/tests/opt/opt_ff.ys
+++ /dev/null
@@ -1,3 +0,0 @@
-read_verilog opt_ff.v
-synth_ice40
-ice40_unlut
diff --git a/tests/opt/opt_lut.ys b/tests/opt/opt_lut.ys
index 59b12c351..a9fccbb62 100644
--- a/tests/opt/opt_lut.ys
+++ b/tests/opt/opt_lut.ys
@@ -1,4 +1,2 @@
 read_verilog opt_lut.v
-synth_ice40
-ice40_unlut
-equiv_opt -map +/ice40/cells_sim.v -assert opt_lut -dlogic SB_CARRY:I0=1:I1=2:CI=3
+equiv_opt -map +/ice40/cells_sim.v -assert synth_ice40
diff --git a/tests/various/opt_rmdff.v b/tests/opt/opt_rmdff.v
similarity index 100%
rename from tests/various/opt_rmdff.v
rename to tests/opt/opt_rmdff.v
diff --git a/tests/various/opt_rmdff.ys b/tests/opt/opt_rmdff.ys
similarity index 100%
rename from tests/various/opt_rmdff.ys
rename to tests/opt/opt_rmdff.ys
diff --git a/tests/opt/opt_ff_sat.v b/tests/opt/opt_rmdff_sat.v
similarity index 100%
rename from tests/opt/opt_ff_sat.v
rename to tests/opt/opt_rmdff_sat.v
diff --git a/tests/opt/opt_ff_sat.ys b/tests/opt/opt_rmdff_sat.ys
similarity index 70%
rename from tests/opt/opt_ff_sat.ys
rename to tests/opt/opt_rmdff_sat.ys
index 4e7cc6ca4..1c3dd9c05 100644
--- a/tests/opt/opt_ff_sat.ys
+++ b/tests/opt/opt_rmdff_sat.ys
@@ -1,4 +1,4 @@
-read_verilog opt_ff_sat.v
+read_verilog opt_rmdff_sat.v
 prep -flatten
 opt_rmdff -sat
 synth
diff --git a/tests/various/wreduce.ys b/tests/various/wreduce.ys
index 4257292f5..2e0812c48 100644
--- a/tests/various/wreduce.ys
+++ b/tests/various/wreduce.ys
@@ -36,7 +36,6 @@ design -save gold
 opt_expr
 wreduce
 
-dump
 select -assert-count 1 t:$sub r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i
 
 design -stash gate
@@ -46,3 +45,35 @@ design -import gate -as gate
 
 miter -equiv -flatten -make_assert -make_outputs gold gate miter
 sat -verify -prove-asserts -show-ports miter
+
+##########
+
+# Testcase from: https://github.com/YosysHQ/yosys/commit/25680f6a078bb32f157bd580705656496717bafb
+design -reset
+read_verilog <<EOT
+module top(
+    input clk,
+    input rst,
+    input [2:0] a,
+    output [1:0] b
+);
+    reg [2:0] b_reg;
+    initial begin
+        b_reg <= 3'b0;
+    end
+
+    assign b = b_reg[1:0];
+    always @(posedge clk or posedge rst) begin
+        if(rst) begin
+            b_reg <= 3'b0;
+        end else begin
+            b_reg <= a;
+        end
+    end
+endmodule
+EOT
+
+proc
+wreduce
+
+select -assert-count 1 t:$adff r:ARST_VALUE=2'b00 %i

From 8a2480526f2ff80cbdf0f0f4279e8989b53b6e9b Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Mon, 12 Aug 2019 12:19:25 -0700
Subject: [PATCH 08/20] Fix $lut pin ordering inside $__ICE40_CARRY_WRAPPER

---
 techlibs/ice40/cells_map.v | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/techlibs/ice40/cells_map.v b/techlibs/ice40/cells_map.v
index 0c10c9ac4..662423f0a 100644
--- a/techlibs/ice40/cells_map.v
+++ b/techlibs/ice40/cells_map.v
@@ -75,7 +75,7 @@ module \$__ICE40_CARRY_WRAPPER (output CO, O, input A, B, CI, I0, I3);
     .WIDTH(4),
     .LUT(LUT)
   ) lut (
-    .A({I3,B,A,I0}),
+    .A({I0,A,B,I3}),
     .Y(O)
   );
 endmodule

From 0c5db07cd6cc3c19b926da21a46599f97592b20f Mon Sep 17 00:00:00 2001
From: Clifford Wolf <clifford@clifford.at>
Date: Sun, 11 Aug 2019 23:25:46 +0200
Subject: [PATCH 09/20] Fix various NDEBUG compiler warnings, closes #1255

Signed-off-by: Clifford Wolf <clifford@clifford.at>
---
 backends/aiger/xaiger.cc      |  2 +-
 frontends/aiger/aigerparse.cc | 20 +++++++++++---------
 frontends/verific/verific.cc  |  2 ++
 kernel/log.h                  |  2 +-
 passes/opt/opt_expr.cc        |  3 ++-
 passes/techmap/abc9.cc        |  2 +-
 6 files changed, 18 insertions(+), 13 deletions(-)

diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc
index f49ecbeda..5e12e9a34 100644
--- a/backends/aiger/xaiger.cc
+++ b/backends/aiger/xaiger.cc
@@ -312,7 +312,7 @@ struct XAigerWriter
 #if 0
 			toposort.analyze_loops = true;
 #endif
-			bool no_loops = toposort.sort();
+			bool no_loops YS_ATTRIBUTE(unused) = toposort.sort();
 #if 0
 			unsigned i = 0;
 			for (auto &it : toposort.loops) {
diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc
index bd0596cc0..534cc0daa 100644
--- a/frontends/aiger/aigerparse.cc
+++ b/frontends/aiger/aigerparse.cc
@@ -67,7 +67,7 @@ struct ConstEvalAig
 				continue;
 			for (auto &it2 : it.second->connections())
 				if (yosys_celltypes.cell_output(it.second->type, it2.first)) {
-					auto r = sig2driver.insert(std::make_pair(it2.second, it.second));
+					auto r YS_ATTRIBUTE(unused) = sig2driver.insert(std::make_pair(it2.second, it.second));
 					log_assert(r.second);
 				}
 		}
@@ -389,9 +389,9 @@ void AigerReader::parse_xaiger(const dict<int,IdString> &box_lookup)
 			f.ignore(1);
 			// XAIGER extensions
 			if (c == 'm') {
-				uint32_t dataSize = parse_xaiger_literal(f);
+				uint32_t dataSize YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
 				uint32_t lutNum = parse_xaiger_literal(f);
-				uint32_t lutSize = parse_xaiger_literal(f);
+				uint32_t lutSize YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
 				log_debug("m: dataSize=%u lutNum=%u lutSize=%u\n", dataSize, lutNum, lutSize);
 				ConstEvalAig ce(module);
 				for (unsigned i = 0; i < lutNum; ++i) {
@@ -416,7 +416,7 @@ void AigerReader::parse_xaiger(const dict<int,IdString> &box_lookup)
 						int gray = j ^ (j >> 1);
 						ce.set_incremental(input_sig, RTLIL::Const{gray, static_cast<int>(cutLeavesM)});
 						RTLIL::SigBit o(output_sig);
-						bool success = ce.eval(o);
+						bool success YS_ATTRIBUTE(unused) = ce.eval(o);
 						log_assert(success);
 						log_assert(o.wire == nullptr);
 						lut_mask[gray] = o.data;
@@ -428,7 +428,7 @@ void AigerReader::parse_xaiger(const dict<int,IdString> &box_lookup)
 				}
 			}
 			else if (c == 'r') {
-				uint32_t dataSize = parse_xaiger_literal(f);
+				uint32_t dataSize YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
 				flopNum = parse_xaiger_literal(f);
 				log_assert(dataSize == (flopNum+1) * sizeof(uint32_t));
 				f.ignore(flopNum * sizeof(uint32_t));
@@ -440,15 +440,15 @@ void AigerReader::parse_xaiger(const dict<int,IdString> &box_lookup)
 			}
 			else if (c == 'h') {
 				f.ignore(sizeof(uint32_t));
-				uint32_t version = parse_xaiger_literal(f);
+				uint32_t version YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
 				log_assert(version == 1);
-				uint32_t ciNum = parse_xaiger_literal(f);
+				uint32_t ciNum YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
 				log_debug("ciNum = %u\n", ciNum);
-				uint32_t coNum = parse_xaiger_literal(f);
+				uint32_t coNum YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
 				log_debug("coNum = %u\n", coNum);
 				piNum = parse_xaiger_literal(f);
 				log_debug("piNum = %u\n", piNum);
-				uint32_t poNum = parse_xaiger_literal(f);
+				uint32_t poNum YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
 				log_debug("poNum = %u\n", poNum);
 				uint32_t boxNum = parse_xaiger_literal(f);
 				log_debug("boxNum = %u\n", poNum);
@@ -901,8 +901,10 @@ void AigerReader::post_process()
 				RTLIL::Cell* cell = module->cell(stringf("$__box%d__", variable));
 				if (cell) { // ABC could have optimised this box away
 					module->rename(cell, escaped_s);
+				#ifndef NDEBUG
 					RTLIL::Module* box_module = design->module(cell->type);
 					log_assert(box_module);
+				#endif
 
 					for (const auto &i : cell->connections()) {
 						RTLIL::IdString port_name = i.first;
diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc
index 17c4a1e5b..64152c9cb 100644
--- a/frontends/verific/verific.cc
+++ b/frontends/verific/verific.cc
@@ -1789,8 +1789,10 @@ struct VerificExtNets
 				new_net = new Net(name.c_str());
 				nl->Add(new_net);
 
+			#ifndef NDEBUG
 				Net *n = route_up(new_net, port->IsOutput(), ca_nl, ca_net);
 				log_assert(n == ca_net);
+			#endif
 			}
 
 			if (verific_verbose)
diff --git a/kernel/log.h b/kernel/log.h
index 3e1facae8..5f53f533a 100644
--- a/kernel/log.h
+++ b/kernel/log.h
@@ -91,7 +91,7 @@ YS_NORETURN void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(prin
 static inline bool ys_debug(int n = 0) { if (log_force_debug) return true; log_debug_suppressed += n; return false; }
 #  define log_debug(...) do { if (ys_debug(1)) log(__VA_ARGS__); } while (0)
 #else
-static inline bool ys_debug(int n = 0) { return false; }
+static inline bool ys_debug(int = 0) { return false; }
 #  define log_debug(_fmt, ...) do { } while (0)
 #endif
 
diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc
index b2dc9a448..1512cea1b 100644
--- a/passes/opt/opt_expr.cc
+++ b/passes/opt/opt_expr.cc
@@ -117,7 +117,8 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
 	}
 }
 
-void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, std::string info, std::string out_port, RTLIL::SigSpec out_val)
+void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell,
+		const std::string &info YS_ATTRIBUTE(unused), IdString out_port, RTLIL::SigSpec out_val)
 {
 	RTLIL::SigSpec Y = cell->getPort(out_port);
 	out_val.extend_u0(Y.size(), false);
diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc
index 7418ed4a3..da376d09e 100644
--- a/passes/techmap/abc9.cc
+++ b/passes/techmap/abc9.cc
@@ -741,7 +741,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
 				for (auto driver_cell : bit_drivers.at(it.first))
 				for (auto user_cell : it.second)
 					toposort.edge(driver_cell, user_cell);
-		bool no_loops = toposort.sort();
+		bool no_loops YS_ATTRIBUTE(unused) = toposort.sort();
 		log_assert(no_loops);
 
 		for (auto ii = toposort.sorted.rbegin(); ii != toposort.sorted.rend(); ii++) {

From 52355f5185fe42e28775e897f458b38a439c0ec5 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Thu, 15 Aug 2019 14:50:10 -0700
Subject: [PATCH 10/20] Use more ID::{A,B,Y,blackbox,whitebox}

---
 kernel/cellaigs.cc                |  96 ++++-----
 kernel/celledges.cc               |  14 +-
 kernel/celltypes.h                |  10 +-
 kernel/consteval.h                |  16 +-
 kernel/macc.h                     |   8 +-
 kernel/rtlil.cc                   | 192 +++++++++---------
 kernel/satgen.h                   | 236 +++++++++++-----------
 kernel/yosys.h                    |   2 +
 passes/opt/muxpack.cc             |  38 ++--
 passes/opt/opt_clean.cc           |   6 +-
 passes/opt/opt_demorgan.cc        |  14 +-
 passes/opt/opt_expr.cc            | 318 +++++++++++++++---------------
 passes/opt/opt_lut.cc             |  28 +--
 passes/opt/opt_merge.cc           |  48 ++---
 passes/opt/opt_muxtree.cc         |  24 +--
 passes/opt/opt_reduce.cc          |  66 +++----
 passes/opt/opt_rmdff.cc           |   8 +-
 passes/opt/pmux2shiftx.cc         |  30 +--
 passes/opt/share.cc               |  70 +++----
 passes/opt/wreduce.cc             |  46 ++---
 passes/techmap/abc.cc             |  86 ++++----
 passes/techmap/abc9.cc            |  26 +--
 passes/techmap/alumacc.cc         |  34 ++--
 passes/techmap/deminout.cc        |   4 +-
 passes/techmap/dff2dffe.cc        |  18 +-
 passes/techmap/dff2dffs.cc        |  10 +-
 passes/techmap/dfflibmap.cc       |   6 +-
 passes/techmap/extract_counter.cc |  38 ++--
 passes/techmap/extract_fa.cc      |  22 +--
 passes/techmap/extract_reduce.cc  |  20 +-
 passes/techmap/iopadmap.cc        |   4 +-
 passes/techmap/lut2mux.cc         |   4 +-
 passes/techmap/maccmap.cc         |  28 +--
 passes/techmap/muxcover.cc        |  30 +--
 passes/techmap/nlutmap.cc         |   2 +-
 passes/techmap/pmuxtree.cc        |   8 +-
 passes/techmap/shregmap.cc        |  22 +--
 passes/techmap/simplemap.cc       | 120 +++++------
 passes/techmap/techmap.cc         |   2 +-
 passes/techmap/tribuf.cc          |  22 +--
 40 files changed, 889 insertions(+), 887 deletions(-)

diff --git a/kernel/cellaigs.cc b/kernel/cellaigs.cc
index 6d496db45..02854edb2 100644
--- a/kernel/cellaigs.cc
+++ b/kernel/cellaigs.cc
@@ -292,19 +292,19 @@ Aig::Aig(Cell *cell)
 
 	if (cell->type.in(ID($not), ID($_NOT_), ID($pos), ID($_BUF_)))
 	{
-		for (int i = 0; i < GetSize(cell->getPort(ID(Y))); i++) {
-			int A = mk.inport(ID(A), i);
+		for (int i = 0; i < GetSize(cell->getPort(ID::Y)); i++) {
+			int A = mk.inport(ID::A, i);
 			int Y = cell->type.in(ID($not), ID($_NOT_)) ? mk.not_gate(A) : A;
-			mk.outport(Y, ID(Y), i);
+			mk.outport(Y, ID::Y, i);
 		}
 		goto optimize;
 	}
 
 	if (cell->type.in(ID($and), ID($_AND_), ID($_NAND_), ID($or), ID($_OR_), ID($_NOR_), ID($xor), ID($xnor), ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_)))
 	{
-		for (int i = 0; i < GetSize(cell->getPort(ID(Y))); i++) {
-			int A = mk.inport(ID(A), i);
-			int B = mk.inport(ID(B), i);
+		for (int i = 0; i < GetSize(cell->getPort(ID::Y)); i++) {
+			int A = mk.inport(ID::A, i);
+			int B = mk.inport(ID::B, i);
 			int Y = cell->type.in(ID($and), ID($_AND_))   ? mk.and_gate(A, B) :
 			        cell->type.in(ID($_NAND_))          ? mk.nand_gate(A, B) :
 			        cell->type.in(ID($or), ID($_OR_))     ? mk.or_gate(A, B) :
@@ -313,7 +313,7 @@ Aig::Aig(Cell *cell)
 			        cell->type.in(ID($xnor), ID($_XNOR_)) ? mk.xnor_gate(A, B) :
 			        cell->type.in(ID($_ANDNOT_))        ? mk.andnot_gate(A, B) :
 			        cell->type.in(ID($_ORNOT_))         ? mk.ornot_gate(A, B) : -1;
-			mk.outport(Y, ID(Y), i);
+			mk.outport(Y, ID::Y, i);
 		}
 		goto optimize;
 	}
@@ -321,22 +321,22 @@ Aig::Aig(Cell *cell)
 	if (cell->type.in(ID($mux), ID($_MUX_)))
 	{
 		int S = mk.inport(ID(S));
-		for (int i = 0; i < GetSize(cell->getPort(ID(Y))); i++) {
-			int A = mk.inport(ID(A), i);
-			int B = mk.inport(ID(B), i);
+		for (int i = 0; i < GetSize(cell->getPort(ID::Y)); i++) {
+			int A = mk.inport(ID::A, i);
+			int B = mk.inport(ID::B, i);
 			int Y = mk.mux_gate(A, B, S);
 			if (cell->type == ID($_NMUX_))
 				Y = mk.not_gate(Y);
-			mk.outport(Y, ID(Y), i);
+			mk.outport(Y, ID::Y, i);
 		}
 		goto optimize;
 	}
 
 	if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool)))
 	{
-		int Y = mk.inport(ID(A), 0);
-		for (int i = 1; i < GetSize(cell->getPort(ID(A))); i++) {
-			int A = mk.inport(ID(A), i);
+		int Y = mk.inport(ID::A, 0);
+		for (int i = 1; i < GetSize(cell->getPort(ID::A)); i++) {
+			int A = mk.inport(ID::A, i);
 			if (cell->type == ID($reduce_and))  Y = mk.and_gate(A, Y);
 			if (cell->type == ID($reduce_or))   Y = mk.or_gate(A, Y);
 			if (cell->type == ID($reduce_bool)) Y = mk.or_gate(A, Y);
@@ -345,35 +345,35 @@ Aig::Aig(Cell *cell)
 		}
 		if (cell->type == ID($reduce_xnor))
 			Y = mk.not_gate(Y);
-		mk.outport(Y, ID(Y), 0);
-		for (int i = 1; i < GetSize(cell->getPort(ID(Y))); i++)
-			mk.outport(mk.bool_node(false), ID(Y), i);
+		mk.outport(Y, ID::Y, 0);
+		for (int i = 1; i < GetSize(cell->getPort(ID::Y)); i++)
+			mk.outport(mk.bool_node(false), ID::Y, i);
 		goto optimize;
 	}
 
 	if (cell->type.in(ID($logic_not), ID($logic_and), ID($logic_or)))
 	{
-		int A = mk.inport(ID(A), 0), Y = -1;
-		for (int i = 1; i < GetSize(cell->getPort(ID(A))); i++)
-			A = mk.or_gate(mk.inport(ID(A), i), A);
+		int A = mk.inport(ID::A, 0), Y = -1;
+		for (int i = 1; i < GetSize(cell->getPort(ID::A)); i++)
+			A = mk.or_gate(mk.inport(ID::A, i), A);
 		if (cell->type.in(ID($logic_and), ID($logic_or))) {
-			int B = mk.inport(ID(B), 0);
-			for (int i = 1; i < GetSize(cell->getPort(ID(B))); i++)
-				B = mk.or_gate(mk.inport(ID(B), i), B);
+			int B = mk.inport(ID::B, 0);
+			for (int i = 1; i < GetSize(cell->getPort(ID::B)); i++)
+				B = mk.or_gate(mk.inport(ID::B, i), B);
 			if (cell->type == ID($logic_and)) Y = mk.and_gate(A, B);
 			if (cell->type == ID($logic_or))  Y = mk.or_gate(A, B);
 		} else {
 			if (cell->type == ID($logic_not)) Y = mk.not_gate(A);
 		}
-		mk.outport_bool(Y, ID(Y));
+		mk.outport_bool(Y, ID::Y);
 		goto optimize;
 	}
 
 	if (cell->type.in(ID($add), ID($sub)))
 	{
-		int width = GetSize(cell->getPort(ID(Y)));
-		vector<int> A = mk.inport_vec(ID(A), width);
-		vector<int> B = mk.inport_vec(ID(B), width);
+		int width = GetSize(cell->getPort(ID::Y));
+		vector<int> A = mk.inport_vec(ID::A, width);
+		vector<int> B = mk.inport_vec(ID::B, width);
 		int carry = mk.bool_node(false);
 		if (cell->type == ID($sub)) {
 			for (auto &n : B)
@@ -381,15 +381,15 @@ Aig::Aig(Cell *cell)
 			carry = mk.not_gate(carry);
 		}
 		vector<int> Y = mk.adder(A, B, carry);
-		mk.outport_vec(Y, ID(Y));
+		mk.outport_vec(Y, ID::Y);
 		goto optimize;
 	}
 
 	if (cell->type == ID($alu))
 	{
-		int width = GetSize(cell->getPort(ID(Y)));
-		vector<int> A = mk.inport_vec(ID(A), width);
-		vector<int> B = mk.inport_vec(ID(B), width);
+		int width = GetSize(cell->getPort(ID::Y));
+		vector<int> A = mk.inport_vec(ID::A, width);
+		vector<int> B = mk.inport_vec(ID::B, width);
 		int carry = mk.inport(ID(CI));
 		int binv = mk.inport(ID(BI));
 		for (auto &n : B)
@@ -398,7 +398,7 @@ Aig::Aig(Cell *cell)
 		vector<int> Y = mk.adder(A, B, carry, &X, &CO);
 		for (int i = 0; i < width; i++)
 			X[i] = mk.xor_gate(A[i], B[i]);
-		mk.outport_vec(Y, ID(Y));
+		mk.outport_vec(Y, ID::Y);
 		mk.outport_vec(X, ID(X));
 		mk.outport_vec(CO, ID(CO));
 		goto optimize;
@@ -406,57 +406,57 @@ Aig::Aig(Cell *cell)
 
 	if (cell->type.in(ID($eq), ID($ne)))
 	{
-		int width = max(GetSize(cell->getPort(ID(A))), GetSize(cell->getPort(ID(B))));
-		vector<int> A = mk.inport_vec(ID(A), width);
-		vector<int> B = mk.inport_vec(ID(B), width);
+		int width = max(GetSize(cell->getPort(ID::A)), GetSize(cell->getPort(ID::B)));
+		vector<int> A = mk.inport_vec(ID::A, width);
+		vector<int> B = mk.inport_vec(ID::B, width);
 		int Y = mk.bool_node(false);
 		for (int i = 0; i < width; i++)
 			Y = mk.or_gate(Y, mk.xor_gate(A[i], B[i]));
 		if (cell->type == ID($eq))
 			Y = mk.not_gate(Y);
-		mk.outport_bool(Y, ID(Y));
+		mk.outport_bool(Y, ID::Y);
 		goto optimize;
 	}
 
 	if (cell->type == ID($_AOI3_))
 	{
-		int A = mk.inport(ID(A));
-		int B = mk.inport(ID(B));
+		int A = mk.inport(ID::A);
+		int B = mk.inport(ID::B);
 		int C = mk.inport(ID(C));
 		int Y = mk.nor_gate(mk.and_gate(A, B), C);
-		mk.outport(Y, ID(Y));
+		mk.outport(Y, ID::Y);
 		goto optimize;
 	}
 
 	if (cell->type == ID($_OAI3_))
 	{
-		int A = mk.inport(ID(A));
-		int B = mk.inport(ID(B));
+		int A = mk.inport(ID::A);
+		int B = mk.inport(ID::B);
 		int C = mk.inport(ID(C));
 		int Y = mk.nand_gate(mk.or_gate(A, B), C);
-		mk.outport(Y, ID(Y));
+		mk.outport(Y, ID::Y);
 		goto optimize;
 	}
 
 	if (cell->type == ID($_AOI4_))
 	{
-		int A = mk.inport(ID(A));
-		int B = mk.inport(ID(B));
+		int A = mk.inport(ID::A);
+		int B = mk.inport(ID::B);
 		int C = mk.inport(ID(C));
 		int D = mk.inport(ID(D));
 		int Y = mk.nor_gate(mk.and_gate(A, B), mk.and_gate(C, D));
-		mk.outport(Y, ID(Y));
+		mk.outport(Y, ID::Y);
 		goto optimize;
 	}
 
 	if (cell->type == ID($_OAI4_))
 	{
-		int A = mk.inport(ID(A));
-		int B = mk.inport(ID(B));
+		int A = mk.inport(ID::A);
+		int B = mk.inport(ID::B);
 		int C = mk.inport(ID(C));
 		int D = mk.inport(ID(D));
 		int Y = mk.nand_gate(mk.or_gate(A, B), mk.or_gate(C, D));
-		mk.outport(Y, ID(Y));
+		mk.outport(Y, ID::Y);
 		goto optimize;
 	}
 
diff --git a/kernel/celledges.cc b/kernel/celledges.cc
index 7a324a06e..d0bb99e83 100644
--- a/kernel/celledges.cc
+++ b/kernel/celledges.cc
@@ -24,7 +24,7 @@ PRIVATE_NAMESPACE_BEGIN
 
 void bitwise_unary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
 {
-	IdString A = ID(A), Y = ID(Y);
+	IdString A = ID::A, Y = ID::Y;
 
 	bool is_signed = cell->getParam(ID(A_SIGNED)).as_bool();
 	int a_width = GetSize(cell->getPort(A));
@@ -41,7 +41,7 @@ void bitwise_unary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
 
 void bitwise_binary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
 {
-	IdString A = ID(A), B = ID(B), Y = ID(Y);
+	IdString A = ID::A, B = ID::B, Y = ID::Y;
 
 	bool is_signed = cell->getParam(ID(A_SIGNED)).as_bool();
 	int a_width = GetSize(cell->getPort(A));
@@ -71,7 +71,7 @@ void bitwise_binary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
 
 void arith_neg_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
 {
-	IdString A = ID(A), Y = ID(Y);
+	IdString A = ID::A, Y = ID::Y;
 
 	bool is_signed = cell->getParam(ID(A_SIGNED)).as_bool();
 	int a_width = GetSize(cell->getPort(A));
@@ -87,7 +87,7 @@ void arith_neg_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
 
 void arith_binary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
 {
-	IdString A = ID(A), B = ID(B), Y = ID(Y);
+	IdString A = ID::A, B = ID::B, Y = ID::Y;
 
 	bool is_signed = cell->getParam(ID(A_SIGNED)).as_bool();
 	int a_width = GetSize(cell->getPort(A));
@@ -114,7 +114,7 @@ void arith_binary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
 
 void reduce_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
 {
-	IdString A = ID(A), Y = ID(Y);
+	IdString A = ID::A, Y = ID::Y;
 
 	int a_width = GetSize(cell->getPort(A));
 
@@ -124,7 +124,7 @@ void reduce_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
 
 void compare_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
 {
-	IdString A = ID(A), B = ID(B), Y = ID(Y);
+	IdString A = ID::A, B = ID::B, Y = ID::Y;
 
 	int a_width = GetSize(cell->getPort(A));
 	int b_width = GetSize(cell->getPort(B));
@@ -138,7 +138,7 @@ void compare_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
 
 void mux_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
 {
-	IdString A = ID(A), B = ID(B), S = ID(S), Y = ID(Y);
+	IdString A = ID::A, B = ID::B, S = ID(S), Y = ID::Y;
 
 	int a_width = GetSize(cell->getPort(A));
 	int b_width = GetSize(cell->getPort(B));
diff --git a/kernel/celltypes.h b/kernel/celltypes.h
index ade305e83..bc96fd602 100644
--- a/kernel/celltypes.h
+++ b/kernel/celltypes.h
@@ -84,7 +84,7 @@ struct CellTypes
 	{
 		setup_internals_eval();
 
-		IdString A = ID(A), B = ID(B), EN = ID(EN), Y = ID(Y);
+		IdString A = ID::A, B = ID::B, EN = ID(EN), Y = ID::Y;
 		IdString SRC = ID(SRC), DST = ID(DST), DAT = ID(DAT);
 		IdString EN_SRC = ID(EN_SRC), EN_DST = ID(EN_DST);
 
@@ -121,7 +121,7 @@ struct CellTypes
 			ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($pow),
 			ID($logic_and), ID($logic_or), ID($concat), ID($macc)
 		};
-		IdString A = ID(A), B = ID(B), S = ID(S), Y = ID(Y);
+		IdString A = ID::A, B = ID::B, S = ID(S), Y = ID::Y;
 		IdString P = ID(P), G = ID(G), C = ID(C), X = ID(X);
 		IdString BI = ID(BI), CI = ID(CI), CO = ID(CO), EN = ID(EN);
 
@@ -177,19 +177,19 @@ struct CellTypes
 	{
 		setup_stdcells_eval();
 
-		IdString A = ID(A), E = ID(E), Y = ID(Y);
+		IdString A = ID::A, E = ID(E), Y = ID::Y;
 
 		setup_type(ID($_TBUF_), {A, E}, {Y}, true);
 	}
 
 	void setup_stdcells_eval()
 	{
-		IdString A = ID(A), B = ID(B), C = ID(C), D = ID(D);
+		IdString A = ID::A, B = ID::B, C = ID(C), D = ID(D);
 		IdString E = ID(E), F = ID(F), G = ID(G), H = ID(H);
 		IdString I = ID(I), J = ID(J), K = ID(K), L = ID(L);
 		IdString M = ID(M), N = ID(N), O = ID(O), P = ID(P);
 		IdString S = ID(S), T = ID(T), U = ID(U), V = ID(V);
-		IdString Y = ID(Y);
+		IdString Y = ID::Y;
 
 		setup_type(ID($_BUF_), {A}, {Y}, true);
 		setup_type(ID($_NOT_), {A}, {Y}, true);
diff --git a/kernel/consteval.h b/kernel/consteval.h
index 09b4c434b..7a83d28e7 100644
--- a/kernel/consteval.h
+++ b/kernel/consteval.h
@@ -128,8 +128,8 @@ struct ConstEval
 
 		RTLIL::SigSpec sig_a, sig_b, sig_s, sig_y;
 
-		log_assert(cell->hasPort(ID(Y)));
-		sig_y = values_map(assign_map(cell->getPort(ID(Y))));
+		log_assert(cell->hasPort(ID::Y));
+		sig_y = values_map(assign_map(cell->getPort(ID::Y)));
 		if (sig_y.is_fully_const())
 			return true;
 
@@ -139,11 +139,11 @@ struct ConstEval
 				return false;
 		}
 
-		if (cell->hasPort(ID(A)))
-			sig_a = cell->getPort(ID(A));
+		if (cell->hasPort(ID::A))
+			sig_a = cell->getPort(ID::A);
 
-		if (cell->hasPort(ID(B)))
-			sig_b = cell->getPort(ID(B));
+		if (cell->hasPort(ID::B))
+			sig_b = cell->getPort(ID::B);
 
 		if (cell->type.in(ID($mux), ID($pmux), ID($_MUX_), ID($_NMUX_)))
 		{
@@ -298,11 +298,11 @@ struct ConstEval
 					return false;
 			}
 
-			RTLIL::Const result(0, GetSize(cell->getPort(ID(Y))));
+			RTLIL::Const result(0, GetSize(cell->getPort(ID::Y)));
 			if (!macc.eval(result))
 				log_abort();
 
-			set(cell->getPort(ID(Y)), result);
+			set(cell->getPort(ID::Y), result);
 		}
 		else
 		{
diff --git a/kernel/macc.h b/kernel/macc.h
index e07e7e01a..371f6737d 100644
--- a/kernel/macc.h
+++ b/kernel/macc.h
@@ -99,10 +99,10 @@ struct Macc
 
 	void from_cell(RTLIL::Cell *cell)
 	{
-		RTLIL::SigSpec port_a = cell->getPort(ID(A));
+		RTLIL::SigSpec port_a = cell->getPort(ID::A);
 
 		ports.clear();
-		bit_ports = cell->getPort(ID(B));
+		bit_ports = cell->getPort(ID::B);
 
 		std::vector<RTLIL::State> config_bits = cell->getParam(ID(CONFIG)).bits;
 		int config_cursor = 0;
@@ -191,8 +191,8 @@ struct Macc
 			port_a.append(port.in_b);
 		}
 
-		cell->setPort(ID(A), port_a);
-		cell->setPort(ID(B), bit_ports);
+		cell->setPort(ID::A, port_a);
+		cell->setPort(ID::B, bit_ports);
 		cell->setParam(ID(CONFIG), config_bits);
 		cell->setParam(ID(CONFIG_WIDTH), GetSize(config_bits));
 		cell->setParam(ID(A_WIDTH), GetSize(port_a));
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index d01bd0c62..1d380135b 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -717,7 +717,7 @@ void RTLIL::Module::makeblackbox()
 	processes.clear();
 
 	remove(delwires);
-	set_bool_attribute(ID(blackbox));
+	set_bool_attribute(ID::blackbox);
 }
 
 void RTLIL::Module::reprocess_module(RTLIL::Design *, dict<RTLIL::IdString, RTLIL::Module *>)
@@ -845,8 +845,8 @@ namespace {
 
 			if (cell->type.in(ID($not), ID($pos), ID($neg))) {
 				param_bool(ID(A_SIGNED));
-				port(ID(A), param(ID(A_WIDTH)));
-				port(ID(Y), param(ID(Y_WIDTH)));
+				port(ID::A, param(ID(A_WIDTH)));
+				port(ID::Y, param(ID(Y_WIDTH)));
 				check_expected();
 				return;
 			}
@@ -854,17 +854,17 @@ namespace {
 			if (cell->type.in(ID($and), ID($or), ID($xor), ID($xnor))) {
 				param_bool(ID(A_SIGNED));
 				param_bool(ID(B_SIGNED));
-				port(ID(A), param(ID(A_WIDTH)));
-				port(ID(B), param(ID(B_WIDTH)));
-				port(ID(Y), param(ID(Y_WIDTH)));
+				port(ID::A, param(ID(A_WIDTH)));
+				port(ID::B, param(ID(B_WIDTH)));
+				port(ID::Y, param(ID(Y_WIDTH)));
 				check_expected();
 				return;
 			}
 
 			if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool))) {
 				param_bool(ID(A_SIGNED));
-				port(ID(A), param(ID(A_WIDTH)));
-				port(ID(Y), param(ID(Y_WIDTH)));
+				port(ID::A, param(ID(A_WIDTH)));
+				port(ID::Y, param(ID(Y_WIDTH)));
 				check_expected();
 				return;
 			}
@@ -872,9 +872,9 @@ namespace {
 			if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx))) {
 				param_bool(ID(A_SIGNED));
 				param_bool(ID(B_SIGNED));
-				port(ID(A), param(ID(A_WIDTH)));
-				port(ID(B), param(ID(B_WIDTH)));
-				port(ID(Y), param(ID(Y_WIDTH)));
+				port(ID::A, param(ID(A_WIDTH)));
+				port(ID::B, param(ID(B_WIDTH)));
+				port(ID::Y, param(ID(Y_WIDTH)));
 				check_expected(false);
 				return;
 			}
@@ -882,9 +882,9 @@ namespace {
 			if (cell->type.in(ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt))) {
 				param_bool(ID(A_SIGNED));
 				param_bool(ID(B_SIGNED));
-				port(ID(A), param(ID(A_WIDTH)));
-				port(ID(B), param(ID(B_WIDTH)));
-				port(ID(Y), param(ID(Y_WIDTH)));
+				port(ID::A, param(ID(A_WIDTH)));
+				port(ID::B, param(ID(B_WIDTH)));
+				port(ID::Y, param(ID(Y_WIDTH)));
 				check_expected();
 				return;
 			}
@@ -892,19 +892,19 @@ namespace {
 			if (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($pow))) {
 				param_bool(ID(A_SIGNED));
 				param_bool(ID(B_SIGNED));
-				port(ID(A), param(ID(A_WIDTH)));
-				port(ID(B), param(ID(B_WIDTH)));
-				port(ID(Y), param(ID(Y_WIDTH)));
+				port(ID::A, param(ID(A_WIDTH)));
+				port(ID::B, param(ID(B_WIDTH)));
+				port(ID::Y, param(ID(Y_WIDTH)));
 				check_expected(cell->type != ID($pow));
 				return;
 			}
 
 			if (cell->type == ID($fa)) {
-				port(ID(A), param(ID(WIDTH)));
-				port(ID(B), param(ID(WIDTH)));
+				port(ID::A, param(ID(WIDTH)));
+				port(ID::B, param(ID(WIDTH)));
 				port(ID(C), param(ID(WIDTH)));
 				port(ID(X), param(ID(WIDTH)));
-				port(ID(Y), param(ID(WIDTH)));
+				port(ID::Y, param(ID(WIDTH)));
 				check_expected();
 				return;
 			}
@@ -921,12 +921,12 @@ namespace {
 			if (cell->type == ID($alu)) {
 				param_bool(ID(A_SIGNED));
 				param_bool(ID(B_SIGNED));
-				port(ID(A), param(ID(A_WIDTH)));
-				port(ID(B), param(ID(B_WIDTH)));
+				port(ID::A, param(ID(A_WIDTH)));
+				port(ID::B, param(ID(B_WIDTH)));
 				port(ID(CI), 1);
 				port(ID(BI), 1);
 				port(ID(X), param(ID(Y_WIDTH)));
-				port(ID(Y), param(ID(Y_WIDTH)));
+				port(ID::Y, param(ID(Y_WIDTH)));
 				port(ID(CO), param(ID(Y_WIDTH)));
 				check_expected();
 				return;
@@ -935,9 +935,9 @@ namespace {
 			if (cell->type == ID($macc)) {
 				param(ID(CONFIG));
 				param(ID(CONFIG_WIDTH));
-				port(ID(A), param(ID(A_WIDTH)));
-				port(ID(B), param(ID(B_WIDTH)));
-				port(ID(Y), param(ID(Y_WIDTH)));
+				port(ID::A, param(ID(A_WIDTH)));
+				port(ID::B, param(ID(B_WIDTH)));
+				port(ID::Y, param(ID(Y_WIDTH)));
 				check_expected();
 				Macc().from_cell(cell);
 				return;
@@ -945,8 +945,8 @@ namespace {
 
 			if (cell->type == ID($logic_not)) {
 				param_bool(ID(A_SIGNED));
-				port(ID(A), param(ID(A_WIDTH)));
-				port(ID(Y), param(ID(Y_WIDTH)));
+				port(ID::A, param(ID(A_WIDTH)));
+				port(ID::Y, param(ID(Y_WIDTH)));
 				check_expected();
 				return;
 			}
@@ -954,17 +954,17 @@ namespace {
 			if (cell->type.in(ID($logic_and), ID($logic_or))) {
 				param_bool(ID(A_SIGNED));
 				param_bool(ID(B_SIGNED));
-				port(ID(A), param(ID(A_WIDTH)));
-				port(ID(B), param(ID(B_WIDTH)));
-				port(ID(Y), param(ID(Y_WIDTH)));
+				port(ID::A, param(ID(A_WIDTH)));
+				port(ID::B, param(ID(B_WIDTH)));
+				port(ID::Y, param(ID(Y_WIDTH)));
 				check_expected(false);
 				return;
 			}
 
 			if (cell->type == ID($slice)) {
 				param(ID(OFFSET));
-				port(ID(A), param(ID(A_WIDTH)));
-				port(ID(Y), param(ID(Y_WIDTH)));
+				port(ID::A, param(ID(A_WIDTH)));
+				port(ID::Y, param(ID(Y_WIDTH)));
 				if (param(ID(OFFSET)) + param(ID(Y_WIDTH)) > param(ID(A_WIDTH)))
 					error(__LINE__);
 				check_expected();
@@ -972,35 +972,35 @@ namespace {
 			}
 
 			if (cell->type == ID($concat)) {
-				port(ID(A), param(ID(A_WIDTH)));
-				port(ID(B), param(ID(B_WIDTH)));
-				port(ID(Y), param(ID(A_WIDTH)) + param(ID(B_WIDTH)));
+				port(ID::A, param(ID(A_WIDTH)));
+				port(ID::B, param(ID(B_WIDTH)));
+				port(ID::Y, param(ID(A_WIDTH)) + param(ID(B_WIDTH)));
 				check_expected();
 				return;
 			}
 
 			if (cell->type == ID($mux)) {
-				port(ID(A), param(ID(WIDTH)));
-				port(ID(B), param(ID(WIDTH)));
+				port(ID::A, param(ID(WIDTH)));
+				port(ID::B, param(ID(WIDTH)));
 				port(ID(S), 1);
-				port(ID(Y), param(ID(WIDTH)));
+				port(ID::Y, param(ID(WIDTH)));
 				check_expected();
 				return;
 			}
 
 			if (cell->type == ID($pmux)) {
-				port(ID(A), param(ID(WIDTH)));
-				port(ID(B), param(ID(WIDTH)) * param(ID(S_WIDTH)));
+				port(ID::A, param(ID(WIDTH)));
+				port(ID::B, param(ID(WIDTH)) * param(ID(S_WIDTH)));
 				port(ID(S), param(ID(S_WIDTH)));
-				port(ID(Y), param(ID(WIDTH)));
+				port(ID::Y, param(ID(WIDTH)));
 				check_expected();
 				return;
 			}
 
 			if (cell->type == ID($lut)) {
 				param(ID(LUT));
-				port(ID(A), param(ID(WIDTH)));
-				port(ID(Y), 1);
+				port(ID::A, param(ID(WIDTH)));
+				port(ID::Y, 1);
 				check_expected();
 				return;
 			}
@@ -1008,8 +1008,8 @@ namespace {
 			if (cell->type == ID($sop)) {
 				param(ID(DEPTH));
 				param(ID(TABLE));
-				port(ID(A), param(ID(WIDTH)));
-				port(ID(Y), 1);
+				port(ID::A, param(ID(WIDTH)));
+				port(ID::Y, 1);
 				check_expected();
 				return;
 			}
@@ -1175,36 +1175,36 @@ namespace {
 			}
 
 			if (cell->type == ID($tribuf)) {
-				port(ID(A), param(ID(WIDTH)));
-				port(ID(Y), param(ID(WIDTH)));
+				port(ID::A, param(ID(WIDTH)));
+				port(ID::Y, param(ID(WIDTH)));
 				port(ID(EN), 1);
 				check_expected();
 				return;
 			}
 
 			if (cell->type.in(ID($assert), ID($assume), ID($live), ID($fair), ID($cover))) {
-				port(ID(A), 1);
+				port(ID::A, 1);
 				port(ID(EN), 1);
 				check_expected();
 				return;
 			}
 
 			if (cell->type == ID($initstate)) {
-				port(ID(Y), 1);
+				port(ID::Y, 1);
 				check_expected();
 				return;
 			}
 
 			if (cell->type.in(ID($anyconst), ID($anyseq), ID($allconst), ID($allseq))) {
-				port(ID(Y), param(ID(WIDTH)));
+				port(ID::Y, param(ID(WIDTH)));
 				check_expected();
 				return;
 			}
 
 			if (cell->type == ID($equiv)) {
-				port(ID(A), 1);
-				port(ID(B), 1);
-				port(ID(Y), 1);
+				port(ID::A, 1);
+				port(ID::B, 1);
+				port(ID::Y, 1);
 				check_expected();
 				return;
 			}
@@ -1831,8 +1831,8 @@ RTLIL::Cell *RTLIL::Module::addCell(RTLIL::IdString name, const RTLIL::Cell *oth
 		cell->parameters[ID(A_SIGNED)] = is_signed;         \
 		cell->parameters[ID(A_WIDTH)] = sig_a.size();       \
 		cell->parameters[ID(Y_WIDTH)] = sig_y.size();       \
-		cell->setPort(ID(A), sig_a);                        \
-		cell->setPort(ID(Y), sig_y);                        \
+		cell->setPort(ID::A, sig_a);                        \
+		cell->setPort(ID::Y, sig_y);                        \
 		cell->set_src_attribute(src);                       \
 		return cell;                                        \
 	} \
@@ -1860,9 +1860,9 @@ DEF_METHOD(LogicNot,   1, ID($logic_not))
 		cell->parameters[ID(A_WIDTH)] = sig_a.size();       \
 		cell->parameters[ID(B_WIDTH)] = sig_b.size();       \
 		cell->parameters[ID(Y_WIDTH)] = sig_y.size();       \
-		cell->setPort(ID(A), sig_a);                        \
-		cell->setPort(ID(B), sig_b);                        \
-		cell->setPort(ID(Y), sig_y);                        \
+		cell->setPort(ID::A, sig_a);                        \
+		cell->setPort(ID::B, sig_b);                        \
+		cell->setPort(ID::Y, sig_y);                        \
 		cell->set_src_attribute(src);                       \
 		return cell;                                        \
 	} \
@@ -1903,10 +1903,10 @@ DEF_METHOD(LogicOr,  1, ID($logic_or))
 		RTLIL::Cell *cell = addCell(name, _type);                 \
 		cell->parameters[ID(WIDTH)] = sig_a.size();               \
 		if (_pmux) cell->parameters[ID(S_WIDTH)] = sig_s.size();  \
-		cell->setPort(ID(A), sig_a);                              \
-		cell->setPort(ID(B), sig_b);                              \
+		cell->setPort(ID::A, sig_a);                              \
+		cell->setPort(ID::B, sig_b);                              \
 		cell->setPort(ID(S), sig_s);                              \
-		cell->setPort(ID(Y), sig_y);                              \
+		cell->setPort(ID::Y, sig_y);                              \
 		cell->set_src_attribute(src);                             \
 		return cell;                                              \
 	} \
@@ -2006,9 +2006,9 @@ RTLIL::Cell* RTLIL::Module::addPow(RTLIL::IdString name, RTLIL::SigSpec sig_a, R
 	cell->parameters[ID(A_WIDTH)] = sig_a.size();
 	cell->parameters[ID(B_WIDTH)] = sig_b.size();
 	cell->parameters[ID(Y_WIDTH)] = sig_y.size();
-	cell->setPort(ID(A), sig_a);
-	cell->setPort(ID(B), sig_b);
-	cell->setPort(ID(Y), sig_y);
+	cell->setPort(ID::A, sig_a);
+	cell->setPort(ID::B, sig_b);
+	cell->setPort(ID::Y, sig_y);
 	cell->set_src_attribute(src);
 	return cell;
 }
@@ -2019,8 +2019,8 @@ RTLIL::Cell* RTLIL::Module::addSlice(RTLIL::IdString name, RTLIL::SigSpec sig_a,
 	cell->parameters[ID(A_WIDTH)] = sig_a.size();
 	cell->parameters[ID(Y_WIDTH)] = sig_y.size();
 	cell->parameters[ID(OFFSET)] = offset;
-	cell->setPort(ID(A), sig_a);
-	cell->setPort(ID(Y), sig_y);
+	cell->setPort(ID::A, sig_a);
+	cell->setPort(ID::Y, sig_y);
 	cell->set_src_attribute(src);
 	return cell;
 }
@@ -2030,9 +2030,9 @@ RTLIL::Cell* RTLIL::Module::addConcat(RTLIL::IdString name, RTLIL::SigSpec sig_a
 	RTLIL::Cell *cell = addCell(name, ID($concat));
 	cell->parameters[ID(A_WIDTH)] = sig_a.size();
 	cell->parameters[ID(B_WIDTH)] = sig_b.size();
-	cell->setPort(ID(A), sig_a);
-	cell->setPort(ID(B), sig_b);
-	cell->setPort(ID(Y), sig_y);
+	cell->setPort(ID::A, sig_a);
+	cell->setPort(ID::B, sig_b);
+	cell->setPort(ID::Y, sig_y);
 	cell->set_src_attribute(src);
 	return cell;
 }
@@ -2042,8 +2042,8 @@ RTLIL::Cell* RTLIL::Module::addLut(RTLIL::IdString name, RTLIL::SigSpec sig_a, R
 	RTLIL::Cell *cell = addCell(name, ID($lut));
 	cell->parameters[ID(LUT)] = lut;
 	cell->parameters[ID(WIDTH)] = sig_a.size();
-	cell->setPort(ID(A), sig_a);
-	cell->setPort(ID(Y), sig_y);
+	cell->setPort(ID::A, sig_a);
+	cell->setPort(ID::Y, sig_y);
 	cell->set_src_attribute(src);
 	return cell;
 }
@@ -2052,9 +2052,9 @@ RTLIL::Cell* RTLIL::Module::addTribuf(RTLIL::IdString name, RTLIL::SigSpec sig_a
 {
 	RTLIL::Cell *cell = addCell(name, ID($tribuf));
 	cell->parameters[ID(WIDTH)] = sig_a.size();
-	cell->setPort(ID(A), sig_a);
+	cell->setPort(ID::A, sig_a);
 	cell->setPort(ID(EN), sig_en);
-	cell->setPort(ID(Y), sig_y);
+	cell->setPort(ID::Y, sig_y);
 	cell->set_src_attribute(src);
 	return cell;
 }
@@ -2062,7 +2062,7 @@ RTLIL::Cell* RTLIL::Module::addTribuf(RTLIL::IdString name, RTLIL::SigSpec sig_a
 RTLIL::Cell* RTLIL::Module::addAssert(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src)
 {
 	RTLIL::Cell *cell = addCell(name, ID($assert));
-	cell->setPort(ID(A), sig_a);
+	cell->setPort(ID::A, sig_a);
 	cell->setPort(ID(EN), sig_en);
 	cell->set_src_attribute(src);
 	return cell;
@@ -2071,7 +2071,7 @@ RTLIL::Cell* RTLIL::Module::addAssert(RTLIL::IdString name, RTLIL::SigSpec sig_a
 RTLIL::Cell* RTLIL::Module::addAssume(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src)
 {
 	RTLIL::Cell *cell = addCell(name, ID($assume));
-	cell->setPort(ID(A), sig_a);
+	cell->setPort(ID::A, sig_a);
 	cell->setPort(ID(EN), sig_en);
 	cell->set_src_attribute(src);
 	return cell;
@@ -2080,7 +2080,7 @@ RTLIL::Cell* RTLIL::Module::addAssume(RTLIL::IdString name, RTLIL::SigSpec sig_a
 RTLIL::Cell* RTLIL::Module::addLive(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src)
 {
 	RTLIL::Cell *cell = addCell(name, ID($live));
-	cell->setPort(ID(A), sig_a);
+	cell->setPort(ID::A, sig_a);
 	cell->setPort(ID(EN), sig_en);
 	cell->set_src_attribute(src);
 	return cell;
@@ -2089,7 +2089,7 @@ RTLIL::Cell* RTLIL::Module::addLive(RTLIL::IdString name, RTLIL::SigSpec sig_a,
 RTLIL::Cell* RTLIL::Module::addFair(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src)
 {
 	RTLIL::Cell *cell = addCell(name, ID($fair));
-	cell->setPort(ID(A), sig_a);
+	cell->setPort(ID::A, sig_a);
 	cell->setPort(ID(EN), sig_en);
 	cell->set_src_attribute(src);
 	return cell;
@@ -2098,7 +2098,7 @@ RTLIL::Cell* RTLIL::Module::addFair(RTLIL::IdString name, RTLIL::SigSpec sig_a,
 RTLIL::Cell* RTLIL::Module::addCover(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src)
 {
 	RTLIL::Cell *cell = addCell(name, ID($cover));
-	cell->setPort(ID(A), sig_a);
+	cell->setPort(ID::A, sig_a);
 	cell->setPort(ID(EN), sig_en);
 	cell->set_src_attribute(src);
 	return cell;
@@ -2107,9 +2107,9 @@ RTLIL::Cell* RTLIL::Module::addCover(RTLIL::IdString name, RTLIL::SigSpec sig_a,
 RTLIL::Cell* RTLIL::Module::addEquiv(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, const std::string &src)
 {
 	RTLIL::Cell *cell = addCell(name, ID($equiv));
-	cell->setPort(ID(A), sig_a);
-	cell->setPort(ID(B), sig_b);
-	cell->setPort(ID(Y), sig_y);
+	cell->setPort(ID::A, sig_a);
+	cell->setPort(ID::B, sig_b);
+	cell->setPort(ID::Y, sig_y);
 	cell->set_src_attribute(src);
 	return cell;
 }
@@ -2308,7 +2308,7 @@ RTLIL::SigSpec RTLIL::Module::Anyconst(RTLIL::IdString name, int width, const st
 	RTLIL::SigSpec sig = addWire(NEW_ID, width);
 	Cell *cell = addCell(name, ID($anyconst));
 	cell->setParam(ID(WIDTH), width);
-	cell->setPort(ID(Y), sig);
+	cell->setPort(ID::Y, sig);
 	cell->set_src_attribute(src);
 	return sig;
 }
@@ -2318,7 +2318,7 @@ RTLIL::SigSpec RTLIL::Module::Anyseq(RTLIL::IdString name, int width, const std:
 	RTLIL::SigSpec sig = addWire(NEW_ID, width);
 	Cell *cell = addCell(name, ID($anyseq));
 	cell->setParam(ID(WIDTH), width);
-	cell->setPort(ID(Y), sig);
+	cell->setPort(ID::Y, sig);
 	cell->set_src_attribute(src);
 	return sig;
 }
@@ -2328,7 +2328,7 @@ RTLIL::SigSpec RTLIL::Module::Allconst(RTLIL::IdString name, int width, const st
 	RTLIL::SigSpec sig = addWire(NEW_ID, width);
 	Cell *cell = addCell(name, ID($allconst));
 	cell->setParam(ID(WIDTH), width);
-	cell->setPort(ID(Y), sig);
+	cell->setPort(ID::Y, sig);
 	cell->set_src_attribute(src);
 	return sig;
 }
@@ -2338,7 +2338,7 @@ RTLIL::SigSpec RTLIL::Module::Allseq(RTLIL::IdString name, int width, const std:
 	RTLIL::SigSpec sig = addWire(NEW_ID, width);
 	Cell *cell = addCell(name, ID($allseq));
 	cell->setParam(ID(WIDTH), width);
-	cell->setPort(ID(Y), sig);
+	cell->setPort(ID::Y, sig);
 	cell->set_src_attribute(src);
 	return sig;
 }
@@ -2347,7 +2347,7 @@ RTLIL::SigSpec RTLIL::Module::Initstate(RTLIL::IdString name, const std::string
 {
 	RTLIL::SigSpec sig = addWire(NEW_ID);
 	Cell *cell = addCell(name, ID($initstate));
-	cell->setPort(ID(Y), sig);
+	cell->setPort(ID::Y, sig);
 	cell->set_src_attribute(src);
 	return sig;
 }
@@ -2569,7 +2569,7 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
 		return;
 
 	if (type == ID($mux) || type == ID($pmux)) {
-		parameters[ID(WIDTH)] = GetSize(connections_[ID(Y)]);
+		parameters[ID(WIDTH)] = GetSize(connections_[ID::Y]);
 		if (type == ID($pmux))
 			parameters[ID(S_WIDTH)] = GetSize(connections_[ID(S)]);
 		check();
@@ -2577,12 +2577,12 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
 	}
 
 	if (type == ID($lut) || type == ID($sop)) {
-		parameters[ID(WIDTH)] = GetSize(connections_[ID(A)]);
+		parameters[ID(WIDTH)] = GetSize(connections_[ID::A]);
 		return;
 	}
 
 	if (type == ID($fa)) {
-		parameters[ID(WIDTH)] = GetSize(connections_[ID(Y)]);
+		parameters[ID(WIDTH)] = GetSize(connections_[ID::Y]);
 		return;
 	}
 
@@ -2593,28 +2593,28 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
 
 	bool signedness_ab = !type.in(ID($slice), ID($concat), ID($macc));
 
-	if (connections_.count(ID(A))) {
+	if (connections_.count(ID::A)) {
 		if (signedness_ab) {
 			if (set_a_signed)
 				parameters[ID(A_SIGNED)] = true;
 			else if (parameters.count(ID(A_SIGNED)) == 0)
 				parameters[ID(A_SIGNED)] = false;
 		}
-		parameters[ID(A_WIDTH)] = GetSize(connections_[ID(A)]);
+		parameters[ID(A_WIDTH)] = GetSize(connections_[ID::A]);
 	}
 
-	if (connections_.count(ID(B))) {
+	if (connections_.count(ID::B)) {
 		if (signedness_ab) {
 			if (set_b_signed)
 				parameters[ID(B_SIGNED)] = true;
 			else if (parameters.count(ID(B_SIGNED)) == 0)
 				parameters[ID(B_SIGNED)] = false;
 		}
-		parameters[ID(B_WIDTH)] = GetSize(connections_[ID(B)]);
+		parameters[ID(B_WIDTH)] = GetSize(connections_[ID::B]);
 	}
 
-	if (connections_.count(ID(Y)))
-		parameters[ID(Y_WIDTH)] = GetSize(connections_[ID(Y)]);
+	if (connections_.count(ID::Y))
+		parameters[ID(Y_WIDTH)] = GetSize(connections_[ID::Y]);
 
 	if (connections_.count(ID(Q)))
 		parameters[ID(WIDTH)] = GetSize(connections_[ID(Q)]);
diff --git a/kernel/satgen.h b/kernel/satgen.h
index aab3017c2..133389eee 100644
--- a/kernel/satgen.h
+++ b/kernel/satgen.h
@@ -281,9 +281,9 @@ struct SatGen
 
 		if (model_undef && (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod)) || is_arith_compare))
 		{
-			std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID(A)), timestep);
-			std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID(B)), timestep);
-			std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID(Y)), timestep);
+			std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+			std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep);
+			std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
 			if (is_arith_compare)
 				extendSignalWidth(undef_a, undef_b, cell, true);
 			else
@@ -294,7 +294,7 @@ struct SatGen
 			int undef_y_bit = ez->OR(undef_any_a, undef_any_b);
 
 			if (cell->type.in(ID($div), ID($mod))) {
-				std::vector<int> b = importSigSpec(cell->getPort(ID(B)), timestep);
+				std::vector<int> b = importSigSpec(cell->getPort(ID::B), timestep);
 				undef_y_bit = ez->OR(undef_y_bit, ez->NOT(ez->expression(ezSAT::OpOr, b)));
 			}
 
@@ -313,9 +313,9 @@ struct SatGen
 		if (cell->type.in(ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_), ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_),
 				ID($and), ID($or), ID($xor), ID($xnor), ID($add), ID($sub)))
 		{
-			std::vector<int> a = importDefSigSpec(cell->getPort(ID(A)), timestep);
-			std::vector<int> b = importDefSigSpec(cell->getPort(ID(B)), timestep);
-			std::vector<int> y = importDefSigSpec(cell->getPort(ID(Y)), timestep);
+			std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+			std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep);
+			std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
 			extendSignalWidth(a, b, y, cell);
 
 			std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
@@ -343,9 +343,9 @@ struct SatGen
 
 			if (model_undef && !arith_undef_handled)
 			{
-				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID(A)), timestep);
-				std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID(B)), timestep);
-				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID(Y)), timestep);
+				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+				std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep);
+				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
 				extendSignalWidth(undef_a, undef_b, undef_y, cell, false);
 
 				if (cell->type.in(ID($and), ID($_AND_), ID($_NAND_))) {
@@ -384,7 +384,7 @@ struct SatGen
 			}
 			else if (model_undef)
 			{
-				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID(Y)), timestep);
+				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
 				undefGating(y, yy, undef_y);
 			}
 			return true;
@@ -395,11 +395,11 @@ struct SatGen
 			bool aoi_mode = cell->type.in(ID($_AOI3_), ID($_AOI4_));
 			bool three_mode = cell->type.in(ID($_AOI3_), ID($_OAI3_));
 
-			int a = importDefSigSpec(cell->getPort(ID(A)), timestep).at(0);
-			int b = importDefSigSpec(cell->getPort(ID(B)), timestep).at(0);
+			int a = importDefSigSpec(cell->getPort(ID::A), timestep).at(0);
+			int b = importDefSigSpec(cell->getPort(ID::B), timestep).at(0);
 			int c = importDefSigSpec(cell->getPort(ID(C)), timestep).at(0);
 			int d = three_mode ? (aoi_mode ? ez->CONST_TRUE : ez->CONST_FALSE) : importDefSigSpec(cell->getPort(ID(D)), timestep).at(0);
-			int y = importDefSigSpec(cell->getPort(ID(Y)), timestep).at(0);
+			int y = importDefSigSpec(cell->getPort(ID::Y), timestep).at(0);
 			int yy = model_undef ? ez->literal() : y;
 
 			if (cell->type.in(ID($_AOI3_), ID($_AOI4_)))
@@ -409,11 +409,11 @@ struct SatGen
 
 			if (model_undef)
 			{
-				int undef_a = importUndefSigSpec(cell->getPort(ID(A)), timestep).at(0);
-				int undef_b = importUndefSigSpec(cell->getPort(ID(B)), timestep).at(0);
+				int undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep).at(0);
+				int undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep).at(0);
 				int undef_c = importUndefSigSpec(cell->getPort(ID(C)), timestep).at(0);
 				int undef_d = three_mode ? ez->CONST_FALSE : importUndefSigSpec(cell->getPort(ID(D)), timestep).at(0);
-				int undef_y = importUndefSigSpec(cell->getPort(ID(Y)), timestep).at(0);
+				int undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep).at(0);
 
 				if (aoi_mode)
 				{
@@ -458,16 +458,16 @@ struct SatGen
 
 		if (cell->type.in(ID($_NOT_), ID($not)))
 		{
-			std::vector<int> a = importDefSigSpec(cell->getPort(ID(A)), timestep);
-			std::vector<int> y = importDefSigSpec(cell->getPort(ID(Y)), timestep);
+			std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+			std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
 			extendSignalWidthUnary(a, y, cell);
 
 			std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
 			ez->assume(ez->vec_eq(ez->vec_not(a), yy));
 
 			if (model_undef) {
-				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID(A)), timestep);
-				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID(Y)), timestep);
+				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
 				extendSignalWidthUnary(undef_a, undef_y, cell, false);
 				ez->assume(ez->vec_eq(undef_a, undef_y));
 				undefGating(y, yy, undef_y);
@@ -477,10 +477,10 @@ struct SatGen
 
 		if (cell->type.in(ID($_MUX_), ID($mux), ID($_NMUX_)))
 		{
-			std::vector<int> a = importDefSigSpec(cell->getPort(ID(A)), timestep);
-			std::vector<int> b = importDefSigSpec(cell->getPort(ID(B)), timestep);
+			std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+			std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep);
 			std::vector<int> s = importDefSigSpec(cell->getPort(ID(S)), timestep);
-			std::vector<int> y = importDefSigSpec(cell->getPort(ID(Y)), timestep);
+			std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
 
 			std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
 			if (cell->type == ID($_NMUX_))
@@ -490,10 +490,10 @@ struct SatGen
 
 			if (model_undef)
 			{
-				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID(A)), timestep);
-				std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID(B)), timestep);
+				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+				std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep);
 				std::vector<int> undef_s = importUndefSigSpec(cell->getPort(ID(S)), timestep);
-				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID(Y)), timestep);
+				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
 
 				std::vector<int> unequal_ab = ez->vec_not(ez->vec_iff(a, b));
 				std::vector<int> undef_ab = ez->vec_or(unequal_ab, ez->vec_or(undef_a, undef_b));
@@ -506,10 +506,10 @@ struct SatGen
 
 		if (cell->type == ID($pmux))
 		{
-			std::vector<int> a = importDefSigSpec(cell->getPort(ID(A)), timestep);
-			std::vector<int> b = importDefSigSpec(cell->getPort(ID(B)), timestep);
+			std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+			std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep);
 			std::vector<int> s = importDefSigSpec(cell->getPort(ID(S)), timestep);
-			std::vector<int> y = importDefSigSpec(cell->getPort(ID(Y)), timestep);
+			std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
 
 			std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
 
@@ -522,10 +522,10 @@ struct SatGen
 
 			if (model_undef)
 			{
-				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID(A)), timestep);
-				std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID(B)), timestep);
+				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+				std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep);
 				std::vector<int> undef_s = importUndefSigSpec(cell->getPort(ID(S)), timestep);
-				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID(Y)), timestep);
+				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
 
 				int maybe_a = ez->CONST_TRUE;
 
@@ -557,8 +557,8 @@ struct SatGen
 
 		if (cell->type.in(ID($pos), ID($neg)))
 		{
-			std::vector<int> a = importDefSigSpec(cell->getPort(ID(A)), timestep);
-			std::vector<int> y = importDefSigSpec(cell->getPort(ID(Y)), timestep);
+			std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+			std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
 			extendSignalWidthUnary(a, y, cell);
 
 			std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
@@ -572,8 +572,8 @@ struct SatGen
 
 			if (model_undef)
 			{
-				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID(A)), timestep);
-				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID(Y)), timestep);
+				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
 				extendSignalWidthUnary(undef_a, undef_y, cell);
 
 				if (cell->type == ID($pos)) {
@@ -591,8 +591,8 @@ struct SatGen
 
 		if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool), ID($logic_not)))
 		{
-			std::vector<int> a = importDefSigSpec(cell->getPort(ID(A)), timestep);
-			std::vector<int> y = importDefSigSpec(cell->getPort(ID(Y)), timestep);
+			std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+			std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
 
 			std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
 
@@ -611,8 +611,8 @@ struct SatGen
 
 			if (model_undef)
 			{
-				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID(A)), timestep);
-				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID(Y)), timestep);
+				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
 				int aX = ez->expression(ezSAT::OpOr, undef_a);
 
 				if (cell->type == ID($reduce_and)) {
@@ -638,12 +638,12 @@ struct SatGen
 
 		if (cell->type.in(ID($logic_and), ID($logic_or)))
 		{
-			std::vector<int> vec_a = importDefSigSpec(cell->getPort(ID(A)), timestep);
-			std::vector<int> vec_b = importDefSigSpec(cell->getPort(ID(B)), timestep);
+			std::vector<int> vec_a = importDefSigSpec(cell->getPort(ID::A), timestep);
+			std::vector<int> vec_b = importDefSigSpec(cell->getPort(ID::B), timestep);
 
 			int a = ez->expression(ez->OpOr, vec_a);
 			int b = ez->expression(ez->OpOr, vec_b);
-			std::vector<int> y = importDefSigSpec(cell->getPort(ID(Y)), timestep);
+			std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
 
 			std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
 
@@ -656,9 +656,9 @@ struct SatGen
 
 			if (model_undef)
 			{
-				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID(A)), timestep);
-				std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID(B)), timestep);
-				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID(Y)), timestep);
+				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+				std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep);
+				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
 
 				int a0 = ez->NOT(ez->OR(ez->expression(ezSAT::OpOr, vec_a), ez->expression(ezSAT::OpOr, undef_a)));
 				int b0 = ez->NOT(ez->OR(ez->expression(ezSAT::OpOr, vec_b), ez->expression(ezSAT::OpOr, undef_b)));
@@ -685,16 +685,16 @@ struct SatGen
 		if (cell->type.in(ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt)))
 		{
 			bool is_signed = cell->parameters[ID(A_SIGNED)].as_bool() && cell->parameters[ID(B_SIGNED)].as_bool();
-			std::vector<int> a = importDefSigSpec(cell->getPort(ID(A)), timestep);
-			std::vector<int> b = importDefSigSpec(cell->getPort(ID(B)), timestep);
-			std::vector<int> y = importDefSigSpec(cell->getPort(ID(Y)), timestep);
+			std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+			std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep);
+			std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
 			extendSignalWidth(a, b, cell);
 
 			std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
 
 			if (model_undef && cell->type.in(ID($eqx), ID($nex))) {
-				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID(A)), timestep);
-				std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID(B)), timestep);
+				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+				std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep);
 				extendSignalWidth(undef_a, undef_b, cell, true);
 				a = ez->vec_or(a, undef_a);
 				b = ez->vec_or(b, undef_b);
@@ -717,9 +717,9 @@ struct SatGen
 
 			if (model_undef && cell->type.in(ID($eqx), ID($nex)))
 			{
-				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID(A)), timestep);
-				std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID(B)), timestep);
-				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID(Y)), timestep);
+				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+				std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep);
+				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
 				extendSignalWidth(undef_a, undef_b, cell, true);
 
 				if (cell->type == ID($eqx))
@@ -734,9 +734,9 @@ struct SatGen
 			}
 			else if (model_undef && cell->type.in(ID($eq), ID($ne)))
 			{
-				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID(A)), timestep);
-				std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID(B)), timestep);
-				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID(Y)), timestep);
+				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+				std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep);
+				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
 				extendSignalWidth(undef_a, undef_b, cell, true);
 
 				int undef_any_a = ez->expression(ezSAT::OpOr, undef_a);
@@ -758,7 +758,7 @@ struct SatGen
 			else
 			{
 				if (model_undef) {
-					std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID(Y)), timestep);
+					std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
 					undefGating(y, yy, undef_y);
 				}
 				log_assert(!model_undef || arith_undef_handled);
@@ -768,9 +768,9 @@ struct SatGen
 
 		if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx)))
 		{
-			std::vector<int> a = importDefSigSpec(cell->getPort(ID(A)), timestep);
-			std::vector<int> b = importDefSigSpec(cell->getPort(ID(B)), timestep);
-			std::vector<int> y = importDefSigSpec(cell->getPort(ID(Y)), timestep);
+			std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+			std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep);
+			std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
 
 			int extend_bit = ez->CONST_FALSE;
 
@@ -801,9 +801,9 @@ struct SatGen
 
 			if (model_undef)
 			{
-				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID(A)), timestep);
-				std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID(B)), timestep);
-				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID(Y)), timestep);
+				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+				std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep);
+				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
 				std::vector<int> undef_a_shifted;
 
 				extend_bit = cell->type == ID($shiftx) ? ez->CONST_TRUE : ez->CONST_FALSE;
@@ -840,9 +840,9 @@ struct SatGen
 
 		if (cell->type == ID($mul))
 		{
-			std::vector<int> a = importDefSigSpec(cell->getPort(ID(A)), timestep);
-			std::vector<int> b = importDefSigSpec(cell->getPort(ID(B)), timestep);
-			std::vector<int> y = importDefSigSpec(cell->getPort(ID(Y)), timestep);
+			std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+			std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep);
+			std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
 			extendSignalWidth(a, b, y, cell);
 
 			std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
@@ -859,7 +859,7 @@ struct SatGen
 
 			if (model_undef) {
 				log_assert(arith_undef_handled);
-				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID(Y)), timestep);
+				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
 				undefGating(y, yy, undef_y);
 			}
 			return true;
@@ -867,9 +867,9 @@ struct SatGen
 
 		if (cell->type == ID($macc))
 		{
-			std::vector<int> a = importDefSigSpec(cell->getPort(ID(A)), timestep);
-			std::vector<int> b = importDefSigSpec(cell->getPort(ID(B)), timestep);
-			std::vector<int> y = importDefSigSpec(cell->getPort(ID(Y)), timestep);
+			std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+			std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep);
+			std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
 
 			Macc macc;
 			macc.from_cell(cell);
@@ -918,13 +918,13 @@ struct SatGen
 
 			if (model_undef)
 			{
-				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID(A)), timestep);
-				std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID(B)), timestep);
+				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+				std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep);
 
 				int undef_any_a = ez->expression(ezSAT::OpOr, undef_a);
 				int undef_any_b = ez->expression(ezSAT::OpOr, undef_b);
 
-				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID(Y)), timestep);
+				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
 				ez->assume(ez->vec_eq(undef_y, std::vector<int>(GetSize(y), ez->OR(undef_any_a, undef_any_b))));
 
 				undefGating(y, tmp, undef_y);
@@ -937,9 +937,9 @@ struct SatGen
 
 		if (cell->type.in(ID($div), ID($mod)))
 		{
-			std::vector<int> a = importDefSigSpec(cell->getPort(ID(A)), timestep);
-			std::vector<int> b = importDefSigSpec(cell->getPort(ID(B)), timestep);
-			std::vector<int> y = importDefSigSpec(cell->getPort(ID(Y)), timestep);
+			std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+			std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep);
+			std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
 			extendSignalWidth(a, b, y, cell);
 
 			std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
@@ -993,11 +993,11 @@ struct SatGen
 						only_first_one.at(0) = ez->CONST_TRUE;
 						div_zero_result = ez->vec_ite(a.back(), only_first_one, all_ones);
 					} else {
-						div_zero_result.insert(div_zero_result.end(), cell->getPort(ID(A)).size(), ez->CONST_TRUE);
+						div_zero_result.insert(div_zero_result.end(), cell->getPort(ID::A).size(), ez->CONST_TRUE);
 						div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->CONST_FALSE);
 					}
 				} else {
-					int copy_a_bits = min(cell->getPort(ID(A)).size(), cell->getPort(ID(B)).size());
+					int copy_a_bits = min(cell->getPort(ID::A).size(), cell->getPort(ID::B).size());
 					div_zero_result.insert(div_zero_result.end(), a.begin(), a.begin() + copy_a_bits);
 					if (cell->parameters[ID(A_SIGNED)].as_bool() && cell->parameters[ID(B_SIGNED)].as_bool())
 						div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), div_zero_result.back());
@@ -1009,7 +1009,7 @@ struct SatGen
 
 			if (model_undef) {
 				log_assert(arith_undef_handled);
-				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID(Y)), timestep);
+				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
 				undefGating(y, yy, undef_y);
 			}
 			return true;
@@ -1017,8 +1017,8 @@ struct SatGen
 
 		if (cell->type == ID($lut))
 		{
-			std::vector<int> a = importDefSigSpec(cell->getPort(ID(A)), timestep);
-			std::vector<int> y = importDefSigSpec(cell->getPort(ID(Y)), timestep);
+			std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+			std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
 
 			std::vector<int> lut;
 			for (auto bit : cell->getParam(ID(LUT)).bits)
@@ -1029,7 +1029,7 @@ struct SatGen
 
 			if (model_undef)
 			{
-				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID(A)), timestep);
+				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
 				std::vector<int> t(lut), u(GetSize(t), ez->CONST_FALSE);
 
 				for (int i = GetSize(a)-1; i >= 0; i--)
@@ -1047,7 +1047,7 @@ struct SatGen
 				log_assert(GetSize(t) == 1);
 				log_assert(GetSize(u) == 1);
 				undefGating(y, t, u);
-				ez->assume(ez->vec_eq(importUndefSigSpec(cell->getPort(ID(Y)), timestep), u));
+				ez->assume(ez->vec_eq(importUndefSigSpec(cell->getPort(ID::Y), timestep), u));
 			}
 			else
 			{
@@ -1067,8 +1067,8 @@ struct SatGen
 
 		if (cell->type == ID($sop))
 		{
-			std::vector<int> a = importDefSigSpec(cell->getPort(ID(A)), timestep);
-			int y = importDefSigSpec(cell->getPort(ID(Y)), timestep).at(0);
+			std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+			int y = importDefSigSpec(cell->getPort(ID::Y), timestep).at(0);
 
 			int width = cell->getParam(ID(WIDTH)).as_int();
 			int depth = cell->getParam(ID(DEPTH)).as_int();
@@ -1096,8 +1096,8 @@ struct SatGen
 			if (model_undef)
 			{
 				std::vector<int> products, undef_products;
-				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID(A)), timestep);
-				int undef_y = importUndefSigSpec(cell->getPort(ID(Y)), timestep).at(0);
+				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+				int undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep).at(0);
 
 				for (int i = 0; i < depth; i++)
 				{
@@ -1149,10 +1149,10 @@ struct SatGen
 
 		if (cell->type == ID($fa))
 		{
-			std::vector<int> a = importDefSigSpec(cell->getPort(ID(A)), timestep);
-			std::vector<int> b = importDefSigSpec(cell->getPort(ID(B)), timestep);
+			std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+			std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep);
 			std::vector<int> c = importDefSigSpec(cell->getPort(ID(C)), timestep);
-			std::vector<int> y = importDefSigSpec(cell->getPort(ID(Y)), timestep);
+			std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
 			std::vector<int> x = importDefSigSpec(cell->getPort(ID(X)), timestep);
 
 			std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
@@ -1167,11 +1167,11 @@ struct SatGen
 
 			if (model_undef)
 			{
-				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID(A)), timestep);
-				std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID(B)), timestep);
+				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+				std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep);
 				std::vector<int> undef_c = importUndefSigSpec(cell->getPort(ID(C)), timestep);
 
-				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID(Y)), timestep);
+				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
 				std::vector<int> undef_x = importUndefSigSpec(cell->getPort(ID(X)), timestep);
 
 				ez->assume(ez->vec_eq(undef_y, ez->vec_or(ez->vec_or(undef_a, undef_b), undef_c)));
@@ -1217,9 +1217,9 @@ struct SatGen
 
 		if (cell->type == ID($alu))
 		{
-			std::vector<int> a = importDefSigSpec(cell->getPort(ID(A)), timestep);
-			std::vector<int> b = importDefSigSpec(cell->getPort(ID(B)), timestep);
-			std::vector<int> y = importDefSigSpec(cell->getPort(ID(Y)), timestep);
+			std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+			std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep);
+			std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
 			std::vector<int> x = importDefSigSpec(cell->getPort(ID(X)), timestep);
 			std::vector<int> ci = importDefSigSpec(cell->getPort(ID(CI)), timestep);
 			std::vector<int> bi = importDefSigSpec(cell->getPort(ID(BI)), timestep);
@@ -1248,12 +1248,12 @@ struct SatGen
 
 			if (model_undef)
 			{
-				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID(A)), timestep);
-				std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID(B)), timestep);
+				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+				std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep);
 				std::vector<int> undef_ci = importUndefSigSpec(cell->getPort(ID(CI)), timestep);
 				std::vector<int> undef_bi = importUndefSigSpec(cell->getPort(ID(BI)), timestep);
 
-				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID(Y)), timestep);
+				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
 				std::vector<int> undef_x = importUndefSigSpec(cell->getPort(ID(X)), timestep);
 				std::vector<int> undef_co = importUndefSigSpec(cell->getPort(ID(CO)), timestep);
 
@@ -1283,17 +1283,17 @@ struct SatGen
 
 		if (cell->type == ID($slice))
 		{
-			RTLIL::SigSpec a = cell->getPort(ID(A));
-			RTLIL::SigSpec y = cell->getPort(ID(Y));
+			RTLIL::SigSpec a = cell->getPort(ID::A);
+			RTLIL::SigSpec y = cell->getPort(ID::Y);
 			ez->assume(signals_eq(a.extract(cell->parameters.at(ID(OFFSET)).as_int(), y.size()), y, timestep));
 			return true;
 		}
 
 		if (cell->type == ID($concat))
 		{
-			RTLIL::SigSpec a = cell->getPort(ID(A));
-			RTLIL::SigSpec b = cell->getPort(ID(B));
-			RTLIL::SigSpec y = cell->getPort(ID(Y));
+			RTLIL::SigSpec a = cell->getPort(ID::A);
+			RTLIL::SigSpec b = cell->getPort(ID::B);
+			RTLIL::SigSpec y = cell->getPort(ID::Y);
 
 			RTLIL::SigSpec ab = a;
 			ab.append(b);
@@ -1333,16 +1333,16 @@ struct SatGen
 			if (timestep < 2)
 				return true;
 
-			std::vector<int> d = importDefSigSpec(cell->getPort(ID(Y)), timestep-1);
-			std::vector<int> q = importDefSigSpec(cell->getPort(ID(Y)), timestep);
+			std::vector<int> d = importDefSigSpec(cell->getPort(ID::Y), timestep-1);
+			std::vector<int> q = importDefSigSpec(cell->getPort(ID::Y), timestep);
 
 			std::vector<int> qq = model_undef ? ez->vec_var(q.size()) : q;
 			ez->assume(ez->vec_eq(d, qq));
 
 			if (model_undef)
 			{
-				std::vector<int> undef_d = importUndefSigSpec(cell->getPort(ID(Y)), timestep-1);
-				std::vector<int> undef_q = importUndefSigSpec(cell->getPort(ID(Y)), timestep);
+				std::vector<int> undef_d = importUndefSigSpec(cell->getPort(ID::Y), timestep-1);
+				std::vector<int> undef_q = importUndefSigSpec(cell->getPort(ID::Y), timestep);
 
 				ez->assume(ez->vec_eq(undef_d, undef_q));
 				undefGating(q, qq, undef_q);
@@ -1357,16 +1357,16 @@ struct SatGen
 
 		if (cell->type.in(ID($_BUF_), ID($equiv)))
 		{
-			std::vector<int> a = importDefSigSpec(cell->getPort(ID(A)), timestep);
-			std::vector<int> y = importDefSigSpec(cell->getPort(ID(Y)), timestep);
+			std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+			std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
 			extendSignalWidthUnary(a, y, cell);
 
 			std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
 			ez->assume(ez->vec_eq(a, yy));
 
 			if (model_undef) {
-				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID(A)), timestep);
-				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID(Y)), timestep);
+				std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
 				extendSignalWidthUnary(undef_a, undef_y, cell, false);
 				ez->assume(ez->vec_eq(undef_a, undef_y));
 				undefGating(y, yy, undef_y);
@@ -1380,12 +1380,12 @@ struct SatGen
 			if (initstates.count(key) == 0)
 				initstates[key] = false;
 
-			std::vector<int> y = importDefSigSpec(cell->getPort(ID(Y)), timestep);
+			std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
 			log_assert(GetSize(y) == 1);
 			ez->SET(y[0], initstates[key] ? ez->CONST_TRUE : ez->CONST_FALSE);
 
 			if (model_undef) {
-				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID(Y)), timestep);
+				std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
 				log_assert(GetSize(undef_y) == 1);
 				ez->SET(undef_y[0], ez->CONST_FALSE);
 			}
@@ -1396,7 +1396,7 @@ struct SatGen
 		if (cell->type == ID($assert))
 		{
 			std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
-			asserts_a[pf].append((*sigmap)(cell->getPort(ID(A))));
+			asserts_a[pf].append((*sigmap)(cell->getPort(ID::A)));
 			asserts_en[pf].append((*sigmap)(cell->getPort(ID(EN))));
 			return true;
 		}
@@ -1404,7 +1404,7 @@ struct SatGen
 		if (cell->type == ID($assume))
 		{
 			std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
-			assumes_a[pf].append((*sigmap)(cell->getPort(ID(A))));
+			assumes_a[pf].append((*sigmap)(cell->getPort(ID::A)));
 			assumes_en[pf].append((*sigmap)(cell->getPort(ID(EN))));
 			return true;
 		}
diff --git a/kernel/yosys.h b/kernel/yosys.h
index 49716ed52..52e7b3383 100644
--- a/kernel/yosys.h
+++ b/kernel/yosys.h
@@ -210,6 +210,7 @@ namespace RTLIL {
 	struct Module;
 	struct Design;
 	struct Monitor;
+    namespace ID {}
 }
 
 namespace AST {
@@ -224,6 +225,7 @@ using RTLIL::Wire;
 using RTLIL::Cell;
 using RTLIL::Module;
 using RTLIL::Design;
+namespace ID = RTLIL::ID;
 
 namespace hashlib {
 	template<> struct hash_ops<RTLIL::Wire*> : hash_obj_ops {};
diff --git a/passes/opt/muxpack.cc b/passes/opt/muxpack.cc
index cf6752b6e..97c88f423 100644
--- a/passes/opt/muxpack.cc
+++ b/passes/opt/muxpack.cc
@@ -38,19 +38,19 @@ struct ExclusiveDatabase
 		pool<Cell*> reduce_or;
 		for (auto cell : module->cells()) {
 			if (cell->type == ID($eq)) {
-				nonconst_sig = sigmap(cell->getPort(ID(A)));
-				const_sig = sigmap(cell->getPort(ID(B)));
+				nonconst_sig = sigmap(cell->getPort(ID::A));
+				const_sig = sigmap(cell->getPort(ID::B));
 				if (!const_sig.is_fully_const()) {
 					if (!nonconst_sig.is_fully_const())
 						continue;
 					std::swap(nonconst_sig, const_sig);
 				}
-				y_port = sigmap(cell->getPort(ID(Y)));
+				y_port = sigmap(cell->getPort(ID::Y));
 			}
 			else if (cell->type == ID($logic_not)) {
-				nonconst_sig = sigmap(cell->getPort(ID(A)));
+				nonconst_sig = sigmap(cell->getPort(ID::A));
 				const_sig = Const(State::S0, GetSize(nonconst_sig));
-				y_port = sigmap(cell->getPort(ID(Y)));
+				y_port = sigmap(cell->getPort(ID::Y));
 			}
 			else if (cell->type == ID($reduce_or)) {
 				reduce_or.insert(cell);
@@ -66,7 +66,7 @@ struct ExclusiveDatabase
 		for (auto cell : reduce_or) {
 			nonconst_sig = SigSpec();
 			std::vector<Const> values;
-			SigSpec a_port = sigmap(cell->getPort(ID(A)));
+			SigSpec a_port = sigmap(cell->getPort(ID::A));
 			for (auto bit : a_port) {
 				auto it = sig_cmp_prev.find(bit);
 				if (it == sig_cmp_prev.end()) {
@@ -84,7 +84,7 @@ struct ExclusiveDatabase
 			}
 			if (nonconst_sig.empty())
 				continue;
-			y_port = sigmap(cell->getPort(ID(Y)));
+			y_port = sigmap(cell->getPort(ID::Y));
 			sig_cmp_prev[y_port] = std::make_pair(nonconst_sig,std::move(values));
 		}
 	}
@@ -145,11 +145,11 @@ struct MuxpackWorker
 		{
 			if (cell->type.in(ID($mux), ID($pmux)) && !cell->get_bool_attribute(ID(keep)))
 			{
-				SigSpec a_sig = sigmap(cell->getPort(ID(A)));
+				SigSpec a_sig = sigmap(cell->getPort(ID::A));
 				SigSpec b_sig;
 				if (cell->type == ID($mux))
-					b_sig = sigmap(cell->getPort(ID(B)));
-				SigSpec y_sig = sigmap(cell->getPort(ID(Y)));
+					b_sig = sigmap(cell->getPort(ID::B));
+				SigSpec y_sig = sigmap(cell->getPort(ID::Y));
    
 				if (sig_chain_next.count(a_sig))
 					for (auto a_bit : a_sig.bits())
@@ -186,9 +186,9 @@ struct MuxpackWorker
 		{
 			log_debug("Considering %s (%s)\n", log_id(cell), log_id(cell->type));
 
-			SigSpec a_sig = sigmap(cell->getPort(ID(A)));
+			SigSpec a_sig = sigmap(cell->getPort(ID::A));
 			if (cell->type == ID($mux)) {
-				SigSpec b_sig = sigmap(cell->getPort(ID(B)));
+				SigSpec b_sig = sigmap(cell->getPort(ID::B));
 				if (sig_chain_prev.count(a_sig) + sig_chain_prev.count(b_sig) != 1)
 					goto start_cell;
 
@@ -230,7 +230,7 @@ struct MuxpackWorker
 		{
 			chain.push_back(c);
 
-			SigSpec y_sig = sigmap(c->getPort(ID(Y)));
+			SigSpec y_sig = sigmap(c->getPort(ID::Y));
 
 			if (sig_chain_next.count(y_sig) == 0)
 				break;
@@ -270,28 +270,28 @@ struct MuxpackWorker
 			pmux_count += 1;
 
 			first_cell->type = ID($pmux);
-			SigSpec b_sig = first_cell->getPort(ID(B));
+			SigSpec b_sig = first_cell->getPort(ID::B);
 			SigSpec s_sig = first_cell->getPort(ID(S));
 
 			for (int i = 1; i < cases; i++) {
 				Cell* prev_cell = chain[cursor+i-1];
 				Cell* cursor_cell = chain[cursor+i];
-				if (sigmap(prev_cell->getPort(ID(Y))) == sigmap(cursor_cell->getPort(ID(A)))) {
-					b_sig.append(cursor_cell->getPort(ID(B)));
+				if (sigmap(prev_cell->getPort(ID::Y)) == sigmap(cursor_cell->getPort(ID::A))) {
+					b_sig.append(cursor_cell->getPort(ID::B));
 					s_sig.append(cursor_cell->getPort(ID(S)));
 				}
 				else {
 					log_assert(cursor_cell->type == ID($mux));
-					b_sig.append(cursor_cell->getPort(ID(A)));
+					b_sig.append(cursor_cell->getPort(ID::A));
 					s_sig.append(module->LogicNot(NEW_ID, cursor_cell->getPort(ID(S))));
 				}
 				remove_cells.insert(cursor_cell);
 			}
 
-			first_cell->setPort(ID(B), b_sig);
+			first_cell->setPort(ID::B, b_sig);
 			first_cell->setPort(ID(S), s_sig);
 			first_cell->setParam(ID(S_WIDTH), GetSize(s_sig));
-			first_cell->setPort(ID(Y), last_cell->getPort(ID(Y)));
+			first_cell->setPort(ID::Y, last_cell->getPort(ID::Y));
 
 			cursor += cases;
 		}
diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc
index 1d3a85b3a..bf75c7adc 100644
--- a/passes/opt/opt_clean.cc
+++ b/passes/opt/opt_clean.cc
@@ -482,8 +482,8 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool
 	for (auto cell : module->cells())
 		if (cell->type.in(ID($pos), ID($_BUF_)) && !cell->has_keep_attr()) {
 			bool is_signed = cell->type == ID($pos) && cell->getParam(ID(A_SIGNED)).as_bool();
-			RTLIL::SigSpec a = cell->getPort(ID(A));
-			RTLIL::SigSpec y = cell->getPort(ID(Y));
+			RTLIL::SigSpec a = cell->getPort(ID::A);
+			RTLIL::SigSpec y = cell->getPort(ID::Y);
 			a.extend_u0(GetSize(y), is_signed);
 			module->connect(y, a);
 			delcells.push_back(cell);
@@ -491,7 +491,7 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool
 	for (auto cell : delcells) {
 		if (verbose)
 			log_debug("  removing buffer cell `%s': %s = %s\n", cell->name.c_str(),
-					log_signal(cell->getPort(ID(Y))), log_signal(cell->getPort(ID(A))));
+					log_signal(cell->getPort(ID::Y)), log_signal(cell->getPort(ID::A)));
 		module->remove(cell);
 	}
 	if (!delcells.empty())
diff --git a/passes/opt/opt_demorgan.cc b/passes/opt/opt_demorgan.cc
index 7defef442..4bc82815b 100644
--- a/passes/opt/opt_demorgan.cc
+++ b/passes/opt/opt_demorgan.cc
@@ -38,7 +38,7 @@ void demorgan_worker(
 	if( (cell->type != ID($reduce_and)) && (cell->type != ID($reduce_or)) )
 		return;
 
-	auto insig = sigmap(cell->getPort(ID(A)));
+	auto insig = sigmap(cell->getPort(ID::A));
 	log("Inspecting %s cell %s (%d inputs)\n", log_id(cell->type), log_id(cell->name), GetSize(insig));
 	int num_inverted = 0;
 	for(int i=0; i<GetSize(insig); i++)
@@ -51,7 +51,7 @@ void demorgan_worker(
 		bool inverted = false;
 		for(auto x : ports)
 		{
-			if(x.port == ID(Y) && x.cell->type == ID($_NOT_))
+			if(x.port == ID::Y && x.cell->type == ID($_NOT_))
 			{
 				inverted = true;
 				break;
@@ -85,7 +85,7 @@ void demorgan_worker(
 		RTLIL::Cell* srcinv = NULL;
 		for(auto x : ports)
 		{
-			if(x.port == ID(Y) && x.cell->type == ID($_NOT_))
+			if(x.port == ID::Y && x.cell->type == ID($_NOT_))
 			{
 				srcinv = x.cell;
 				break;
@@ -103,7 +103,7 @@ void demorgan_worker(
 		//We ARE inverted - bypass it
 		//Don't automatically delete the inverter since other stuff might still use it
 		else
-			insig[i] = srcinv->getPort(ID(A));
+			insig[i] = srcinv->getPort(ID::A);
 	}
 
 	//Cosmetic fixup: If our input is just a scrambled version of one bus, rearrange it
@@ -151,7 +151,7 @@ void demorgan_worker(
 	}
 
 	//Push the new input signal back to the reduction (after bypassing/adding inverters)
-	cell->setPort(ID(A), insig);
+	cell->setPort(ID::A, insig);
 
 	//Change the cell type
 	if(cell->type == ID($reduce_and))
@@ -161,10 +161,10 @@ void demorgan_worker(
 	//don't change XOR
 
 	//Add an inverter to the output
-	auto inverted_output = cell->getPort(ID(Y));
+	auto inverted_output = cell->getPort(ID::Y);
 	auto uninverted_output = m->addWire(NEW_ID);
 	m->addNot(NEW_ID, RTLIL::SigSpec(uninverted_output), inverted_output);
-	cell->setPort(ID(Y), uninverted_output);
+	cell->setPort(ID::Y, uninverted_output);
 }
 
 struct OptDemorganPass : public Pass {
diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc
index 6dea611e3..85ec9a55a 100644
--- a/passes/opt/opt_expr.cc
+++ b/passes/opt/opt_expr.cc
@@ -134,14 +134,14 @@ void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell,
 
 bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutative, SigMap &sigmap)
 {
-	IdString b_name = cell->hasPort(ID(B)) ? ID(B) : ID(A);
+	IdString b_name = cell->hasPort(ID::B) ? ID::B : ID::A;
 
 	bool a_signed = cell->parameters.at(ID(A_SIGNED)).as_bool();
 	bool b_signed = cell->parameters.at(b_name.str() + "_SIGNED").as_bool();
 
-	RTLIL::SigSpec sig_a = sigmap(cell->getPort(ID(A)));
+	RTLIL::SigSpec sig_a = sigmap(cell->getPort(ID::A));
 	RTLIL::SigSpec sig_b = sigmap(cell->getPort(b_name));
-	RTLIL::SigSpec sig_y = sigmap(cell->getPort(ID(Y)));
+	RTLIL::SigSpec sig_y = sigmap(cell->getPort(ID::Y));
 
 	sig_a.extend_u0(sig_y.size(), a_signed);
 	sig_b.extend_u0(sig_y.size(), b_signed);
@@ -208,24 +208,24 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ
 
 		RTLIL::Cell *c = module->addCell(NEW_ID, cell->type);
 
-		c->setPort(ID(A), new_a);
+		c->setPort(ID::A, new_a);
 		c->parameters[ID(A_WIDTH)] = new_a.size();
 		c->parameters[ID(A_SIGNED)] = false;
 
-		if (b_name == ID(B)) {
-			c->setPort(ID(B), new_b);
+		if (b_name == ID::B) {
+			c->setPort(ID::B, new_b);
 			c->parameters[ID(B_WIDTH)] = new_b.size();
 			c->parameters[ID(B_SIGNED)] = false;
 		}
 
-		c->setPort(ID(Y), new_y);
+		c->setPort(ID::Y, new_y);
 		c->parameters[ID(Y_WIDTH)] = new_y->width;
 		c->check();
 
 		module->connect(new_conn);
 
 		log_debug("  New cell `%s': A=%s", log_id(c), log_signal(new_a));
-		if (b_name == ID(B))
+		if (b_name == ID::B)
 			log_debug(", B=%s", log_signal(new_b));
 		log_debug("\n");
 	}
@@ -368,11 +368,11 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 	for (auto cell : module->cells())
 		if (design->selected(module, cell) && cell->type[0] == '$') {
 			if (cell->type.in(ID($_NOT_), ID($not), ID($logic_not)) &&
-					cell->getPort(ID(A)).size() == 1 && cell->getPort(ID(Y)).size() == 1)
-				invert_map[assign_map(cell->getPort(ID(Y)))] = assign_map(cell->getPort(ID(A)));
+					cell->getPort(ID::A).size() == 1 && cell->getPort(ID::Y).size() == 1)
+				invert_map[assign_map(cell->getPort(ID::Y))] = assign_map(cell->getPort(ID::A));
 			if (cell->type.in(ID($mux), ID($_MUX_)) &&
-					cell->getPort(ID(A)) == SigSpec(State::S1) && cell->getPort(ID(B)) == SigSpec(State::S0))
-				invert_map[assign_map(cell->getPort(ID(Y)))] = assign_map(cell->getPort(ID(S)));
+					cell->getPort(ID::A) == SigSpec(State::S1) && cell->getPort(ID::B) == SigSpec(State::S0))
+				invert_map[assign_map(cell->getPort(ID::Y))] = assign_map(cell->getPort(ID(S)));
 			if (ct_combinational.cell_known(cell->type))
 				for (auto &conn : cell->connections()) {
 					RTLIL::SigSpec sig = assign_map(conn.second);
@@ -396,7 +396,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 	for (auto cell : cells.sorted)
 	{
 #define ACTION_DO(_p_, _s_) do { cover("opt.opt_expr.action_" S__LINE__); replace_cell(assign_map, module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0)
-#define ACTION_DO_Y(_v_) ACTION_DO(ID(Y), RTLIL::SigSpec(RTLIL::State::S ## _v_))
+#define ACTION_DO_Y(_v_) ACTION_DO(ID::Y, RTLIL::SigSpec(RTLIL::State::S ## _v_))
 
 		if (clkinv)
 		{
@@ -439,23 +439,23 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 		if (cell->type.in(ID($reduce_and), ID($_AND_)))
 			detect_const_and = true;
 
-		if (cell->type.in(ID($and), ID($logic_and)) && GetSize(cell->getPort(ID(A))) == 1 && GetSize(cell->getPort(ID(B))) == 1 && !cell->getParam(ID(A_SIGNED)).as_bool())
+		if (cell->type.in(ID($and), ID($logic_and)) && GetSize(cell->getPort(ID::A)) == 1 && GetSize(cell->getPort(ID::B)) == 1 && !cell->getParam(ID(A_SIGNED)).as_bool())
 			detect_const_and = true;
 
 		if (cell->type.in(ID($reduce_or), ID($reduce_bool), ID($_OR_)))
 			detect_const_or = true;
 
-		if (cell->type.in(ID($or), ID($logic_or)) && GetSize(cell->getPort(ID(A))) == 1 && GetSize(cell->getPort(ID(B))) == 1 && !cell->getParam(ID(A_SIGNED)).as_bool())
+		if (cell->type.in(ID($or), ID($logic_or)) && GetSize(cell->getPort(ID::A)) == 1 && GetSize(cell->getPort(ID::B)) == 1 && !cell->getParam(ID(A_SIGNED)).as_bool())
 			detect_const_or = true;
 
 		if (detect_const_and || detect_const_or)
 		{
-			pool<SigBit> input_bits = assign_map(cell->getPort(ID(A))).to_sigbit_pool();
+			pool<SigBit> input_bits = assign_map(cell->getPort(ID::A)).to_sigbit_pool();
 			bool found_zero = false, found_one = false, found_undef = false, found_inv = false, many_conconst = false;
 			SigBit non_const_input = State::Sm;
 
-			if (cell->hasPort(ID(B))) {
-				vector<SigBit> more_bits = assign_map(cell->getPort(ID(B))).to_sigbit_vector();
+			if (cell->hasPort(ID::B)) {
+				vector<SigBit> more_bits = assign_map(cell->getPort(ID::B)).to_sigbit_vector();
 				input_bits.insert(more_bits.begin(), more_bits.end());
 			}
 
@@ -478,25 +478,25 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 
 			if (detect_const_and && (found_zero || found_inv)) {
 				cover("opt.opt_expr.const_and");
-				replace_cell(assign_map, module, cell, "const_and", ID(Y), RTLIL::State::S0);
+				replace_cell(assign_map, module, cell, "const_and", ID::Y, RTLIL::State::S0);
 				goto next_cell;
 			}
 
 			if (detect_const_or && (found_one || found_inv)) {
 				cover("opt.opt_expr.const_or");
-				replace_cell(assign_map, module, cell, "const_or", ID(Y), RTLIL::State::S1);
+				replace_cell(assign_map, module, cell, "const_or", ID::Y, RTLIL::State::S1);
 				goto next_cell;
 			}
 
 			if (non_const_input != State::Sm && !found_undef) {
 				cover("opt.opt_expr.and_or_buffer");
-				replace_cell(assign_map, module, cell, "and_or_buffer", ID(Y), non_const_input);
+				replace_cell(assign_map, module, cell, "and_or_buffer", ID::Y, non_const_input);
 				goto next_cell;
 			}
 		}
 
 		if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_bool), ID($reduce_xor), ID($reduce_xnor), ID($neg)) &&
-				GetSize(cell->getPort(ID(A))) == 1 && GetSize(cell->getPort(ID(Y))) == 1)
+				GetSize(cell->getPort(ID::A)) == 1 && GetSize(cell->getPort(ID::Y)) == 1)
 		{
 			if (cell->type == ID($reduce_xnor)) {
 				cover("opt.opt_expr.reduce_xnor_not");
@@ -506,7 +506,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 				did_something = true;
 			} else {
 				cover("opt.opt_expr.unary_buffer");
-				replace_cell(assign_map, module, cell, "unary_buffer", ID(Y), cell->getPort(ID(A)));
+				replace_cell(assign_map, module, cell, "unary_buffer", ID::Y, cell->getPort(ID::A));
 			}
 			goto next_cell;
 		}
@@ -521,7 +521,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 			{
 				SigBit neutral_bit = cell->type == ID($reduce_and) ? State::S1 : State::S0;
 
-				RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID(A)));
+				RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A));
 				RTLIL::SigSpec new_sig_a;
 
 				for (auto bit : sig_a)
@@ -534,7 +534,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 					cover_list("opt.opt_expr.fine.neutral_A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_and", "$reduce_bool", cell->type.str());
 					log_debug("Replacing port A of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n",
 							cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_sig_a));
-					cell->setPort(ID(A), new_sig_a);
+					cell->setPort(ID::A, new_sig_a);
 					cell->parameters.at(ID(A_WIDTH)) = GetSize(new_sig_a);
 					did_something = true;
 				}
@@ -544,7 +544,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 			{
 				SigBit neutral_bit = State::S0;
 
-				RTLIL::SigSpec sig_b = assign_map(cell->getPort(ID(B)));
+				RTLIL::SigSpec sig_b = assign_map(cell->getPort(ID::B));
 				RTLIL::SigSpec new_sig_b;
 
 				for (auto bit : sig_b)
@@ -557,7 +557,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 					cover_list("opt.opt_expr.fine.neutral_B", "$logic_and", "$logic_or", cell->type.str());
 					log_debug("Replacing port B of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n",
 							cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_sig_b));
-					cell->setPort(ID(B), new_sig_b);
+					cell->setPort(ID::B, new_sig_b);
 					cell->parameters.at(ID(B_WIDTH)) = GetSize(new_sig_b);
 					did_something = true;
 				}
@@ -565,7 +565,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 
 			if (cell->type == ID($reduce_and))
 			{
-				RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID(A)));
+				RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A));
 
 				RTLIL::State new_a = RTLIL::State::S1;
 				for (auto &bit : sig_a.to_sigbit_vector())
@@ -583,7 +583,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 					cover("opt.opt_expr.fine.$reduce_and");
 					log_debug("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
 							cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a));
-					cell->setPort(ID(A), sig_a = new_a);
+					cell->setPort(ID::A, sig_a = new_a);
 					cell->parameters.at(ID(A_WIDTH)) = 1;
 					did_something = true;
 				}
@@ -591,7 +591,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 
 			if (cell->type.in(ID($logic_not), ID($logic_and), ID($logic_or), ID($reduce_or), ID($reduce_bool)))
 			{
-				RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID(A)));
+				RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A));
 
 				RTLIL::State new_a = RTLIL::State::S0;
 				for (auto &bit : sig_a.to_sigbit_vector())
@@ -609,7 +609,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 					cover_list("opt.opt_expr.fine.A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_bool", cell->type.str());
 					log_debug("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
 							cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a));
-					cell->setPort(ID(A), sig_a = new_a);
+					cell->setPort(ID::A, sig_a = new_a);
 					cell->parameters.at(ID(A_WIDTH)) = 1;
 					did_something = true;
 				}
@@ -617,7 +617,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 
 			if (cell->type.in(ID($logic_and), ID($logic_or)))
 			{
-				RTLIL::SigSpec sig_b = assign_map(cell->getPort(ID(B)));
+				RTLIL::SigSpec sig_b = assign_map(cell->getPort(ID::B));
 
 				RTLIL::State new_b = RTLIL::State::S0;
 				for (auto &bit : sig_b.to_sigbit_vector())
@@ -635,7 +635,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 					cover_list("opt.opt_expr.fine.B", "$logic_and", "$logic_or", cell->type.str());
 					log_debug("Replacing port B of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
 							cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_b));
-					cell->setPort(ID(B), sig_b = new_b);
+					cell->setPort(ID::B, sig_b = new_b);
 					cell->parameters.at(ID(B_WIDTH)) = 1;
 					did_something = true;
 				}
@@ -643,9 +643,9 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 
 			if (cell->type.in(ID($add), ID($sub)))
 			{
-				RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID(A)));
-				RTLIL::SigSpec sig_b = assign_map(cell->getPort(ID(B)));
-				RTLIL::SigSpec sig_y = cell->getPort(ID(Y));
+				RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A));
+				RTLIL::SigSpec sig_b = assign_map(cell->getPort(ID::B));
+				RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
 				bool sub = cell->type == ID($sub);
 
 				int i;
@@ -659,9 +659,9 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 				}
 				if (i > 0) {
 					cover_list("opt.opt_expr.fine", "$add", "$sub", cell->type.str());
-					cell->setPort(ID(A), sig_a.extract_end(i));
-					cell->setPort(ID(B), sig_b.extract_end(i));
-					cell->setPort(ID(Y), sig_y.extract_end(i));
+					cell->setPort(ID::A, sig_a.extract_end(i));
+					cell->setPort(ID::B, sig_b.extract_end(i));
+					cell->setPort(ID::Y, sig_y.extract_end(i));
 					cell->fixup_parameters();
 					did_something = true;
 				}
@@ -669,12 +669,12 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 
 			if (cell->type == "$alu")
 			{
-				RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID(A)));
-				RTLIL::SigSpec sig_b = assign_map(cell->getPort(ID(B)));
+				RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A));
+				RTLIL::SigSpec sig_b = assign_map(cell->getPort(ID::B));
 				RTLIL::SigBit sig_ci = assign_map(cell->getPort(ID(CI)));
 				RTLIL::SigBit sig_bi = assign_map(cell->getPort(ID(BI)));
 				RTLIL::SigSpec sig_x = cell->getPort(ID(X));
-				RTLIL::SigSpec sig_y = cell->getPort(ID(Y));
+				RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
 				RTLIL::SigSpec sig_co = cell->getPort(ID(CO));
 
 				if (sig_ci.wire || sig_bi.wire)
@@ -704,10 +704,10 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 				}
 				if (i > 0) {
 					cover("opt.opt_expr.fine.$alu");
-					cell->setPort(ID(A), sig_a.extract_end(i));
-					cell->setPort(ID(B), sig_b.extract_end(i));
+					cell->setPort(ID::A, sig_a.extract_end(i));
+					cell->setPort(ID::B, sig_b.extract_end(i));
 					cell->setPort(ID(X), sig_x.extract_end(i));
-					cell->setPort(ID(Y), sig_y.extract_end(i));
+					cell->setPort(ID::Y, sig_y.extract_end(i));
 					cell->setPort(ID(CO), sig_co.extract_end(i));
 					cell->fixup_parameters();
 					did_something = true;
@@ -718,8 +718,8 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 		if (cell->type.in(ID($reduce_xor), ID($reduce_xnor), ID($shift), ID($shiftx), ID($shl), ID($shr), ID($sshl), ID($sshr),
 					ID($lt), ID($le), ID($ge), ID($gt), ID($neg), ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($pow)))
 		{
-			RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID(A)));
-			RTLIL::SigSpec sig_b = cell->hasPort(ID(B)) ? assign_map(cell->getPort(ID(B))) : RTLIL::SigSpec();
+			RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A));
+			RTLIL::SigSpec sig_b = cell->hasPort(ID::B) ? assign_map(cell->getPort(ID::B)) : RTLIL::SigSpec();
 
 			if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx)))
 				sig_a = RTLIL::SigSpec();
@@ -737,33 +737,33 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 				cover_list("opt.opt_expr.xbit", "$reduce_xor", "$reduce_xnor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
 						"$lt", "$le", "$ge", "$gt", "$neg", "$add", "$sub", "$mul", "$div", "$mod", "$pow", cell->type.str());
 				if (cell->type.in(ID($reduce_xor), ID($reduce_xnor), ID($lt), ID($le), ID($ge), ID($gt)))
-					replace_cell(assign_map, module, cell, "x-bit in input", ID(Y), RTLIL::State::Sx);
+					replace_cell(assign_map, module, cell, "x-bit in input", ID::Y, RTLIL::State::Sx);
 				else
-					replace_cell(assign_map, module, cell, "x-bit in input", ID(Y), RTLIL::SigSpec(RTLIL::State::Sx, cell->getPort(ID(Y)).size()));
+					replace_cell(assign_map, module, cell, "x-bit in input", ID::Y, RTLIL::SigSpec(RTLIL::State::Sx, cell->getPort(ID::Y).size()));
 				goto next_cell;
 			}
 		}
 
-		if (cell->type.in(ID($_NOT_), ID($not), ID($logic_not)) && cell->getPort(ID(Y)).size() == 1 &&
-				invert_map.count(assign_map(cell->getPort(ID(A)))) != 0) {
+		if (cell->type.in(ID($_NOT_), ID($not), ID($logic_not)) && cell->getPort(ID::Y).size() == 1 &&
+				invert_map.count(assign_map(cell->getPort(ID::A))) != 0) {
 			cover_list("opt.opt_expr.invert.double", "$_NOT_", "$not", "$logic_not", cell->type.str());
-			replace_cell(assign_map, module, cell, "double_invert", ID(Y), invert_map.at(assign_map(cell->getPort(ID(A)))));
+			replace_cell(assign_map, module, cell, "double_invert", ID::Y, invert_map.at(assign_map(cell->getPort(ID::A))));
 			goto next_cell;
 		}
 
 		if (cell->type.in(ID($_MUX_), ID($mux)) && invert_map.count(assign_map(cell->getPort(ID(S)))) != 0) {
 			cover_list("opt.opt_expr.invert.muxsel", "$_MUX_", "$mux", cell->type.str());
 			log_debug("Optimizing away select inverter for %s cell `%s' in module `%s'.\n", log_id(cell->type), log_id(cell), log_id(module));
-			RTLIL::SigSpec tmp = cell->getPort(ID(A));
-			cell->setPort(ID(A), cell->getPort(ID(B)));
-			cell->setPort(ID(B), tmp);
+			RTLIL::SigSpec tmp = cell->getPort(ID::A);
+			cell->setPort(ID::A, cell->getPort(ID::B));
+			cell->setPort(ID::B, tmp);
 			cell->setPort(ID(S), invert_map.at(assign_map(cell->getPort(ID(S)))));
 			did_something = true;
 			goto next_cell;
 		}
 
 		if (cell->type == ID($_NOT_)) {
-			RTLIL::SigSpec input = cell->getPort(ID(A));
+			RTLIL::SigSpec input = cell->getPort(ID::A);
 			assign_map.apply(input);
 			if (input.match("1")) ACTION_DO_Y(0);
 			if (input.match("0")) ACTION_DO_Y(1);
@@ -772,8 +772,8 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 
 		if (cell->type == ID($_AND_)) {
 			RTLIL::SigSpec input;
-			input.append(cell->getPort(ID(B)));
-			input.append(cell->getPort(ID(A)));
+			input.append(cell->getPort(ID::B));
+			input.append(cell->getPort(ID::A));
 			assign_map.apply(input);
 			if (input.match(" 0")) ACTION_DO_Y(0);
 			if (input.match("0 ")) ACTION_DO_Y(0);
@@ -785,14 +785,14 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 				if (input.match(" *")) ACTION_DO_Y(0);
 				if (input.match("* ")) ACTION_DO_Y(0);
 			}
-			if (input.match(" 1")) ACTION_DO(ID(Y), input.extract(1, 1));
-			if (input.match("1 ")) ACTION_DO(ID(Y), input.extract(0, 1));
+			if (input.match(" 1")) ACTION_DO(ID::Y, input.extract(1, 1));
+			if (input.match("1 ")) ACTION_DO(ID::Y, input.extract(0, 1));
 		}
 
 		if (cell->type == ID($_OR_)) {
 			RTLIL::SigSpec input;
-			input.append(cell->getPort(ID(B)));
-			input.append(cell->getPort(ID(A)));
+			input.append(cell->getPort(ID::B));
+			input.append(cell->getPort(ID::A));
 			assign_map.apply(input);
 			if (input.match(" 1")) ACTION_DO_Y(1);
 			if (input.match("1 ")) ACTION_DO_Y(1);
@@ -804,14 +804,14 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 				if (input.match(" *")) ACTION_DO_Y(1);
 				if (input.match("* ")) ACTION_DO_Y(1);
 			}
-			if (input.match(" 0")) ACTION_DO(ID(Y), input.extract(1, 1));
-			if (input.match("0 ")) ACTION_DO(ID(Y), input.extract(0, 1));
+			if (input.match(" 0")) ACTION_DO(ID::Y, input.extract(1, 1));
+			if (input.match("0 ")) ACTION_DO(ID::Y, input.extract(0, 1));
 		}
 
 		if (cell->type == ID($_XOR_)) {
 			RTLIL::SigSpec input;
-			input.append(cell->getPort(ID(B)));
-			input.append(cell->getPort(ID(A)));
+			input.append(cell->getPort(ID::B));
+			input.append(cell->getPort(ID::A));
 			assign_map.apply(input);
 			if (input.match("00")) ACTION_DO_Y(0);
 			if (input.match("01")) ACTION_DO_Y(1);
@@ -819,26 +819,26 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 			if (input.match("11")) ACTION_DO_Y(0);
 			if (input.match(" *")) ACTION_DO_Y(x);
 			if (input.match("* ")) ACTION_DO_Y(x);
-			if (input.match(" 0")) ACTION_DO(ID(Y), input.extract(1, 1));
-			if (input.match("0 ")) ACTION_DO(ID(Y), input.extract(0, 1));
+			if (input.match(" 0")) ACTION_DO(ID::Y, input.extract(1, 1));
+			if (input.match("0 ")) ACTION_DO(ID::Y, input.extract(0, 1));
 		}
 
 		if (cell->type == ID($_MUX_)) {
 			RTLIL::SigSpec input;
 			input.append(cell->getPort(ID(S)));
-			input.append(cell->getPort(ID(B)));
-			input.append(cell->getPort(ID(A)));
+			input.append(cell->getPort(ID::B));
+			input.append(cell->getPort(ID::A));
 			assign_map.apply(input);
 			if (input.extract(2, 1) == input.extract(1, 1))
-				ACTION_DO(ID(Y), input.extract(2, 1));
-			if (input.match("  0")) ACTION_DO(ID(Y), input.extract(2, 1));
-			if (input.match("  1")) ACTION_DO(ID(Y), input.extract(1, 1));
-			if (input.match("01 ")) ACTION_DO(ID(Y), input.extract(0, 1));
+				ACTION_DO(ID::Y, input.extract(2, 1));
+			if (input.match("  0")) ACTION_DO(ID::Y, input.extract(2, 1));
+			if (input.match("  1")) ACTION_DO(ID::Y, input.extract(1, 1));
+			if (input.match("01 ")) ACTION_DO(ID::Y, input.extract(0, 1));
 			if (input.match("10 ")) {
 				cover("opt.opt_expr.mux_to_inv");
 				cell->type = ID($_NOT_);
-				cell->setPort(ID(A), input.extract(0, 1));
-				cell->unsetPort(ID(B));
+				cell->setPort(ID::A, input.extract(0, 1));
+				cell->unsetPort(ID::B);
 				cell->unsetPort(ID(S));
 				goto next_cell;
 			}
@@ -848,24 +848,24 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 			if (input.match("01*")) ACTION_DO_Y(x);
 			if (input.match("10*")) ACTION_DO_Y(x);
 			if (mux_undef) {
-				if (input.match("*  ")) ACTION_DO(ID(Y), input.extract(1, 1));
-				if (input.match(" * ")) ACTION_DO(ID(Y), input.extract(2, 1));
-				if (input.match("  *")) ACTION_DO(ID(Y), input.extract(2, 1));
+				if (input.match("*  ")) ACTION_DO(ID::Y, input.extract(1, 1));
+				if (input.match(" * ")) ACTION_DO(ID::Y, input.extract(2, 1));
+				if (input.match("  *")) ACTION_DO(ID::Y, input.extract(2, 1));
 			}
 		}
 
 		if (cell->type.in(ID($_TBUF_), ID($tribuf))) {
 			RTLIL::SigSpec input = cell->getPort(cell->type == ID($_TBUF_) ? ID(E) : ID(EN));
-			RTLIL::SigSpec a = cell->getPort(ID(A));
+			RTLIL::SigSpec a = cell->getPort(ID::A);
 			assign_map.apply(input);
 			assign_map.apply(a);
 			if (input == State::S1)
-				ACTION_DO(ID(Y), cell->getPort(ID(A)));
+				ACTION_DO(ID::Y, cell->getPort(ID::A));
 			if (input == State::S0 && !a.is_fully_undef()) {
 				cover("opt.opt_expr.action_" S__LINE__);
 				log_debug("Replacing data input of %s cell `%s' in module `%s' with constant undef.\n",
 					cell->type.c_str(), cell->name.c_str(), module->name.c_str());
-				cell->setPort(ID(A), SigSpec(State::Sx, GetSize(a)));
+				cell->setPort(ID::A, SigSpec(State::Sx, GetSize(a)));
 				did_something = true;
 				goto next_cell;
 			}
@@ -873,8 +873,8 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 
 		if (cell->type.in(ID($eq), ID($ne), ID($eqx), ID($nex)))
 		{
-			RTLIL::SigSpec a = cell->getPort(ID(A));
-			RTLIL::SigSpec b = cell->getPort(ID(B));
+			RTLIL::SigSpec a = cell->getPort(ID::A);
+			RTLIL::SigSpec b = cell->getPort(ID::B);
 
 			if (cell->parameters[ID(A_WIDTH)].as_int() != cell->parameters[ID(B_WIDTH)].as_int()) {
 				int width = max(cell->parameters[ID(A_WIDTH)].as_int(), cell->parameters[ID(B_WIDTH)].as_int());
@@ -890,7 +890,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 					cover_list("opt.opt_expr.eqneq.isneq", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
 					RTLIL::SigSpec new_y = RTLIL::SigSpec(cell->type.in(ID($eq), ID($eqx)) ?  RTLIL::State::S0 : RTLIL::State::S1);
 					new_y.extend_u0(cell->parameters[ID(Y_WIDTH)].as_int(), false);
-					replace_cell(assign_map, module, cell, "isneq", ID(Y), new_y);
+					replace_cell(assign_map, module, cell, "isneq", ID::Y, new_y);
 					goto next_cell;
 				}
 				if (a[i] == b[i])
@@ -903,14 +903,14 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 				cover_list("opt.opt_expr.eqneq.empty", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
 				RTLIL::SigSpec new_y = RTLIL::SigSpec(cell->type.in(ID($eq), ID($eqx)) ?  RTLIL::State::S1 : RTLIL::State::S0);
 				new_y.extend_u0(cell->parameters[ID(Y_WIDTH)].as_int(), false);
-				replace_cell(assign_map, module, cell, "empty", ID(Y), new_y);
+				replace_cell(assign_map, module, cell, "empty", ID::Y, new_y);
 				goto next_cell;
 			}
 
 			if (new_a.size() < a.size() || new_b.size() < b.size()) {
 				cover_list("opt.opt_expr.eqneq.resize", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
-				cell->setPort(ID(A), new_a);
-				cell->setPort(ID(B), new_b);
+				cell->setPort(ID::A, new_a);
+				cell->setPort(ID::B, new_b);
 				cell->parameters[ID(A_WIDTH)] = new_a.size();
 				cell->parameters[ID(B_WIDTH)] = new_b.size();
 			}
@@ -919,27 +919,27 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 		if (cell->type.in(ID($eq), ID($ne)) && cell->parameters[ID(Y_WIDTH)].as_int() == 1 &&
 				cell->parameters[ID(A_WIDTH)].as_int() == 1 && cell->parameters[ID(B_WIDTH)].as_int() == 1)
 		{
-			RTLIL::SigSpec a = assign_map(cell->getPort(ID(A)));
-			RTLIL::SigSpec b = assign_map(cell->getPort(ID(B)));
+			RTLIL::SigSpec a = assign_map(cell->getPort(ID::A));
+			RTLIL::SigSpec b = assign_map(cell->getPort(ID::B));
 
 			if (a.is_fully_const() && !b.is_fully_const()) {
 				cover_list("opt.opt_expr.eqneq.swapconst", "$eq", "$ne", cell->type.str());
-				cell->setPort(ID(A), b);
-				cell->setPort(ID(B), a);
+				cell->setPort(ID::A, b);
+				cell->setPort(ID::B, a);
 				std::swap(a, b);
 			}
 
 			if (b.is_fully_const()) {
 				if (b.as_bool() == (cell->type == ID($eq))) {
 					RTLIL::SigSpec input = b;
-					ACTION_DO(ID(Y), cell->getPort(ID(A)));
+					ACTION_DO(ID::Y, cell->getPort(ID::A));
 				} else {
 					cover_list("opt.opt_expr.eqneq.isnot", "$eq", "$ne", cell->type.str());
 					log_debug("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module));
 					cell->type = ID($not);
 					cell->parameters.erase(ID(B_WIDTH));
 					cell->parameters.erase(ID(B_SIGNED));
-					cell->unsetPort(ID(B));
+					cell->unsetPort(ID::B);
 					did_something = true;
 				}
 				goto next_cell;
@@ -947,33 +947,33 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 		}
 
 		if (cell->type.in(ID($eq), ID($ne)) &&
-				(assign_map(cell->getPort(ID(A))).is_fully_zero() || assign_map(cell->getPort(ID(B))).is_fully_zero()))
+				(assign_map(cell->getPort(ID::A)).is_fully_zero() || assign_map(cell->getPort(ID::B)).is_fully_zero()))
 		{
 			cover_list("opt.opt_expr.eqneq.cmpzero", "$eq", "$ne", cell->type.str());
 			log_debug("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell->type), log_id(cell),
 					log_id(module), "$eq" ? "$logic_not" : "$reduce_bool");
 			cell->type = cell->type == ID($eq) ? ID($logic_not) : ID($reduce_bool);
-			if (assign_map(cell->getPort(ID(A))).is_fully_zero()) {
-				cell->setPort(ID(A), cell->getPort(ID(B)));
+			if (assign_map(cell->getPort(ID::A)).is_fully_zero()) {
+				cell->setPort(ID::A, cell->getPort(ID::B));
 				cell->setParam(ID(A_SIGNED), cell->getParam(ID(B_SIGNED)));
 				cell->setParam(ID(A_WIDTH), cell->getParam(ID(B_WIDTH)));
 			}
-			cell->unsetPort(ID(B));
+			cell->unsetPort(ID::B);
 			cell->unsetParam(ID(B_SIGNED));
 			cell->unsetParam(ID(B_WIDTH));
 			did_something = true;
 			goto next_cell;
 		}
 
-		if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx)) && assign_map(cell->getPort(ID(B))).is_fully_const())
+		if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx)) && assign_map(cell->getPort(ID::B)).is_fully_const())
 		{
 			bool sign_ext = cell->type == ID($sshr) && cell->getParam(ID(A_SIGNED)).as_bool();
-			int shift_bits = assign_map(cell->getPort(ID(B))).as_int(cell->type.in(ID($shift), ID($shiftx)) && cell->getParam(ID(B_SIGNED)).as_bool());
+			int shift_bits = assign_map(cell->getPort(ID::B)).as_int(cell->type.in(ID($shift), ID($shiftx)) && cell->getParam(ID(B_SIGNED)).as_bool());
 
 			if (cell->type.in(ID($shl), ID($sshl)))
 				shift_bits *= -1;
 
-			RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID(A)));
+			RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A));
 			RTLIL::SigSpec sig_y(cell->type == ID($shiftx) ? RTLIL::State::Sx : RTLIL::State::S0, cell->getParam(ID(Y_WIDTH)).as_int());
 
 			if (GetSize(sig_a) < GetSize(sig_y))
@@ -990,9 +990,9 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 			cover_list("opt.opt_expr.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell->type.str());
 
 			log_debug("Replacing %s cell `%s' (B=%s, SHR=%d) in module `%s' with fixed wiring: %s\n",
-					log_id(cell->type), log_id(cell), log_signal(assign_map(cell->getPort(ID(B)))), shift_bits, log_id(module), log_signal(sig_y));
+					log_id(cell->type), log_id(cell), log_signal(assign_map(cell->getPort(ID::B))), shift_bits, log_id(module), log_signal(sig_y));
 
-			module->connect(cell->getPort(ID(Y)), sig_y);
+			module->connect(cell->getPort(ID::Y), sig_y);
 			module->remove(cell);
 
 			did_something = true;
@@ -1007,8 +1007,8 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 
 			if (cell->type.in(ID($add), ID($sub), ID($or), ID($xor)))
 			{
-				RTLIL::SigSpec a = assign_map(cell->getPort(ID(A)));
-				RTLIL::SigSpec b = assign_map(cell->getPort(ID(B)));
+				RTLIL::SigSpec a = assign_map(cell->getPort(ID::A));
+				RTLIL::SigSpec b = assign_map(cell->getPort(ID::B));
 
 				if (cell->type != ID($sub) && a.is_fully_const() && a.as_bool() == false)
 					identity_wrt_b = true;
@@ -1019,7 +1019,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 
 			if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx)))
 			{
-				RTLIL::SigSpec b = assign_map(cell->getPort(ID(B)));
+				RTLIL::SigSpec b = assign_map(cell->getPort(ID::B));
 
 				if (b.is_fully_const() && b.as_bool() == false)
 					identity_wrt_a = true;
@@ -1027,8 +1027,8 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 
 			if (cell->type == ID($mul))
 			{
-				RTLIL::SigSpec a = assign_map(cell->getPort(ID(A)));
-				RTLIL::SigSpec b = assign_map(cell->getPort(ID(B)));
+				RTLIL::SigSpec a = assign_map(cell->getPort(ID::A));
+				RTLIL::SigSpec b = assign_map(cell->getPort(ID::B));
 
 				if (a.is_fully_const() && is_one_or_minus_one(a.as_const(), cell->getParam(ID(A_SIGNED)).as_bool(), arith_inverse))
 					identity_wrt_b = true;
@@ -1039,7 +1039,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 
 			if (cell->type == ID($div))
 			{
-				RTLIL::SigSpec b = assign_map(cell->getPort(ID(B)));
+				RTLIL::SigSpec b = assign_map(cell->getPort(ID::B));
 
 				if (b.is_fully_const() && b.size() <= 32 && b.as_int() == 1)
 					identity_wrt_a = true;
@@ -1056,13 +1056,13 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 					cell->type.c_str(), cell->name.c_str(), module->name.c_str(), identity_wrt_a ? 'A' : 'B');
 
 				if (!identity_wrt_a) {
-					cell->setPort(ID(A), cell->getPort(ID(B)));
+					cell->setPort(ID::A, cell->getPort(ID::B));
 					cell->parameters.at(ID(A_WIDTH)) = cell->parameters.at(ID(B_WIDTH));
 					cell->parameters.at(ID(A_SIGNED)) = cell->parameters.at(ID(B_SIGNED));
 				}
 
 				cell->type = arith_inverse ? ID($neg) : ID($pos);
-				cell->unsetPort(ID(B));
+				cell->unsetPort(ID::B);
 				cell->parameters.erase(ID(B_WIDTH));
 				cell->parameters.erase(ID(B_SIGNED));
 				cell->check();
@@ -1073,18 +1073,18 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 		}
 
 		if (mux_bool && cell->type.in(ID($mux), ID($_MUX_)) &&
-				cell->getPort(ID(A)) == State::S0 && cell->getPort(ID(B)) == State::S1) {
+				cell->getPort(ID::A) == State::S0 && cell->getPort(ID::B) == State::S1) {
 			cover_list("opt.opt_expr.mux_bool", "$mux", "$_MUX_", cell->type.str());
-			replace_cell(assign_map, module, cell, "mux_bool", ID(Y), cell->getPort(ID(S)));
+			replace_cell(assign_map, module, cell, "mux_bool", ID::Y, cell->getPort(ID(S)));
 			goto next_cell;
 		}
 
 		if (mux_bool && cell->type.in(ID($mux), ID($_MUX_)) &&
-				cell->getPort(ID(A)) == State::S1 && cell->getPort(ID(B)) == State::S0) {
+				cell->getPort(ID::A) == State::S1 && cell->getPort(ID::B) == State::S0) {
 			cover_list("opt.opt_expr.mux_invert", "$mux", "$_MUX_", cell->type.str());
 			log_debug("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module));
-			cell->setPort(ID(A), cell->getPort(ID(S)));
-			cell->unsetPort(ID(B));
+			cell->setPort(ID::A, cell->getPort(ID(S)));
+			cell->unsetPort(ID::B);
 			cell->unsetPort(ID(S));
 			if (cell->type == ID($mux)) {
 				Const width = cell->parameters[ID(WIDTH)];
@@ -1099,10 +1099,10 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 			goto next_cell;
 		}
 
-		if (consume_x && mux_bool && cell->type.in(ID($mux), ID($_MUX_)) && cell->getPort(ID(A)) == State::S0) {
+		if (consume_x && mux_bool && cell->type.in(ID($mux), ID($_MUX_)) && cell->getPort(ID::A) == State::S0) {
 			cover_list("opt.opt_expr.mux_and", "$mux", "$_MUX_", cell->type.str());
 			log_debug("Replacing %s cell `%s' in module `%s' with and-gate.\n", log_id(cell->type), log_id(cell), log_id(module));
-			cell->setPort(ID(A), cell->getPort(ID(S)));
+			cell->setPort(ID::A, cell->getPort(ID(S)));
 			cell->unsetPort(ID(S));
 			if (cell->type == ID($mux)) {
 				Const width = cell->parameters[ID(WIDTH)];
@@ -1119,10 +1119,10 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 			goto next_cell;
 		}
 
-		if (consume_x && mux_bool && cell->type.in(ID($mux), ID($_MUX_)) && cell->getPort(ID(B)) == State::S1) {
+		if (consume_x && mux_bool && cell->type.in(ID($mux), ID($_MUX_)) && cell->getPort(ID::B) == State::S1) {
 			cover_list("opt.opt_expr.mux_or", "$mux", "$_MUX_", cell->type.str());
 			log_debug("Replacing %s cell `%s' in module `%s' with or-gate.\n", log_id(cell->type), log_id(cell), log_id(module));
-			cell->setPort(ID(B), cell->getPort(ID(S)));
+			cell->setPort(ID::B, cell->getPort(ID(S)));
 			cell->unsetPort(ID(S));
 			if (cell->type == ID($mux)) {
 				Const width = cell->parameters[ID(WIDTH)];
@@ -1141,22 +1141,22 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 
 		if (mux_undef && cell->type.in(ID($mux), ID($pmux))) {
 			RTLIL::SigSpec new_a, new_b, new_s;
-			int width = cell->getPort(ID(A)).size();
-			if ((cell->getPort(ID(A)).is_fully_undef() && cell->getPort(ID(B)).is_fully_undef()) ||
+			int width = cell->getPort(ID::A).size();
+			if ((cell->getPort(ID::A).is_fully_undef() && cell->getPort(ID::B).is_fully_undef()) ||
 					cell->getPort(ID(S)).is_fully_undef()) {
 				cover_list("opt.opt_expr.mux_undef", "$mux", "$pmux", cell->type.str());
-				replace_cell(assign_map, module, cell, "mux_undef", ID(Y), cell->getPort(ID(A)));
+				replace_cell(assign_map, module, cell, "mux_undef", ID::Y, cell->getPort(ID::A));
 				goto next_cell;
 			}
 			for (int i = 0; i < cell->getPort(ID(S)).size(); i++) {
-				RTLIL::SigSpec old_b = cell->getPort(ID(B)).extract(i*width, width);
+				RTLIL::SigSpec old_b = cell->getPort(ID::B).extract(i*width, width);
 				RTLIL::SigSpec old_s = cell->getPort(ID(S)).extract(i, 1);
 				if (old_b.is_fully_undef() || old_s.is_fully_undef())
 					continue;
 				new_b.append(old_b);
 				new_s.append(old_s);
 			}
-			new_a = cell->getPort(ID(A));
+			new_a = cell->getPort(ID::A);
 			if (new_a.is_fully_undef() && new_s.size() > 0) {
 				new_a = new_b.extract((new_s.size()-1)*width, width);
 				new_b = new_b.extract(0, (new_s.size()-1)*width);
@@ -1164,20 +1164,20 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 			}
 			if (new_s.size() == 0) {
 				cover_list("opt.opt_expr.mux_empty", "$mux", "$pmux", cell->type.str());
-				replace_cell(assign_map, module, cell, "mux_empty", ID(Y), new_a);
+				replace_cell(assign_map, module, cell, "mux_empty", ID::Y, new_a);
 				goto next_cell;
 			}
 			if (new_a == RTLIL::SigSpec(RTLIL::State::S0) && new_b == RTLIL::SigSpec(RTLIL::State::S1)) {
 				cover_list("opt.opt_expr.mux_sel01", "$mux", "$pmux", cell->type.str());
-				replace_cell(assign_map, module, cell, "mux_sel01", ID(Y), new_s);
+				replace_cell(assign_map, module, cell, "mux_sel01", ID::Y, new_s);
 				goto next_cell;
 			}
 			if (cell->getPort(ID(S)).size() != new_s.size()) {
 				cover_list("opt.opt_expr.mux_reduce", "$mux", "$pmux", cell->type.str());
 				log_debug("Optimized away %d select inputs of %s cell `%s' in module `%s'.\n",
 						GetSize(cell->getPort(ID(S))) - GetSize(new_s), log_id(cell->type), log_id(cell), log_id(module));
-				cell->setPort(ID(A), new_a);
-				cell->setPort(ID(B), new_b);
+				cell->setPort(ID::A, new_a);
+				cell->setPort(ID::B, new_b);
 				cell->setPort(ID(S), new_s);
 				if (new_s.size() > 1) {
 					cell->type = ID($pmux);
@@ -1192,7 +1192,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 
 #define FOLD_1ARG_CELL(_t) \
 		if (cell->type == "$" #_t) { \
-			RTLIL::SigSpec a = cell->getPort(ID(A)); \
+			RTLIL::SigSpec a = cell->getPort(ID::A); \
 			assign_map.apply(a); \
 			if (a.is_fully_const()) { \
 				RTLIL::Const dummy_arg(RTLIL::State::S0, 1); \
@@ -1200,14 +1200,14 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 						cell->parameters[ID(A_SIGNED)].as_bool(), false, \
 						cell->parameters[ID(Y_WIDTH)].as_int())); \
 				cover("opt.opt_expr.const.$" #_t); \
-				replace_cell(assign_map, module, cell, stringf("%s", log_signal(a)), ID(Y), y); \
+				replace_cell(assign_map, module, cell, stringf("%s", log_signal(a)), ID::Y, y); \
 				goto next_cell; \
 			} \
 		}
 #define FOLD_2ARG_CELL(_t) \
 		if (cell->type == "$" #_t) { \
-			RTLIL::SigSpec a = cell->getPort(ID(A)); \
-			RTLIL::SigSpec b = cell->getPort(ID(B)); \
+			RTLIL::SigSpec a = cell->getPort(ID::A); \
+			RTLIL::SigSpec b = cell->getPort(ID::B); \
 			assign_map.apply(a), assign_map.apply(b); \
 			if (a.is_fully_const() && b.is_fully_const()) { \
 				RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), b.as_const(), \
@@ -1215,7 +1215,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 						cell->parameters[ID(B_SIGNED)].as_bool(), \
 						cell->parameters[ID(Y_WIDTH)].as_int())); \
 				cover("opt.opt_expr.const.$" #_t); \
-				replace_cell(assign_map, module, cell, stringf("%s, %s", log_signal(a), log_signal(b)), ID(Y), y); \
+				replace_cell(assign_map, module, cell, stringf("%s, %s", log_signal(a), log_signal(b)), ID::Y, y); \
 				goto next_cell; \
 			} \
 		}
@@ -1263,12 +1263,12 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 		// be very conservative with optimizing $mux cells as we do not want to break mux trees
 		if (cell->type == ID($mux)) {
 			RTLIL::SigSpec input = assign_map(cell->getPort(ID(S)));
-			RTLIL::SigSpec inA = assign_map(cell->getPort(ID(A)));
-			RTLIL::SigSpec inB = assign_map(cell->getPort(ID(B)));
+			RTLIL::SigSpec inA = assign_map(cell->getPort(ID::A));
+			RTLIL::SigSpec inB = assign_map(cell->getPort(ID::B));
 			if (input.is_fully_const())
-				ACTION_DO(ID(Y), input.as_bool() ? cell->getPort(ID(B)) : cell->getPort(ID(A)));
+				ACTION_DO(ID::Y, input.as_bool() ? cell->getPort(ID::B) : cell->getPort(ID::A));
 			else if (inA == inB)
-				ACTION_DO(ID(Y), cell->getPort(ID(A)));
+				ACTION_DO(ID::Y, cell->getPort(ID::A));
 		}
 
 		if (!keepdc && cell->type == ID($mul))
@@ -1277,9 +1277,9 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 			bool b_signed = cell->parameters[ID(B_SIGNED)].as_bool();
 			bool swapped_ab = false;
 
-			RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID(A)));
-			RTLIL::SigSpec sig_b = assign_map(cell->getPort(ID(B)));
-			RTLIL::SigSpec sig_y = assign_map(cell->getPort(ID(Y)));
+			RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A));
+			RTLIL::SigSpec sig_b = assign_map(cell->getPort(ID::B));
+			RTLIL::SigSpec sig_y = assign_map(cell->getPort(ID::Y));
 
 			if (sig_b.is_fully_const() && sig_b.size() <= 32)
 				std::swap(sig_a, sig_b), std::swap(a_signed, b_signed), swapped_ab = true;
@@ -1314,7 +1314,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 								a_val, cell->name.c_str(), module->name.c_str(), i);
 
 						if (!swapped_ab) {
-							cell->setPort(ID(A), cell->getPort(ID(B)));
+							cell->setPort(ID::A, cell->getPort(ID::B));
 							cell->parameters.at(ID(A_WIDTH)) = cell->parameters.at(ID(B_WIDTH));
 							cell->parameters.at(ID(A_SIGNED)) = cell->parameters.at(ID(B_SIGNED));
 						}
@@ -1327,7 +1327,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 						cell->type = ID($shl);
 						cell->parameters[ID(B_WIDTH)] = GetSize(new_b);
 						cell->parameters[ID(B_SIGNED)] = false;
-						cell->setPort(ID(B), new_b);
+						cell->setPort(ID::B, new_b);
 						cell->check();
 
 						did_something = true;
@@ -1339,8 +1339,8 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 		if (!keepdc && cell->type.in(ID($div), ID($mod)))
 		{
 			bool b_signed = cell->parameters[ID(B_SIGNED)].as_bool();
-			SigSpec sig_b = assign_map(cell->getPort(ID(B)));
-			SigSpec sig_y = assign_map(cell->getPort(ID(Y)));
+			SigSpec sig_b = assign_map(cell->getPort(ID::B));
+			SigSpec sig_y = assign_map(cell->getPort(ID::Y));
 
 			if (sig_b.is_fully_def() && sig_b.size() <= 32)
 			{
@@ -1378,7 +1378,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 							cell->type = ID($shr);
 							cell->parameters[ID(B_WIDTH)] = GetSize(new_b);
 							cell->parameters[ID(B_SIGNED)] = false;
-							cell->setPort(ID(B), new_b);
+							cell->setPort(ID::B, new_b);
 							cell->check();
 						}
 						else
@@ -1395,7 +1395,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 
 							cell->type = ID($and);
 							cell->parameters[ID(B_WIDTH)] = GetSize(new_b);
-							cell->setPort(ID(B), new_b);
+							cell->setPort(ID::B, new_b);
 							cell->check();
 						}
 
@@ -1421,8 +1421,8 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 			bool is_signed = cell->getParam(ID(A_SIGNED)).as_bool();
 			int width = is_signed ? std::min(a_width, b_width) : std::max(a_width, b_width);
 
-			SigSpec sig_a = cell->getPort(ID(A));
-			SigSpec sig_b = cell->getPort(ID(B));
+			SigSpec sig_a = cell->getPort(ID::A);
+			SigSpec sig_b = cell->getPort(ID::B);
 
 			int redundant_bits = 0;
 
@@ -1452,7 +1452,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 
 			if (contradiction_cache.find(State::S0) == contradiction_cache.find(State::S1))
 			{
-				SigSpec y_sig = cell->getPort(ID(Y));
+				SigSpec y_sig = cell->getPort(ID::Y);
 				Const y_value(cell->type.in(ID($eq), ID($eqx)) ? 0 : 1, GetSize(y_sig));
 
 				log_debug("Replacing cell `%s' in module `%s' with constant driver %s.\n",
@@ -1470,8 +1470,8 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 				log_debug("Removed %d redundant input bits from %s cell `%s' in module `%s'.\n",
 						redundant_bits, log_id(cell->type), log_id(cell), log_id(module));
 
-				cell->setPort(ID(A), sig_a);
-				cell->setPort(ID(B), sig_b);
+				cell->setPort(ID::A, sig_a);
+				cell->setPort(ID::B, sig_b);
 				cell->setParam(ID(A_WIDTH), GetSize(sig_a));
 				cell->setParam(ID(B_WIDTH), GetSize(sig_b));
 
@@ -1484,8 +1484,8 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 		if (do_fine && cell->type.in(ID($lt), ID($ge), ID($gt), ID($le)))
 		{
 			IdString cmp_type = cell->type;
-			SigSpec var_sig = cell->getPort(ID(A));
-			SigSpec const_sig = cell->getPort(ID(B));
+			SigSpec var_sig = cell->getPort(ID::A);
+			SigSpec const_sig = cell->getPort(ID::B);
 			int var_width = cell->parameters[ID(A_WIDTH)].as_int();
 			int const_width = cell->parameters[ID(B_WIDTH)].as_int();
 			bool is_signed = cell->getParam(ID(A_SIGNED)).as_bool();
@@ -1507,7 +1507,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 			if (const_sig.is_fully_def() && const_sig.is_fully_const())
 			{
 				std::string condition, replacement;
-				SigSpec replace_sig(State::S0, GetSize(cell->getPort(ID(Y))));
+				SigSpec replace_sig(State::S0, GetSize(cell->getPort(ID::Y)));
 				bool replace = false;
 				bool remove = false;
 
@@ -1550,14 +1550,14 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 						{
 							condition   = stringf("unsigned X<%s", log_signal(const_sig));
 							replacement = stringf("!X[%d:%d]", var_width - 1, const_bit_hot);
-							module->addLogicNot(NEW_ID, var_high_sig, cell->getPort(ID(Y)));
+							module->addLogicNot(NEW_ID, var_high_sig, cell->getPort(ID::Y));
 							remove = true;
 						}
 						if (cmp_type == ID($ge))
 						{
 							condition   = stringf("unsigned X>=%s", log_signal(const_sig));
 							replacement = stringf("|X[%d:%d]", var_width - 1, const_bit_hot);
-							module->addReduceOr(NEW_ID, var_high_sig, cell->getPort(ID(Y)));
+							module->addReduceOr(NEW_ID, var_high_sig, cell->getPort(ID::Y));
 							remove = true;
 						}
 					}
@@ -1599,7 +1599,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 					{
 						condition   = "signed X>=0";
 						replacement = stringf("X[%d]", var_width - 1);
-						module->addNot(NEW_ID, var_sig[var_width - 1], cell->getPort(ID(Y)));
+						module->addNot(NEW_ID, var_sig[var_width - 1], cell->getPort(ID::Y));
 						remove = true;
 					}
 				}
@@ -1609,7 +1609,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 					log_debug("Replacing %s cell `%s' (implementing %s) with %s.\n",
 							log_id(cell->type), log_id(cell), condition.c_str(), replacement.c_str());
 					if (replace)
-						module->connect(cell->getPort(ID(Y)), replace_sig);
+						module->connect(cell->getPort(ID::Y), replace_sig);
 					module->remove(cell);
 					did_something = true;
 					goto next_cell;
diff --git a/passes/opt/opt_lut.cc b/passes/opt/opt_lut.cc
index e9d72044b..733bc547c 100644
--- a/passes/opt/opt_lut.cc
+++ b/passes/opt/opt_lut.cc
@@ -40,7 +40,7 @@ struct OptLutWorker
 
 	bool evaluate_lut(RTLIL::Cell *lut, dict<SigBit, bool> inputs)
 	{
-		SigSpec lut_input = sigmap(lut->getPort(ID(A)));
+		SigSpec lut_input = sigmap(lut->getPort(ID::A));
 		int lut_width = lut->getParam(ID(WIDTH)).as_int();
 		Const lut_table = lut->getParam(ID(LUT));
 		int lut_index = 0;
@@ -103,12 +103,12 @@ struct OptLutWorker
 			{
 				if (cell->has_keep_attr())
 					continue;
-				SigBit lut_output = cell->getPort(ID(Y));
+				SigBit lut_output = cell->getPort(ID::Y);
 				if (lut_output.wire->get_bool_attribute(ID(keep)))
 					continue;
 
 				int lut_width = cell->getParam(ID(WIDTH)).as_int();
-				SigSpec lut_input = cell->getPort(ID(A));
+				SigSpec lut_input = cell->getPort(ID::A);
 				int lut_arity = 0;
 
 				log_debug("Found $lut\\WIDTH=%d cell %s.%s.\n", lut_width, log_id(module), log_id(cell));
@@ -205,7 +205,7 @@ struct OptLutWorker
 			}
 
 			auto lut = worklist.pop();
-			SigSpec lut_input = sigmap(lut->getPort(ID(A)));
+			SigSpec lut_input = sigmap(lut->getPort(ID::A));
 			pool<int> &lut_dlogic_inputs = luts_dlogic_inputs[lut];
 
 			vector<SigBit> lut_inputs;
@@ -267,7 +267,7 @@ struct OptLutWorker
 					log_debug("  Not eliminating cell (connected to dedicated logic).\n");
 				else
 				{
-					SigSpec lut_output = lut->getPort(ID(Y));
+					SigSpec lut_output = lut->getPort(ID::Y);
 					for (auto &port : index.query_ports(lut_output))
 					{
 						if (port.cell != lut && luts.count(port.cell))
@@ -303,13 +303,13 @@ struct OptLutWorker
 			}
 
 			auto lutA = worklist.pop();
-			SigSpec lutA_input = sigmap(lutA->getPort(ID(A)));
-			SigSpec lutA_output = sigmap(lutA->getPort(ID(Y))[0]);
+			SigSpec lutA_input = sigmap(lutA->getPort(ID::A));
+			SigSpec lutA_output = sigmap(lutA->getPort(ID::Y)[0]);
 			int lutA_width = lutA->getParam(ID(WIDTH)).as_int();
 			int lutA_arity = luts_arity[lutA];
 			pool<int> &lutA_dlogic_inputs = luts_dlogic_inputs[lutA];
 
-			auto lutA_output_ports = index.query_ports(lutA->getPort(ID(Y)));
+			auto lutA_output_ports = index.query_ports(lutA->getPort(ID::Y));
 			if (lutA_output_ports.size() != 2)
 				continue;
 
@@ -321,15 +321,15 @@ struct OptLutWorker
 				if (luts.count(port.cell))
 				{
 					auto lutB = port.cell;
-					SigSpec lutB_input = sigmap(lutB->getPort(ID(A)));
-					SigSpec lutB_output = sigmap(lutB->getPort(ID(Y))[0]);
+					SigSpec lutB_input = sigmap(lutB->getPort(ID::A));
+					SigSpec lutB_output = sigmap(lutB->getPort(ID::Y)[0]);
 					int lutB_width = lutB->getParam(ID(WIDTH)).as_int();
 					int lutB_arity = luts_arity[lutB];
 					pool<int> &lutB_dlogic_inputs = luts_dlogic_inputs[lutB];
 
 					log_debug("Found %s.%s (cell A) feeding %s.%s (cell B).\n", log_id(module), log_id(lutA), log_id(module), log_id(lutB));
 
-					if (index.query_is_output(lutA->getPort(ID(Y))))
+					if (index.query_is_output(lutA->getPort(ID::Y)))
 					{
 						log_debug("  Not combining LUTs (cascade connection feeds module output).\n");
 						continue;
@@ -441,7 +441,7 @@ struct OptLutWorker
 					}
 
 					int lutM_width = lutM->getParam(ID(WIDTH)).as_int();
-					SigSpec lutM_input = sigmap(lutM->getPort(ID(A)));
+					SigSpec lutM_input = sigmap(lutM->getPort(ID::A));
 					std::vector<SigBit> lutM_new_inputs;
 					for (int i = 0; i < lutM_width; i++)
 					{
@@ -487,8 +487,8 @@ struct OptLutWorker
 					log_debug("  Merged truth table: %s.\n", lutM_new_table.as_string().c_str());
 
 					lutM->setParam(ID(LUT), lutM_new_table);
-					lutM->setPort(ID(A), lutM_new_inputs);
-					lutM->setPort(ID(Y), lutB_output);
+					lutM->setPort(ID::A, lutM_new_inputs);
+					lutM->setPort(ID::Y, lutB_output);
 
 					luts_arity[lutM] = lutM_arity;
 					luts.erase(lutR);
diff --git a/passes/opt/opt_merge.cc b/passes/opt/opt_merge.cc
index aa1a5c75c..aaea6159e 100644
--- a/passes/opt/opt_merge.cc
+++ b/passes/opt/opt_merge.cc
@@ -48,7 +48,7 @@ struct OptMergeWorker
 	static void sort_pmux_conn(dict<RTLIL::IdString, RTLIL::SigSpec> &conn)
 	{
 		SigSpec sig_s = conn.at(ID(S));
-		SigSpec sig_b = conn.at(ID(B));
+		SigSpec sig_b = conn.at(ID::B);
 
 		int s_width = GetSize(sig_s);
 		int width = GetSize(sig_b) / s_width;
@@ -60,11 +60,11 @@ struct OptMergeWorker
 		std::sort(sb_pairs.begin(), sb_pairs.end());
 
 		conn[ID(S)] = SigSpec();
-		conn[ID(B)] = SigSpec();
+		conn[ID::B] = SigSpec();
 
 		for (auto &it : sb_pairs) {
 			conn[ID(S)].append(it.first);
-			conn[ID(B)].append(it.second);
+			conn[ID::B].append(it.second);
 		}
 	}
 
@@ -97,28 +97,28 @@ struct OptMergeWorker
 		if (cell->type.in(ID($and), ID($or), ID($xor), ID($xnor), ID($add), ID($mul),
 				ID($logic_and), ID($logic_or), ID($_AND_), ID($_OR_), ID($_XOR_))) {
 			alt_conn = *conn;
-			if (assign_map(alt_conn.at(ID(A))) < assign_map(alt_conn.at(ID(B)))) {
-				alt_conn[ID(A)] = conn->at(ID(B));
-				alt_conn[ID(B)] = conn->at(ID(A));
+			if (assign_map(alt_conn.at(ID::A)) < assign_map(alt_conn.at(ID::B))) {
+				alt_conn[ID::A] = conn->at(ID::B);
+				alt_conn[ID::B] = conn->at(ID::A);
 			}
 			conn = &alt_conn;
 		} else
 		if (cell->type.in(ID($reduce_xor), ID($reduce_xnor))) {
 			alt_conn = *conn;
-			assign_map.apply(alt_conn.at(ID(A)));
-			alt_conn.at(ID(A)).sort();
+			assign_map.apply(alt_conn.at(ID::A));
+			alt_conn.at(ID::A).sort();
 			conn = &alt_conn;
 		} else
 		if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_bool))) {
 			alt_conn = *conn;
-			assign_map.apply(alt_conn.at(ID(A)));
-			alt_conn.at(ID(A)).sort_and_unify();
+			assign_map.apply(alt_conn.at(ID::A));
+			alt_conn.at(ID::A).sort_and_unify();
 			conn = &alt_conn;
 		} else
 		if (cell->type == ID($pmux)) {
 			alt_conn = *conn;
-			assign_map.apply(alt_conn.at(ID(A)));
-			assign_map.apply(alt_conn.at(ID(B)));
+			assign_map.apply(alt_conn.at(ID::A));
+			assign_map.apply(alt_conn.at(ID::B));
 			assign_map.apply(alt_conn.at(ID(S)));
 			sort_pmux_conn(alt_conn);
 			conn = &alt_conn;
@@ -191,24 +191,24 @@ struct OptMergeWorker
 
 		if (cell1->type == ID($and) || cell1->type == ID($or) || cell1->type == ID($xor) || cell1->type == ID($xnor) || cell1->type == ID($add) || cell1->type == ID($mul) ||
 				cell1->type == ID($logic_and) || cell1->type == ID($logic_or) || cell1->type == ID($_AND_) || cell1->type == ID($_OR_) || cell1->type == ID($_XOR_)) {
-			if (conn1.at(ID(A)) < conn1.at(ID(B))) {
-				RTLIL::SigSpec tmp = conn1[ID(A)];
-				conn1[ID(A)] = conn1[ID(B)];
-				conn1[ID(B)] = tmp;
+			if (conn1.at(ID::A) < conn1.at(ID::B)) {
+				RTLIL::SigSpec tmp = conn1[ID::A];
+				conn1[ID::A] = conn1[ID::B];
+				conn1[ID::B] = tmp;
 			}
-			if (conn2.at(ID(A)) < conn2.at(ID(B))) {
-				RTLIL::SigSpec tmp = conn2[ID(A)];
-				conn2[ID(A)] = conn2[ID(B)];
-				conn2[ID(B)] = tmp;
+			if (conn2.at(ID::A) < conn2.at(ID::B)) {
+				RTLIL::SigSpec tmp = conn2[ID::A];
+				conn2[ID::A] = conn2[ID::B];
+				conn2[ID::B] = tmp;
 			}
 		} else
 		if (cell1->type == ID($reduce_xor) || cell1->type == ID($reduce_xnor)) {
-			conn1[ID(A)].sort();
-			conn2[ID(A)].sort();
+			conn1[ID::A].sort();
+			conn2[ID::A].sort();
 		} else
 		if (cell1->type == ID($reduce_and) || cell1->type == ID($reduce_or) || cell1->type == ID($reduce_bool)) {
-			conn1[ID(A)].sort_and_unify();
-			conn2[ID(A)].sort_and_unify();
+			conn1[ID::A].sort_and_unify();
+			conn2[ID::A].sort_and_unify();
 		} else
 		if (cell1->type == ID($pmux)) {
 			sort_pmux_conn(conn1);
diff --git a/passes/opt/opt_muxtree.cc b/passes/opt/opt_muxtree.cc
index 61f194569..3d7e9cccb 100644
--- a/passes/opt/opt_muxtree.cc
+++ b/passes/opt/opt_muxtree.cc
@@ -86,10 +86,10 @@ struct OptMuxtreeWorker
 		{
 			if (cell->type.in(ID($mux), ID($pmux)))
 			{
-				RTLIL::SigSpec sig_a = cell->getPort(ID(A));
-				RTLIL::SigSpec sig_b = cell->getPort(ID(B));
+				RTLIL::SigSpec sig_a = cell->getPort(ID::A);
+				RTLIL::SigSpec sig_b = cell->getPort(ID::B);
 				RTLIL::SigSpec sig_s = cell->getPort(ID(S));
-				RTLIL::SigSpec sig_y = cell->getPort(ID(Y));
+				RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
 
 				muxinfo_t muxinfo;
 				muxinfo.cell = cell;
@@ -227,10 +227,10 @@ struct OptMuxtreeWorker
 				continue;
 			}
 
-			RTLIL::SigSpec sig_a = mi.cell->getPort(ID(A));
-			RTLIL::SigSpec sig_b = mi.cell->getPort(ID(B));
+			RTLIL::SigSpec sig_a = mi.cell->getPort(ID::A);
+			RTLIL::SigSpec sig_b = mi.cell->getPort(ID::B);
 			RTLIL::SigSpec sig_s = mi.cell->getPort(ID(S));
-			RTLIL::SigSpec sig_y = mi.cell->getPort(ID(Y));
+			RTLIL::SigSpec sig_y = mi.cell->getPort(ID::Y);
 
 			RTLIL::SigSpec sig_ports = sig_b;
 			sig_ports.append(sig_a);
@@ -255,8 +255,8 @@ struct OptMuxtreeWorker
 					}
 				}
 
-				mi.cell->setPort(ID(A), new_sig_a);
-				mi.cell->setPort(ID(B), new_sig_b);
+				mi.cell->setPort(ID::A, new_sig_a);
+				mi.cell->setPort(ID::B, new_sig_b);
 				mi.cell->setPort(ID(S), new_sig_s);
 				if (GetSize(new_sig_s) == 1) {
 					mi.cell->type = ID($mux);
@@ -364,8 +364,8 @@ struct OptMuxtreeWorker
 
 		int width = 0;
 		idict<int> ctrl_bits;
-		if (portname == ID(B))
-			width = GetSize(muxinfo.cell->getPort(ID(A)));
+		if (portname == ID::B)
+			width = GetSize(muxinfo.cell->getPort(ID::A));
 		for (int bit : sig2bits(muxinfo.cell->getPort(ID(S)), false))
 			ctrl_bits(bit);
 
@@ -414,8 +414,8 @@ struct OptMuxtreeWorker
 
 		// set input ports to constants if we find known active or inactive signals
 		if (do_replace_known) {
-			replace_known(knowledge, muxinfo, ID(A));
-			replace_known(knowledge, muxinfo, ID(B));
+			replace_known(knowledge, muxinfo, ID::A);
+			replace_known(knowledge, muxinfo, ID::B);
 		}
 
 		// if there is a constant activated port we just use it
diff --git a/passes/opt/opt_reduce.cc b/passes/opt/opt_reduce.cc
index 332e0443e..6a8d8cabd 100644
--- a/passes/opt/opt_reduce.cc
+++ b/passes/opt/opt_reduce.cc
@@ -43,7 +43,7 @@ struct OptReduceWorker
 			return;
 		cells.erase(cell);
 
-		RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID(A)));
+		RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A));
 		pool<RTLIL::SigBit> new_sig_a_bits;
 
 		for (auto &bit : sig_a.to_sigbit_set())
@@ -73,8 +73,8 @@ struct OptReduceWorker
 			for (auto child_cell : drivers.find(bit)) {
 				if (child_cell->type == cell->type) {
 					opt_reduce(cells, drivers, child_cell);
-					if (child_cell->getPort(ID(Y))[0] == bit) {
-						pool<RTLIL::SigBit> child_sig_a_bits = assign_map(child_cell->getPort(ID(A))).to_sigbit_pool();
+					if (child_cell->getPort(ID::Y)[0] == bit) {
+						pool<RTLIL::SigBit> child_sig_a_bits = assign_map(child_cell->getPort(ID::A)).to_sigbit_pool();
 						new_sig_a_bits.insert(child_sig_a_bits.begin(), child_sig_a_bits.end());
 					} else
 						new_sig_a_bits.insert(RTLIL::State::S0);
@@ -87,21 +87,21 @@ struct OptReduceWorker
 
 		RTLIL::SigSpec new_sig_a(new_sig_a_bits);
 
-		if (new_sig_a != sig_a || sig_a.size() != cell->getPort(ID(A)).size()) {
+		if (new_sig_a != sig_a || sig_a.size() != cell->getPort(ID::A).size()) {
 			log("    New input vector for %s cell %s: %s\n", cell->type.c_str(), cell->name.c_str(), log_signal(new_sig_a));
 			did_something = true;
 			total_count++;
 		}
 
-		cell->setPort(ID(A), new_sig_a);
+		cell->setPort(ID::A, new_sig_a);
 		cell->parameters[ID(A_WIDTH)] = RTLIL::Const(new_sig_a.size());
 		return;
 	}
 
 	void opt_mux(RTLIL::Cell *cell)
 	{
-		RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID(A)));
-		RTLIL::SigSpec sig_b = assign_map(cell->getPort(ID(B)));
+		RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A));
+		RTLIL::SigSpec sig_b = assign_map(cell->getPort(ID::B));
 		RTLIL::SigSpec sig_s = assign_map(cell->getPort(ID(S)));
 
 		RTLIL::SigSpec new_sig_b, new_sig_s;
@@ -124,14 +124,14 @@ struct OptReduceWorker
 			if (this_s.size() > 1)
 			{
 				RTLIL::Cell *reduce_or_cell = module->addCell(NEW_ID, ID($reduce_or));
-				reduce_or_cell->setPort(ID(A), this_s);
+				reduce_or_cell->setPort(ID::A, this_s);
 				reduce_or_cell->parameters[ID(A_SIGNED)] = RTLIL::Const(0);
 				reduce_or_cell->parameters[ID(A_WIDTH)] = RTLIL::Const(this_s.size());
 				reduce_or_cell->parameters[ID(Y_WIDTH)] = RTLIL::Const(1);
 
 				RTLIL::Wire *reduce_or_wire = module->addWire(NEW_ID);
 				this_s = RTLIL::SigSpec(reduce_or_wire);
-				reduce_or_cell->setPort(ID(Y), this_s);
+				reduce_or_cell->setPort(ID::Y, this_s);
 			}
 
 			new_sig_b.append(this_b);
@@ -147,13 +147,13 @@ struct OptReduceWorker
 
 		if (new_sig_s.size() == 0)
 		{
-			module->connect(RTLIL::SigSig(cell->getPort(ID(Y)), cell->getPort(ID(A))));
-			assign_map.add(cell->getPort(ID(Y)), cell->getPort(ID(A)));
+			module->connect(RTLIL::SigSig(cell->getPort(ID::Y), cell->getPort(ID::A)));
+			assign_map.add(cell->getPort(ID::Y), cell->getPort(ID::A));
 			module->remove(cell);
 		}
 		else
 		{
-			cell->setPort(ID(B), new_sig_b);
+			cell->setPort(ID::B, new_sig_b);
 			cell->setPort(ID(S), new_sig_s);
 			if (new_sig_s.size() > 1) {
 				cell->parameters[ID(S_WIDTH)] = RTLIL::Const(new_sig_s.size());
@@ -166,9 +166,9 @@ struct OptReduceWorker
 
 	void opt_mux_bits(RTLIL::Cell *cell)
 	{
-		std::vector<RTLIL::SigBit> sig_a = assign_map(cell->getPort(ID(A))).to_sigbit_vector();
-		std::vector<RTLIL::SigBit> sig_b = assign_map(cell->getPort(ID(B))).to_sigbit_vector();
-		std::vector<RTLIL::SigBit> sig_y = assign_map(cell->getPort(ID(Y))).to_sigbit_vector();
+		std::vector<RTLIL::SigBit> sig_a = assign_map(cell->getPort(ID::A)).to_sigbit_vector();
+		std::vector<RTLIL::SigBit> sig_b = assign_map(cell->getPort(ID::B)).to_sigbit_vector();
+		std::vector<RTLIL::SigBit> sig_y = assign_map(cell->getPort(ID::Y)).to_sigbit_vector();
 
 		std::vector<RTLIL::SigBit> new_sig_y;
 		RTLIL::SigSig old_sig_conn;
@@ -209,29 +209,29 @@ struct OptReduceWorker
 		if (new_sig_y.size() != sig_y.size())
 		{
 			log("    Consolidated identical input bits for %s cell %s:\n", cell->type.c_str(), cell->name.c_str());
-			log("      Old ports: A=%s, B=%s, Y=%s\n", log_signal(cell->getPort(ID(A))),
-					log_signal(cell->getPort(ID(B))), log_signal(cell->getPort(ID(Y))));
+			log("      Old ports: A=%s, B=%s, Y=%s\n", log_signal(cell->getPort(ID::A)),
+					log_signal(cell->getPort(ID::B)), log_signal(cell->getPort(ID::Y)));
 
-			cell->setPort(ID(A), RTLIL::SigSpec());
+			cell->setPort(ID::A, RTLIL::SigSpec());
 			for (auto &in_tuple : consolidated_in_tuples) {
-				RTLIL::SigSpec new_a = cell->getPort(ID(A));
+				RTLIL::SigSpec new_a = cell->getPort(ID::A);
 				new_a.append(in_tuple.at(0));
-				cell->setPort(ID(A), new_a);
+				cell->setPort(ID::A, new_a);
 			}
 
-			cell->setPort(ID(B), RTLIL::SigSpec());
+			cell->setPort(ID::B, RTLIL::SigSpec());
 			for (int i = 1; i <= cell->getPort(ID(S)).size(); i++)
 				for (auto &in_tuple : consolidated_in_tuples) {
-					RTLIL::SigSpec new_b = cell->getPort(ID(B));
+					RTLIL::SigSpec new_b = cell->getPort(ID::B);
 					new_b.append(in_tuple.at(i));
-					cell->setPort(ID(B), new_b);
+					cell->setPort(ID::B, new_b);
 				}
 
 			cell->parameters[ID(WIDTH)] = RTLIL::Const(new_sig_y.size());
-			cell->setPort(ID(Y), new_sig_y);
+			cell->setPort(ID::Y, new_sig_y);
 
-			log("      New ports: A=%s, B=%s, Y=%s\n", log_signal(cell->getPort(ID(A))),
-					log_signal(cell->getPort(ID(B))), log_signal(cell->getPort(ID(Y))));
+			log("      New ports: A=%s, B=%s, Y=%s\n", log_signal(cell->getPort(ID::A)),
+					log_signal(cell->getPort(ID::B)), log_signal(cell->getPort(ID::Y)));
 			log("      New connections: %s = %s\n", log_signal(old_sig_conn.first), log_signal(old_sig_conn.second));
 
 			module->connect(old_sig_conn);
@@ -269,12 +269,12 @@ struct OptReduceWorker
 			keep_expanding_mem_wren_sigs = false;
 			for (auto &cell_it : module->cells_) {
 				RTLIL::Cell *cell = cell_it.second;
-				if (cell->type == ID($mux) && mem_wren_sigs.check_any(assign_map(cell->getPort(ID(Y))))) {
-					if (!mem_wren_sigs.check_all(assign_map(cell->getPort(ID(A)))) ||
-							!mem_wren_sigs.check_all(assign_map(cell->getPort(ID(B)))))
+				if (cell->type == ID($mux) && mem_wren_sigs.check_any(assign_map(cell->getPort(ID::Y)))) {
+					if (!mem_wren_sigs.check_all(assign_map(cell->getPort(ID::A))) ||
+							!mem_wren_sigs.check_all(assign_map(cell->getPort(ID::B))))
 						keep_expanding_mem_wren_sigs = true;
-					mem_wren_sigs.add(assign_map(cell->getPort(ID(A))));
-					mem_wren_sigs.add(assign_map(cell->getPort(ID(B))));
+					mem_wren_sigs.add(assign_map(cell->getPort(ID::A)));
+					mem_wren_sigs.add(assign_map(cell->getPort(ID::B)));
 				}
 			}
 		}
@@ -296,7 +296,7 @@ struct OptReduceWorker
 					RTLIL::Cell *cell = cell_it.second;
 					if (cell->type != type || !design->selected(module, cell))
 						continue;
-					drivers.insert(assign_map(cell->getPort(ID(Y))), cell);
+					drivers.insert(assign_map(cell->getPort(ID::Y)), cell);
 					cells.insert(cell);
 				}
 
@@ -318,7 +318,7 @@ struct OptReduceWorker
 			{
 				// this optimization is to aggressive for most coarse-grain applications.
 				// but we always want it for multiplexers driving write enable ports.
-				if (do_fine || mem_wren_sigs.check_any(assign_map(cell->getPort(ID(Y)))))
+				if (do_fine || mem_wren_sigs.check_any(assign_map(cell->getPort(ID::Y))))
 					opt_mux_bits(cell);
 
 				opt_mux(cell);
diff --git a/passes/opt/opt_rmdff.cc b/passes/opt/opt_rmdff.cc
index 4ba61e512..0bf74098a 100644
--- a/passes/opt/opt_rmdff.cc
+++ b/passes/opt/opt_rmdff.cc
@@ -347,8 +347,8 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
 		std::set<RTLIL::Cell*> muxes;
 		mux_drivers.find(sig_d, muxes);
 		for (auto mux : muxes) {
-			RTLIL::SigSpec sig_a = assign_map(mux->getPort(ID(A)));
-			RTLIL::SigSpec sig_b = assign_map(mux->getPort(ID(B)));
+			RTLIL::SigSpec sig_a = assign_map(mux->getPort(ID::A));
+			RTLIL::SigSpec sig_b = assign_map(mux->getPort(ID::B));
 			if (sig_a == sig_q && sig_b.is_fully_const() && (!has_init || val_init == sig_b.as_const())) {
 				mod->connect(sig_q, sig_b);
 				goto delete_dff;
@@ -625,8 +625,8 @@ struct OptRmdffPass : public Pass {
 				}
 
 				if (cell->type.in(ID($mux), ID($pmux))) {
-					if (cell->getPort(ID(A)).size() == cell->getPort(ID(B)).size())
-						mux_drivers.insert(assign_map(cell->getPort(ID(Y))), cell);
+					if (cell->getPort(ID::A).size() == cell->getPort(ID::B).size())
+						mux_drivers.insert(assign_map(cell->getPort(ID::Y)), cell);
 					continue;
 				}
 
diff --git a/passes/opt/pmux2shiftx.cc b/passes/opt/pmux2shiftx.cc
index 3e34bfbbd..92b5794ac 100644
--- a/passes/opt/pmux2shiftx.cc
+++ b/passes/opt/pmux2shiftx.cc
@@ -73,9 +73,9 @@ struct OnehotDatabase
 
 			if (cell->type.in(ID($mux), ID($pmux)))
 			{
-				output = cell->getPort(ID(Y));
-				inputs.push_back(cell->getPort(ID(A)));
-				SigSpec B = cell->getPort(ID(B));
+				output = cell->getPort(ID::Y);
+				inputs.push_back(cell->getPort(ID::A));
+				SigSpec B = cell->getPort(ID::B);
 				for (int i = 0; i < GetSize(B); i += GetSize(output))
 					inputs.push_back(B.extract(i, GetSize(output)));
 			}
@@ -296,8 +296,8 @@ struct Pmux2ShiftxPass : public Pass {
 				{
 					dict<SigBit, State> bits;
 
-					SigSpec A = sigmap(cell->getPort(ID(A)));
-					SigSpec B = sigmap(cell->getPort(ID(B)));
+					SigSpec A = sigmap(cell->getPort(ID::A));
+					SigSpec B = sigmap(cell->getPort(ID::B));
 
 					int a_width = cell->getParam(ID(A_WIDTH)).as_int();
 					int b_width = cell->getParam(ID(B_WIDTH)).as_int();
@@ -335,7 +335,7 @@ struct Pmux2ShiftxPass : public Pass {
 						entry.second.bits.push_back(it.second);
 					}
 
-					eqdb[sigmap(cell->getPort(ID(Y))[0])] = entry;
+					eqdb[sigmap(cell->getPort(ID::Y)[0])] = entry;
 					goto next_cell;
 				}
 
@@ -343,7 +343,7 @@ struct Pmux2ShiftxPass : public Pass {
 				{
 					dict<SigBit, State> bits;
 
-					SigSpec A = sigmap(cell->getPort(ID(A)));
+					SigSpec A = sigmap(cell->getPort(ID::A));
 
 					for (int i = 0; i < GetSize(A); i++)
 						bits[A[i]] = State::S0;
@@ -356,7 +356,7 @@ struct Pmux2ShiftxPass : public Pass {
 						entry.second.bits.push_back(it.second);
 					}
 
-					eqdb[sigmap(cell->getPort(ID(Y))[0])] = entry;
+					eqdb[sigmap(cell->getPort(ID::Y)[0])] = entry;
 					goto next_cell;
 				}
 		next_cell:;
@@ -377,8 +377,8 @@ struct Pmux2ShiftxPass : public Pass {
 
 				dict<SigSpec, pool<int>> seldb;
 
-				SigSpec A = cell->getPort(ID(A));
-				SigSpec B = cell->getPort(ID(B));
+				SigSpec A = cell->getPort(ID::A);
+				SigSpec B = cell->getPort(ID::B);
 				SigSpec S = sigmap(cell->getPort(ID(S)));
 				for (int i = 0; i < GetSize(S); i++)
 				{
@@ -401,7 +401,7 @@ struct Pmux2ShiftxPass : public Pass {
 				}
 
 				SigSpec updated_S = cell->getPort(ID(S));
-				SigSpec updated_B = cell->getPort(ID(B));
+				SigSpec updated_B = cell->getPort(ID::B);
 
 				while (!seldb.empty())
 				{
@@ -728,7 +728,7 @@ struct Pmux2ShiftxPass : public Pass {
 
 				// update $pmux cell
 				cell->setPort(ID(S), updated_S);
-				cell->setPort(ID(B), updated_B);
+				cell->setPort(ID::B, updated_B);
 				cell->setParam(ID(S_WIDTH), GetSize(updated_S));
 			}
 		}
@@ -782,8 +782,8 @@ struct OnehotPass : public Pass {
 				if (cell->type != ID($eq))
 					continue;
 
-				SigSpec A = sigmap(cell->getPort(ID(A)));
-				SigSpec B = sigmap(cell->getPort(ID(B)));
+				SigSpec A = sigmap(cell->getPort(ID::A));
+				SigSpec B = sigmap(cell->getPort(ID::B));
 
 				int a_width = cell->getParam(ID(A_WIDTH)).as_int();
 				int b_width = cell->getParam(ID(B_WIDTH)).as_int();
@@ -830,7 +830,7 @@ struct OnehotPass : public Pass {
 					continue;
 				}
 
-				SigSpec Y = cell->getPort(ID(Y));
+				SigSpec Y = cell->getPort(ID::Y);
 
 				if (not_onehot)
 				{
diff --git a/passes/opt/share.cc b/passes/opt/share.cc
index 84290bb97..92ce3fd11 100644
--- a/passes/opt/share.cc
+++ b/passes/opt/share.cc
@@ -128,7 +128,7 @@ struct ShareWorker
 	static int bits_macc(RTLIL::Cell *c)
 	{
 		Macc m(c);
-		int width = GetSize(c->getPort(ID(Y)));
+		int width = GetSize(c->getPort(ID::Y));
 		return bits_macc(m, width);
 	}
 
@@ -242,7 +242,7 @@ struct ShareWorker
 	{
 		Macc m1(c1), m2(c2), supermacc;
 
-		int w1 = GetSize(c1->getPort(ID(Y))), w2 = GetSize(c2->getPort(ID(Y)));
+		int w1 = GetSize(c1->getPort(ID::Y)), w2 = GetSize(c2->getPort(ID::Y));
 		int width = max(w1, w2);
 
 		m1.optimize(w1);
@@ -328,11 +328,11 @@ struct ShareWorker
 		{
 			RTLIL::SigSpec sig_y = module->addWire(NEW_ID, width);
 
-			supercell_aux->insert(module->addPos(NEW_ID, sig_y, c1->getPort(ID(Y))));
-			supercell_aux->insert(module->addPos(NEW_ID, sig_y, c2->getPort(ID(Y))));
+			supercell_aux->insert(module->addPos(NEW_ID, sig_y, c1->getPort(ID::Y)));
+			supercell_aux->insert(module->addPos(NEW_ID, sig_y, c2->getPort(ID::Y)));
 
 			supercell->setParam(ID(Y_WIDTH), width);
-			supercell->setPort(ID(Y), sig_y);
+			supercell->setPort(ID::Y, sig_y);
 
 			supermacc.optimize(width);
 			supermacc.to_cell(supercell);
@@ -513,11 +513,11 @@ struct ShareWorker
 			if (c1->parameters.at(ID(A_SIGNED)).as_bool() != c2->parameters.at(ID(A_SIGNED)).as_bool())
 			{
 				RTLIL::Cell *unsigned_cell = c1->parameters.at(ID(A_SIGNED)).as_bool() ? c2 : c1;
-				if (unsigned_cell->getPort(ID(A)).to_sigbit_vector().back() != RTLIL::State::S0) {
+				if (unsigned_cell->getPort(ID::A).to_sigbit_vector().back() != RTLIL::State::S0) {
 					unsigned_cell->parameters.at(ID(A_WIDTH)) = unsigned_cell->parameters.at(ID(A_WIDTH)).as_int() + 1;
-					RTLIL::SigSpec new_a = unsigned_cell->getPort(ID(A));
+					RTLIL::SigSpec new_a = unsigned_cell->getPort(ID::A);
 					new_a.append_bit(RTLIL::State::S0);
-					unsigned_cell->setPort(ID(A), new_a);
+					unsigned_cell->setPort(ID::A, new_a);
 				}
 				unsigned_cell->parameters.at(ID(A_SIGNED)) = true;
 				unsigned_cell->check();
@@ -526,11 +526,11 @@ struct ShareWorker
 			bool a_signed = c1->parameters.at(ID(A_SIGNED)).as_bool();
 			log_assert(a_signed == c2->parameters.at(ID(A_SIGNED)).as_bool());
 
-			RTLIL::SigSpec a1 = c1->getPort(ID(A));
-			RTLIL::SigSpec y1 = c1->getPort(ID(Y));
+			RTLIL::SigSpec a1 = c1->getPort(ID::A);
+			RTLIL::SigSpec y1 = c1->getPort(ID::Y);
 
-			RTLIL::SigSpec a2 = c2->getPort(ID(A));
-			RTLIL::SigSpec y2 = c2->getPort(ID(Y));
+			RTLIL::SigSpec a2 = c2->getPort(ID::A);
+			RTLIL::SigSpec y2 = c2->getPort(ID::Y);
 
 			int a_width = max(a1.size(), a2.size());
 			int y_width = max(y1.size(), y2.size());
@@ -547,8 +547,8 @@ struct ShareWorker
 			supercell->parameters[ID(A_SIGNED)] = a_signed;
 			supercell->parameters[ID(A_WIDTH)] = a_width;
 			supercell->parameters[ID(Y_WIDTH)] = y_width;
-			supercell->setPort(ID(A), a);
-			supercell->setPort(ID(Y), y);
+			supercell->setPort(ID::A, a);
+			supercell->setPort(ID::Y, y);
 
 			supercell_aux.insert(module->addPos(NEW_ID, y, y1));
 			supercell_aux.insert(module->addPos(NEW_ID, y, y2));
@@ -571,9 +571,9 @@ struct ShareWorker
 
 				if (score_flipped < score_unflipped)
 				{
-					RTLIL::SigSpec tmp = c2->getPort(ID(A));
-					c2->setPort(ID(A), c2->getPort(ID(B)));
-					c2->setPort(ID(B), tmp);
+					RTLIL::SigSpec tmp = c2->getPort(ID::A);
+					c2->setPort(ID::A, c2->getPort(ID::B));
+					c2->setPort(ID::B, tmp);
 
 					std::swap(c2->parameters.at(ID(A_WIDTH)), c2->parameters.at(ID(B_WIDTH)));
 					std::swap(c2->parameters.at(ID(A_SIGNED)), c2->parameters.at(ID(B_SIGNED)));
@@ -585,11 +585,11 @@ struct ShareWorker
 
 			{
 				RTLIL::Cell *unsigned_cell = c1->parameters.at(ID(A_SIGNED)).as_bool() ? c2 : c1;
-				if (unsigned_cell->getPort(ID(A)).to_sigbit_vector().back() != RTLIL::State::S0) {
+				if (unsigned_cell->getPort(ID::A).to_sigbit_vector().back() != RTLIL::State::S0) {
 					unsigned_cell->parameters.at(ID(A_WIDTH)) = unsigned_cell->parameters.at(ID(A_WIDTH)).as_int() + 1;
-					RTLIL::SigSpec new_a = unsigned_cell->getPort(ID(A));
+					RTLIL::SigSpec new_a = unsigned_cell->getPort(ID::A);
 					new_a.append_bit(RTLIL::State::S0);
-					unsigned_cell->setPort(ID(A), new_a);
+					unsigned_cell->setPort(ID::A, new_a);
 				}
 				unsigned_cell->parameters.at(ID(A_SIGNED)) = true;
 				modified_src_cells = true;
@@ -598,11 +598,11 @@ struct ShareWorker
 			if (c1->parameters.at(ID(B_SIGNED)).as_bool() != c2->parameters.at(ID(B_SIGNED)).as_bool())
 			{
 				RTLIL::Cell *unsigned_cell = c1->parameters.at(ID(B_SIGNED)).as_bool() ? c2 : c1;
-				if (unsigned_cell->getPort(ID(B)).to_sigbit_vector().back() != RTLIL::State::S0) {
+				if (unsigned_cell->getPort(ID::B).to_sigbit_vector().back() != RTLIL::State::S0) {
 					unsigned_cell->parameters.at(ID(B_WIDTH)) = unsigned_cell->parameters.at(ID(B_WIDTH)).as_int() + 1;
-					RTLIL::SigSpec new_b = unsigned_cell->getPort(ID(B));
+					RTLIL::SigSpec new_b = unsigned_cell->getPort(ID::B);
 					new_b.append_bit(RTLIL::State::S0);
-					unsigned_cell->setPort(ID(B), new_b);
+					unsigned_cell->setPort(ID::B, new_b);
 				}
 				unsigned_cell->parameters.at(ID(B_SIGNED)) = true;
 				modified_src_cells = true;
@@ -622,13 +622,13 @@ struct ShareWorker
 			if (c1->type == ID($shl) || c1->type == ID($shr) || c1->type == ID($sshl) || c1->type == ID($sshr))
 				b_signed = false;
 
-			RTLIL::SigSpec a1 = c1->getPort(ID(A));
-			RTLIL::SigSpec b1 = c1->getPort(ID(B));
-			RTLIL::SigSpec y1 = c1->getPort(ID(Y));
+			RTLIL::SigSpec a1 = c1->getPort(ID::A);
+			RTLIL::SigSpec b1 = c1->getPort(ID::B);
+			RTLIL::SigSpec y1 = c1->getPort(ID::Y);
 
-			RTLIL::SigSpec a2 = c2->getPort(ID(A));
-			RTLIL::SigSpec b2 = c2->getPort(ID(B));
-			RTLIL::SigSpec y2 = c2->getPort(ID(Y));
+			RTLIL::SigSpec a2 = c2->getPort(ID::A);
+			RTLIL::SigSpec b2 = c2->getPort(ID::B);
+			RTLIL::SigSpec y2 = c2->getPort(ID::Y);
 
 			int a_width = max(a1.size(), a2.size());
 			int b_width = max(b1.size(), b2.size());
@@ -669,9 +669,9 @@ struct ShareWorker
 			supercell->parameters[ID(A_WIDTH)] = a_width;
 			supercell->parameters[ID(B_WIDTH)] = b_width;
 			supercell->parameters[ID(Y_WIDTH)] = y_width;
-			supercell->setPort(ID(A), a);
-			supercell->setPort(ID(B), b);
-			supercell->setPort(ID(Y), y);
+			supercell->setPort(ID::A, a);
+			supercell->setPort(ID::B, b);
+			supercell->setPort(ID::Y, y);
 			if (c1->type == ID($alu)) {
 				RTLIL::Wire *ci = module->addWire(NEW_ID), *bi = module->addWire(NEW_ID);
 				supercell_aux.insert(module->addMux(NEW_ID, c2->getPort(ID(CI)), c1->getPort(ID(CI)), act, ci));
@@ -874,7 +874,7 @@ struct ShareWorker
 			}
 			for (auto &pbit : modwalker.signal_consumers[bit]) {
 				log_assert(fwd_ct.cell_known(pbit.cell->type));
-				if ((pbit.cell->type == ID($mux) || pbit.cell->type == ID($pmux)) && (pbit.port == ID(A) || pbit.port == ID(B)))
+				if ((pbit.cell->type == ID($mux) || pbit.cell->type == ID($pmux)) && (pbit.port == ID::A || pbit.port == ID::B))
 					driven_data_muxes.insert(pbit.cell);
 				else
 					driven_cells.insert(pbit.cell);
@@ -891,8 +891,8 @@ struct ShareWorker
 			std::set<int> used_in_b_parts;
 
 			int width = c->parameters.at(ID(WIDTH)).as_int();
-			std::vector<RTLIL::SigBit> sig_a = modwalker.sigmap(c->getPort(ID(A)));
-			std::vector<RTLIL::SigBit> sig_b = modwalker.sigmap(c->getPort(ID(B)));
+			std::vector<RTLIL::SigBit> sig_a = modwalker.sigmap(c->getPort(ID::A));
+			std::vector<RTLIL::SigBit> sig_b = modwalker.sigmap(c->getPort(ID::B));
 			std::vector<RTLIL::SigBit> sig_s = modwalker.sigmap(c->getPort(ID(S)));
 
 			for (auto &bit : sig_a)
diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc
index ca0be54d2..792c69c55 100644
--- a/passes/opt/wreduce.cc
+++ b/passes/opt/wreduce.cc
@@ -64,10 +64,10 @@ struct WreduceWorker
 	{
 		// Reduce size of MUX if inputs agree on a value for a bit or a output bit is unused
 
-		SigSpec sig_a = mi.sigmap(cell->getPort(ID(A)));
-		SigSpec sig_b = mi.sigmap(cell->getPort(ID(B)));
+		SigSpec sig_a = mi.sigmap(cell->getPort(ID::A));
+		SigSpec sig_b = mi.sigmap(cell->getPort(ID::B));
 		SigSpec sig_s = mi.sigmap(cell->getPort(ID(S)));
-		SigSpec sig_y = mi.sigmap(cell->getPort(ID(Y)));
+		SigSpec sig_y = mi.sigmap(cell->getPort(ID::Y));
 		std::vector<SigBit> bits_removed;
 
 		if (sig_y.has_const())
@@ -130,9 +130,9 @@ struct WreduceWorker
 		for (auto bit : new_work_queue_bits)
 			work_queue_bits.insert(bit);
 
-		cell->setPort(ID(A), new_sig_a);
-		cell->setPort(ID(B), new_sig_b);
-		cell->setPort(ID(Y), new_sig_y);
+		cell->setPort(ID::A, new_sig_a);
+		cell->setPort(ID::B, new_sig_b);
+		cell->setPort(ID::Y, new_sig_y);
 		cell->fixup_parameters();
 
 		module->connect(sig_y.extract(n_kept, n_removed), sig_removed);
@@ -270,7 +270,7 @@ struct WreduceWorker
 		if (cell->type.in(ID($dff), ID($adff)))
 			return run_cell_dff(cell);
 
-		SigSpec sig = mi.sigmap(cell->getPort(ID(Y)));
+		SigSpec sig = mi.sigmap(cell->getPort(ID::Y));
 
 		if (sig.has_const())
 			return;
@@ -278,8 +278,8 @@ struct WreduceWorker
 
 		// Reduce size of ports A and B based on constant input bits and size of output port
 
-		int max_port_a_size = cell->hasPort(ID(A)) ? GetSize(cell->getPort(ID(A))) : -1;
-		int max_port_b_size = cell->hasPort(ID(B)) ? GetSize(cell->getPort(ID(B))) : -1;
+		int max_port_a_size = cell->hasPort(ID::A) ? GetSize(cell->getPort(ID::A)) : -1;
+		int max_port_b_size = cell->hasPort(ID::B) ? GetSize(cell->getPort(ID::B)) : -1;
 
 		if (cell->type.in(ID($not), ID($pos), ID($neg), ID($and), ID($or), ID($xor), ID($add), ID($sub))) {
 			max_port_a_size = min(max_port_a_size, GetSize(sig));
@@ -295,8 +295,8 @@ struct WreduceWorker
 		if (max_port_b_size >= 0)
 			run_reduce_inport(cell, 'B', max_port_b_size, port_b_signed, did_something);
 
-		if (cell->hasPort(ID(A)) && cell->hasPort(ID(B)) && port_a_signed && port_b_signed) {
-			SigSpec sig_a = mi.sigmap(cell->getPort(ID(A))), sig_b = mi.sigmap(cell->getPort(ID(B)));
+		if (cell->hasPort(ID::A) && cell->hasPort(ID::B) && port_a_signed && port_b_signed) {
+			SigSpec sig_a = mi.sigmap(cell->getPort(ID::A)), sig_b = mi.sigmap(cell->getPort(ID::B));
 			if (GetSize(sig_a) > 0 && sig_a[GetSize(sig_a)-1] == State::S0 &&
 					GetSize(sig_b) > 0 && sig_b[GetSize(sig_b)-1] == State::S0) {
 				log("Converting cell %s.%s (%s) from signed to unsigned.\n",
@@ -309,8 +309,8 @@ struct WreduceWorker
 			}
 		}
 
-		if (cell->hasPort(ID(A)) && !cell->hasPort(ID(B)) && port_a_signed) {
-			SigSpec sig_a = mi.sigmap(cell->getPort(ID(A)));
+		if (cell->hasPort(ID::A) && !cell->hasPort(ID::B) && port_a_signed) {
+			SigSpec sig_a = mi.sigmap(cell->getPort(ID::A));
 			if (GetSize(sig_a) > 0 && sig_a[GetSize(sig_a)-1] == State::S0) {
 				log("Converting cell %s.%s (%s) from signed to unsigned.\n",
 						log_id(module), log_id(cell), log_id(cell->type));
@@ -347,8 +347,8 @@ struct WreduceWorker
 			bool is_signed = cell->getParam(ID(A_SIGNED)).as_bool() || cell->type == ID($sub);
 
 			int a_size = 0, b_size = 0;
-			if (cell->hasPort(ID(A))) a_size = GetSize(cell->getPort(ID(A)));
-			if (cell->hasPort(ID(B))) b_size = GetSize(cell->getPort(ID(B)));
+			if (cell->hasPort(ID::A)) a_size = GetSize(cell->getPort(ID::A));
+			if (cell->hasPort(ID::B)) b_size = GetSize(cell->getPort(ID::B));
 
 			int max_y_size = max(a_size, b_size);
 
@@ -374,7 +374,7 @@ struct WreduceWorker
 		if (bits_removed) {
 			log("Removed top %d bits (of %d) from port Y of cell %s.%s (%s).\n",
 					bits_removed, GetSize(sig) + bits_removed, log_id(module), log_id(cell), log_id(cell->type));
-			cell->setPort(ID(Y), sig);
+			cell->setPort(ID::Y, sig);
 			did_something = true;
 		}
 
@@ -530,10 +530,10 @@ struct WreducePass : public Pass {
 			{
 				if (c->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool),
 						ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt),
-						ID($logic_not), ID($logic_and), ID($logic_or)) && GetSize(c->getPort(ID(Y))) > 1) {
-					SigSpec sig = c->getPort(ID(Y));
+						ID($logic_not), ID($logic_and), ID($logic_or)) && GetSize(c->getPort(ID::Y)) > 1) {
+					SigSpec sig = c->getPort(ID::Y);
 					if (!sig.has_const()) {
-						c->setPort(ID(Y), sig[0]);
+						c->setPort(ID::Y, sig[0]);
 						c->setParam(ID(Y_WIDTH), 1);
 						sig.remove(0);
 						module->connect(sig, Const(0, GetSize(sig)));
@@ -542,7 +542,7 @@ struct WreducePass : public Pass {
 
 				if (c->type.in(ID($div), ID($mod), ID($pow)))
 				{
-					SigSpec A = c->getPort(ID(A));
+					SigSpec A = c->getPort(ID::A);
 					int original_a_width = GetSize(A);
 					if (c->getParam(ID(A_SIGNED)).as_bool()) {
 						while (GetSize(A) > 1 && A[GetSize(A)-1] == State::S0 && A[GetSize(A)-2] == State::S0)
@@ -554,11 +554,11 @@ struct WreducePass : public Pass {
 					if (original_a_width != GetSize(A)) {
 						log("Removed top %d bits (of %d) from port A of cell %s.%s (%s).\n",
 								original_a_width-GetSize(A), original_a_width, log_id(module), log_id(c), log_id(c->type));
-						c->setPort(ID(A), A);
+						c->setPort(ID::A, A);
 						c->setParam(ID(A_WIDTH), GetSize(A));
 					}
 
-					SigSpec B = c->getPort(ID(B));
+					SigSpec B = c->getPort(ID::B);
 					int original_b_width = GetSize(B);
 					if (c->getParam(ID(B_SIGNED)).as_bool()) {
 						while (GetSize(B) > 1 && B[GetSize(B)-1] == State::S0 && B[GetSize(B)-2] == State::S0)
@@ -570,7 +570,7 @@ struct WreducePass : public Pass {
 					if (original_b_width != GetSize(B)) {
 						log("Removed top %d bits (of %d) from port B of cell %s.%s (%s).\n",
 								original_b_width-GetSize(B), original_b_width, log_id(module), log_id(c), log_id(c->type));
-						c->setPort(ID(B), B);
+						c->setPort(ID::B, B);
 						c->setParam(ID(B_WIDTH), GetSize(B));
 					}
 				}
diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc
index 20ebc73c8..205f05ab9 100644
--- a/passes/techmap/abc.cc
+++ b/passes/techmap/abc.cc
@@ -211,8 +211,8 @@ void extract_cell(RTLIL::Cell *cell, bool keepff)
 
 	if (cell->type.in(ID($_BUF_), ID($_NOT_)))
 	{
-		RTLIL::SigSpec sig_a = cell->getPort(ID(A));
-		RTLIL::SigSpec sig_y = cell->getPort(ID(Y));
+		RTLIL::SigSpec sig_a = cell->getPort(ID::A);
+		RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
 
 		assign_map.apply(sig_a);
 		assign_map.apply(sig_y);
@@ -225,9 +225,9 @@ void extract_cell(RTLIL::Cell *cell, bool keepff)
 
 	if (cell->type.in(ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_), ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_)))
 	{
-		RTLIL::SigSpec sig_a = cell->getPort(ID(A));
-		RTLIL::SigSpec sig_b = cell->getPort(ID(B));
-		RTLIL::SigSpec sig_y = cell->getPort(ID(Y));
+		RTLIL::SigSpec sig_a = cell->getPort(ID::A);
+		RTLIL::SigSpec sig_b = cell->getPort(ID::B);
+		RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
 
 		assign_map.apply(sig_a);
 		assign_map.apply(sig_b);
@@ -261,10 +261,10 @@ void extract_cell(RTLIL::Cell *cell, bool keepff)
 
 	if (cell->type.in(ID($_MUX_), ID($_NMUX_)))
 	{
-		RTLIL::SigSpec sig_a = cell->getPort(ID(A));
-		RTLIL::SigSpec sig_b = cell->getPort(ID(B));
+		RTLIL::SigSpec sig_a = cell->getPort(ID::A);
+		RTLIL::SigSpec sig_b = cell->getPort(ID::B);
 		RTLIL::SigSpec sig_s = cell->getPort(ID(S));
-		RTLIL::SigSpec sig_y = cell->getPort(ID(Y));
+		RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
 
 		assign_map.apply(sig_a);
 		assign_map.apply(sig_b);
@@ -283,10 +283,10 @@ void extract_cell(RTLIL::Cell *cell, bool keepff)
 
 	if (cell->type.in(ID($_AOI3_), ID($_OAI3_)))
 	{
-		RTLIL::SigSpec sig_a = cell->getPort(ID(A));
-		RTLIL::SigSpec sig_b = cell->getPort(ID(B));
+		RTLIL::SigSpec sig_a = cell->getPort(ID::A);
+		RTLIL::SigSpec sig_b = cell->getPort(ID::B);
 		RTLIL::SigSpec sig_c = cell->getPort(ID(C));
-		RTLIL::SigSpec sig_y = cell->getPort(ID(Y));
+		RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
 
 		assign_map.apply(sig_a);
 		assign_map.apply(sig_b);
@@ -305,11 +305,11 @@ void extract_cell(RTLIL::Cell *cell, bool keepff)
 
 	if (cell->type.in(ID($_AOI4_), ID($_OAI4_)))
 	{
-		RTLIL::SigSpec sig_a = cell->getPort(ID(A));
-		RTLIL::SigSpec sig_b = cell->getPort(ID(B));
+		RTLIL::SigSpec sig_a = cell->getPort(ID::A);
+		RTLIL::SigSpec sig_b = cell->getPort(ID::B);
 		RTLIL::SigSpec sig_c = cell->getPort(ID(C));
 		RTLIL::SigSpec sig_d = cell->getPort(ID(D));
-		RTLIL::SigSpec sig_y = cell->getPort(ID(Y));
+		RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
 
 		assign_map.apply(sig_a);
 		assign_map.apply(sig_b);
@@ -1042,63 +1042,63 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
 				cell_stats[RTLIL::unescape_id(c->type)]++;
 				if (c->type.in(ID(ZERO), ID(ONE))) {
 					RTLIL::SigSig conn;
-					conn.first = RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(Y)).as_wire()->name)]);
+					conn.first = RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]);
 					conn.second = RTLIL::SigSpec(c->type == ID(ZERO) ? 0 : 1, 1);
 					module->connect(conn);
 					continue;
 				}
 				if (c->type == ID(BUF)) {
 					RTLIL::SigSig conn;
-					conn.first = RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(Y)).as_wire()->name)]);
-					conn.second = RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(A)).as_wire()->name)]);
+					conn.first = RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]);
+					conn.second = RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)]);
 					module->connect(conn);
 					continue;
 				}
 				if (c->type == ID(NOT)) {
 					RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_NOT_));
 					if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx;
-					cell->setPort(ID(A), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(A)).as_wire()->name)]));
-					cell->setPort(ID(Y), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(Y)).as_wire()->name)]));
+					cell->setPort(ID::A, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)]));
+					cell->setPort(ID::Y, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]));
 					design->select(module, cell);
 					continue;
 				}
 				if (c->type.in(ID(AND), ID(OR), ID(XOR), ID(NAND), ID(NOR), ID(XNOR), ID(ANDNOT), ID(ORNOT))) {
 					RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1));
 					if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx;
-					cell->setPort(ID(A), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(A)).as_wire()->name)]));
-					cell->setPort(ID(B), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(B)).as_wire()->name)]));
-					cell->setPort(ID(Y), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(Y)).as_wire()->name)]));
+					cell->setPort(ID::A, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)]));
+					cell->setPort(ID::B, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::B).as_wire()->name)]));
+					cell->setPort(ID::Y, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]));
 					design->select(module, cell);
 					continue;
 				}
 				if (c->type.in(ID(MUX), ID(NMUX))) {
 					RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1));
 					if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx;
-					cell->setPort(ID(A), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(A)).as_wire()->name)]));
-					cell->setPort(ID(B), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(B)).as_wire()->name)]));
+					cell->setPort(ID::A, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)]));
+					cell->setPort(ID::B, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::B).as_wire()->name)]));
 					cell->setPort(ID(S), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(S)).as_wire()->name)]));
-					cell->setPort(ID(Y), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(Y)).as_wire()->name)]));
+					cell->setPort(ID::Y, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]));
 					design->select(module, cell);
 					continue;
 				}
 				if (c->type == ID(MUX4)) {
 					RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_MUX4_));
 					if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx;
-					cell->setPort(ID(A), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(A)).as_wire()->name)]));
-					cell->setPort(ID(B), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(B)).as_wire()->name)]));
+					cell->setPort(ID::A, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)]));
+					cell->setPort(ID::B, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::B).as_wire()->name)]));
 					cell->setPort(ID(C), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(C)).as_wire()->name)]));
 					cell->setPort(ID(D), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(D)).as_wire()->name)]));
 					cell->setPort(ID(S), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(S)).as_wire()->name)]));
 					cell->setPort(ID(T), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(T)).as_wire()->name)]));
-					cell->setPort(ID(Y), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(Y)).as_wire()->name)]));
+					cell->setPort(ID::Y, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]));
 					design->select(module, cell);
 					continue;
 				}
 				if (c->type == ID(MUX8)) {
 					RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_MUX8_));
 					if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx;
-					cell->setPort(ID(A), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(A)).as_wire()->name)]));
-					cell->setPort(ID(B), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(B)).as_wire()->name)]));
+					cell->setPort(ID::A, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)]));
+					cell->setPort(ID::B, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::B).as_wire()->name)]));
 					cell->setPort(ID(C), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(C)).as_wire()->name)]));
 					cell->setPort(ID(D), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(D)).as_wire()->name)]));
 					cell->setPort(ID(E), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(E)).as_wire()->name)]));
@@ -1108,15 +1108,15 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
 					cell->setPort(ID(S), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(S)).as_wire()->name)]));
 					cell->setPort(ID(T), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(T)).as_wire()->name)]));
 					cell->setPort(ID(U), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(U)).as_wire()->name)]));
-					cell->setPort(ID(Y), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(Y)).as_wire()->name)]));
+					cell->setPort(ID::Y, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]));
 					design->select(module, cell);
 					continue;
 				}
 				if (c->type == ID(MUX16)) {
 					RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_MUX16_));
 					if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx;
-					cell->setPort(ID(A), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(A)).as_wire()->name)]));
-					cell->setPort(ID(B), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(B)).as_wire()->name)]));
+					cell->setPort(ID::A, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)]));
+					cell->setPort(ID::B, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::B).as_wire()->name)]));
 					cell->setPort(ID(C), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(C)).as_wire()->name)]));
 					cell->setPort(ID(D), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(D)).as_wire()->name)]));
 					cell->setPort(ID(E), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(E)).as_wire()->name)]));
@@ -1135,28 +1135,28 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
 					cell->setPort(ID(T), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(T)).as_wire()->name)]));
 					cell->setPort(ID(U), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(U)).as_wire()->name)]));
 					cell->setPort(ID(V), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(V)).as_wire()->name)]));
-					cell->setPort(ID(Y), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(Y)).as_wire()->name)]));
+					cell->setPort(ID::Y, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]));
 					design->select(module, cell);
 					continue;
 				}
 				if (c->type.in(ID(AOI3), ID(OAI3))) {
 					RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1));
 					if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx;
-					cell->setPort(ID(A), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(A)).as_wire()->name)]));
-					cell->setPort(ID(B), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(B)).as_wire()->name)]));
+					cell->setPort(ID::A, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)]));
+					cell->setPort(ID::B, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::B).as_wire()->name)]));
 					cell->setPort(ID(C), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(C)).as_wire()->name)]));
-					cell->setPort(ID(Y), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(Y)).as_wire()->name)]));
+					cell->setPort(ID::Y, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]));
 					design->select(module, cell);
 					continue;
 				}
 				if (c->type.in(ID(AOI4), ID(OAI4))) {
 					RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1));
 					if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx;
-					cell->setPort(ID(A), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(A)).as_wire()->name)]));
-					cell->setPort(ID(B), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(B)).as_wire()->name)]));
+					cell->setPort(ID::A, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)]));
+					cell->setPort(ID::B, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::B).as_wire()->name)]));
 					cell->setPort(ID(C), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(C)).as_wire()->name)]));
 					cell->setPort(ID(D), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(D)).as_wire()->name)]));
-					cell->setPort(ID(Y), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(Y)).as_wire()->name)]));
+					cell->setPort(ID::Y, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]));
 					design->select(module, cell);
 					continue;
 				}
@@ -1207,9 +1207,9 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
 				continue;
 			}
 
-			if (c->type == ID($lut) && GetSize(c->getPort(ID(A))) == 1 && c->getParam(ID(LUT)).as_int() == 2) {
-				SigSpec my_a = module->wires_[remap_name(c->getPort(ID(A)).as_wire()->name)];
-				SigSpec my_y = module->wires_[remap_name(c->getPort(ID(Y)).as_wire()->name)];
+			if (c->type == ID($lut) && GetSize(c->getPort(ID::A)) == 1 && c->getParam(ID(LUT)).as_int() == 2) {
+				SigSpec my_a = module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)];
+				SigSpec my_y = module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)];
 				module->connect(my_y, my_a);
 				continue;
 			}
diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc
index 752535f34..b3de7cdc5 100644
--- a/passes/techmap/abc9.cc
+++ b/passes/techmap/abc9.cc
@@ -582,13 +582,13 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
 
 			RTLIL::Cell *cell = nullptr;
 			if (c->type == ID($_NOT_)) {
-				RTLIL::SigBit a_bit = c->getPort(ID(A));
-				RTLIL::SigBit y_bit = c->getPort(ID(Y));
+				RTLIL::SigBit a_bit = c->getPort(ID::A);
+				RTLIL::SigBit y_bit = c->getPort(ID::Y);
 				bit_users[a_bit].insert(c->name);
 				bit_drivers[y_bit].insert(c->name);
 
 				if (!a_bit.wire) {
-					c->setPort(ID(Y), module->addWire(NEW_ID));
+					c->setPort(ID::Y, module->addWire(NEW_ID));
 					RTLIL::Wire *wire = module->wire(remap_name(y_bit.wire->name));
 					log_assert(wire);
 					module->connect(RTLIL::SigBit(wire, y_bit.offset), State::S1);
@@ -616,7 +616,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
 								RTLIL::SigBit(module->wires_.at(remap_name(a_bit.wire->name)), a_bit.offset),
 								RTLIL::SigBit(module->wires_.at(remap_name(y_bit.wire->name)), y_bit.offset),
 								RTLIL::Const::from_string("01"));
-						bit2sinks[cell->getPort(ID(A))].push_back(cell);
+						bit2sinks[cell->getPort(ID::A)].push_back(cell);
 						cell_stats[ID($lut)]++;
 					}
 					else
@@ -632,9 +632,9 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
 
 			RTLIL::Cell *existing_cell = nullptr;
 			if (c->type == ID($lut)) {
-				if (GetSize(c->getPort(ID(A))) == 1 && c->getParam(ID(LUT)) == RTLIL::Const::from_string("01")) {
-					SigSpec my_a = module->wires_.at(remap_name(c->getPort(ID(A)).as_wire()->name));
-					SigSpec my_y = module->wires_.at(remap_name(c->getPort(ID(Y)).as_wire()->name));
+				if (GetSize(c->getPort(ID::A)) == 1 && c->getParam(ID(LUT)) == RTLIL::Const::from_string("01")) {
+					SigSpec my_a = module->wires_.at(remap_name(c->getPort(ID::A).as_wire()->name));
+					SigSpec my_y = module->wires_.at(remap_name(c->getPort(ID::Y).as_wire()->name));
 					module->connect(my_y, my_a);
 					if (markgroups) c->attributes[ID(abcgroup)] = map_autoidx;
 					log_abort();
@@ -751,8 +751,8 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
 			if (it == not2drivers.end())
 				continue;
 			RTLIL::Cell *driver_lut = it->second;
-			RTLIL::SigBit a_bit = not_cell->getPort(ID(A));
-			RTLIL::SigBit y_bit = not_cell->getPort(ID(Y));
+			RTLIL::SigBit a_bit = not_cell->getPort(ID::A);
+			RTLIL::SigBit y_bit = not_cell->getPort(ID::Y);
 			RTLIL::Const driver_mask;
 
 			a_bit.wire = module->wires_.at(remap_name(a_bit.wire->name));
@@ -768,7 +768,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
 
 			// Push downstream LUTs past inverter
 			for (auto sink_cell : jt->second) {
-				SigSpec A = sink_cell->getPort(ID(A));
+				SigSpec A = sink_cell->getPort(ID::A);
 				RTLIL::Const mask = sink_cell->getParam(ID(LUT));
 				int index = 0;
 				for (; index < GetSize(A); index++)
@@ -782,7 +782,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
 					i += 1 << (index+1);
 				}
 				A[index] = y_bit;
-				sink_cell->setPort(ID(A), A);
+				sink_cell->setPort(ID::A, A);
 				sink_cell->setParam(ID(LUT), mask);
 			}
 
@@ -798,10 +798,10 @@ clone_lut:
 				else if (b == RTLIL::State::S1) b = RTLIL::State::S0;
 			}
 			auto cell = module->addLut(NEW_ID,
-					driver_lut->getPort(ID(A)),
+					driver_lut->getPort(ID::A),
 					y_bit,
 					driver_mask);
-			for (auto &bit : cell->connections_.at(ID(A))) {
+			for (auto &bit : cell->connections_.at(ID::A)) {
 				bit.wire = module->wires_.at(remap_name(bit.wire->name));
 				bit2sinks[bit].push_back(cell);
 			}
diff --git a/passes/techmap/alumacc.cc b/passes/techmap/alumacc.cc
index 58ed47ccf..5b168d524 100644
--- a/passes/techmap/alumacc.cc
+++ b/passes/techmap/alumacc.cc
@@ -91,7 +91,7 @@ struct AlumaccWorker
 
 		RTLIL::SigSpec get_sf() {
 			if (GetSize(cached_sf) == 0) {
-				cached_sf = alu_cell->getPort(ID(Y));
+				cached_sf = alu_cell->getPort(ID::Y);
 				cached_sf = cached_sf[GetSize(cached_sf)-1];
 			}
 			return cached_sf;
@@ -134,7 +134,7 @@ struct AlumaccWorker
 			Macc::port_t new_port;
 
 			n->cell = cell;
-			n->y = sigmap(cell->getPort(ID(Y)));
+			n->y = sigmap(cell->getPort(ID::Y));
 			n->users = 0;
 
 			for (auto bit : n->y)
@@ -142,7 +142,7 @@ struct AlumaccWorker
 
 			if (cell->type.in(ID($pos), ID($neg)))
 			{
-				new_port.in_a = sigmap(cell->getPort(ID(A)));
+				new_port.in_a = sigmap(cell->getPort(ID::A));
 				new_port.is_signed = cell->getParam(ID(A_SIGNED)).as_bool();
 				new_port.do_subtract = cell->type == ID($neg);
 				n->macc.ports.push_back(new_port);
@@ -150,12 +150,12 @@ struct AlumaccWorker
 
 			if (cell->type.in(ID($add), ID($sub)))
 			{
-				new_port.in_a = sigmap(cell->getPort(ID(A)));
+				new_port.in_a = sigmap(cell->getPort(ID::A));
 				new_port.is_signed = cell->getParam(ID(A_SIGNED)).as_bool();
 				new_port.do_subtract = false;
 				n->macc.ports.push_back(new_port);
 
-				new_port.in_a = sigmap(cell->getPort(ID(B)));
+				new_port.in_a = sigmap(cell->getPort(ID::B));
 				new_port.is_signed = cell->getParam(ID(B_SIGNED)).as_bool();
 				new_port.do_subtract = cell->type == ID($sub);
 				n->macc.ports.push_back(new_port);
@@ -163,8 +163,8 @@ struct AlumaccWorker
 
 			if (cell->type.in(ID($mul)))
 			{
-				new_port.in_a = sigmap(cell->getPort(ID(A)));
-				new_port.in_b = sigmap(cell->getPort(ID(B)));
+				new_port.in_a = sigmap(cell->getPort(ID::A));
+				new_port.in_b = sigmap(cell->getPort(ID::B));
 				new_port.is_signed = cell->getParam(ID(A_SIGNED)).as_bool();
 				new_port.do_subtract = false;
 				n->macc.ports.push_back(new_port);
@@ -361,7 +361,7 @@ struct AlumaccWorker
 
 			n->macc.optimize(GetSize(n->y));
 			n->macc.to_cell(cell);
-			cell->setPort(ID(Y), n->y);
+			cell->setPort(ID::Y, n->y);
 			cell->fixup_parameters();
 			module->remove(n->cell);
 			delete n;
@@ -390,9 +390,9 @@ struct AlumaccWorker
 			bool cmp_equal = cell->type.in(ID($le), ID($ge));
 			bool is_signed = cell->getParam(ID(A_SIGNED)).as_bool();
 
-			RTLIL::SigSpec A = sigmap(cell->getPort(ID(A)));
-			RTLIL::SigSpec B = sigmap(cell->getPort(ID(B)));
-			RTLIL::SigSpec Y = sigmap(cell->getPort(ID(Y)));
+			RTLIL::SigSpec A = sigmap(cell->getPort(ID::A));
+			RTLIL::SigSpec B = sigmap(cell->getPort(ID::B));
+			RTLIL::SigSpec Y = sigmap(cell->getPort(ID::Y));
 
 			if (B < A && GetSize(B)) {
 				cmp_less = !cmp_less;
@@ -430,9 +430,9 @@ struct AlumaccWorker
 			bool cmp_equal = cell->type.in(ID($eq), ID($eqx));
 			bool is_signed = cell->getParam(ID(A_SIGNED)).as_bool();
 
-			RTLIL::SigSpec A = sigmap(cell->getPort(ID(A)));
-			RTLIL::SigSpec B = sigmap(cell->getPort(ID(B)));
-			RTLIL::SigSpec Y = sigmap(cell->getPort(ID(Y)));
+			RTLIL::SigSpec A = sigmap(cell->getPort(ID::A));
+			RTLIL::SigSpec B = sigmap(cell->getPort(ID::B));
+			RTLIL::SigSpec Y = sigmap(cell->getPort(ID::Y));
 
 			if (B < A && GetSize(B))
 				std::swap(A, B);
@@ -482,11 +482,11 @@ struct AlumaccWorker
 			if (n->cells.size() > 0)
 				n->alu_cell->set_src_attribute(n->cells[0]->get_src_attribute());
 
-			n->alu_cell->setPort(ID(A), n->a);
-			n->alu_cell->setPort(ID(B), n->b);
+			n->alu_cell->setPort(ID::A, n->a);
+			n->alu_cell->setPort(ID::B, n->b);
 			n->alu_cell->setPort(ID(CI), GetSize(n->c) ? n->c : State::S0);
 			n->alu_cell->setPort(ID(BI), n->invert_b ? State::S1 : State::S0);
-			n->alu_cell->setPort(ID(Y), n->y);
+			n->alu_cell->setPort(ID::Y, n->y);
 			n->alu_cell->setPort(ID(X), module->addWire(NEW_ID, GetSize(n->y)));
 			n->alu_cell->setPort(ID(CO), module->addWire(NEW_ID, GetSize(n->y)));
 			n->alu_cell->fixup_parameters(n->is_signed, n->is_signed);
diff --git a/passes/techmap/deminout.cc b/passes/techmap/deminout.cc
index 585732e6b..b976b401b 100644
--- a/passes/techmap/deminout.cc
+++ b/passes/techmap/deminout.cc
@@ -83,13 +83,13 @@ struct DeminoutPass : public Pass {
 						for (auto bit : sigmap(conn.second))
 							bits_used.insert(bit);
 
-					if (conn.first == ID(Y) && cell->type.in(ID($mux), ID($pmux), ID($_MUX_), ID($_TBUF_), ID($tribuf)))
+					if (conn.first == ID::Y && cell->type.in(ID($mux), ID($pmux), ID($_MUX_), ID($_TBUF_), ID($tribuf)))
 					{
 						bool tribuf = cell->type.in(ID($_TBUF_), ID($tribuf));
 
 						if (!tribuf) {
 							for (auto &c : cell->connections()) {
-								if (!c.first.in(ID(A), ID(B)))
+								if (!c.first.in(ID::A, ID::B))
 									continue;
 								for (auto b : sigmap(c.second))
 									if (b == State::Sz)
diff --git a/passes/techmap/dff2dffe.cc b/passes/techmap/dff2dffe.cc
index 24760420a..e766f2cf6 100644
--- a/passes/techmap/dff2dffe.cc
+++ b/passes/techmap/dff2dffe.cc
@@ -53,7 +53,7 @@ struct Dff2dffeWorker
 
 		for (auto cell : module->cells()) {
 			if (cell->type.in(ID($mux), ID($pmux), ID($_MUX_))) {
-				RTLIL::SigSpec sig_y = sigmap(cell->getPort(ID(Y)));
+				RTLIL::SigSpec sig_y = sigmap(cell->getPort(ID::Y));
 				for (int i = 0; i < GetSize(sig_y); i++)
 					bit2mux[sig_y[i]] = cell_int_t(cell, i);
 			}
@@ -86,8 +86,8 @@ struct Dff2dffeWorker
 			return ret;
 
 		cell_int_t mux_cell_int = bit2mux.at(d);
-		RTLIL::SigSpec sig_a = sigmap(mux_cell_int.first->getPort(ID(A)));
-		RTLIL::SigSpec sig_b = sigmap(mux_cell_int.first->getPort(ID(B)));
+		RTLIL::SigSpec sig_a = sigmap(mux_cell_int.first->getPort(ID::A));
+		RTLIL::SigSpec sig_b = sigmap(mux_cell_int.first->getPort(ID::B));
 		RTLIL::SigSpec sig_s = sigmap(mux_cell_int.first->getPort(ID(S)));
 		int width = GetSize(sig_a), index = mux_cell_int.second;
 
@@ -97,9 +97,9 @@ struct Dff2dffeWorker
 				ret = find_muxtree_feedback_patterns(sig_b[i*width + index], q, path);
 
 				if (sig_b[i*width + index] == q) {
-					RTLIL::SigSpec s = mux_cell_int.first->getPort(ID(B));
+					RTLIL::SigSpec s = mux_cell_int.first->getPort(ID::B);
 					s[i*width + index] = RTLIL::Sx;
-					mux_cell_int.first->setPort(ID(B), s);
+					mux_cell_int.first->setPort(ID::B, s);
 				}
 
 				return ret;
@@ -120,9 +120,9 @@ struct Dff2dffeWorker
 				ret.insert(pat);
 
 			if (sig_b[i*width + index] == q) {
-				RTLIL::SigSpec s = mux_cell_int.first->getPort(ID(B));
+				RTLIL::SigSpec s = mux_cell_int.first->getPort(ID::B);
 				s[i*width + index] = RTLIL::Sx;
-				mux_cell_int.first->setPort(ID(B), s);
+				mux_cell_int.first->setPort(ID::B, s);
 			}
 		}
 
@@ -130,9 +130,9 @@ struct Dff2dffeWorker
 			ret.insert(pat);
 
 		if (sig_a[index] == q) {
-			RTLIL::SigSpec s = mux_cell_int.first->getPort(ID(A));
+			RTLIL::SigSpec s = mux_cell_int.first->getPort(ID::A);
 			s[index] = RTLIL::Sx;
-			mux_cell_int.first->setPort(ID(A), s);
+			mux_cell_int.first->setPort(ID::A, s);
 		}
 
 		return ret;
diff --git a/passes/techmap/dff2dffs.cc b/passes/techmap/dff2dffs.cc
index f74001b77..0ea033513 100644
--- a/passes/techmap/dff2dffs.cc
+++ b/passes/techmap/dff2dffs.cc
@@ -72,11 +72,11 @@ struct Dff2dffsPass : public Pass {
 				if (cell->type != ID($_MUX_))
 					continue;
 
-				SigBit bit_a = sigmap(cell->getPort(ID(A)));
-				SigBit bit_b = sigmap(cell->getPort(ID(B)));
+				SigBit bit_a = sigmap(cell->getPort(ID::A));
+				SigBit bit_b = sigmap(cell->getPort(ID::B));
 
 				if (bit_a.wire == nullptr || bit_b.wire == nullptr)
-					sr_muxes[sigmap(cell->getPort(ID(Y)))] = cell;
+					sr_muxes[sigmap(cell->getPort(ID::Y))] = cell;
 			}
 
 			for (auto cell : ff_cells)
@@ -92,8 +92,8 @@ struct Dff2dffsPass : public Pass {
 					continue;
 
 				Cell *mux_cell = sr_muxes.at(bit_d);
-				SigBit bit_a = sigmap(mux_cell->getPort(ID(A)));
-				SigBit bit_b = sigmap(mux_cell->getPort(ID(B)));
+				SigBit bit_a = sigmap(mux_cell->getPort(ID::A));
+				SigBit bit_b = sigmap(mux_cell->getPort(ID::B));
 				SigBit bit_s = sigmap(mux_cell->getPort(ID(S)));
 
 				log("  Merging %s (A=%s, B=%s, S=%s) into %s (%s).\n", log_id(mux_cell),
diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc
index c62224f9d..8a378068e 100644
--- a/passes/techmap/dfflibmap.cc
+++ b/passes/techmap/dfflibmap.cc
@@ -485,7 +485,7 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare
 		if (design->selected(module, it.second) && cell_mappings.count(it.second->type) > 0)
 			cell_list.push_back(it.second);
 		if (it.second->type == ID($_NOT_))
-			notmap[sigmap(it.second->getPort(ID(A)))].insert(it.second);
+			notmap[sigmap(it.second->getPort(ID::A))].insert(it.second);
 	}
 
 	std::map<std::string, int> stats;
@@ -519,8 +519,8 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare
 				sig = module->addWire(NEW_ID, GetSize(old_sig));
 				if (has_q && has_qn) {
 					for (auto &it : notmap[sigmap(old_sig)]) {
-						module->connect(it->getPort(ID(Y)), sig);
-						it->setPort(ID(Y), module->addWire(NEW_ID, GetSize(old_sig)));
+						module->connect(it->getPort(ID::Y), sig);
+						it->setPort(ID::Y, module->addWire(NEW_ID, GetSize(old_sig)));
 					}
 				} else {
 					module->addNotGate(NEW_ID, sig, old_sig);
diff --git a/passes/techmap/extract_counter.cc b/passes/techmap/extract_counter.cc
index 2e50bb7b3..17a99493d 100644
--- a/passes/techmap/extract_counter.cc
+++ b/passes/techmap/extract_counter.cc
@@ -138,7 +138,7 @@ int counter_tryextract(
 
 	//To be a counter, one input of the ALU must be a constant 1
 	//TODO: can A or B be swapped in synthesized RTL or is B always the 1?
-	const RTLIL::SigSpec b_port = sigmap(cell->getPort(ID(B)));
+	const RTLIL::SigSpec b_port = sigmap(cell->getPort(ID::B));
 	if(!b_port.is_fully_const() || (b_port.as_int() != 1) )
 		return 4;
 
@@ -158,7 +158,7 @@ int counter_tryextract(
 
 	//Y must have exactly one connection, and it has to be a $mux cell.
 	//We must have a direct bus connection from our Y to their A.
-	const RTLIL::SigSpec aluy = sigmap(cell->getPort(ID(Y)));
+	const RTLIL::SigSpec aluy = sigmap(cell->getPort(ID::Y));
 	pool<Cell*> y_loads = get_other_cells(aluy, index, cell);
 	if(y_loads.size() != 1)
 		return 9;
@@ -166,11 +166,11 @@ int counter_tryextract(
 	extract.count_mux = count_mux;
 	if(count_mux->type != ID($mux))
 		return 10;
-	if(!is_full_bus(aluy, index, cell, ID(Y), count_mux, ID(A)))
+	if(!is_full_bus(aluy, index, cell, ID::Y, count_mux, ID::A))
 		return 11;
 
 	//B connection of the mux is our underflow value
-	const RTLIL::SigSpec underflow = sigmap(count_mux->getPort(ID(B)));
+	const RTLIL::SigSpec underflow = sigmap(count_mux->getPort(ID::B));
 	if(!underflow.is_fully_const())
 		return 12;
 	extract.count_value = underflow.as_int();
@@ -184,7 +184,7 @@ int counter_tryextract(
 	{
 		if(c->type != ID($logic_not))
 			continue;
-		if(!is_full_bus(muxsel, index, c, ID(Y), count_mux, ID(S), true))
+		if(!is_full_bus(muxsel, index, c, ID::Y, count_mux, ID(S), true))
 			continue;
 
 		underflow_inv = c;
@@ -196,7 +196,7 @@ int counter_tryextract(
 
 	//Y connection of the mux must have exactly one load, the counter's internal register, if there's no clock enable
 	//If we have a clock enable, Y drives the B input of a mux. A of that mux must come from our register
-	const RTLIL::SigSpec muxy = sigmap(count_mux->getPort(ID(Y)));
+	const RTLIL::SigSpec muxy = sigmap(count_mux->getPort(ID::Y));
 	pool<Cell*> muxy_loads = get_other_cells(muxy, index, count_mux);
 	if(muxy_loads.size() != 1)
 		return 14;
@@ -209,7 +209,7 @@ int counter_tryextract(
 		//This mux is probably a clock enable mux.
 		//Find our count register (should be our only load)
 		cemux = muxload;
-		cey = sigmap(cemux->getPort(ID(Y)));
+		cey = sigmap(cemux->getPort(ID::Y));
 		pool<Cell*> cey_loads = get_other_cells(cey, index, cemux);
 		if(cey_loads.size() != 1)
 			return 24;
@@ -217,11 +217,11 @@ int counter_tryextract(
 
 		//Mux should have A driven by count Q, and B by muxy
 		//TODO: if A and B are swapped, CE polarity is inverted
-		if(sigmap(cemux->getPort(ID(B))) != muxy)
+		if(sigmap(cemux->getPort(ID::B)) != muxy)
 			return 24;
-		if(sigmap(cemux->getPort(ID(A))) != sigmap(count_reg->getPort(ID(Q))))
+		if(sigmap(cemux->getPort(ID::A)) != sigmap(count_reg->getPort(ID(Q))))
 			return 24;
-		if(sigmap(cemux->getPort(ID(Y))) != sigmap(count_reg->getPort(ID(D))))
+		if(sigmap(cemux->getPort(ID::Y)) != sigmap(count_reg->getPort(ID(D))))
 			return 24;
 
 		//Select of the mux is our clock enable
@@ -260,12 +260,12 @@ int counter_tryextract(
 	//Sanity check that we use the ALU output properly
 	if(extract.has_ce)
 	{
-		if(!is_full_bus(muxy, index, count_mux, ID(Y), cemux, ID(B)))
+		if(!is_full_bus(muxy, index, count_mux, ID::Y, cemux, ID::B))
 			return 16;
-		if(!is_full_bus(cey, index, cemux, ID(Y), count_reg, ID(D)))
+		if(!is_full_bus(cey, index, cemux, ID::Y, count_reg, ID(D)))
 			return 16;
 	}
-	else if(!is_full_bus(muxy, index, count_mux, ID(Y), count_reg, ID(D)))
+	else if(!is_full_bus(muxy, index, count_mux, ID::Y, count_reg, ID(D)))
 		return 16;
 
 	//TODO: Verify count_reg CLK_POLARITY is 1
@@ -312,9 +312,9 @@ int counter_tryextract(
 			}
 		}
 	}
-	if(!is_full_bus(cnout, index, count_reg, ID(Q), underflow_inv, ID(A), true))
+	if(!is_full_bus(cnout, index, count_reg, ID(Q), underflow_inv, ID::A, true))
 		return 18;
-	if(!is_full_bus(cnout, index, count_reg, ID(Q), cell, ID(A), true))
+	if(!is_full_bus(cnout, index, count_reg, ID(Q), cell, ID::A, true))
 		return 19;
 
 	//Look up the clock from the register
@@ -348,7 +348,7 @@ void counter_worker(
 
 	//A input is the count value. Check if it has COUNT_EXTRACT set.
 	//If it's not a wire, don't even try
-	auto port = sigmap(cell->getPort(ID(A)));
+	auto port = sigmap(cell->getPort(ID::A));
 	if(!port.is_wire())
 		return;
 	RTLIL::Wire* a_wire = port.as_wire();
@@ -434,13 +434,13 @@ void counter_worker(
 	string countname = string("$COUNTx$") + log_id(extract.rwire->name.str());
 
 	//Wipe all of the old connections to the ALU
-	cell->unsetPort(ID(A));
-	cell->unsetPort(ID(B));
+	cell->unsetPort(ID::A);
+	cell->unsetPort(ID::B);
 	cell->unsetPort(ID(BI));
 	cell->unsetPort(ID(CI));
 	cell->unsetPort(ID(CO));
 	cell->unsetPort(ID(X));
-	cell->unsetPort(ID(Y));
+	cell->unsetPort(ID::Y);
 	cell->unsetParam(ID(A_SIGNED));
 	cell->unsetParam(ID(A_WIDTH));
 	cell->unsetParam(ID(B_SIGNED));
diff --git a/passes/techmap/extract_fa.cc b/passes/techmap/extract_fa.cc
index ff3de1272..29700c37b 100644
--- a/passes/techmap/extract_fa.cc
+++ b/passes/techmap/extract_fa.cc
@@ -89,7 +89,7 @@ struct ExtractFaWorker
 					ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_), ID($_MUX_), ID($_NMUX_),
 					ID($_AOI3_), ID($_OAI3_), ID($_AOI4_), ID($_OAI4_)))
 			{
-				SigBit y = sigmap(SigBit(cell->getPort(ID(Y))));
+				SigBit y = sigmap(SigBit(cell->getPort(ID::Y)));
 				log_assert(driver.count(y) == 0);
 				driver[y] = cell;
 			}
@@ -262,8 +262,8 @@ struct ExtractFaWorker
 			pool<SigBit> new_leaves = leaves;
 
 			new_leaves.erase(bit);
-			if (cell->hasPort(ID(A))) new_leaves.insert(sigmap(SigBit(cell->getPort(ID(A)))));
-			if (cell->hasPort(ID(B))) new_leaves.insert(sigmap(SigBit(cell->getPort(ID(B)))));
+			if (cell->hasPort(ID::A)) new_leaves.insert(sigmap(SigBit(cell->getPort(ID::A))));
+			if (cell->hasPort(ID::B)) new_leaves.insert(sigmap(SigBit(cell->getPort(ID::B))));
 			if (cell->hasPort(ID(C))) new_leaves.insert(sigmap(SigBit(cell->getPort(ID(C)))));
 			if (cell->hasPort(ID(D))) new_leaves.insert(sigmap(SigBit(cell->getPort(ID(D)))));
 
@@ -277,8 +277,8 @@ struct ExtractFaWorker
 	void assign_new_driver(SigBit bit, SigBit new_driver)
 	{
 		Cell *cell = driver.at(bit);
-		if (sigmap(cell->getPort(ID(Y))) == bit) {
-			cell->setPort(ID(Y), module->addWire(NEW_ID));
+		if (sigmap(cell->getPort(ID::Y)) == bit) {
+			cell->setPort(ID::Y, module->addWire(NEW_ID));
 			module->connect(bit, new_driver);
 		}
 	}
@@ -395,15 +395,15 @@ struct ExtractFaWorker
 
 					log("      Created $fa cell %s.\n", log_id(cell));
 
-					cell->setPort(ID(A), f3i.inv_a ? module->NotGate(NEW_ID, A) : A);
-					cell->setPort(ID(B), f3i.inv_b ? module->NotGate(NEW_ID, B) : B);
+					cell->setPort(ID::A, f3i.inv_a ? module->NotGate(NEW_ID, A) : A);
+					cell->setPort(ID::B, f3i.inv_b ? module->NotGate(NEW_ID, B) : B);
 					cell->setPort(ID(C), f3i.inv_c ? module->NotGate(NEW_ID, C) : C);
 
 					X = module->addWire(NEW_ID);
 					Y = module->addWire(NEW_ID);
 
 					cell->setPort(ID(X), X);
-					cell->setPort(ID(Y), Y);
+					cell->setPort(ID::Y, Y);
 
 					facache[fakey] = make_tuple(X, Y, cell);
 				}
@@ -501,15 +501,15 @@ struct ExtractFaWorker
 
 					log("      Created $fa cell %s.\n", log_id(cell));
 
-					cell->setPort(ID(A), f2i.inv_a ? module->NotGate(NEW_ID, A) : A);
-					cell->setPort(ID(B), f2i.inv_b ? module->NotGate(NEW_ID, B) : B);
+					cell->setPort(ID::A, f2i.inv_a ? module->NotGate(NEW_ID, A) : A);
+					cell->setPort(ID::B, f2i.inv_b ? module->NotGate(NEW_ID, B) : B);
 					cell->setPort(ID(C), State::S0);
 
 					X = module->addWire(NEW_ID);
 					Y = module->addWire(NEW_ID);
 
 					cell->setPort(ID(X), X);
-					cell->setPort(ID(Y), Y);
+					cell->setPort(ID::Y, Y);
 				}
 
 				if (func2.at(key).count(xor2_func)) {
diff --git a/passes/techmap/extract_reduce.cc b/passes/techmap/extract_reduce.cc
index 2ce111b4f..11cfddcd9 100644
--- a/passes/techmap/extract_reduce.cc
+++ b/passes/techmap/extract_reduce.cc
@@ -148,7 +148,7 @@ struct ExtractReducePass : public Pass
 
 						head_cell = x;
 
-						auto y = sigmap(x->getPort(ID(Y)));
+						auto y = sigmap(x->getPort(ID::Y));
 						log_assert(y.size() == 1);
 
 						// Should only continue if there is one fanout back into a cell (not to a port)
@@ -166,7 +166,7 @@ struct ExtractReducePass : public Pass
 				{
 					//BFS, following all chains until they hit a cell of a different type
 					//Pick the longest one
-					auto y = sigmap(cell->getPort(ID(Y)));
+					auto y = sigmap(cell->getPort(ID::Y));
 					pool<Cell*> current_loads = sig_to_sink[y];
 					pool<Cell*> next_loads;
 
@@ -233,7 +233,7 @@ struct ExtractReducePass : public Pass
 
 						cur_supercell.insert(x);
 
-						auto a = sigmap(x->getPort(ID(A)));
+						auto a = sigmap(x->getPort(ID::A));
 						log_assert(a.size() == 1);
 
 						// Must have only one sink unless we're going off chain
@@ -249,7 +249,7 @@ struct ExtractReducePass : public Pass
 							}
 						}
 
-						auto b = sigmap(x->getPort(ID(B)));
+						auto b = sigmap(x->getPort(ID::B));
 						log_assert(b.size() == 1);
 
 						// Must have only one sink
@@ -279,16 +279,16 @@ struct ExtractReducePass : public Pass
 						pool<SigBit> input_pool_intermed;
 						for (auto x : cur_supercell)
 						{
-							input_pool.insert(sigmap(x->getPort(ID(A)))[0]);
-							input_pool.insert(sigmap(x->getPort(ID(B)))[0]);
-							input_pool_intermed.insert(sigmap(x->getPort(ID(Y)))[0]);
+							input_pool.insert(sigmap(x->getPort(ID::A))[0]);
+							input_pool.insert(sigmap(x->getPort(ID::B))[0]);
+							input_pool_intermed.insert(sigmap(x->getPort(ID::Y))[0]);
 						}
 						SigSpec input;
 						for (auto b : input_pool)
 							if (input_pool_intermed.count(b) == 0)
 								input.append_bit(b);
 
-						SigBit output = sigmap(head_cell->getPort(ID(Y))[0]);
+						SigBit output = sigmap(head_cell->getPort(ID::Y)[0]);
 
 						auto new_reduce_cell = module->addCell(NEW_ID,
 							gt == GateType::And ? ID($reduce_and) :
@@ -297,8 +297,8 @@ struct ExtractReducePass : public Pass
 						new_reduce_cell->setParam(ID(A_SIGNED), 0);
 						new_reduce_cell->setParam(ID(A_WIDTH), input.size());
 						new_reduce_cell->setParam(ID(Y_WIDTH), 1);
-						new_reduce_cell->setPort(ID(A), input);
-						new_reduce_cell->setPort(ID(Y), output);
+						new_reduce_cell->setPort(ID::A, input);
+						new_reduce_cell->setPort(ID::Y, output);
 
 						if(allow_off_chain)
 							consumed_cells.insert(head_cell);
diff --git a/passes/techmap/iopadmap.cc b/passes/techmap/iopadmap.cc
index 726fcb905..898cb77a4 100644
--- a/passes/techmap/iopadmap.cc
+++ b/passes/techmap/iopadmap.cc
@@ -180,7 +180,7 @@ struct IopadmapPass : public Pass {
 
 				for (auto cell : module->cells())
 					if (cell->type == ID($_TBUF_)) {
-						SigBit bit = sigmap(cell->getPort(ID(Y)).as_bit());
+						SigBit bit = sigmap(cell->getPort(ID::Y).as_bit());
 						tbuf_bits[bit].first = cell->name;
 					}
 
@@ -213,7 +213,7 @@ struct IopadmapPass : public Pass {
 							continue;
 
 						SigBit en_sig = tbuf_cell->getPort(ID(E)).as_bit();
-						SigBit data_sig = tbuf_cell->getPort(ID(A)).as_bit();
+						SigBit data_sig = tbuf_cell->getPort(ID::A).as_bit();
 
 						if (wire->port_input && !tinoutpad_celltype.empty())
 						{
diff --git a/passes/techmap/lut2mux.cc b/passes/techmap/lut2mux.cc
index 6877a75e2..c6618fc9d 100644
--- a/passes/techmap/lut2mux.cc
+++ b/passes/techmap/lut2mux.cc
@@ -25,8 +25,8 @@ PRIVATE_NAMESPACE_BEGIN
 
 int lut2mux(Cell *cell)
 {
-	SigSpec sig_a = cell->getPort(ID(A));
-	SigSpec sig_y = cell->getPort(ID(Y));
+	SigSpec sig_a = cell->getPort(ID::A);
+	SigSpec sig_y = cell->getPort(ID::Y);
 	Const lut = cell->getParam(ID(LUT));
 	int count = 1;
 
diff --git a/passes/techmap/maccmap.cc b/passes/techmap/maccmap.cc
index 616ff21f2..09f61927c 100644
--- a/passes/techmap/maccmap.cc
+++ b/passes/techmap/maccmap.cc
@@ -113,10 +113,10 @@ struct MaccmapWorker
 
 			RTLIL::Cell *cell = module->addCell(NEW_ID, ID($fa));
 			cell->setParam(ID(WIDTH), width);
-			cell->setPort(ID(A), in1);
-			cell->setPort(ID(B), in2);
+			cell->setPort(ID::A, in1);
+			cell->setPort(ID::B, in2);
 			cell->setPort(ID(C), in3);
-			cell->setPort(ID(Y), w1);
+			cell->setPort(ID::Y, w1);
 			cell->setPort(ID(X), w2);
 
 			out1 = {out_zeros_msb, w1, out_zeros_lsb};
@@ -238,11 +238,11 @@ struct MaccmapWorker
 
 
 		RTLIL::Cell *c = module->addCell(NEW_ID, ID($alu));
-		c->setPort(ID(A), summands.front());
-		c->setPort(ID(B), summands.back());
+		c->setPort(ID::A, summands.front());
+		c->setPort(ID::B, summands.back());
 		c->setPort(ID(CI), State::S0);
 		c->setPort(ID(BI), State::S0);
-		c->setPort(ID(Y), module->addWire(NEW_ID, width));
+		c->setPort(ID::Y, module->addWire(NEW_ID, width));
 		c->setPort(ID(X), module->addWire(NEW_ID, width));
 		c->setPort(ID(CO), module->addWire(NEW_ID, width));
 		c->fixup_parameters();
@@ -253,7 +253,7 @@ struct MaccmapWorker
 		}
 		log_assert(tree_sum_bits.empty());
 
-		return c->getPort(ID(Y));
+		return c->getPort(ID::Y);
 	}
 };
 
@@ -264,17 +264,17 @@ extern void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap = false
 
 void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap)
 {
-	int width = GetSize(cell->getPort(ID(Y)));
+	int width = GetSize(cell->getPort(ID::Y));
 
 	Macc macc;
 	macc.from_cell(cell);
 
 	RTLIL::SigSpec all_input_bits;
-	all_input_bits.append(cell->getPort(ID(A)));
-	all_input_bits.append(cell->getPort(ID(B)));
+	all_input_bits.append(cell->getPort(ID::A));
+	all_input_bits.append(cell->getPort(ID::B));
 
 	if (all_input_bits.to_sigbit_set().count(RTLIL::Sx)) {
-		module->connect(cell->getPort(ID(Y)), RTLIL::SigSpec(RTLIL::Sx, width));
+		module->connect(cell->getPort(ID::Y), RTLIL::SigSpec(RTLIL::Sx, width));
 		return;
 	}
 
@@ -339,9 +339,9 @@ void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap)
 		}
 
 		if (summands.front().second)
-			module->addNeg(NEW_ID, summands.front().first, cell->getPort(ID(Y)));
+			module->addNeg(NEW_ID, summands.front().first, cell->getPort(ID::Y));
 		else
-			module->connect(cell->getPort(ID(Y)), summands.front().first);
+			module->connect(cell->getPort(ID::Y), summands.front().first);
 	}
 	else
 	{
@@ -356,7 +356,7 @@ void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap)
 		for (auto &bit : macc.bit_ports)
 			worker.add(bit, 0);
 
-		module->connect(cell->getPort(ID(Y)), worker.synth());
+		module->connect(cell->getPort(ID::Y), worker.synth());
 	}
 }
 
diff --git a/passes/techmap/muxcover.cc b/passes/techmap/muxcover.cc
index 64d5b4f7b..5541b6122 100644
--- a/passes/techmap/muxcover.cc
+++ b/passes/techmap/muxcover.cc
@@ -122,7 +122,7 @@ struct MuxcoverWorker
 				}
 			}
 			if (cell->type == ID($_MUX_))
-				sig_to_mux[sigmap(cell->getPort(ID(Y)))] = cell;
+				sig_to_mux[sigmap(cell->getPort(ID::Y))] = cell;
 		}
 
 		log("  Treeifying %d MUXes:\n", GetSize(sig_to_mux));
@@ -141,8 +141,8 @@ struct MuxcoverWorker
 				if (sig_to_mux.count(bit) && (bit == rootsig || !roots.count(bit))) {
 					Cell *c = sig_to_mux.at(bit);
 					tree.muxes[bit] = c;
-					wavefront.insert(sigmap(c->getPort(ID(A))));
-					wavefront.insert(sigmap(c->getPort(ID(B))));
+					wavefront.insert(sigmap(c->getPort(ID::A)));
+					wavefront.insert(sigmap(c->getPort(ID::B)));
 				}
 			}
 
@@ -517,31 +517,31 @@ struct MuxcoverWorker
 		if (GetSize(mux.inputs) == 2) {
 			count_muxes_by_type[0]++;
 			Cell *cell = module->addCell(NEW_ID, ID($_MUX_));
-			cell->setPort(ID(A), mux.inputs[0]);
-			cell->setPort(ID(B), mux.inputs[1]);
+			cell->setPort(ID::A, mux.inputs[0]);
+			cell->setPort(ID::B, mux.inputs[1]);
 			cell->setPort(ID(S), mux.selects[0]);
-			cell->setPort(ID(Y), bit);
+			cell->setPort(ID::Y, bit);
 			return;
 		}
 
 		if (GetSize(mux.inputs) == 4) {
 			count_muxes_by_type[1]++;
 			Cell *cell = module->addCell(NEW_ID, ID($_MUX4_));
-			cell->setPort(ID(A), mux.inputs[0]);
-			cell->setPort(ID(B), mux.inputs[1]);
+			cell->setPort(ID::A, mux.inputs[0]);
+			cell->setPort(ID::B, mux.inputs[1]);
 			cell->setPort(ID(C), mux.inputs[2]);
 			cell->setPort(ID(D), mux.inputs[3]);
 			cell->setPort(ID(S), mux.selects[0]);
 			cell->setPort(ID(T), mux.selects[1]);
-			cell->setPort(ID(Y), bit);
+			cell->setPort(ID::Y, bit);
 			return;
 		}
 
 		if (GetSize(mux.inputs) == 8) {
 			count_muxes_by_type[2]++;
 			Cell *cell = module->addCell(NEW_ID, ID($_MUX8_));
-			cell->setPort(ID(A), mux.inputs[0]);
-			cell->setPort(ID(B), mux.inputs[1]);
+			cell->setPort(ID::A, mux.inputs[0]);
+			cell->setPort(ID::B, mux.inputs[1]);
 			cell->setPort(ID(C), mux.inputs[2]);
 			cell->setPort(ID(D), mux.inputs[3]);
 			cell->setPort(ID(E), mux.inputs[4]);
@@ -551,15 +551,15 @@ struct MuxcoverWorker
 			cell->setPort(ID(S), mux.selects[0]);
 			cell->setPort(ID(T), mux.selects[1]);
 			cell->setPort(ID(U), mux.selects[2]);
-			cell->setPort(ID(Y), bit);
+			cell->setPort(ID::Y, bit);
 			return;
 		}
 
 		if (GetSize(mux.inputs) == 16) {
 			count_muxes_by_type[3]++;
 			Cell *cell = module->addCell(NEW_ID, ID($_MUX16_));
-			cell->setPort(ID(A), mux.inputs[0]);
-			cell->setPort(ID(B), mux.inputs[1]);
+			cell->setPort(ID::A, mux.inputs[0]);
+			cell->setPort(ID::B, mux.inputs[1]);
 			cell->setPort(ID(C), mux.inputs[2]);
 			cell->setPort(ID(D), mux.inputs[3]);
 			cell->setPort(ID(E), mux.inputs[4]);
@@ -578,7 +578,7 @@ struct MuxcoverWorker
 			cell->setPort(ID(T), mux.selects[1]);
 			cell->setPort(ID(U), mux.selects[2]);
 			cell->setPort(ID(V), mux.selects[3]);
-			cell->setPort(ID(Y), bit);
+			cell->setPort(ID::Y, bit);
 			return;
 		}
 
diff --git a/passes/techmap/nlutmap.cc b/passes/techmap/nlutmap.cc
index 4a3428b3c..798d82248 100644
--- a/passes/techmap/nlutmap.cc
+++ b/passes/techmap/nlutmap.cc
@@ -85,7 +85,7 @@ struct NlutmapWorker
 				if (cell->type != ID($lut) || mapped_cells.count(cell))
 					continue;
 
-				if (GetSize(cell->getPort(ID(A))) == lut_size || lut_size == 2)
+				if (GetSize(cell->getPort(ID::A)) == lut_size || lut_size == 2)
 					candidate_ratings[cell] = 0;
 
 				for (auto &conn : cell->connections())
diff --git a/passes/techmap/pmuxtree.cc b/passes/techmap/pmuxtree.cc
index f77652f3b..31ab13cec 100644
--- a/passes/techmap/pmuxtree.cc
+++ b/passes/techmap/pmuxtree.cc
@@ -92,18 +92,18 @@ struct PmuxtreePass : public Pass {
 			if (cell->type != ID($pmux))
 				continue;
 
-			SigSpec sig_data = cell->getPort(ID(B));
+			SigSpec sig_data = cell->getPort(ID::B);
 			SigSpec sig_sel = cell->getPort(ID(S));
 
-			if (!cell->getPort(ID(A)).is_fully_undef()) {
-				sig_data.append(cell->getPort(ID(A)));
+			if (!cell->getPort(ID::A).is_fully_undef()) {
+				sig_data.append(cell->getPort(ID::A));
 				SigSpec sig_sel_or = module->ReduceOr(NEW_ID, sig_sel);
 				sig_sel.append(module->Not(NEW_ID, sig_sel_or));
 			}
 
 			SigSpec result, result_or;
 			result = recursive_mux_generator(module, sig_data, sig_sel, result_or);
-			module->connect(cell->getPort(ID(Y)), result);
+			module->connect(cell->getPort(ID::Y), result);
 			module->remove(cell);
 		}
 	}
diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc
index 92637dfa8..cb877c2f4 100644
--- a/passes/techmap/shregmap.cc
+++ b/passes/techmap/shregmap.cc
@@ -107,16 +107,16 @@ struct ShregmapTechXilinx7 : ShregmapTech
 			if (cell->type == ID($shiftx)) {
 				if (cell->getParam(ID(Y_WIDTH)) != 1) continue;
 				int j = 0;
-				for (auto bit : sigmap(cell->getPort(ID(A))))
+				for (auto bit : sigmap(cell->getPort(ID::A)))
 					sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, j++, 0);
 				log_assert(j == cell->getParam(ID(A_WIDTH)).as_int());
 			}
 			else if (cell->type == ID($mux)) {
 				int j = 0;
-				for (auto bit : sigmap(cell->getPort(ID(A))))
+				for (auto bit : sigmap(cell->getPort(ID::A)))
 					sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 0, j++);
 				j = 0;
-				for (auto bit : sigmap(cell->getPort(ID(B))))
+				for (auto bit : sigmap(cell->getPort(ID::B)))
 					sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 1, j++);
 			}
 		}
@@ -128,9 +128,9 @@ struct ShregmapTechXilinx7 : ShregmapTech
 		if (it == sigbit_to_shiftx_offset.end())
 			return;
 		if (cell) {
-			if (cell->type == ID($shiftx) && port == ID(A))
+			if (cell->type == ID($shiftx) && port == ID::A)
 				return;
-			if (cell->type == ID($mux) && port.in(ID(A), ID(B)))
+			if (cell->type == ID($mux) && port.in(ID::A, ID::B))
 				return;
 		}
 		sigbit_to_shiftx_offset.erase(it);
@@ -183,7 +183,7 @@ struct ShregmapTechXilinx7 : ShregmapTech
 			// Due to padding the most significant bits of A may be 1'bx,
 			//   and if so, discount them
 			if (GetSize(taps) < shiftx->getParam(ID(A_WIDTH)).as_int()) {
-				const SigSpec A = shiftx->getPort(ID(A));
+				const SigSpec A = shiftx->getPort(ID::A);
 				const int A_width = shiftx->getParam(ID(A_WIDTH)).as_int();
 				for (int i = GetSize(taps); i < A_width; ++i)
 					if (A[i] != RTLIL::Sx) return false;
@@ -223,14 +223,14 @@ struct ShregmapTechXilinx7 : ShregmapTech
 		Cell* shiftx = std::get<0>(it->second);
 		RTLIL::SigSpec l_wire, q_wire;
 		if (shiftx->type == ID($shiftx)) {
-			l_wire = shiftx->getPort(ID(B));
-			q_wire = shiftx->getPort(ID(Y));
-			shiftx->setPort(ID(Y), cell->module->addWire(NEW_ID));
+			l_wire = shiftx->getPort(ID::B);
+			q_wire = shiftx->getPort(ID::Y);
+			shiftx->setPort(ID::Y, cell->module->addWire(NEW_ID));
 		}
 		else if (shiftx->type == ID($mux)) {
 			l_wire = shiftx->getPort(ID(S));
-			q_wire = shiftx->getPort(ID(Y));
-			shiftx->setPort(ID(Y), cell->module->addWire(NEW_ID));
+			q_wire = shiftx->getPort(ID::Y);
+			shiftx->setPort(ID::Y, cell->module->addWire(NEW_ID));
 		}
 		else log_abort();
 
diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc
index 325a816ee..91574f3c6 100644
--- a/passes/techmap/simplemap.cc
+++ b/passes/techmap/simplemap.cc
@@ -28,23 +28,23 @@ YOSYS_NAMESPACE_BEGIN
 
 void simplemap_not(RTLIL::Module *module, RTLIL::Cell *cell)
 {
-	RTLIL::SigSpec sig_a = cell->getPort(ID(A));
-	RTLIL::SigSpec sig_y = cell->getPort(ID(Y));
+	RTLIL::SigSpec sig_a = cell->getPort(ID::A);
+	RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
 
 	sig_a.extend_u0(GetSize(sig_y), cell->parameters.at(ID(A_SIGNED)).as_bool());
 
 	for (int i = 0; i < GetSize(sig_y); i++) {
 		RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_NOT_));
 		gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src)));
-		gate->setPort(ID(A), sig_a[i]);
-		gate->setPort(ID(Y), sig_y[i]);
+		gate->setPort(ID::A, sig_a[i]);
+		gate->setPort(ID::Y, sig_y[i]);
 	}
 }
 
 void simplemap_pos(RTLIL::Module *module, RTLIL::Cell *cell)
 {
-	RTLIL::SigSpec sig_a = cell->getPort(ID(A));
-	RTLIL::SigSpec sig_y = cell->getPort(ID(Y));
+	RTLIL::SigSpec sig_a = cell->getPort(ID::A);
+	RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
 
 	sig_a.extend_u0(GetSize(sig_y), cell->parameters.at(ID(A_SIGNED)).as_bool());
 
@@ -53,9 +53,9 @@ void simplemap_pos(RTLIL::Module *module, RTLIL::Cell *cell)
 
 void simplemap_bitop(RTLIL::Module *module, RTLIL::Cell *cell)
 {
-	RTLIL::SigSpec sig_a = cell->getPort(ID(A));
-	RTLIL::SigSpec sig_b = cell->getPort(ID(B));
-	RTLIL::SigSpec sig_y = cell->getPort(ID(Y));
+	RTLIL::SigSpec sig_a = cell->getPort(ID::A);
+	RTLIL::SigSpec sig_b = cell->getPort(ID::B);
+	RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
 
 	sig_a.extend_u0(GetSize(sig_y), cell->parameters.at(ID(A_SIGNED)).as_bool());
 	sig_b.extend_u0(GetSize(sig_y), cell->parameters.at(ID(B_SIGNED)).as_bool());
@@ -67,8 +67,8 @@ void simplemap_bitop(RTLIL::Module *module, RTLIL::Cell *cell)
 		for (int i = 0; i < GetSize(sig_y); i++) {
 			RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_NOT_));
 			gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src)));
-			gate->setPort(ID(A), sig_t[i]);
-			gate->setPort(ID(Y), sig_y[i]);
+			gate->setPort(ID::A, sig_t[i]);
+			gate->setPort(ID::Y, sig_y[i]);
 		}
 
 		sig_y = sig_t;
@@ -84,16 +84,16 @@ void simplemap_bitop(RTLIL::Module *module, RTLIL::Cell *cell)
 	for (int i = 0; i < GetSize(sig_y); i++) {
 		RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
 		gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src)));
-		gate->setPort(ID(A), sig_a[i]);
-		gate->setPort(ID(B), sig_b[i]);
-		gate->setPort(ID(Y), sig_y[i]);
+		gate->setPort(ID::A, sig_a[i]);
+		gate->setPort(ID::B, sig_b[i]);
+		gate->setPort(ID::Y, sig_y[i]);
 	}
 }
 
 void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell)
 {
-	RTLIL::SigSpec sig_a = cell->getPort(ID(A));
-	RTLIL::SigSpec sig_y = cell->getPort(ID(Y));
+	RTLIL::SigSpec sig_a = cell->getPort(ID::A);
+	RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
 
 	if (sig_y.size() == 0)
 		return;
@@ -135,9 +135,9 @@ void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell)
 
 			RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
 			gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src)));
-			gate->setPort(ID(A), sig_a[i]);
-			gate->setPort(ID(B), sig_a[i+1]);
-			gate->setPort(ID(Y), sig_t[i/2]);
+			gate->setPort(ID::A, sig_a[i]);
+			gate->setPort(ID::B, sig_a[i+1]);
+			gate->setPort(ID::Y, sig_t[i/2]);
 			last_output_cell = gate;
 		}
 
@@ -148,8 +148,8 @@ void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell)
 		RTLIL::SigSpec sig_t = module->addWire(NEW_ID);
 		RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_NOT_));
 		gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src)));
-		gate->setPort(ID(A), sig_a);
-		gate->setPort(ID(Y), sig_t);
+		gate->setPort(ID::A, sig_a);
+		gate->setPort(ID::Y, sig_t);
 		last_output_cell = gate;
 		sig_a = sig_t;
 	}
@@ -157,7 +157,7 @@ void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell)
 	if (last_output_cell == NULL) {
 		module->connect(RTLIL::SigSig(sig_y, sig_a));
 	} else {
-		last_output_cell->setPort(ID(Y), sig_y);
+		last_output_cell->setPort(ID::Y, sig_y);
 	}
 }
 
@@ -176,9 +176,9 @@ static void logic_reduce(RTLIL::Module *module, RTLIL::SigSpec &sig, RTLIL::Cell
 
 			RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_OR_));
 			gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src)));
-			gate->setPort(ID(A), sig[i]);
-			gate->setPort(ID(B), sig[i+1]);
-			gate->setPort(ID(Y), sig_t[i/2]);
+			gate->setPort(ID::A, sig[i]);
+			gate->setPort(ID::B, sig[i+1]);
+			gate->setPort(ID::Y, sig_t[i/2]);
 		}
 
 		sig = sig_t;
@@ -190,10 +190,10 @@ static void logic_reduce(RTLIL::Module *module, RTLIL::SigSpec &sig, RTLIL::Cell
 
 void simplemap_lognot(RTLIL::Module *module, RTLIL::Cell *cell)
 {
-	RTLIL::SigSpec sig_a = cell->getPort(ID(A));
+	RTLIL::SigSpec sig_a = cell->getPort(ID::A);
 	logic_reduce(module, sig_a, cell);
 
-	RTLIL::SigSpec sig_y = cell->getPort(ID(Y));
+	RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
 
 	if (sig_y.size() == 0)
 		return;
@@ -205,19 +205,19 @@ void simplemap_lognot(RTLIL::Module *module, RTLIL::Cell *cell)
 
 	RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_NOT_));
 	gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src)));
-	gate->setPort(ID(A), sig_a);
-	gate->setPort(ID(Y), sig_y);
+	gate->setPort(ID::A, sig_a);
+	gate->setPort(ID::Y, sig_y);
 }
 
 void simplemap_logbin(RTLIL::Module *module, RTLIL::Cell *cell)
 {
-	RTLIL::SigSpec sig_a = cell->getPort(ID(A));
+	RTLIL::SigSpec sig_a = cell->getPort(ID::A);
 	logic_reduce(module, sig_a, cell);
 
-	RTLIL::SigSpec sig_b = cell->getPort(ID(B));
+	RTLIL::SigSpec sig_b = cell->getPort(ID::B);
 	logic_reduce(module, sig_b, cell);
 
-	RTLIL::SigSpec sig_y = cell->getPort(ID(Y));
+	RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
 
 	if (sig_y.size() == 0)
 		return;
@@ -234,16 +234,16 @@ void simplemap_logbin(RTLIL::Module *module, RTLIL::Cell *cell)
 
 	RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
 	gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src)));
-	gate->setPort(ID(A), sig_a);
-	gate->setPort(ID(B), sig_b);
-	gate->setPort(ID(Y), sig_y);
+	gate->setPort(ID::A, sig_a);
+	gate->setPort(ID::B, sig_b);
+	gate->setPort(ID::Y, sig_y);
 }
 
 void simplemap_eqne(RTLIL::Module *module, RTLIL::Cell *cell)
 {
-	RTLIL::SigSpec sig_a = cell->getPort(ID(A));
-	RTLIL::SigSpec sig_b = cell->getPort(ID(B));
-	RTLIL::SigSpec sig_y = cell->getPort(ID(Y));
+	RTLIL::SigSpec sig_a = cell->getPort(ID::A);
+	RTLIL::SigSpec sig_b = cell->getPort(ID::B);
+	RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
 	bool is_signed = cell->parameters.at(ID(A_SIGNED)).as_bool();
 	bool is_ne = cell->type.in(ID($ne), ID($nex));
 
@@ -269,38 +269,38 @@ void simplemap_eqne(RTLIL::Module *module, RTLIL::Cell *cell)
 
 void simplemap_mux(RTLIL::Module *module, RTLIL::Cell *cell)
 {
-	RTLIL::SigSpec sig_a = cell->getPort(ID(A));
-	RTLIL::SigSpec sig_b = cell->getPort(ID(B));
-	RTLIL::SigSpec sig_y = cell->getPort(ID(Y));
+	RTLIL::SigSpec sig_a = cell->getPort(ID::A);
+	RTLIL::SigSpec sig_b = cell->getPort(ID::B);
+	RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
 
 	for (int i = 0; i < GetSize(sig_y); i++) {
 		RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_));
 		gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src)));
-		gate->setPort(ID(A), sig_a[i]);
-		gate->setPort(ID(B), sig_b[i]);
+		gate->setPort(ID::A, sig_a[i]);
+		gate->setPort(ID::B, sig_b[i]);
 		gate->setPort(ID(S), cell->getPort(ID(S)));
-		gate->setPort(ID(Y), sig_y[i]);
+		gate->setPort(ID::Y, sig_y[i]);
 	}
 }
 
 void simplemap_tribuf(RTLIL::Module *module, RTLIL::Cell *cell)
 {
-	RTLIL::SigSpec sig_a = cell->getPort(ID(A));
+	RTLIL::SigSpec sig_a = cell->getPort(ID::A);
 	RTLIL::SigSpec sig_e = cell->getPort(ID(EN));
-	RTLIL::SigSpec sig_y = cell->getPort(ID(Y));
+	RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
 
 	for (int i = 0; i < GetSize(sig_y); i++) {
 		RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_TBUF_));
 		gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src)));
-		gate->setPort(ID(A), sig_a[i]);
+		gate->setPort(ID::A, sig_a[i]);
 		gate->setPort(ID(E), sig_e);
-		gate->setPort(ID(Y), sig_y[i]);
+		gate->setPort(ID::Y, sig_y[i]);
 	}
 }
 
 void simplemap_lut(RTLIL::Module *module, RTLIL::Cell *cell)
 {
-	SigSpec lut_ctrl = cell->getPort(ID(A));
+	SigSpec lut_ctrl = cell->getPort(ID::A);
 	SigSpec lut_data = cell->getParam(ID(LUT));
 	lut_data.extend_u0(1 << cell->getParam(ID(WIDTH)).as_int());
 
@@ -310,20 +310,20 @@ void simplemap_lut(RTLIL::Module *module, RTLIL::Cell *cell)
 		for (int i = 0; i < GetSize(lut_data); i += 2) {
 			RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_));
 			gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src)));
-			gate->setPort(ID(A), lut_data[i]);
-			gate->setPort(ID(B), lut_data[i+1]);
+			gate->setPort(ID::A, lut_data[i]);
+			gate->setPort(ID::B, lut_data[i+1]);
 			gate->setPort(ID(S), lut_ctrl[idx]);
-			gate->setPort(ID(Y), new_lut_data[i/2]);
+			gate->setPort(ID::Y, new_lut_data[i/2]);
 		}
 		lut_data = new_lut_data;
 	}
 
-	module->connect(cell->getPort(ID(Y)), lut_data);
+	module->connect(cell->getPort(ID::Y), lut_data);
 }
 
 void simplemap_sop(RTLIL::Module *module, RTLIL::Cell *cell)
 {
-	SigSpec ctrl = cell->getPort(ID(A));
+	SigSpec ctrl = cell->getPort(ID::A);
 	SigSpec table = cell->getParam(ID(TABLE));
 
 	int width = cell->getParam(ID(WIDTH)).as_int();
@@ -348,22 +348,22 @@ void simplemap_sop(RTLIL::Module *module, RTLIL::Cell *cell)
 		products.append(GetSize(in) > 0 ? module->Eq(NEW_ID, in, pat) : State::S1);
 	}
 
-	module->connect(cell->getPort(ID(Y)), module->ReduceOr(NEW_ID, products));
+	module->connect(cell->getPort(ID::Y), module->ReduceOr(NEW_ID, products));
 }
 
 void simplemap_slice(RTLIL::Module *module, RTLIL::Cell *cell)
 {
 	int offset = cell->parameters.at(ID(OFFSET)).as_int();
-	RTLIL::SigSpec sig_a = cell->getPort(ID(A));
-	RTLIL::SigSpec sig_y = cell->getPort(ID(Y));
+	RTLIL::SigSpec sig_a = cell->getPort(ID::A);
+	RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
 	module->connect(RTLIL::SigSig(sig_y, sig_a.extract(offset, sig_y.size())));
 }
 
 void simplemap_concat(RTLIL::Module *module, RTLIL::Cell *cell)
 {
-	RTLIL::SigSpec sig_ab = cell->getPort(ID(A));
-	sig_ab.append(cell->getPort(ID(B)));
-	RTLIL::SigSpec sig_y = cell->getPort(ID(Y));
+	RTLIL::SigSpec sig_ab = cell->getPort(ID::A);
+	sig_ab.append(cell->getPort(ID::B));
+	RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
 	module->connect(RTLIL::SigSig(sig_y, sig_ab));
 }
 
diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc
index e81dc33ee..fa038c1b9 100644
--- a/passes/techmap/techmap.cc
+++ b/passes/techmap/techmap.cc
@@ -520,7 +520,7 @@ struct TechmapWorker
 								int port_counter = 1;
 								for (auto &c : extmapper_cell->connections_) {
 									RTLIL::Wire *w = extmapper_module->addWire(c.first, GetSize(c.second));
-									if (w->name.in(ID(Y), ID(Q)))
+									if (w->name.in(ID::Y, ID(Q)))
 										w->port_output = true;
 									else
 										w->port_input = true;
diff --git a/passes/techmap/tribuf.cc b/passes/techmap/tribuf.cc
index 509a9198b..41fdc8f3d 100644
--- a/passes/techmap/tribuf.cc
+++ b/passes/techmap/tribuf.cc
@@ -64,37 +64,37 @@ struct TribufWorker {
 		for (auto cell : module->selected_cells())
 		{
 			if (cell->type == ID($tribuf))
-				tribuf_cells[sigmap(cell->getPort(ID(Y)))].push_back(cell);
+				tribuf_cells[sigmap(cell->getPort(ID::Y))].push_back(cell);
 
 			if (cell->type == ID($_TBUF_))
-				tribuf_cells[sigmap(cell->getPort(ID(Y)))].push_back(cell);
+				tribuf_cells[sigmap(cell->getPort(ID::Y))].push_back(cell);
 
 			if (cell->type.in(ID($mux), ID($_MUX_)))
 			{
 				IdString en_port = cell->type == ID($mux) ? ID(EN) : ID(E);
 				IdString tri_type = cell->type == ID($mux) ? ID($tribuf) : ID($_TBUF_);
 
-				if (is_all_z(cell->getPort(ID(A))) && is_all_z(cell->getPort(ID(B)))) {
+				if (is_all_z(cell->getPort(ID::A)) && is_all_z(cell->getPort(ID::B))) {
 					module->remove(cell);
 					continue;
 				}
 
-				if (is_all_z(cell->getPort(ID(A)))) {
-					cell->setPort(ID(A), cell->getPort(ID(B)));
+				if (is_all_z(cell->getPort(ID::A))) {
+					cell->setPort(ID::A, cell->getPort(ID::B));
 					cell->setPort(en_port, cell->getPort(ID(S)));
-					cell->unsetPort(ID(B));
+					cell->unsetPort(ID::B);
 					cell->unsetPort(ID(S));
 					cell->type = tri_type;
-					tribuf_cells[sigmap(cell->getPort(ID(Y)))].push_back(cell);
+					tribuf_cells[sigmap(cell->getPort(ID::Y))].push_back(cell);
 					continue;
 				}
 
-				if (is_all_z(cell->getPort(ID(B)))) {
+				if (is_all_z(cell->getPort(ID::B))) {
 					cell->setPort(en_port, module->Not(NEW_ID, cell->getPort(ID(S))));
-					cell->unsetPort(ID(B));
+					cell->unsetPort(ID::B);
 					cell->unsetPort(ID(S));
 					cell->type = tri_type;
-					tribuf_cells[sigmap(cell->getPort(ID(Y)))].push_back(cell);
+					tribuf_cells[sigmap(cell->getPort(ID::Y))].push_back(cell);
 					continue;
 				}
 			}
@@ -122,7 +122,7 @@ struct TribufWorker {
 						pmux_s.append(cell->getPort(ID(EN)));
 					else
 						pmux_s.append(cell->getPort(ID(E)));
-					pmux_b.append(cell->getPort(ID(A)));
+					pmux_b.append(cell->getPort(ID::A));
 					module->remove(cell);
 				}
 

From eae5a6b12c0f44230f61ed23068e7200507f9520 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Thu, 15 Aug 2019 14:51:12 -0700
Subject: [PATCH 11/20] Use ID::keep more liberally too

---
 passes/opt/muxpack.cc      | 4 ++--
 passes/opt/opt_clean.cc    | 8 ++++----
 passes/opt/opt_expr.cc     | 2 +-
 passes/opt/opt_lut.cc      | 2 +-
 passes/opt/opt_muxtree.cc  | 2 +-
 passes/opt/wreduce.cc      | 2 +-
 passes/techmap/abc.cc      | 4 ++--
 passes/techmap/iopadmap.cc | 8 ++++----
 passes/techmap/shregmap.cc | 4 ++--
 passes/techmap/techmap.cc  | 2 +-
 10 files changed, 19 insertions(+), 19 deletions(-)

diff --git a/passes/opt/muxpack.cc b/passes/opt/muxpack.cc
index 97c88f423..c40c02acd 100644
--- a/passes/opt/muxpack.cc
+++ b/passes/opt/muxpack.cc
@@ -135,7 +135,7 @@ struct MuxpackWorker
 	{
 		for (auto wire : module->wires())
 		{
-			if (wire->port_output || wire->get_bool_attribute(ID(keep))) {
+			if (wire->port_output || wire->get_bool_attribute(ID::keep)) {
 				for (auto bit : sigmap(wire))
 					sigbit_with_non_chain_users.insert(bit);
 			}
@@ -143,7 +143,7 @@ struct MuxpackWorker
 
 		for (auto cell : module->cells())
 		{
-			if (cell->type.in(ID($mux), ID($pmux)) && !cell->get_bool_attribute(ID(keep)))
+			if (cell->type.in(ID($mux), ID($pmux)) && !cell->get_bool_attribute(ID::keep))
 			{
 				SigSpec a_sig = sigmap(cell->getPort(ID::A));
 				SigSpec b_sig;
diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc
index bf75c7adc..2f69b3d4c 100644
--- a/passes/opt/opt_clean.cc
+++ b/passes/opt/opt_clean.cc
@@ -52,7 +52,7 @@ struct keep_cache_t
 			return cache.at(module);
 
 		cache[module] = true;
-		if (!module->get_bool_attribute(ID(keep))) {
+		if (!module->get_bool_attribute(ID::keep)) {
 			bool found_keep = false;
 			for (auto cell : module->cells())
 				if (query(cell)) found_keep = true;
@@ -122,7 +122,7 @@ void rmunused_module_cells(Module *module, bool verbose)
 
 	for (auto &it : module->wires_) {
 		Wire *wire = it.second;
-		if (wire->port_output || wire->get_bool_attribute(ID(keep))) {
+		if (wire->port_output || wire->get_bool_attribute(ID::keep)) {
 			for (auto bit : sigmap(wire))
 			for (auto c : wire2driver[bit])
 				queue.insert(c), unused.erase(c);
@@ -297,7 +297,7 @@ bool rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
 			if (!wire->port_input)
 				used_signals_nodrivers.add(sig);
 		}
-		if (wire->get_bool_attribute(ID(keep))) {
+		if (wire->get_bool_attribute(ID::keep)) {
 			RTLIL::SigSpec sig = RTLIL::SigSpec(wire);
 			assign_map.apply(sig);
 			used_signals.add(sig);
@@ -323,7 +323,7 @@ bool rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
 			if (wire->port_id == 0)
 				goto delete_this_wire;
 		} else
-		if (wire->port_id != 0 || wire->get_bool_attribute(ID(keep)) || !initval.is_fully_undef()) {
+		if (wire->port_id != 0 || wire->get_bool_attribute(ID::keep) || !initval.is_fully_undef()) {
 			// do not delete anything with "keep" or module ports or initialized wires
 		} else
 		if (!purge_mode && check_public_name(wire->name) && (raw_used_signals.check_any(s1) || used_signals.check_any(s2) || s1 != s2)) {
diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc
index 85ec9a55a..f7469853b 100644
--- a/passes/opt/opt_expr.cc
+++ b/passes/opt/opt_expr.cc
@@ -61,7 +61,7 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
 		}
 		if (wire->port_input)
 			driven_signals.add(sigmap(wire));
-		if (wire->port_output || wire->get_bool_attribute(ID(keep)))
+		if (wire->port_output || wire->get_bool_attribute(ID::keep))
 			used_signals.add(sigmap(wire));
 		all_signals.add(sigmap(wire));
 	}
diff --git a/passes/opt/opt_lut.cc b/passes/opt/opt_lut.cc
index 733bc547c..c4f278706 100644
--- a/passes/opt/opt_lut.cc
+++ b/passes/opt/opt_lut.cc
@@ -104,7 +104,7 @@ struct OptLutWorker
 				if (cell->has_keep_attr())
 					continue;
 				SigBit lut_output = cell->getPort(ID::Y);
-				if (lut_output.wire->get_bool_attribute(ID(keep)))
+				if (lut_output.wire->get_bool_attribute(ID::keep))
 					continue;
 
 				int lut_width = cell->getParam(ID(WIDTH)).as_int();
diff --git a/passes/opt/opt_muxtree.cc b/passes/opt/opt_muxtree.cc
index 3d7e9cccb..3c486bbcc 100644
--- a/passes/opt/opt_muxtree.cc
+++ b/passes/opt/opt_muxtree.cc
@@ -137,7 +137,7 @@ struct OptMuxtreeWorker
 			}
 		}
 		for (auto wire : module->wires()) {
-			if (wire->port_output || wire->get_bool_attribute(ID(keep)))
+			if (wire->port_output || wire->get_bool_attribute(ID::keep))
 				for (int idx : sig2bits(RTLIL::SigSpec(wire)))
 					bit2info[idx].seen_non_mux = true;
 		}
diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc
index 792c69c55..37de8cb61 100644
--- a/passes/opt/wreduce.cc
+++ b/passes/opt/wreduce.cc
@@ -398,7 +398,7 @@ struct WreduceWorker
 		SigMap init_attr_sigmap = mi.sigmap;
 
 		for (auto w : module->wires()) {
-			if (w->get_bool_attribute(ID(keep)))
+			if (w->get_bool_attribute(ID::keep))
 				for (auto bit : mi.sigmap(w))
 					keep_bits.insert(bit);
 			if (w->attributes.count(ID(init))) {
diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc
index 205f05ab9..4e49b73ba 100644
--- a/passes/techmap/abc.cc
+++ b/passes/techmap/abc.cc
@@ -198,7 +198,7 @@ void extract_cell(RTLIL::Cell *cell, bool keepff)
 		if (keepff)
 			for (auto &c : sig_q.chunks())
 				if (c.wire != NULL)
-					c.wire->attributes[ID(keep)] = 1;
+					c.wire->attributes[ID::keep] = 1;
 
 		assign_map.apply(sig_d);
 		assign_map.apply(sig_q);
@@ -787,7 +787,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
 		extract_cell(c, keepff);
 
 	for (auto &wire_it : module->wires_) {
-		if (wire_it.second->port_id > 0 || wire_it.second->get_bool_attribute(ID(keep)))
+		if (wire_it.second->port_id > 0 || wire_it.second->get_bool_attribute(ID::keep))
 			mark_port(RTLIL::SigSpec(wire_it.second));
 	}
 
diff --git a/passes/techmap/iopadmap.cc b/passes/techmap/iopadmap.cc
index 898cb77a4..a2551316f 100644
--- a/passes/techmap/iopadmap.cc
+++ b/passes/techmap/iopadmap.cc
@@ -226,7 +226,7 @@ struct IopadmapPass : public Pass {
 							cell->setPort(RTLIL::escape_id(tinoutpad_portname2), owire);
 							cell->setPort(RTLIL::escape_id(tinoutpad_portname3), data_sig);
 							cell->setPort(RTLIL::escape_id(tinoutpad_portname4), wire_bit);
-							cell->attributes[ID(keep)] = RTLIL::Const(1);
+							cell->attributes[ID::keep] = RTLIL::Const(1);
 
 							for (auto cn : tbuf_cache.second) {
 								auto c = module->cell(cn);
@@ -263,7 +263,7 @@ struct IopadmapPass : public Pass {
 							cell->setPort(RTLIL::escape_id(toutpad_portname), en_sig);
 							cell->setPort(RTLIL::escape_id(toutpad_portname2), data_sig);
 							cell->setPort(RTLIL::escape_id(toutpad_portname3), wire_bit);
-							cell->attributes[ID(keep)] = RTLIL::Const(1);
+							cell->attributes[ID::keep] = RTLIL::Const(1);
 
 							for (auto cn : tbuf_cache.second) {
 								auto c = module->cell(cn);
@@ -390,7 +390,7 @@ struct IopadmapPass : public Pass {
 							cell->parameters[RTLIL::escape_id(widthparam)] = RTLIL::Const(1);
 						if (!nameparam.empty())
 							cell->parameters[RTLIL::escape_id(nameparam)] = RTLIL::Const(stringf("%s[%d]", RTLIL::id2cstr(wire->name), i));
-						cell->attributes[ID(keep)] = RTLIL::Const(1);
+						cell->attributes[ID::keep] = RTLIL::Const(1);
 					}
 				}
 				else
@@ -403,7 +403,7 @@ struct IopadmapPass : public Pass {
 						cell->parameters[RTLIL::escape_id(widthparam)] = RTLIL::Const(wire->width);
 					if (!nameparam.empty())
 						cell->parameters[RTLIL::escape_id(nameparam)] = RTLIL::Const(RTLIL::id2cstr(wire->name));
-					cell->attributes[ID(keep)] = RTLIL::Const(1);
+					cell->attributes[ID::keep] = RTLIL::Const(1);
 				}
 
 				wire->port_id = 0;
diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc
index cb877c2f4..5e298d8dd 100644
--- a/passes/techmap/shregmap.cc
+++ b/passes/techmap/shregmap.cc
@@ -263,7 +263,7 @@ struct ShregmapWorker
 	{
 		for (auto wire : module->wires())
 		{
-			if (wire->port_output || wire->get_bool_attribute(ID(keep))) {
+			if (wire->port_output || wire->get_bool_attribute(ID::keep)) {
 				for (auto bit : sigmap(wire)) {
 					sigbit_with_non_chain_users.insert(bit);
 					if (opts.tech) opts.tech->non_chain_user(bit, nullptr, {});
@@ -283,7 +283,7 @@ struct ShregmapWorker
 
 		for (auto cell : module->cells())
 		{
-			if (opts.ffcells.count(cell->type) && !cell->get_bool_attribute(ID(keep)))
+			if (opts.ffcells.count(cell->type) && !cell->get_bool_attribute(ID::keep))
 			{
 				IdString d_port = opts.ffcells.at(cell->type).first;
 				IdString q_port = opts.ffcells.at(cell->type).second;
diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc
index fa038c1b9..b271c8781 100644
--- a/passes/techmap/techmap.cc
+++ b/passes/techmap/techmap.cc
@@ -145,7 +145,7 @@ struct TechmapWorker
 				record.wire = it.second;
 				record.value = it.second;
 				result[p].push_back(record);
-				it.second->attributes[ID(keep)] = RTLIL::Const(1);
+				it.second->attributes[ID::keep] = RTLIL::Const(1);
 				it.second->attributes[ID(_techmap_special_)] = RTLIL::Const(1);
 			}
 		}

From 453a9429b67551f94f8c714c24f12929e472052c Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Thu, 15 Aug 2019 14:54:41 -0700
Subject: [PATCH 12/20] Fix spacing

---
 kernel/yosys.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel/yosys.h b/kernel/yosys.h
index 52e7b3383..0cf230722 100644
--- a/kernel/yosys.h
+++ b/kernel/yosys.h
@@ -210,7 +210,7 @@ namespace RTLIL {
 	struct Module;
 	struct Design;
 	struct Monitor;
-    namespace ID {}
+	namespace ID {}
 }
 
 namespace AST {

From 0b9ee4fbbf3a5fc818e5ae39a013cdd9e17f641f Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Thu, 15 Aug 2019 16:20:54 -0700
Subject: [PATCH 13/20] Try this for gcc-4.8?

---
 kernel/yosys.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel/yosys.h b/kernel/yosys.h
index 0cf230722..895286a53 100644
--- a/kernel/yosys.h
+++ b/kernel/yosys.h
@@ -225,7 +225,7 @@ using RTLIL::Wire;
 using RTLIL::Cell;
 using RTLIL::Module;
 using RTLIL::Design;
-namespace ID = RTLIL::ID;
+namespace ID = ::YOSYS_NAMESPACE::RTLIL::ID;
 
 namespace hashlib {
 	template<> struct hash_ops<RTLIL::Wire*> : hash_obj_ops {};

From 29e14e674eccc173b354dacd96fdbe0040c423d0 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Fri, 16 Aug 2019 19:36:45 +0000
Subject: [PATCH 14/20] Remove `using namespace RTLIL;`

---
 passes/opt/wreduce.cc | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc
index 37de8cb61..c02c355cb 100644
--- a/passes/opt/wreduce.cc
+++ b/passes/opt/wreduce.cc
@@ -22,7 +22,6 @@
 #include "kernel/modtools.h"
 
 USING_YOSYS_NAMESPACE
-using namespace RTLIL;
 
 PRIVATE_NAMESPACE_BEGIN
 
@@ -77,15 +76,15 @@ struct WreduceWorker
 		{
 			auto info = mi.query(sig_y[i]);
 			if (!info->is_output && GetSize(info->ports) <= 1 && !keep_bits.count(mi.sigmap(sig_y[i]))) {
-				bits_removed.push_back(Sx);
+				bits_removed.push_back(State::Sx);
 				continue;
 			}
 
 			SigBit ref = sig_a[i];
 			for (int k = 0; k < GetSize(sig_s); k++) {
-				if ((config->keepdc || (ref != Sx && sig_b[k*GetSize(sig_a) + i] != Sx)) && ref != sig_b[k*GetSize(sig_a) + i])
+				if ((config->keepdc || (ref != State::Sx && sig_b[k*GetSize(sig_a) + i] != State::Sx)) && ref != sig_b[k*GetSize(sig_a) + i])
 					goto no_match_ab;
-				if (sig_b[k*GetSize(sig_a) + i] != Sx)
+				if (sig_b[k*GetSize(sig_a) + i] != State::Sx)
 					ref = sig_b[k*GetSize(sig_a) + i];
 			}
 			if (0)
@@ -245,7 +244,7 @@ struct WreduceWorker
 			while (GetSize(sig) > 1 && sig[GetSize(sig)-1] == sig[GetSize(sig)-2])
 				work_queue_bits.insert(sig[GetSize(sig)-1]), sig.remove(GetSize(sig)-1), bits_removed++;
 		} else {
-			while (GetSize(sig) > 1 && sig[GetSize(sig)-1] == S0)
+			while (GetSize(sig) > 1 && sig[GetSize(sig)-1] == State::S0)
 				work_queue_bits.insert(sig[GetSize(sig)-1]), sig.remove(GetSize(sig)-1), bits_removed++;
 		}
 
@@ -359,7 +358,7 @@ struct WreduceWorker
 				max_y_size = a_size + b_size;
 
 			while (GetSize(sig) > 1 && GetSize(sig) > max_y_size) {
-				module->connect(sig[GetSize(sig)-1], is_signed ? sig[GetSize(sig)-2] : S0);
+				module->connect(sig[GetSize(sig)-1], is_signed ? sig[GetSize(sig)-2] : State::S0);
 				sig.remove(GetSize(sig)-1);
 				bits_removed++;
 			}

From 3b19c3657cda6d972bd3b1c3eeacdfca5fb35de8 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Fri, 16 Aug 2019 19:37:11 +0000
Subject: [PATCH 15/20] Move namespace alias

---
 kernel/yosys.h | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/kernel/yosys.h b/kernel/yosys.h
index 895286a53..a80cb00b4 100644
--- a/kernel/yosys.h
+++ b/kernel/yosys.h
@@ -210,7 +210,6 @@ namespace RTLIL {
 	struct Module;
 	struct Design;
 	struct Monitor;
-	namespace ID {}
 }
 
 namespace AST {
@@ -225,7 +224,6 @@ using RTLIL::Wire;
 using RTLIL::Cell;
 using RTLIL::Module;
 using RTLIL::Design;
-namespace ID = ::YOSYS_NAMESPACE::RTLIL::ID;
 
 namespace hashlib {
 	template<> struct hash_ops<RTLIL::Wire*> : hash_obj_ops {};
@@ -317,6 +315,7 @@ RTLIL::IdString new_id(std::string file, int line, std::string func);
 //
 #define ID(_id) ([]() { const char *p = "\\" #_id, *q = p[1] == '$' ? p+1 : p; \
         static const YOSYS_NAMESPACE_PREFIX RTLIL::IdString id(q); return id; })()
+namespace ID = RTLIL::ID;
 
 RTLIL::Design *yosys_get_design();
 std::string proc_self_dirname();

From 6b156beda16cce69e7318a3a2fdbc3ad547370c6 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Fri, 16 Aug 2019 13:35:39 -0700
Subject: [PATCH 16/20] Remove unused variable

---
 frontends/aiger/aigerparse.cc | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc
index 534cc0daa..ac9e31f70 100644
--- a/frontends/aiger/aigerparse.cc
+++ b/frontends/aiger/aigerparse.cc
@@ -901,11 +901,6 @@ void AigerReader::post_process()
 				RTLIL::Cell* cell = module->cell(stringf("$__box%d__", variable));
 				if (cell) { // ABC could have optimised this box away
 					module->rename(cell, escaped_s);
-				#ifndef NDEBUG
-					RTLIL::Module* box_module = design->module(cell->type);
-					log_assert(box_module);
-				#endif
-
 					for (const auto &i : cell->connections()) {
 						RTLIL::IdString port_name = i.first;
 						RTLIL::SigSpec rhs = i.second;

From fab067cecef205ce246904cf122a5e545e348f99 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Fri, 16 Aug 2019 13:47:37 -0700
Subject: [PATCH 17/20] Add 'opt_share' to 'opt -full'

---
 passes/opt/opt.cc | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/passes/opt/opt.cc b/passes/opt/opt.cc
index e9a43e0f3..396819883 100644
--- a/passes/opt/opt.cc
+++ b/passes/opt/opt.cc
@@ -44,6 +44,7 @@ struct OptPass : public Pass {
 		log("        opt_muxtree\n");
 		log("        opt_reduce [-fine] [-full]\n");
 		log("        opt_merge [-share_all]\n");
+		log("        opt_share (-full only)\n");
 		log("        opt_rmdff [-keepdc] [-sat]\n");
 		log("        opt_clean [-purge]\n");
 		log("        opt_expr [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n");
@@ -70,6 +71,7 @@ struct OptPass : public Pass {
 		std::string opt_reduce_args;
 		std::string opt_merge_args;
 		std::string opt_rmdff_args;
+		bool opt_share = false;
 		bool fast_mode = false;
 
 		log_header(design, "Executing OPT pass (performing simple optimizations).\n");
@@ -105,6 +107,7 @@ struct OptPass : public Pass {
 			if (args[argidx] == "-full") {
 				opt_expr_args += " -full";
 				opt_reduce_args += " -full";
+				opt_share = true;
 				continue;
 			}
 			if (args[argidx] == "-keepdc") {
@@ -151,6 +154,8 @@ struct OptPass : public Pass {
 				Pass::call(design, "opt_muxtree");
 				Pass::call(design, "opt_reduce" + opt_reduce_args);
 				Pass::call(design, "opt_merge" + opt_merge_args);
+				if (opt_share)
+					Pass::call(design, "opt_share");
 				Pass::call(design, "opt_rmdff" + opt_rmdff_args);
 				Pass::call(design, "opt_clean" + opt_clean_args);
 				Pass::call(design, "opt_expr" + opt_expr_args);

From a29814ca3f448481d351bc9f8ba0a20084afd883 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Fri, 16 Aug 2019 13:47:51 -0700
Subject: [PATCH 18/20] Add 'opt_share' to CHANGELOG

---
 CHANGELOG | 1 +
 1 file changed, 1 insertion(+)

diff --git a/CHANGELOG b/CHANGELOG
index 638c36121..8dbe1aee3 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -19,6 +19,7 @@ Yosys 0.9 .. Yosys 0.9-dev
     - Added automatic gzip compression (based on filename extension) for backends
     - Improve attribute and parameter encoding in JSON to avoid ambiguities between
       bit vectors and strings containing [01xz]*
+    - Added "opt_share" pass, run as part of "opt -full"
 
 Yosys 0.8 .. Yosys 0.8-dev
 --------------------------

From 3d3779b0376b8204ed7637053176a07b7271ac1d Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Fri, 16 Aug 2019 14:01:55 -0700
Subject: [PATCH 19/20] Use ID() macro

---
 passes/opt/opt_share.cc | 228 +++++++++++++++++++---------------------
 1 file changed, 110 insertions(+), 118 deletions(-)

diff --git a/passes/opt/opt_share.cc b/passes/opt/opt_share.cc
index a2ec9cc37..734cbcf81 100644
--- a/passes/opt/opt_share.cc
+++ b/passes/opt/opt_share.cc
@@ -83,52 +83,51 @@ struct ExtSigSpec {
 	bool operator==(const ExtSigSpec &other) const { return is_signed == other.is_signed && sign == other.sign && sig == other.sig && semantics == other.semantics; }
 };
 
-#define BITWISE_OPS "$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_", "$and", "$or", "$xor", "$xnor"
+#define BITWISE_OPS ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_), ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_), ID($and), ID($or), ID($xor), ID($xnor)
 
-#define REDUCTION_OPS "$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool", "$reduce_nand"
+#define REDUCTION_OPS ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool), ID($reduce_nand)
 
-#define LOGICAL_OPS "$logic_and", "$logic_or"
+#define LOGICAL_OPS ID($logic_and), ID($logic_or)
 
-#define SHIFT_OPS "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx"
+#define SHIFT_OPS ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx)
 
-#define RELATIONAL_OPS "$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt"
+#define RELATIONAL_OPS ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt)
 
 bool cell_supported(RTLIL::Cell *cell)
 {
-
-	if (cell->type.in("$alu")) {
-		RTLIL::SigSpec sig_bi = cell->getPort("\\BI");
-		RTLIL::SigSpec sig_ci = cell->getPort("\\CI");
+	if (cell->type.in(ID($alu))) {
+		RTLIL::SigSpec sig_bi = cell->getPort(ID(BI));
+		RTLIL::SigSpec sig_ci = cell->getPort(ID(CI));
 
 		if (sig_bi.is_fully_const() && sig_ci.is_fully_const() && sig_bi == sig_ci)
 			return true;
-	} else if (cell->type.in(LOGICAL_OPS, SHIFT_OPS, BITWISE_OPS, RELATIONAL_OPS, "$add", "$sub", "$mul", "$div", "$mod", "$concat")) {
+	} else if (cell->type.in(LOGICAL_OPS, SHIFT_OPS, BITWISE_OPS, RELATIONAL_OPS, ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($concat))) {
 		return true;
 	}
 
 	return false;
 }
 
-std::map<std::string, std::string> mergeable_type_map{
-  {"$sub", "$add"},
+std::map<IdString, IdString> mergeable_type_map{
+  {ID($sub), ID($add)},
 };
 
 bool mergeable(RTLIL::Cell *a, RTLIL::Cell *b)
 {
 	auto a_type = a->type;
-	if (mergeable_type_map.count(a_type.str()))
-		a_type = mergeable_type_map.at(a_type.str());
+	if (mergeable_type_map.count(a_type))
+		a_type = mergeable_type_map.at(a_type);
 
 	auto b_type = b->type;
-	if (mergeable_type_map.count(b_type.str()))
-		b_type = mergeable_type_map.at(b_type.str());
+	if (mergeable_type_map.count(b_type))
+		b_type = mergeable_type_map.at(b_type);
 
 	return a_type == b_type;
 }
 
 RTLIL::IdString decode_port_semantics(RTLIL::Cell *cell, RTLIL::IdString port_name)
 {
-	if (cell->type.in("$lt", "$le", "$ge", "$gt", "$div", "$mod", "$concat", SHIFT_OPS) && port_name == "\\B")
+	if (cell->type.in(ID($lt), ID($le), ID($ge), ID($gt), ID($div), ID($mod), ID($concat), SHIFT_OPS) && port_name == ID(B))
 		return port_name;
 
 	return "";
@@ -136,9 +135,9 @@ RTLIL::IdString decode_port_semantics(RTLIL::Cell *cell, RTLIL::IdString port_na
 
 RTLIL::SigSpec decode_port_sign(RTLIL::Cell *cell, RTLIL::IdString port_name) {
 
-	if (cell->type == "$alu" && port_name == "\\B")
-		return cell->getPort("\\BI");
-	else if (cell->type == "$sub" && port_name == "\\B")
+	if (cell->type == ID($alu) && port_name == ID(B))
+		return cell->getPort(ID(BI));
+	else if (cell->type == ID($sub) && port_name == ID(B))
 		return RTLIL::Const(1, 1);
 
 	return RTLIL::Const(0, 1);
@@ -153,7 +152,6 @@ bool decode_port_signed(RTLIL::Cell *cell, RTLIL::IdString port_name)
 		return cell->getParam(port_name.str() + "_SIGNED").as_bool();
 
 	return false;
-
 }
 
 ExtSigSpec decode_port(RTLIL::Cell *cell, RTLIL::IdString port_name, SigMap *sigmap)
@@ -170,15 +168,14 @@ ExtSigSpec decode_port(RTLIL::Cell *cell, RTLIL::IdString port_name, SigMap *sig
 
 void merge_operators(RTLIL::Module *module, RTLIL::Cell *mux, const std::vector<OpMuxConn> &ports, const ExtSigSpec &operand)
 {
-
 	std::vector<ExtSigSpec> muxed_operands;
 	int max_width = 0;
 	for (const auto& p : ports) {
 		auto op = p.op;
 
-		RTLIL::IdString muxed_port_name = "\\A";
-		if (decode_port(op, "\\A", &assign_map) == operand)
-			muxed_port_name = "\\B";
+		RTLIL::IdString muxed_port_name = ID(A);
+		if (decode_port(op, ID(A), &assign_map) == operand)
+			muxed_port_name = ID(B);
 
 		auto operand = decode_port(op, muxed_port_name, &assign_map);
 		if (operand.sig.size() > max_width)
@@ -190,8 +187,7 @@ void merge_operators(RTLIL::Module *module, RTLIL::Cell *mux, const std::vector<
 	auto shared_op = ports[0].op;
 
 	if (std::any_of(muxed_operands.begin(), muxed_operands.end(), [&](ExtSigSpec &op) { return op.sign != muxed_operands[0].sign; }))
-		if (max_width < shared_op->getParam("\\Y_WIDTH").as_int())
-			max_width = shared_op->getParam("\\Y_WIDTH").as_int();
+        max_width = std::max(max_width, shared_op->getParam(ID(Y_WIDTH)).as_int());
 
 
 	for (auto &operand : muxed_operands)
@@ -208,11 +204,10 @@ void merge_operators(RTLIL::Module *module, RTLIL::Cell *mux, const std::vector<
 		if (muxed_op.sign != muxed_operands[0].sign)
 			muxed_op = ExtSigSpec(module->Neg(NEW_ID, muxed_op.sig, muxed_op.is_signed));
 
-
-	RTLIL::SigSpec mux_y = mux->getPort("\\Y");
-	RTLIL::SigSpec mux_a = mux->getPort("\\A");
-	RTLIL::SigSpec mux_b = mux->getPort("\\B");
-	RTLIL::SigSpec mux_s = mux->getPort("\\S");
+	RTLIL::SigSpec mux_y = mux->getPort(ID(Y));
+	RTLIL::SigSpec mux_a = mux->getPort(ID(A));
+	RTLIL::SigSpec mux_b = mux->getPort(ID(B));
+	RTLIL::SigSpec mux_s = mux->getPort(ID(S));
 
 	RTLIL::SigSpec shared_pmux_a = RTLIL::Const(RTLIL::State::Sx, max_width);
 	RTLIL::SigSpec shared_pmux_b;
@@ -221,49 +216,48 @@ void merge_operators(RTLIL::Module *module, RTLIL::Cell *mux, const std::vector<
 	int conn_width = ports[0].sig.size();
 	int conn_offset = ports[0].mux_port_offset;
 
-	shared_op->setPort("\\Y", shared_op->getPort("\\Y").extract(0, conn_width));
+	shared_op->setPort(ID(Y), shared_op->getPort(ID(Y)).extract(0, conn_width));
 
-	if (mux->type == "$pmux") {
+	if (mux->type == ID($pmux)) {
 		shared_pmux_s = RTLIL::SigSpec();
 
 		for (const auto &p : ports) {
 			shared_pmux_s.append(mux_s[p.mux_port_id]);
-			mux_b.replace(p.mux_port_id * mux_a.size() + conn_offset, shared_op->getPort("\\Y"));
+			mux_b.replace(p.mux_port_id * mux_a.size() + conn_offset, shared_op->getPort(ID(Y)));
 		}
 	} else {
 		shared_pmux_s = RTLIL::SigSpec{mux_s, module->Not(NEW_ID, mux_s)};
-		mux_a.replace(conn_offset, shared_op->getPort("\\Y"));
-		mux_b.replace(conn_offset, shared_op->getPort("\\Y"));
+		mux_a.replace(conn_offset, shared_op->getPort(ID(Y)));
+		mux_b.replace(conn_offset, shared_op->getPort(ID(Y)));
 	}
 
-	mux->setPort("\\A", mux_a);
-	mux->setPort("\\B", mux_b);
-	mux->setPort("\\Y", mux_y);
-	mux->setPort("\\S", mux_s);
+	mux->setPort(ID(A), mux_a);
+	mux->setPort(ID(B), mux_b);
+	mux->setPort(ID(Y), mux_y);
+	mux->setPort(ID(S), mux_s);
 
 	for (const auto &op : muxed_operands)
 		shared_pmux_b.append(op.sig);
 
 	auto mux_to_oper = module->Pmux(NEW_ID, shared_pmux_a, shared_pmux_b, shared_pmux_s);
 
-	if (shared_op->type.in("$alu")) {
-		RTLIL::SigSpec alu_x = shared_op->getPort("\\X");
-		RTLIL::SigSpec alu_co = shared_op->getPort("\\CO");
+	if (shared_op->type.in(ID($alu))) {
+		RTLIL::SigSpec alu_x = shared_op->getPort(ID(X));
+		RTLIL::SigSpec alu_co = shared_op->getPort(ID(CO));
 
-		shared_op->setPort("\\X", alu_x.extract(0, conn_width));
-		shared_op->setPort("\\CO", alu_co.extract(0, conn_width));
+		shared_op->setPort(ID(X), alu_x.extract(0, conn_width));
+		shared_op->setPort(ID(CO), alu_co.extract(0, conn_width));
 	}
 
-	shared_op->setParam("\\Y_WIDTH", conn_width);
+	shared_op->setParam(ID(Y_WIDTH), conn_width);
 
-	if (decode_port(shared_op, "\\A", &assign_map) == operand) {
-		shared_op->setPort("\\B", mux_to_oper);
-		shared_op->setParam("\\B_WIDTH", max_width);
+	if (decode_port(shared_op, ID(A), &assign_map) == operand) {
+		shared_op->setPort(ID(B), mux_to_oper);
+		shared_op->setParam(ID(B_WIDTH), max_width);
 	} else {
-		shared_op->setPort("\\A", mux_to_oper);
-		shared_op->setParam("\\A_WIDTH", max_width);
+		shared_op->setPort(ID(A), mux_to_oper);
+		shared_op->setParam(ID(A_WIDTH), max_width);
 	}
-
 }
 
 typedef struct {
@@ -285,7 +279,6 @@ template <typename T> void remove_val(std::vector<T> &v, const std::vector<T> &v
 
 void check_muxed_operands(std::vector<const OpMuxConn *> &ports, const ExtSigSpec &shared_operand)
 {
-
 	auto it = ports.begin();
 	ExtSigSpec seed;
 
@@ -293,9 +286,9 @@ void check_muxed_operands(std::vector<const OpMuxConn *> &ports, const ExtSigSpe
 		auto p = *it;
 		auto op = p->op;
 
-		RTLIL::IdString muxed_port_name = "\\A";
-		if (decode_port(op, "\\A", &assign_map) == shared_operand) {
-			muxed_port_name = "\\B";
+		RTLIL::IdString muxed_port_name = ID(A);
+		if (decode_port(op, ID(A), &assign_map) == shared_operand) {
+			muxed_port_name = ID(B);
 		}
 
 		auto operand = decode_port(op, muxed_port_name, &assign_map);
@@ -322,7 +315,7 @@ ExtSigSpec find_shared_operand(const OpMuxConn* seed, std::vector<const OpMuxCon
 
 	auto op_a = seed->op;
 
-	for (RTLIL::IdString port_name : {"\\A", "\\B"}) {
+	for (RTLIL::IdString port_name : {ID(A), ID(B)}) {
 		oper = decode_port(op_a, port_name, &assign_map);
 		auto operand_users = operand_to_users.at(oper);
 
@@ -362,78 +355,77 @@ dict<RTLIL::SigSpec, OpMuxConn> find_valid_op_mux_conns(RTLIL::Module *module, d
 	std::function<void(RTLIL::SigBit)> remove_outsig_from_aux_bit = [&](RTLIL::SigBit auxbit) {
 		auto aux_outsig = op_aux_to_outsig.at(auxbit);
 		auto op = outsig_to_operator.at(aux_outsig);
-		auto op_outsig = assign_map(op->getPort("\\Y"));
+		auto op_outsig = assign_map(op->getPort(ID(Y)));
 		remove_outsig(op_outsig);
 
 		for (auto aux_outbit : aux_outsig)
 			op_aux_to_outsig.erase(aux_outbit);
 	};
 
-	std::function<void(RTLIL::Cell *)>
-	  find_op_mux_conns = [&](RTLIL::Cell *mux) {
-		  RTLIL::SigSpec sig;
-		  int mux_port_size;
+	std::function<void(RTLIL::Cell *)> find_op_mux_conns = [&](RTLIL::Cell *mux) {
+		RTLIL::SigSpec sig;
+		int mux_port_size;
 
-		  if (mux->type.in("$mux", "$_MUX_")) {
-			  mux_port_size = mux->getPort("\\A").size();
-			  sig = RTLIL::SigSpec{mux->getPort("\\B"), mux->getPort("\\A")};
-		  } else {
-			  mux_port_size = mux->getPort("\\A").size();
-			  sig = mux->getPort("\\B");
-		  }
+		if (mux->type.in(ID($mux), ID($_MUX_))) {
+			mux_port_size = mux->getPort(ID(A)).size();
+			sig = RTLIL::SigSpec{mux->getPort(ID(B)), mux->getPort(ID(A))};
+		} else {
+			mux_port_size = mux->getPort(ID(A)).size();
+			sig = mux->getPort(ID(B));
+		}
 
-		  auto mux_insig = assign_map(sig);
+		auto mux_insig = assign_map(sig);
 
-		  for (int i = 0; i < mux_insig.size(); ++i) {
-			  if (op_aux_to_outsig.count(mux_insig[i])) {
-				  remove_outsig_from_aux_bit(mux_insig[i]);
-				  continue;
-			  }
+		for (int i = 0; i < mux_insig.size(); ++i) {
+			if (op_aux_to_outsig.count(mux_insig[i])) {
+				remove_outsig_from_aux_bit(mux_insig[i]);
+				continue;
+			}
 
-			  if (!op_outbit_to_outsig.count(mux_insig[i]))
-				  continue;
+			if (!op_outbit_to_outsig.count(mux_insig[i]))
+				continue;
 
-			  auto op_outsig = op_outbit_to_outsig.at(mux_insig[i]);
+			auto op_outsig = op_outbit_to_outsig.at(mux_insig[i]);
 
-			  if (op_mux_conn_map.count(op_outsig)) {
-					remove_outsig(op_outsig);
-				  continue;
-			  }
+			if (op_mux_conn_map.count(op_outsig)) {
+				remove_outsig(op_outsig);
+				continue;
+			}
 
-			  int mux_port_id = i / mux_port_size;
-			  int mux_port_offset = i % mux_port_size;
+			int mux_port_id = i / mux_port_size;
+			int mux_port_offset = i % mux_port_size;
 
-			  int op_outsig_offset;
-			  for (op_outsig_offset = 0; op_outsig[op_outsig_offset] != mux_insig[i]; ++op_outsig_offset)
-				  ;
+			int op_outsig_offset;
+			for (op_outsig_offset = 0; op_outsig[op_outsig_offset] != mux_insig[i]; ++op_outsig_offset)
+				;
 
-			  int j = op_outsig_offset;
-			  do {
-				  if (!op_outbit_to_outsig.count(mux_insig[i]))
-					  break;
+			int j = op_outsig_offset;
+			do {
+				if (!op_outbit_to_outsig.count(mux_insig[i]))
+					break;
 
-				  if (op_outbit_to_outsig.at(mux_insig[i]) != op_outsig)
-					  break;
+				if (op_outbit_to_outsig.at(mux_insig[i]) != op_outsig)
+					break;
 
-				  ++i;
-				  ++j;
-			  } while ((i / mux_port_size == mux_port_id) && (j < op_outsig.size()));
+				++i;
+				++j;
+			} while ((i / mux_port_size == mux_port_id) && (j < op_outsig.size()));
 
-			  int op_conn_width = j - op_outsig_offset;
-			  OpMuxConn inp = {
-			    op_outsig.extract(op_outsig_offset, op_conn_width),
-			    mux,
-			    outsig_to_operator.at(op_outsig),
-			    mux_port_id,
-			    mux_port_offset,
-			    op_outsig_offset,
-			  };
+			int op_conn_width = j - op_outsig_offset;
+			OpMuxConn inp = {
+				op_outsig.extract(op_outsig_offset, op_conn_width),
+				mux,
+				outsig_to_operator.at(op_outsig),
+				mux_port_id,
+				mux_port_offset,
+				op_outsig_offset,
+			};
 
-			  op_mux_conn_map[op_outsig] = inp;
+			op_mux_conn_map[op_outsig] = inp;
 
-			  --i;
-		  }
-	  };
+			--i;
+		}
+	};
 
 	std::function<void(RTLIL::SigSpec)> remove_connected_ops = [&](RTLIL::SigSpec sig) {
 		auto mux_insig = assign_map(sig);
@@ -451,8 +443,8 @@ dict<RTLIL::SigSpec, OpMuxConn> find_valid_op_mux_conns(RTLIL::Module *module, d
 	};
 
 	for (auto cell : module->cells()) {
-		if (cell->type.in("$mux", "$_MUX_", "$pmux")) {
-			remove_connected_ops(cell->getPort("\\S"));
+		if (cell->type.in(ID($mux), ID($_MUX_), ID($pmux))) {
+			remove_connected_ops(cell->getPort(ID(S)));
 			find_op_mux_conns(cell);
 		} else {
 			for (auto &conn : cell->connections())
@@ -509,8 +501,8 @@ struct OptSharePass : public Pass {
 				if (!cell_supported(cell))
 					continue;
 
-				if (cell->type == "$alu") {
-					for (RTLIL::IdString port_name : {"\\X", "\\CO"}) {
+				if (cell->type == ID($alu)) {
+					for (RTLIL::IdString port_name : {ID(X), ID(CO)}) {
 						auto mux_insig = assign_map(cell->getPort(port_name));
 						outsig_to_operator[mux_insig] = cell;
 						for (auto outbit : mux_insig)
@@ -518,12 +510,12 @@ struct OptSharePass : public Pass {
 					}
 				}
 
-				auto mux_insig = assign_map(cell->getPort("\\Y"));
+				auto mux_insig = assign_map(cell->getPort(ID(Y)));
 				outsig_to_operator[mux_insig] = cell;
 				for (auto outbit : mux_insig)
 					op_outbit_to_outsig[outbit] = mux_insig;
 
-				for (RTLIL::IdString port_name : {"\\A", "\\B"}) {
+				for (RTLIL::IdString port_name : {ID(A), ID(B)}) {
 					auto op_insig = decode_port(cell, port_name, &assign_map);
 					op_insigs.push_back(op_insig);
 					operand_to_users[op_insig].insert(cell);
@@ -549,10 +541,10 @@ struct OptSharePass : public Pass {
 				if (mux_port_conns.size() == 0) {
 					int mux_port_num;
 
-					if (p.mux->type.in("$mux", "$_MUX_"))
+					if (p.mux->type.in(ID($mux), ID($_MUX_)))
 						mux_port_num = 2;
 					else
-						mux_port_num = p.mux->getPort("\\S").size();
+						mux_port_num = p.mux->getPort(ID(S)).size();
 
 					mux_port_conns.resize(mux_port_num);
 				}

From 27d59dc0550432458d4bd636081a7b9f4b4411fe Mon Sep 17 00:00:00 2001
From: Clifford Wolf <clifford@clifford.at>
Date: Sat, 17 Aug 2019 14:47:02 +0200
Subject: [PATCH 20/20] Fix erroneous ifndef-NDEBUG in verific.cc

Signed-off-by: Clifford Wolf <clifford@clifford.at>
---
 frontends/verific/verific.cc | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc
index 64152c9cb..c5eef4b55 100644
--- a/frontends/verific/verific.cc
+++ b/frontends/verific/verific.cc
@@ -1789,10 +1789,8 @@ struct VerificExtNets
 				new_net = new Net(name.c_str());
 				nl->Add(new_net);
 
-			#ifndef NDEBUG
-				Net *n = route_up(new_net, port->IsOutput(), ca_nl, ca_net);
+				Net *n YS_ATTRIBUTE(unused) = route_up(new_net, port->IsOutput(), ca_nl, ca_net);
 				log_assert(n == ca_net);
-			#endif
 			}
 
 			if (verific_verbose)