From acd8c5c205ca9292ff5e7546cf748cb1715f1ec0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= <mwk@0x04.net>
Date: Wed, 15 Jul 2020 02:54:40 +0200
Subject: [PATCH 1/4] Remove now-redundant opt_rmdff pass.

---
 passes/opt/Makefile.inc |   1 -
 passes/opt/opt_rmdff.cc | 711 ----------------------------------------
 2 files changed, 712 deletions(-)
 delete mode 100644 passes/opt/opt_rmdff.cc

diff --git a/passes/opt/Makefile.inc b/passes/opt/Makefile.inc
index 64fee76b3..4ae9b8895 100644
--- a/passes/opt/Makefile.inc
+++ b/passes/opt/Makefile.inc
@@ -4,7 +4,6 @@ OBJS += passes/opt/opt_merge.o
 OBJS += passes/opt/opt_mem.o
 OBJS += passes/opt/opt_muxtree.o
 OBJS += passes/opt/opt_reduce.o
-OBJS += passes/opt/opt_rmdff.o
 OBJS += passes/opt/opt_dff.o
 OBJS += passes/opt/opt_share.o
 OBJS += passes/opt/opt_clean.o
diff --git a/passes/opt/opt_rmdff.cc b/passes/opt/opt_rmdff.cc
deleted file mode 100644
index 8f7628a4a..000000000
--- a/passes/opt/opt_rmdff.cc
+++ /dev/null
@@ -1,711 +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/log.h"
-#include "kernel/register.h"
-#include "kernel/rtlil.h"
-#include "kernel/satgen.h"
-#include "kernel/sigtools.h"
-#include <stdio.h>
-#include <stdlib.h>
-
-USING_YOSYS_NAMESPACE
-PRIVATE_NAMESPACE_BEGIN
-
-SigMap assign_map, dff_init_map;
-SigSet<RTLIL::Cell*> mux_drivers;
-dict<SigBit, RTLIL::Cell*> bit2driver;
-dict<SigBit, pool<SigBit>> init_attributes;
-
-bool keepdc;
-bool sat;
-
-void remove_init_attr(SigSpec sig)
-{
-	for (auto bit : assign_map(sig))
-		if (init_attributes.count(bit))
-			for (auto wbit : init_attributes.at(bit))
-				wbit.wire->attributes.at(ID::init)[wbit.offset] = State::Sx;
-}
-
-bool handle_dffsr(RTLIL::Module *mod, RTLIL::Cell *cell)
-{
-	SigSpec sig_set, sig_clr;
-	State pol_set, pol_clr;
-
-	if (cell->hasPort(ID::S))
-		sig_set = cell->getPort(ID::S);
-
-	if (cell->hasPort(ID::R))
-		sig_clr = cell->getPort(ID::R);
-
-	if (cell->hasPort(ID::SET))
-		sig_set = cell->getPort(ID::SET);
-
-	if (cell->hasPort(ID::CLR))
-		sig_clr = cell->getPort(ID::CLR);
-
-	log_assert(GetSize(sig_set) == GetSize(sig_clr));
-
-	if (cell->type.begins_with("$_DFFSR_")) {
-		pol_set = cell->type[9] == 'P' ? State::S1 : State::S0;
-		pol_clr = cell->type[10] == 'P' ? State::S1 : State::S0;
-	} else
-	if (cell->type.begins_with("$_DLATCHSR_")) {
-		pol_set = cell->type[12] == 'P' ? State::S1 : State::S0;
-		pol_clr = cell->type[13] == 'P' ? State::S1 : State::S0;
-	} else
-	if (cell->type.in(ID($dffsr), ID($dlatchsr))) {
-		pol_set = cell->parameters[ID::SET_POLARITY].as_bool() ? State::S1 : State::S0;
-		pol_clr = cell->parameters[ID::CLR_POLARITY].as_bool() ? State::S1 : State::S0;
-	} else
-		log_abort();
-
-	State npol_set = pol_set == State::S0 ? State::S1 : State::S0;
-	State npol_clr = pol_clr == State::S0 ? State::S1 : State::S0;
-
-	SigSpec sig_d = cell->getPort(ID::D);
-	SigSpec sig_q = cell->getPort(ID::Q);
-
-	bool did_something = false;
-	bool proper_sr = false;
-	bool used_pol_set = false;
-	bool used_pol_clr = false;
-	bool hasreset = false;
-	Const reset_val;
-	SigSpec sig_reset;
-
-	for (int i = 0; i < GetSize(sig_set); i++)
-	{
-		SigBit s = sig_set[i], c = sig_clr[i];
-
-		if (s != npol_set || c != npol_clr)
-			hasreset = true;
-
-		if (s == pol_set || c == pol_clr)
-		{
-			log("Constantly %s Q bit %s for SR cell %s (%s) from module %s.\n",
-					s == pol_set ? "set" : "cleared", log_signal(sig_q[i]),
-					log_id(cell), log_id(cell->type), log_id(mod));
-
-			remove_init_attr(sig_q[i]);
-			mod->connect(sig_q[i], s == pol_set ? State::S1 : State::S0);
-			sig_set.remove(i);
-			sig_clr.remove(i);
-			sig_d.remove(i);
-			sig_q.remove(i--);
-			did_something = true;
-			continue;
-		}
-		if (sig_reset.empty() && s.wire != nullptr) sig_reset = s;
-		if (sig_reset.empty() && c.wire != nullptr) sig_reset = c;
-
-		if (s.wire != nullptr && s != sig_reset) proper_sr = true;
-		if (c.wire != nullptr && c != sig_reset) proper_sr = true;
-
-		if ((s.wire == nullptr) != (c.wire == nullptr)) {
-			if (s.wire != nullptr) used_pol_set = true;
-			if (c.wire != nullptr) used_pol_clr = true;
-			reset_val.bits.push_back(c.wire == nullptr ? State::S1 : State::S0);
-		} else
-			proper_sr = true;
-	}
-
-	if (!hasreset)
-		proper_sr = false;
-
-	if (GetSize(sig_set) == 0)
-	{
-		log("Removing %s (%s) from module %s.\n", log_id(cell), log_id(cell->type), log_id(mod));
-		mod->remove(cell);
-		return true;
-	}
-
-	if (cell->type.in(ID($dffsr), ID($dlatchsr)))
-	{
-		cell->setParam(ID::WIDTH, GetSize(sig_d));
-		cell->setPort(ID::SET, sig_set);
-		cell->setPort(ID::CLR, sig_clr);
-		cell->setPort(ID::D, sig_d);
-		cell->setPort(ID::Q, sig_q);
-	}
-	else
-	{
-		cell->setPort(ID::S, sig_set);
-		cell->setPort(ID::R, sig_clr);
-		cell->setPort(ID::D, sig_d);
-		cell->setPort(ID::Q, sig_q);
-	}
-
-	if (proper_sr)
-		return did_something;
-
-	if (used_pol_set && used_pol_clr && pol_set != pol_clr)
-		return did_something;
-
-	if (cell->type == ID($dlatchsr))
-		return did_something;
-
-	State unified_pol = used_pol_set ? pol_set : pol_clr;
-
-	if (cell->type == ID($dffsr))
-	{
-		if (hasreset)
-		{
-			log("Converting %s (%s) to %s in module %s.\n", log_id(cell), log_id(cell->type), "$adff", log_id(mod));
-
-			cell->type = ID($adff);
-			cell->setParam(ID::ARST_POLARITY, unified_pol);
-			cell->setParam(ID::ARST_VALUE, reset_val);
-			cell->setPort(ID::ARST, sig_reset);
-
-			cell->unsetParam(ID::SET_POLARITY);
-			cell->unsetParam(ID::CLR_POLARITY);
-			cell->unsetPort(ID::SET);
-			cell->unsetPort(ID::CLR);
-		}
-		else
-		{
-			log("Converting %s (%s) to %s in module %s.\n", log_id(cell), log_id(cell->type), "$dff", log_id(mod));
-
-			cell->type = ID($dff);
-			cell->unsetParam(ID::SET_POLARITY);
-			cell->unsetParam(ID::CLR_POLARITY);
-			cell->unsetPort(ID::SET);
-			cell->unsetPort(ID::CLR);
-		}
-
-		return true;
-	}
-
-	if (!hasreset)
-	{
-		IdString new_type;
-
-		if (cell->type.begins_with("$_DFFSR_"))
-			new_type = stringf("$_DFF_%c_", cell->type[8]);
-		else if (cell->type.begins_with("$_DLATCHSR_"))
-			new_type = stringf("$_DLATCH_%c_", cell->type[11]);
-		else
-			log_abort();
-
-		log("Converting %s (%s) to %s in module %s.\n", log_id(cell), log_id(cell->type), log_id(new_type), log_id(mod));
-
-		cell->type = new_type;
-		cell->unsetPort(ID::S);
-		cell->unsetPort(ID::R);
-
-		return true;
-	}
-
-	return did_something;
-}
-
-bool handle_dlatch(RTLIL::Module *mod, RTLIL::Cell *dlatch)
-{
-	SigSpec sig_e;
-	State on_state, off_state;
-
-	if (dlatch->type == ID($dlatch)) {
-		sig_e = assign_map(dlatch->getPort(ID::EN));
-		on_state = dlatch->getParam(ID::EN_POLARITY).as_bool() ? State::S1 : State::S0;
-		off_state = dlatch->getParam(ID::EN_POLARITY).as_bool() ? State::S0 : State::S1;
-	} else
-	if (dlatch->type == ID($_DLATCH_P_)) {
-		sig_e = assign_map(dlatch->getPort(ID::E));
-		on_state = State::S1;
-		off_state = State::S0;
-	} else
-	if (dlatch->type == ID($_DLATCH_N_)) {
-		sig_e = assign_map(dlatch->getPort(ID::E));
-		on_state = State::S0;
-		off_state = State::S1;
-	} else
-		log_abort();
-
-	if (sig_e == off_state)
-	{
-		RTLIL::Const val_init;
-		for (auto bit : dff_init_map(dlatch->getPort(ID::Q)))
-			val_init.bits.push_back(bit.wire == NULL ? bit.data : State::Sx);
-		mod->connect(dlatch->getPort(ID::Q), val_init);
-		goto delete_dlatch;
-	}
-
-	if (sig_e == on_state)
-	{
-		mod->connect(dlatch->getPort(ID::Q), dlatch->getPort(ID::D));
-		goto delete_dlatch;
-	}
-
-	return false;
-
-delete_dlatch:
-	log("Removing %s (%s) from module %s.\n", log_id(dlatch), log_id(dlatch->type), log_id(mod));
-	remove_init_attr(dlatch->getPort(ID::Q));
-	mod->remove(dlatch);
-	return true;
-}
-
-bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
-{
-	RTLIL::SigSpec sig_d, sig_q, sig_c, sig_r, sig_e;
-	RTLIL::Const val_cp, val_rp, val_rv, val_ep;
-
-	if (dff->type == ID($_FF_)) {
-		sig_d = dff->getPort(ID::D);
-		sig_q = dff->getPort(ID::Q);
-	}
-	else if (dff->type == ID($_DFF_N_) || dff->type == ID($_DFF_P_)) {
-		sig_d = dff->getPort(ID::D);
-		sig_q = dff->getPort(ID::Q);
-		sig_c = dff->getPort(ID::C);
-		val_cp = RTLIL::Const(dff->type == ID($_DFF_P_), 1);
-	}
-	else if (dff->type.begins_with("$_DFF_") && dff->type.compare(9, 1, "_") == 0 &&
-			(dff->type[6] == 'N' || dff->type[6] == 'P') &&
-			(dff->type[7] == 'N' || dff->type[7] == 'P') &&
-			(dff->type[8] == '0' || dff->type[8] == '1')) {
-		sig_d = dff->getPort(ID::D);
-		sig_q = dff->getPort(ID::Q);
-		sig_c = dff->getPort(ID::C);
-		sig_r = dff->getPort(ID::R);
-		val_cp = RTLIL::Const(dff->type[6] == 'P', 1);
-		val_rp = RTLIL::Const(dff->type[7] == 'P', 1);
-		val_rv = RTLIL::Const(dff->type[8] == '1', 1);
-	}
-	else if (dff->type.begins_with("$_DFFE_") && dff->type.compare(9, 1, "_") == 0 &&
-			(dff->type[7] == 'N' || dff->type[7] == 'P') &&
-			(dff->type[8] == 'N' || dff->type[8] == 'P')) {
-		sig_d = dff->getPort(ID::D);
-		sig_q = dff->getPort(ID::Q);
-		sig_c = dff->getPort(ID::C);
-		sig_e = dff->getPort(ID::E);
-		val_cp = RTLIL::Const(dff->type[7] == 'P', 1);
-		val_ep = RTLIL::Const(dff->type[8] == 'P', 1);
-	}
-	else if (dff->type == ID($ff)) {
-		sig_d = dff->getPort(ID::D);
-		sig_q = dff->getPort(ID::Q);
-	}
-	else if (dff->type == ID($dff)) {
-		sig_d = dff->getPort(ID::D);
-		sig_q = dff->getPort(ID::Q);
-		sig_c = dff->getPort(ID::CLK);
-		val_cp = RTLIL::Const(dff->parameters[ID::CLK_POLARITY].as_bool(), 1);
-	}
-	else if (dff->type == ID($dffe)) {
-		sig_e = dff->getPort(ID::EN);
-		sig_d = dff->getPort(ID::D);
-		sig_q = dff->getPort(ID::Q);
-		sig_c = dff->getPort(ID::CLK);
-		val_cp = RTLIL::Const(dff->parameters[ID::CLK_POLARITY].as_bool(), 1);
-		val_ep = RTLIL::Const(dff->parameters[ID::EN_POLARITY].as_bool(), 1);
-	}
-	else if (dff->type == ID($adff)) {
-		sig_d = dff->getPort(ID::D);
-		sig_q = dff->getPort(ID::Q);
-		sig_c = dff->getPort(ID::CLK);
-		sig_r = dff->getPort(ID::ARST);
-		val_cp = RTLIL::Const(dff->parameters[ID::CLK_POLARITY].as_bool(), 1);
-		val_rp = RTLIL::Const(dff->parameters[ID::ARST_POLARITY].as_bool(), 1);
-		val_rv = dff->parameters[ID::ARST_VALUE];
-	}
-	else
-		log_abort();
-
-	assign_map.apply(sig_d);
-	assign_map.apply(sig_q);
-	assign_map.apply(sig_c);
-	assign_map.apply(sig_r);
-
-	bool has_init = false;
-	RTLIL::Const val_init;
-	for (auto bit : dff_init_map(sig_q).to_sigbit_vector()) {
-		if (bit.wire == NULL || keepdc)
-			has_init = true;
-		val_init.bits.push_back(bit.wire == NULL ? bit.data : RTLIL::State::Sx);
-	}
-
-	if (dff->type.in(ID($ff), ID($dff)) && mux_drivers.has(sig_d)) {
-		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));
-			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;
-			}
-			if (sig_b == sig_q && sig_a.is_fully_const() && (!has_init || val_init == sig_a.as_const())) {
-				mod->connect(sig_q, sig_a);
-				goto delete_dff;
-			}
-		}
-	}
-
-	// If clock is driven by a constant and (i) no reset signal
-	//                                      (ii) Q has no initial value
-	//                                      (iii) initial value is same as reset value
-	if (!sig_c.empty() && sig_c.is_fully_const() && (!sig_r.size() || !has_init || val_init == val_rv)) {
-		if (val_rv.bits.size() == 0)
-			val_rv = val_init;
-		// Q is permanently reset value or initial value
-		mod->connect(sig_q, val_rv);
-		goto delete_dff;
-	}
-
-	// If D is fully undefined and reset signal present and (i) Q has no initial value
-	//                                                     (ii) initial value is same as reset value
-	if (sig_d.is_fully_undef() && sig_r.size() && (!has_init || val_init == val_rv)) {
-		// Q is permanently reset value
-		mod->connect(sig_q, val_rv);
-		goto delete_dff;
-	}
-
-	// If D is fully undefined and no reset signal and Q has an initial value
-	if (sig_d.is_fully_undef() && !sig_r.size() && has_init) {
-		// Q is permanently initial value
-		mod->connect(sig_q, val_init);
-		goto delete_dff;
-	}
-
-	// If D is fully constant and (i) no reset signal
-	//                            (ii) reset value is same as constant D
-	//                        and (a) has no initial value
-	//                            (b) initial value same as constant D
-	if (sig_d.is_fully_const() && (!sig_r.size() || val_rv == sig_d.as_const()) && (!has_init || val_init == sig_d.as_const())) {
-		// Q is permanently D
-		mod->connect(sig_q, sig_d);
-		goto delete_dff;
-	}
-
-	// If D input is same as Q output and (i) no reset signal
-	//                                    (ii) no initial signal
-	//                                    (iii) initial value is same as reset value
-	if (sig_d == sig_q && (sig_r.empty() || !has_init || val_init == val_rv)) {
-		// Q is permanently reset value or initial value
-		if (sig_r.size())
-			mod->connect(sig_q, val_rv);
-		else if (has_init)
-			mod->connect(sig_q, val_init);
-		goto delete_dff;
-	}
-
-	// If reset signal is present, and is fully constant
-	if (!sig_r.empty() && sig_r.is_fully_const())
-	{
-		// If reset value is permanently active or if reset is undefined
-		if (sig_r == val_rp || sig_r.is_fully_undef()) {
-			// Q is permanently reset value
-			mod->connect(sig_q, val_rv);
-			goto delete_dff;
-		}
-
-		log("Removing unused reset from %s (%s) from module %s.\n", log_id(dff), log_id(dff->type), log_id(mod));
-
-		if (dff->type == ID($adff)) {
-			dff->type = ID($dff);
-			dff->unsetPort(ID::ARST);
-			dff->unsetParam(ID::ARST_POLARITY);
-			dff->unsetParam(ID::ARST_VALUE);
-			return true;
-		}
-
-		log_assert(dff->type.begins_with("$_DFF_"));
-		dff->type = stringf("$_DFF_%c_", + dff->type[6]);
-		dff->unsetPort(ID::R);
-	}
-
-	// If enable signal is present, and is fully constant
-	if (!sig_e.empty() && sig_e.is_fully_const())
-	{
-		// If enable value is permanently inactive
-		if (sig_e != val_ep) {
-			// Q is permanently initial value
-			mod->connect(sig_q, val_init);
-			goto delete_dff;
-		}
-
-		log("Removing unused enable from %s (%s) from module %s.\n", log_id(dff), log_id(dff->type), log_id(mod));
-
-		if (dff->type == ID($dffe)) {
-			dff->type = ID($dff);
-			dff->unsetPort(ID::EN);
-			dff->unsetParam(ID::EN_POLARITY);
-			return true;
-		}
-
-		log_assert(dff->type.begins_with("$_DFFE_"));
-		dff->type = stringf("$_DFF_%c_", + dff->type[7]);
-		dff->unsetPort(ID::E);
-	}
-
-	if (sat && has_init && (!sig_r.size() || val_init == val_rv))
-	{
-		bool removed_sigbits = false;
-
-		ezSatPtr ez;
-		SatGen satgen(ez.get(), &assign_map);
-		pool<Cell*> sat_cells;
-
-		std::function<void(Cell*)> sat_import_cell = [&](Cell *c) {
-			if (!sat_cells.insert(c).second)
-				return;
-			if (!satgen.importCell(c))
-				return;
-			for (auto &conn : c->connections()) {
-				if (!c->input(conn.first))
-					continue;
-				for (auto bit : assign_map(conn.second))
-					if (bit2driver.count(bit))
-						sat_import_cell(bit2driver.at(bit));
-			}
-		};
-
-		// For each register bit, try to prove that it cannot change from the initial value. If so, remove it
-		for (int position = 0; position < GetSize(sig_d); position += 1) {
-			RTLIL::SigBit q_sigbit = sig_q[position];
-			RTLIL::SigBit d_sigbit = sig_d[position];
-
-			if ((!q_sigbit.wire) || (!d_sigbit.wire))
-				continue;
-
-			if (!bit2driver.count(d_sigbit))
-				continue;
-
-			sat_import_cell(bit2driver.at(d_sigbit));
-
-			RTLIL::State sigbit_init_val = val_init[position];
-			if (sigbit_init_val != State::S0 && sigbit_init_val != State::S1)
-				continue;
-
-			int init_sat_pi = satgen.importSigSpec(sigbit_init_val).front();
-			int q_sat_pi = satgen.importSigBit(q_sigbit);
-			int d_sat_pi = satgen.importSigBit(d_sigbit);
-
-			// Try to find out whether the register bit can change under some circumstances
-			bool counter_example_found = ez->solve(ez->IFF(q_sat_pi, init_sat_pi), ez->NOT(ez->IFF(d_sat_pi, init_sat_pi)));
-
-			// If the register bit cannot change, we can replace it with a constant
-			if (!counter_example_found)
-			{
-				log("Setting constant %d-bit at position %d on %s (%s) from module %s.\n", sigbit_init_val ? 1 : 0,
-						position, log_id(dff), log_id(dff->type), log_id(mod));
-
-				SigSpec tmp = dff->getPort(ID::D);
-				tmp[position] = sigbit_init_val;
-				dff->setPort(ID::D, tmp);
-
-				removed_sigbits = true;
-			}
-		}
-
-		if (removed_sigbits) {
-			handle_dff(mod, dff);
-			return true;
-		}
-	}
-
-
-	return false;
-
-delete_dff:
-	log("Removing %s (%s) from module %s.\n", log_id(dff), log_id(dff->type), log_id(mod));
-	remove_init_attr(dff->getPort(ID::Q));
-	mod->remove(dff);
-
-	for (auto &entry : bit2driver)
-		if (entry.second == dff)
-			bit2driver.erase(entry.first);
-
-	return true;
-}
-
-struct OptRmdffPass : public Pass {
-	OptRmdffPass() : Pass("opt_rmdff", "remove DFFs with constant inputs") { }
-	void help() override
-	{
-		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
-		log("\n");
-		log("    opt_rmdff [-keepdc] [-sat] [selection]\n");
-		log("\n");
-		log("This pass identifies flip-flops with constant inputs and replaces them with\n");
-		log("a constant driver.\n");
-		log("\n");
-		log("    -sat\n");
-		log("        additionally invoke SAT solver to detect and remove flip-flops (with \n");
-		log("        non-constant inputs) that can also be replaced with a constant driver\n");
-		log("\n");
-	}
-	void execute(std::vector<std::string> args, RTLIL::Design *design) override
-	{
-		int total_count = 0, total_initdrv = 0;
-		log_header(design, "Executing OPT_RMDFF pass (remove dff with constant values).\n");
-
-		keepdc = false;
-		sat = false;
-
-		size_t argidx;
-		for (argidx = 1; argidx < args.size(); argidx++) {
-			if (args[argidx] == "-keepdc") {
-				keepdc = true;
-				continue;
-			}
-			if (args[argidx] == "-sat") {
-				sat = true;
-				continue;
-			}
-			break;
-		}
-		extra_args(args, argidx, design);
-
-		for (auto module : design->selected_modules()) {
-			pool<SigBit> driven_bits;
-			dict<SigBit, State> init_bits;
-
-			assign_map.set(module);
-			dff_init_map.set(module);
-			mux_drivers.clear();
-			bit2driver.clear();
-			init_attributes.clear();
-
-			for (auto wire : module->wires())
-			{
-				if (wire->attributes.count(ID::init) != 0) {
-					Const initval = wire->attributes.at(ID::init);
-					for (int i = 0; i < GetSize(initval) && i < GetSize(wire); i++)
-						if (initval[i] == State::S0 || initval[i] == State::S1)
-							dff_init_map.add(SigBit(wire, i), initval[i]);
-					for (int i = 0; i < GetSize(wire); i++) {
-						SigBit wire_bit(wire, i), mapped_bit = assign_map(wire_bit);
-						if (mapped_bit.wire) {
-							init_attributes[mapped_bit].insert(wire_bit);
-							if (i < GetSize(initval))
-								init_bits[mapped_bit] = initval[i];
-						}
-					}
-				}
-
-				if (wire->port_input) {
-					for (auto bit : assign_map(wire))
-						driven_bits.insert(bit);
-				}
-			}
-
-			std::vector<RTLIL::IdString> dff_list;
-			std::vector<RTLIL::IdString> dffsr_list;
-			std::vector<RTLIL::IdString> dlatch_list;
-			for (auto cell : module->cells())
-			{
-				for (auto &conn : cell->connections()) {
-					bool is_output = cell->output(conn.first);
-					if (is_output || !cell->known())
-						for (auto bit : assign_map(conn.second)) {
-							if (is_output)
-								bit2driver[bit] = cell;
-							driven_bits.insert(bit);
-						}
-				}
-
-				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);
-					continue;
-				}
-
-				if (!design->selected(module, cell))
-					continue;
-
-				if (cell->type.in(ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_),
-						ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_), ID($dffsr),
-						ID($_DLATCHSR_NNN_), ID($_DLATCHSR_NNP_), ID($_DLATCHSR_NPN_), ID($_DLATCHSR_NPP_),
-						ID($_DLATCHSR_PNN_), ID($_DLATCHSR_PNP_), ID($_DLATCHSR_PPN_), ID($_DLATCHSR_PPP_), ID($dlatchsr)))
-					dffsr_list.push_back(cell->name);
-
-				if (cell->type.in(ID($_FF_), ID($_DFF_N_), ID($_DFF_P_),
-						ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_),
-						ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_),
-						ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_),
-						ID($ff), ID($dff), ID($dffe), ID($adff)))
-					dff_list.push_back(cell->name);
-
-				if (cell->type.in(ID($dlatch), ID($_DLATCH_P_), ID($_DLATCH_N_)))
-					dlatch_list.push_back(cell->name);
-			}
-
-			for (auto &id : dffsr_list) {
-				if (module->cell(id) != nullptr &&
-						handle_dffsr(module, module->cells_[id]))
-					total_count++;
-			}
-
-			for (auto &id : dff_list) {
-				if (module->cell(id) != nullptr &&
-						handle_dff(module, module->cells_[id]))
-					total_count++;
-			}
-
-			for (auto &id : dlatch_list) {
-				if (module->cell(id) != nullptr &&
-						handle_dlatch(module, module->cells_[id]))
-					total_count++;
-			}
-
-			SigSpec const_init_sigs;
-
-			for (auto bit : init_bits)
-				if (!driven_bits.count(bit.first))
-					const_init_sigs.append(bit.first);
-
-			const_init_sigs.sort_and_unify();
-
-			for (SigSpec sig : const_init_sigs.chunks())
-			{
-				Const val;
-
-				for (auto bit : sig)
-					val.bits.push_back(init_bits.at(bit));
-
-				log("Promoting init spec %s = %s to constant driver in module %s.\n",
-						log_signal(sig), log_signal(val), log_id(module));
-
-				module->connect(sig, val);
-				remove_init_attr(sig);
-				total_initdrv++;
-			}
-		}
-
-		assign_map.clear();
-		mux_drivers.clear();
-		bit2driver.clear();
-		init_attributes.clear();
-
-		if (total_count || total_initdrv)
-			design->scratchpad_set_bool("opt.did_something", true);
-
-		if (total_initdrv)
-			log("Promoted %d init specs to constant drivers.\n", total_initdrv);
-
-		if (total_count)
-			log("Replaced %d DFF cells.\n", total_count);
-	}
-} OptRmdffPass;
-
-PRIVATE_NAMESPACE_END

From a0e99a9f3f0a52e3a6f2000791d93b54ce116928 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= <mwk@0x04.net>
Date: Wed, 15 Jul 2020 02:37:43 +0200
Subject: [PATCH 2/4] peepopt: Remove now-redundant dffmux pattern.

---
 passes/pmgen/Makefile.inc       |   1 -
 passes/pmgen/peepopt.cc         |   3 -
 passes/pmgen/peepopt_dffmux.pmg | 171 --------------------------------
 tests/opt/opt_dff_dffmux.ys     | 129 ++++++++++++++++++++++++
 tests/various/peepopt.ys        | 143 --------------------------
 5 files changed, 129 insertions(+), 318 deletions(-)
 delete mode 100644 passes/pmgen/peepopt_dffmux.pmg
 create mode 100644 tests/opt/opt_dff_dffmux.ys

diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc
index 1a57bef7d..c6bbc386a 100644
--- a/passes/pmgen/Makefile.inc
+++ b/passes/pmgen/Makefile.inc
@@ -36,7 +36,6 @@ $(eval $(call add_extra_objs,passes/pmgen/peepopt_pm.h))
 
 PEEPOPT_PATTERN  = passes/pmgen/peepopt_shiftmul.pmg
 PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv.pmg
-PEEPOPT_PATTERN += passes/pmgen/peepopt_dffmux.pmg
 
 passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN)
 	$(P) mkdir -p passes/pmgen && $(PYTHON_EXECUTABLE) $< -o $@ -p peepopt $(filter-out $<,$^)
diff --git a/passes/pmgen/peepopt.cc b/passes/pmgen/peepopt.cc
index c16b4486d..a9c62fcf6 100644
--- a/passes/pmgen/peepopt.cc
+++ b/passes/pmgen/peepopt.cc
@@ -67,8 +67,6 @@ struct PeepoptPass : public Pass {
 				GENERATE_PATTERN(peepopt_pm, shiftmul);
 			else if (genmode == "muldiv")
 				GENERATE_PATTERN(peepopt_pm, muldiv);
-			else if (genmode == "dffmux")
-				GENERATE_PATTERN(peepopt_pm, dffmux);
 			else
 				log_abort();
 			return;
@@ -106,7 +104,6 @@ struct PeepoptPass : public Pass {
 
 				pm.run_shiftmul();
 				pm.run_muldiv();
-				pm.run_dffmux();
 
 				for (auto w : module->wires()) {
 					auto it = w->attributes.find(ID::init);
diff --git a/passes/pmgen/peepopt_dffmux.pmg b/passes/pmgen/peepopt_dffmux.pmg
deleted file mode 100644
index 0069b0570..000000000
--- a/passes/pmgen/peepopt_dffmux.pmg
+++ /dev/null
@@ -1,171 +0,0 @@
-pattern dffmux
-
-state <IdString> cemuxAB rstmuxBA
-state <SigSpec> sigD
-
-match dff
-	select dff->type == $dff
-	select GetSize(port(dff, \D)) > 1
-endmatch
-
-code sigD
-	sigD = port(dff, \D);
-endcode
-
-match rstmux
-	select rstmux->type == $mux
-	select GetSize(port(rstmux, \Y)) > 1
-	index <SigSpec> port(rstmux, \Y) === sigD
-	choice <IdString> BA {\B, \A}
-	select port(rstmux, BA).is_fully_const()
-	set rstmuxBA BA
-	semioptional
-endmatch
-
-code sigD
-	if (rstmux)
-		sigD = port(rstmux, rstmuxBA == \B ? \A : \B);
-endcode
-
-match cemux
-	select cemux->type == $mux
-	select GetSize(port(cemux, \Y)) > 1
-	index <SigSpec> port(cemux, \Y) === sigD
-	choice <IdString> AB {\A, \B}
-	index <SigSpec> port(cemux, AB) === port(dff, \Q)
-	set cemuxAB AB
-	semioptional
-endmatch
-
-code
-	if (!cemux && !rstmux)
-		reject;
-endcode
-
-code
-	Const rst;
-	SigSpec D;
-	if (cemux) {
-		D = port(cemux, cemuxAB == \A ? \B : \A);
-		if (rstmux)
-			rst = port(rstmux, rstmuxBA).as_const();
-		else
-			rst = Const(State::Sx, GetSize(D));
-	}
-	else {
-		log_assert(rstmux);
-		D = port(rstmux, rstmuxBA  == \B ? \A : \B);
-		rst = port(rstmux, rstmuxBA).as_const();
-	}
-	SigSpec Q = port(dff, \Q);
-	int width = GetSize(D);
-
-	SigSpec dffD = dff->getPort(\D);
-	SigSpec dffQ = dff->getPort(\Q);
-
-	Const initval;
-	for (auto b : Q) {
-		auto it = initbits.find(b);
-		initval.bits.push_back(it == initbits.end() ? State::Sx : it->second);
-	}
-
-	auto cmpx = [=](State lhs, State rhs) {
-		if (lhs == State::Sx || rhs == State::Sx)
-			return true;
-		return lhs == rhs;
-	};
-
-	int i = width-1;
-	while (i > 1) {
-		if (D[i] != D[i-1])
-			break;
-		if (!cmpx(rst[i], rst[i-1]))
-			break;
-		if (!cmpx(initval[i], initval[i-1]))
-			break;
-		if (!cmpx(rst[i], initval[i]))
-			break;
-		rminitbits.insert(Q[i]);
-		module->connect(Q[i], Q[i-1]);
-		i--;
-	}
-	if (i < width-1) {
-		did_something = true;
-		if (cemux) {
-			SigSpec ceA = cemux->getPort(\A);
-			SigSpec ceB = cemux->getPort(\B);
-			SigSpec ceY = cemux->getPort(\Y);
-			ceA.remove(i, width-1-i);
-			ceB.remove(i, width-1-i);
-			ceY.remove(i, width-1-i);
-			cemux->setPort(\A, ceA);
-			cemux->setPort(\B, ceB);
-			cemux->setPort(\Y, ceY);
-			cemux->fixup_parameters();
-			blacklist(cemux);
-		}
-		if (rstmux) {
-			SigSpec rstA = rstmux->getPort(\A);
-			SigSpec rstB = rstmux->getPort(\B);
-			SigSpec rstY = rstmux->getPort(\Y);
-			rstA.remove(i, width-1-i);
-			rstB.remove(i, width-1-i);
-			rstY.remove(i, width-1-i);
-			rstmux->setPort(\A, rstA);
-			rstmux->setPort(\B, rstB);
-			rstmux->setPort(\Y, rstY);
-			rstmux->fixup_parameters();
-			blacklist(rstmux);
-		}
-		dffD.remove(i, width-1-i);
-		dffQ.remove(i, width-1-i);
-		dff->setPort(\D, dffD);
-		dff->setPort(\Q, dffQ);
-		dff->fixup_parameters();
-		blacklist(dff);
-
-		log("dffcemux pattern in %s: dff=%s, cemux=%s, rstmux=%s; removed top %d bits.\n", log_id(module), log_id(dff), log_id(cemux, "n/a"), log_id(rstmux, "n/a"), width-1-i);
-		width = i+1;
-	}
-	if (cemux) {
-		SigSpec ceA = cemux->getPort(\A);
-		SigSpec ceB = cemux->getPort(\B);
-		SigSpec ceY = cemux->getPort(\Y);
-
-		int count = 0;
-		for (int i = width-1; i >= 0; i--) {
-			if (D[i].wire)
-				continue;
-			if (cmpx(rst[i], D[i].data) && cmpx(initval[i], D[i].data)) {
-				count++;
-				rminitbits.insert(Q[i]);
-				module->connect(Q[i], D[i]);
-				ceA.remove(i);
-				ceB.remove(i);
-				ceY.remove(i);
-				dffD.remove(i);
-				dffQ.remove(i);
-			}
-		}
-		if (count > 0)
-		{
-			did_something = true;
-
-			cemux->setPort(\A, ceA);
-			cemux->setPort(\B, ceB);
-			cemux->setPort(\Y, ceY);
-			cemux->fixup_parameters();
-			blacklist(cemux);
-
-			dff->setPort(\D, dffD);
-			dff->setPort(\Q, dffQ);
-			dff->fixup_parameters();
-			blacklist(dff);
-
-			log("dffcemux pattern in %s: dff=%s, cemux=%s, rstmux=%s; removed %d constant bits.\n", log_id(module), log_id(dff), log_id(cemux), log_id(rstmux, "n/a"), count);
-		}
-	}
-
-	if (did_something)
-		accept;
-endcode
diff --git a/tests/opt/opt_dff_dffmux.ys b/tests/opt/opt_dff_dffmux.ys
new file mode 100644
index 000000000..43190cc31
--- /dev/null
+++ b/tests/opt/opt_dff_dffmux.ys
@@ -0,0 +1,129 @@
+design -reset
+read_verilog <<EOT
+module opt_dffmuxext_unsigned(input clk, ce, input [1:0] i, output reg [3:0] o);
+    always @(posedge clk) if (ce) o <= i;
+endmodule
+EOT
+
+proc
+equiv_opt -assert opt
+design -load postopt
+select -assert-count 1 t:$dffe r:WIDTH=2 %i
+select -assert-count 0 t:$dffe %% t:* %D
+
+####################
+
+design -reset
+read_verilog <<EOT
+module opt_dffmuxext_signed(input clk, ce, input signed [1:0] i, output reg signed [3:0] o);
+    always @(posedge clk) if (ce) o <= i;
+endmodule
+EOT
+
+proc
+equiv_opt -assert opt
+design -load postopt
+wreduce
+select -assert-count 1 t:$dffe r:WIDTH=2 %i
+select -assert-count 0 t:$dffe %% t:* %D
+
+###################
+
+design -reset
+read_verilog <<EOT
+module opt_dffmuxext_const(input clk, ce, input [1:0] i, output reg [5:0] o);
+    always @(posedge clk) if (ce) o <= {1'b0, i[1], 2'b1x, i[0], 1'bz};
+endmodule
+EOT
+
+proc
+equiv_opt -assert opt
+design -load postopt
+select -assert-count 1 t:$dffe r:WIDTH=2 %i
+select -assert-count 0 t:$dffe %% t:* %D
+
+###################
+
+design -reset
+read_verilog <<EOT
+module opt_dffmuxext_const_init(input clk, ce, input [1:0] i, (* init=6'b0x00x1 *) output reg [5:0] o);
+    always @(posedge clk) if (ce) o <= {1'b0, i[1], 2'b1x, i[0], 1'bz};
+endmodule
+EOT
+
+proc
+equiv_opt -assert opt
+design -load postopt
+select -assert-count 1 t:$dffe r:WIDTH=4 %i
+select -assert-count 0 t:$dffe %% t:* %D
+
+####################
+
+design -reset
+read_verilog <<EOT
+module opt_dffmuxext_unsigned_rst(input clk, ce, rst, input [1:0] i, output reg [3:0] o);
+    always @(posedge clk) if (rst) o <= 0; else if (ce) o <= i;
+endmodule
+EOT
+
+proc
+equiv_opt -assert opt
+design -load postopt
+wreduce
+select -assert-count 1 t:$sdffe r:WIDTH=2 %i
+select -assert-count 0 t:$sdffe %% t:* %D
+
+####################
+
+design -reset
+read_verilog <<EOT
+module opt_dffmuxext_signed_rst(input clk, ce, rstn, input signed [1:0] i, output reg signed [3:0] o);
+    always @(posedge clk) begin
+        if (ce) o <= i;
+        if (!rstn) o <= 4'b1111;
+    end
+endmodule
+EOT
+
+proc
+equiv_opt -assert opt
+design -load postopt
+wreduce
+select -assert-count 1 t:$sdffe r:WIDTH=2 %i
+select -assert-count 0 t:$sdffe %% t:* %D
+
+####################
+
+design -reset
+read_verilog <<EOT
+module opt_dffmuxext_signed_rst_init(input clk, ce, rstn, input signed [1:0] i, output reg signed [3:0] o);
+    initial o <= 4'b0010;
+    always @(posedge clk) begin
+        if (ce) o <= i;
+        if (!rstn) o <= 4'b1111;
+    end
+endmodule
+EOT
+
+proc
+# NB: equiv_opt uses equiv_induct which covers
+#     only the induction half of temporal induction
+#     --- missing the base-case half
+#     This makes it akin to `sat -tempinduct-inductonly`
+#     instead of `sat -tempinduct-baseonly` or
+#     `sat -tempinduct` which is necessary for this
+#     testcase
+#equiv_opt -assert opt
+
+design -save gold
+opt
+wreduce
+design -stash gate
+design -import gold -as gold
+design -import gate -as gate
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -tempinduct -verify -prove-asserts -show-ports miter
+
+design -load gate
+select -assert-count 1 t:$sdffe r:WIDTH=3 %i
+select -assert-count 0 t:$sdffe %% t:* %D
diff --git a/tests/various/peepopt.ys b/tests/various/peepopt.ys
index ee5ad8a1a..45e936a21 100644
--- a/tests/various/peepopt.ys
+++ b/tests/various/peepopt.ys
@@ -68,146 +68,3 @@ equiv_opt -assert peepopt
 design -load postopt
 clean
 select -assert-count 0 t:*
-
-####################
-
-design -reset
-read_verilog <<EOT
-module peepopt_dffmuxext_unsigned(input clk, ce, input [1:0] i, output reg [3:0] o);
-    always @(posedge clk) if (ce) o <= i;
-endmodule
-EOT
-
-proc
-equiv_opt -assert peepopt
-design -load postopt
-clean
-select -assert-count 1 t:$dff r:WIDTH=2 %i
-select -assert-count 1 t:$mux r:WIDTH=2 %i
-select -assert-count 0 t:$dff t:$mux %% t:* %D
-
-####################
-
-design -reset
-read_verilog <<EOT
-module peepopt_dffmuxext_signed(input clk, ce, input signed [1:0] i, output reg signed [3:0] o);
-    always @(posedge clk) if (ce) o <= i;
-endmodule
-EOT
-
-proc
-equiv_opt -assert peepopt
-design -load postopt
-clean
-select -assert-count 1 t:$dff r:WIDTH=2 %i
-select -assert-count 1 t:$mux r:WIDTH=2 %i
-select -assert-count 0 t:$dff t:$mux %% t:* %D
-
-###################
-
-design -reset
-read_verilog <<EOT
-module peepopt_dffmuxext_const(input clk, ce, input [1:0] i, output reg [5:0] o);
-    always @(posedge clk) if (ce) o <= {1'b0, i[1], 2'b1x, i[0], 1'bz};
-endmodule
-EOT
-
-proc
-equiv_opt -assert peepopt
-design -load postopt
-select -assert-count 1 t:$dff r:WIDTH=2 %i
-select -assert-count 1 t:$mux r:WIDTH=2 %i
-select -assert-count 0 t:$dff t:$mux %% t:* %D
-
-###################
-
-design -reset
-read_verilog <<EOT
-module peepopt_dffmuxext_const_init(input clk, ce, input [1:0] i, (* init=6'b0x00x1 *) output reg [5:0] o);
-    always @(posedge clk) if (ce) o <= {1'b0, i[1], 2'b1x, i[0], 1'bz};
-endmodule
-EOT
-
-proc
-equiv_opt -assert peepopt
-design -load postopt
-select -assert-count 1 t:$dff r:WIDTH=4 %i
-select -assert-count 1 t:$mux r:WIDTH=4 %i
-select -assert-count 0 t:$dff t:$mux %% t:* %D
-
-####################
-
-design -reset
-read_verilog <<EOT
-module peepopt_dffmuxext_unsigned_rst(input clk, ce, rst, input [1:0] i, output reg [3:0] o);
-    always @(posedge clk) if (rst) o <= 0; else if (ce) o <= i;
-endmodule
-EOT
-
-proc
-equiv_opt -assert peepopt
-design -load postopt
-wreduce
-select -assert-count 1 t:$dff r:WIDTH=2 %i
-select -assert-count 2 t:$mux
-select -assert-count 2 t:$mux r:WIDTH=2 %i
-select -assert-count 0 t:$dff t:$mux %% t:* %D
-
-####################
-
-design -reset
-read_verilog <<EOT
-module peepopt_dffmuxext_signed_rst(input clk, ce, rstn, input signed [1:0] i, output reg signed [3:0] o);
-    always @(posedge clk) begin
-        if (ce) o <= i;
-        if (!rstn) o <= 4'b1111;
-    end
-endmodule
-EOT
-
-proc
-equiv_opt -assert peepopt
-design -load postopt
-wreduce
-select -assert-count 1 t:$dff r:WIDTH=2 %i
-select -assert-count 2 t:$mux
-select -assert-count 2 t:$mux r:WIDTH=2 %i
-select -assert-count 0 t:$logic_not t:$dff t:$mux %% t:* %D
-
-####################
-
-design -reset
-read_verilog <<EOT
-module peepopt_dffmuxext_signed_rst_init(input clk, ce, rstn, input signed [1:0] i, output reg signed [3:0] o);
-    initial o <= 4'b0010;
-    always @(posedge clk) begin
-        if (ce) o <= i;
-        if (!rstn) o <= 4'b1111;
-    end
-endmodule
-EOT
-
-proc
-# NB: equiv_opt uses equiv_induct which covers
-#     only the induction half of temporal induction
-#     --- missing the base-case half
-#     This makes it akin to `sat -tempinduct-inductonly`
-#     instead of `sat -tempinduct-baseonly` or
-#     `sat -tempinduct` which is necessary for this
-#     testcase
-#equiv_opt -assert peepopt
-
-design -save gold
-peepopt
-wreduce
-design -stash gate
-design -import gold -as gold
-design -import gate -as gate
-miter -equiv -flatten -make_assert -make_outputs gold gate miter
-sat -tempinduct -verify -prove-asserts -show-ports miter
-
-design -load gate
-select -assert-count 1 t:$dff r:WIDTH=4 %i
-select -assert-count 2 t:$mux
-select -assert-count 2 t:$mux r:WIDTH=4 %i
-select -assert-count 0 t:$logic_not t:$dff t:$mux %% t:* %D

From 5693386a4ec7fc05c12a6c98900e19d5b2851396 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= <mwk@0x04.net>
Date: Tue, 21 Jul 2020 16:41:26 +0200
Subject: [PATCH 3/4] Remove now-redundant dff2dffs pass.

---
 passes/techmap/Makefile.inc |   1 -
 passes/techmap/dff2dffs.cc  | 165 ------------------------------------
 tests/techmap/dff2dffs.ys   |  50 -----------
 3 files changed, 216 deletions(-)
 delete mode 100644 passes/techmap/dff2dffs.cc
 delete mode 100644 tests/techmap/dff2dffs.ys

diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc
index 5a4d84f94..fed0226d4 100644
--- a/passes/techmap/Makefile.inc
+++ b/passes/techmap/Makefile.inc
@@ -42,7 +42,6 @@ OBJS += passes/techmap/attrmvcp.o
 OBJS += passes/techmap/attrmap.o
 OBJS += passes/techmap/zinit.o
 OBJS += passes/techmap/dfflegalize.o
-OBJS += passes/techmap/dff2dffs.o
 OBJS += passes/techmap/dffunmap.o
 OBJS += passes/techmap/flowmap.o
 OBJS += passes/techmap/extractinv.o
diff --git a/passes/techmap/dff2dffs.cc b/passes/techmap/dff2dffs.cc
deleted file mode 100644
index 6c2cca4bc..000000000
--- a/passes/techmap/dff2dffs.cc
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- *  yosys -- Yosys Open SYnthesis Suite
- *
- *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
- *  Copyright (C) 2018  David Shah <dave@ds0.me>
- *
- *  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
-
-struct Dff2dffsPass : public Pass {
-	Dff2dffsPass() : Pass("dff2dffs", "process sync set/reset with SR over CE priority") { }
-	void help() override
-	{
-		log("\n");
-		log("    dff2dffs [options] [selection]\n");
-		log("\n");
-		log("Merge synchronous set/reset $_MUX_ cells to create $_SDFF_[NP][NP][01]_, to be run before\n");
-		log("dff2dffe for SR over CE priority.\n");
-		log("\n");
-		log("    -match-init\n");
-		log("        Disallow merging synchronous set/reset that has polarity opposite of the\n");
-		log("        output wire's init attribute (if any).\n");
-		log("\n");
-	}
-	void execute(std::vector<std::string> args, RTLIL::Design *design) override
-	{
-		log_header(design, "Executing dff2dffs pass (merge synchronous set/reset into FF cells).\n");
-
-		bool match_init = false;
-		size_t argidx;
-		for (argidx = 1; argidx < args.size(); argidx++)
-		{
-			// if (args[argidx] == "-singleton") {
-			// 	singleton_mode = true;
-			// 	continue;
-			// }
-			if (args[argidx] == "-match-init") {
-				match_init = true;
-				continue;
-			}
-			break;
-		}
-		extra_args(args, argidx, design);
-
-		pool<IdString> dff_types;
-		dff_types.insert(ID($_DFF_N_));
-		dff_types.insert(ID($_DFF_P_));
-
-		for (auto module : design->selected_modules())
-		{
-			log("Merging set/reset $_MUX_ cells into DFFs in %s.\n", log_id(module));
-
-			SigMap sigmap(module);
-			dict<SigBit, Cell*> sr_muxes;
-			vector<Cell*> ff_cells;
-
-			for (auto cell : module->selected_cells())
-			{
-				if (dff_types.count(cell->type)) {
-					ff_cells.push_back(cell);
-					continue;
-				}
-
-				if (cell->type != ID($_MUX_))
-					continue;
-
-				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;
-			}
-
-			for (auto cell : ff_cells)
-			{
-				SigSpec sig_d = cell->getPort(ID::D);
-
-				if (GetSize(sig_d) < 1)
-					continue;
-
-				SigBit bit_d = sigmap(sig_d[0]);
-
-				if (sr_muxes.count(bit_d) == 0)
-					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_s = sigmap(mux_cell->getPort(ID::S));
-
-				SigBit sr_val, sr_sig;
-				bool invert_sr;
-				sr_sig = bit_s;
-				if (bit_a.wire == nullptr) {
-					bit_d = bit_b;
-					sr_val = bit_a;
-					invert_sr = true;
-				} else {
-					log_assert(bit_b.wire == nullptr);
-					bit_d = bit_a;
-					sr_val = bit_b;
-					invert_sr = false;
-				}
-
-				if (match_init) {
-					SigBit bit_q = cell->getPort(ID::Q);
-					if (bit_q.wire) {
-						auto it = bit_q.wire->attributes.find(ID::init);
-						if (it != bit_q.wire->attributes.end()) {
-							auto init_val = it->second[bit_q.offset];
-							if (init_val == State::S1 && sr_val != State::S1)
-								continue;
-							if (init_val == State::S0 && sr_val != State::S0)
-								continue;
-						}
-					}
-				}
-
-				log("  Merging %s (A=%s, B=%s, S=%s) into %s (%s).\n", log_id(mux_cell),
-						log_signal(bit_a), log_signal(bit_b), log_signal(bit_s), log_id(cell), log_id(cell->type));
-
-				if (sr_val == State::S1) {
-					if (cell->type == ID($_DFF_N_)) {
-						if (invert_sr) cell->type = ID($_SDFF_NN1_);
-						else cell->type = ID($_SDFF_NP1_);
-					} else {
-						log_assert(cell->type == ID($_DFF_P_));
-						if (invert_sr) cell->type = ID($_SDFF_PN1_);
-						else cell->type = ID($_SDFF_PP1_);
-					}
-				} else {
-					if (cell->type == ID($_DFF_N_)) {
-						if (invert_sr) cell->type = ID($_SDFF_NN0_);
-						else cell->type = ID($_SDFF_NP0_);
-					} else {
-						log_assert(cell->type == ID($_DFF_P_));
-						if (invert_sr) cell->type = ID($_SDFF_PN0_);
-						else cell->type = ID($_SDFF_PP0_);
-					}
-				}
-				cell->setPort(ID::R, sr_sig);
-				cell->setPort(ID::D, bit_d);
-			}
-		}
-	}
-} Dff2dffsPass;
-
-PRIVATE_NAMESPACE_END
diff --git a/tests/techmap/dff2dffs.ys b/tests/techmap/dff2dffs.ys
deleted file mode 100644
index 105a89400..000000000
--- a/tests/techmap/dff2dffs.ys
+++ /dev/null
@@ -1,50 +0,0 @@
-read_verilog << EOT
-module top(...);
-input clk;
-input d;
-input sr;
-output reg q0, q1, q2, q3, q4, q5;
-
-initial q0 = 1'b0;
-initial q1 = 1'b0;
-initial q2 = 1'b1;
-initial q3 = 1'b1;
-initial q4 = 1'bx;
-initial q5 = 1'bx;
-
-always @(posedge clk) begin
-	q0 <= sr ? 1'b0 : d;
-	q1 <= sr ? 1'b1 : d;
-	q2 <= sr ? 1'b0 : d;
-	q3 <= sr ? 1'b1 : d;
-	q4 <= sr ? 1'b0 : d;
-	q5 <= sr ? 1'b1 : d;
-end
-
-endmodule
-EOT
-
-proc
-simplemap
-design -save ref
-
-dff2dffs
-clean
-
-select -assert-count 1 w:q0 %x t:$_SDFF_PP0_ %i
-select -assert-count 1 w:q1 %x t:$_SDFF_PP1_ %i
-select -assert-count 1 w:q2 %x t:$_SDFF_PP0_ %i
-select -assert-count 1 w:q3 %x t:$_SDFF_PP1_ %i
-select -assert-count 1 w:q4 %x t:$_SDFF_PP0_ %i
-select -assert-count 1 w:q5 %x t:$_SDFF_PP1_ %i
-
-design -load ref
-dff2dffs -match-init
-clean
-
-select -assert-count 1 w:q0 %x t:$_SDFF_PP0_ %i
-select -assert-count 0 w:q1 %x t:$_SDFF_PP1_ %i
-select -assert-count 0 w:q2 %x t:$_SDFF_PP0_ %i
-select -assert-count 1 w:q3 %x t:$_SDFF_PP1_ %i
-select -assert-count 1 w:q4 %x t:$_SDFF_PP0_ %i
-select -assert-count 1 w:q5 %x t:$_SDFF_PP1_ %i

From 54a0c083a111efaf5e8b486cb0a6725f4eb260df Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= <mwk@0x04.net>
Date: Tue, 21 Jul 2020 19:24:09 +0200
Subject: [PATCH 4/4] Remove now-redundant dff2dffe pass.

---
 passes/techmap/Makefile.inc |   1 -
 passes/techmap/dff2dffe.cc  | 414 ------------------------------------
 2 files changed, 415 deletions(-)
 delete mode 100644 passes/techmap/dff2dffe.cc

diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc
index fed0226d4..035699603 100644
--- a/passes/techmap/Makefile.inc
+++ b/passes/techmap/Makefile.inc
@@ -27,7 +27,6 @@ OBJS += passes/techmap/extract_fa.o
 OBJS += passes/techmap/extract_counter.o
 OBJS += passes/techmap/extract_reduce.o
 OBJS += passes/techmap/alumacc.o
-OBJS += passes/techmap/dff2dffe.o
 OBJS += passes/techmap/dffinit.o
 OBJS += passes/techmap/pmuxtree.o
 OBJS += passes/techmap/muxcover.o
diff --git a/passes/techmap/dff2dffe.cc b/passes/techmap/dff2dffe.cc
deleted file mode 100644
index 62ee3fea6..000000000
--- a/passes/techmap/dff2dffe.cc
+++ /dev/null
@@ -1,414 +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 "kernel/celltypes.h"
-#include "passes/techmap/simplemap.h"
-
-USING_YOSYS_NAMESPACE
-PRIVATE_NAMESPACE_BEGIN
-
-struct Dff2dffeWorker
-{
-	const dict<IdString, IdString> &direct_dict;
-
-	RTLIL::Module *module;
-	SigMap sigmap;
-	CellTypes ct;
-
-	typedef std::pair<RTLIL::Cell*, int> cell_int_t;
-	std::map<RTLIL::SigBit, cell_int_t> bit2mux;
-	std::vector<RTLIL::Cell*> dff_cells;
-	std::map<RTLIL::SigBit, int> bitusers;
-
-	typedef std::map<RTLIL::SigBit, bool> pattern_t;
-	typedef std::set<pattern_t> patterns_t;
-
-
-	Dff2dffeWorker(RTLIL::Module *module, const dict<IdString, IdString> &direct_dict) :
-			direct_dict(direct_dict), module(module), sigmap(module), ct(module->design)
-	{
-		for (auto wire : module->wires()) {
-			if (wire->port_output)
-				for (auto bit : sigmap(wire))
-					bitusers[bit]++;
-		}
-
-		for (auto cell : module->cells()) {
-			if (cell->type.in(ID($mux), ID($pmux), ID($_MUX_))) {
-				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);
-			}
-			if (direct_dict.empty()) {
-				if (cell->type.in(ID($dff), ID($_DFF_N_), ID($_DFF_P_)))
-					dff_cells.push_back(cell);
-			} else {
-				if (direct_dict.count(cell->type))
-					dff_cells.push_back(cell);
-			}
-			for (auto conn : cell->connections()) {
-				if (ct.cell_output(cell->type, conn.first))
-					continue;
-				for (auto bit : sigmap(conn.second))
-					bitusers[bit]++;
-			}
-		}
-	}
-
-	patterns_t find_muxtree_feedback_patterns(RTLIL::SigBit d, RTLIL::SigBit q, pattern_t path)
-	{
-		patterns_t ret;
-
-		if (d == q) {
-			ret.insert(path);
-			return ret;
-		}
-
-		if (bit2mux.count(d) == 0 || bitusers[d] > 1)
-			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_s = sigmap(mux_cell_int.first->getPort(ID::S));
-		int width = GetSize(sig_a), index = mux_cell_int.second;
-
-		for (int i = 0; i < GetSize(sig_s); i++)
-			if (path.count(sig_s[i]) && path.at(sig_s[i]))
-			{
-				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);
-					s[i*width + index] = RTLIL::Sx;
-					mux_cell_int.first->setPort(ID::B, s);
-				}
-
-				return ret;
-			}
-
-		pattern_t path_else = path;
-
-		for (int i = 0; i < GetSize(sig_s); i++)
-		{
-			if (path.count(sig_s[i]))
-				continue;
-
-			pattern_t path_this = path;
-			path_else[sig_s[i]] = false;
-			path_this[sig_s[i]] = true;
-
-			for (auto &pat : find_muxtree_feedback_patterns(sig_b[i*width + index], q, path_this))
-				ret.insert(pat);
-
-			if (sig_b[i*width + index] == q) {
-				RTLIL::SigSpec s = mux_cell_int.first->getPort(ID::B);
-				s[i*width + index] = RTLIL::Sx;
-				mux_cell_int.first->setPort(ID::B, s);
-			}
-		}
-
-		for (auto &pat : find_muxtree_feedback_patterns(sig_a[index], q, path_else))
-			ret.insert(pat);
-
-		if (sig_a[index] == q) {
-			RTLIL::SigSpec s = mux_cell_int.first->getPort(ID::A);
-			s[index] = RTLIL::Sx;
-			mux_cell_int.first->setPort(ID::A, s);
-		}
-
-		return ret;
-	}
-
-	void simplify_patterns(patterns_t&)
-	{
-		// TBD
-	}
-
-	RTLIL::SigSpec make_patterns_logic(patterns_t patterns, bool make_gates)
-	{
-		RTLIL::SigSpec or_input;
-
-		for (auto pat : patterns)
-		{
-			RTLIL::SigSpec s1, s2;
-			for (auto it : pat) {
-				s1.append(it.first);
-				s2.append(it.second);
-			}
-
-			RTLIL::SigSpec y = module->addWire(NEW_ID);
-			RTLIL::Cell *c = module->addNe(NEW_ID, s1, s2, y);
-
-			if (make_gates) {
-				simplemap(module, c);
-				module->remove(c);
-			}
-
-			or_input.append(y);
-		}
-
-		if (GetSize(or_input) == 0)
-			return State::S1;
-
-		if (GetSize(or_input) == 1)
-			return or_input;
-
-		RTLIL::SigSpec y = module->addWire(NEW_ID);
-		RTLIL::Cell *c = module->addReduceAnd(NEW_ID, or_input, y);
-
-		if (make_gates) {
-			simplemap(module, c);
-			module->remove(c);
-		}
-
-		return y;
-	}
-
-	void handle_dff_cell(RTLIL::Cell *dff_cell)
-	{
-		RTLIL::SigSpec sig_d = sigmap(dff_cell->getPort(ID::D));
-		RTLIL::SigSpec sig_q = sigmap(dff_cell->getPort(ID::Q));
-
-		std::map<patterns_t, std::set<int>> grouped_patterns;
-		std::set<int> remaining_indices;
-
-		for (int i = 0 ; i < GetSize(sig_d); i++) {
-			patterns_t patterns = find_muxtree_feedback_patterns(sig_d[i], sig_q[i], pattern_t());
-			if (!patterns.empty()) {
-				simplify_patterns(patterns);
-				grouped_patterns[patterns].insert(i);
-			} else
-				remaining_indices.insert(i);
-		}
-
-		for (auto &it : grouped_patterns) {
-			RTLIL::SigSpec new_sig_d, new_sig_q;
-			for (int i : it.second) {
-				new_sig_d.append(sig_d[i]);
-				new_sig_q.append(sig_q[i]);
-			}
-			if (!direct_dict.empty()) {
-				log("  converting %s cell %s to %s for %s -> %s.\n", log_id(dff_cell->type), log_id(dff_cell), log_id(direct_dict.at(dff_cell->type)), log_signal(new_sig_d), log_signal(new_sig_q));
-				dff_cell->setPort(ID::E, make_patterns_logic(it.first, true));
-				dff_cell->type = direct_dict.at(dff_cell->type);
-			} else
-			if (dff_cell->type == ID($dff)) {
-				RTLIL::Cell *new_cell = module->addDffe(NEW_ID, dff_cell->getPort(ID::CLK), make_patterns_logic(it.first, false),
-						new_sig_d, new_sig_q, dff_cell->getParam(ID::CLK_POLARITY).as_bool(), true);
-				log("  created $dffe cell %s for %s -> %s.\n", log_id(new_cell), log_signal(new_sig_d), log_signal(new_sig_q));
-			} else {
-				RTLIL::Cell *new_cell = module->addDffeGate(NEW_ID, dff_cell->getPort(ID::C), make_patterns_logic(it.first, true),
-						new_sig_d, new_sig_q, dff_cell->type == ID($_DFF_P_), true);
-				log("  created %s cell %s for %s -> %s.\n", log_id(new_cell->type), log_id(new_cell), log_signal(new_sig_d), log_signal(new_sig_q));
-			}
-		}
-
-		if (!direct_dict.empty())
-			return;
-
-		if (remaining_indices.empty()) {
-			log("  removing now obsolete cell %s.\n", log_id(dff_cell));
-			module->remove(dff_cell);
-		} else if (GetSize(remaining_indices) != GetSize(sig_d)) {
-			log("  removing %d now obsolete bits from cell %s.\n", GetSize(sig_d) - GetSize(remaining_indices), log_id(dff_cell));
-			RTLIL::SigSpec new_sig_d, new_sig_q;
-			for (int i : remaining_indices) {
-				new_sig_d.append(sig_d[i]);
-				new_sig_q.append(sig_q[i]);
-			}
-			dff_cell->setPort(ID::D, new_sig_d);
-			dff_cell->setPort(ID::Q, new_sig_q);
-			dff_cell->setParam(ID::WIDTH, GetSize(remaining_indices));
-		}
-	}
-
-	void run()
-	{
-		log("Transforming FF to FF+Enable cells in module %s:\n", log_id(module));
-		for (auto dff_cell : dff_cells) {
-			// log("Handling candidate %s:\n", log_id(dff_cell));
-			handle_dff_cell(dff_cell);
-		}
-	}
-};
-
-struct Dff2dffePass : public Pass {
-	Dff2dffePass() : Pass("dff2dffe", "transform $dff cells to $dffe cells") { }
-	void help() override
-	{
-		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
-		log("\n");
-		log("    dff2dffe [options] [selection]\n");
-		log("\n");
-		log("This pass transforms $dff cells driven by a tree of multiplexers with one or\n");
-		log("more feedback paths to $dffe cells. It also works on gate-level cells such as\n");
-		log("$_DFF_P_, $_DFF_N_ and $_MUX_.\n");
-		log("\n");
-		log("    -unmap\n");
-		log("        operate in the opposite direction: replace $dffe cells with combinations\n");
-		log("        of $dff and $mux cells. the options below are ignored in unmap mode.\n");
-		log("\n");
-		log("    -unmap-mince N\n");
-		log("        Same as -unmap but only unmap $dffe where the clock enable port\n");
-		log("        signal is used by less $dffe than the specified number\n");
-		log("\n");
-		log("    -direct <internal_gate_type> <external_gate_type>\n");
-		log("        map directly to external gate type. <internal_gate_type> can\n");
-		log("        be any internal gate-level FF cell (except $_DFFE_??_). the\n");
-		log("        <external_gate_type> is the cell type name for a cell with an\n");
-		log("        identical interface to the <internal_gate_type>, except it\n");
-		log("        also has an high-active enable port 'E'.\n");
-		log("          Usually <external_gate_type> is an intermediate cell type\n");
-		log("        that is then translated to the final type using 'techmap'.\n");
-		log("\n");
-		log("    -direct-match <pattern>\n");
-		log("        like -direct for all DFF cell types matching the expression.\n");
-		log("        this will use $_DFFE_* as <external_gate_type> matching the\n");
-		log("        internal gate type $_DFF_*_, and $_SDFFE_* for those matching\n");
-		log("        $_SDFF_*_, except for $_DFF_[NP]_, which is converted to \n");
-		log("        $_DFFE_[NP]_.\n");
-		log("\n");
-	}
-	void execute(std::vector<std::string> args, RTLIL::Design *design) override
-	{
-		log_header(design, "Executing DFF2DFFE pass (transform $dff to $dffe where applicable).\n");
-
-		bool unmap_mode = false;
-		int min_ce_use = -1;
-		dict<IdString, IdString> direct_dict;
-
-		size_t argidx;
-		for (argidx = 1; argidx < args.size(); argidx++) {
-			if (args[argidx] == "-unmap") {
-				unmap_mode = true;
-				continue;
-			}
-			if (args[argidx] == "-unmap-mince" && argidx + 1 < args.size()) {
-				unmap_mode = true;
-				min_ce_use = atoi(args[++argidx].c_str());
-				continue;
-			}
-			if (args[argidx] == "-direct" && argidx + 2 < args.size()) {
-				string direct_from = RTLIL::escape_id(args[++argidx]);
-				string direct_to = RTLIL::escape_id(args[++argidx]);
-				direct_dict[direct_from] = direct_to;
-				continue;
-			}
-			if (args[argidx] == "-direct-match" && argidx + 1 < args.size()) {
-				bool found_match = false;
-				const char *pattern = args[++argidx].c_str();
-				if (patmatch(pattern, "$_DFF_P_"  )) found_match = true, direct_dict[ID($_DFF_P_)  ] = ID($_DFFE_PP_);
-				if (patmatch(pattern, "$_DFF_N_"  )) found_match = true, direct_dict[ID($_DFF_N_)  ] = ID($_DFFE_NP_);
-				if (patmatch(pattern, "$_DFF_NN0_")) found_match = true, direct_dict[ID($_DFF_NN0_)] = ID($_DFFE_NN0P_);
-				if (patmatch(pattern, "$_DFF_NN1_")) found_match = true, direct_dict[ID($_DFF_NN1_)] = ID($_DFFE_NN1P_);
-				if (patmatch(pattern, "$_DFF_NP0_")) found_match = true, direct_dict[ID($_DFF_NP0_)] = ID($_DFFE_NP0P_);
-				if (patmatch(pattern, "$_DFF_NP1_")) found_match = true, direct_dict[ID($_DFF_NP1_)] = ID($_DFFE_NP1P_);
-				if (patmatch(pattern, "$_DFF_PN0_")) found_match = true, direct_dict[ID($_DFF_PN0_)] = ID($_DFFE_PN0P_);
-				if (patmatch(pattern, "$_DFF_PN1_")) found_match = true, direct_dict[ID($_DFF_PN1_)] = ID($_DFFE_PN1P_);
-				if (patmatch(pattern, "$_DFF_PP0_")) found_match = true, direct_dict[ID($_DFF_PP0_)] = ID($_DFFE_PP0P_);
-				if (patmatch(pattern, "$_DFF_PP1_")) found_match = true, direct_dict[ID($_DFF_PP1_)] = ID($_DFFE_PP1P_);
-
-				if (patmatch(pattern, "$_SDFF_NN0_")) found_match = true, direct_dict[ID($_SDFF_NN0_)] = ID($_SDFFE_NN0P_);
-				if (patmatch(pattern, "$_SDFF_NN1_")) found_match = true, direct_dict[ID($_SDFF_NN1_)] = ID($_SDFFE_NN1P_);
-				if (patmatch(pattern, "$_SDFF_NP0_")) found_match = true, direct_dict[ID($_SDFF_NP0_)] = ID($_SDFFE_NP0P_);
-				if (patmatch(pattern, "$_SDFF_NP1_")) found_match = true, direct_dict[ID($_SDFF_NP1_)] = ID($_SDFFE_NP1P_);
-				if (patmatch(pattern, "$_SDFF_PN0_")) found_match = true, direct_dict[ID($_SDFF_PN0_)] = ID($_SDFFE_PN0P_);
-				if (patmatch(pattern, "$_SDFF_PN1_")) found_match = true, direct_dict[ID($_SDFF_PN1_)] = ID($_SDFFE_PN1P_);
-				if (patmatch(pattern, "$_SDFF_PP0_")) found_match = true, direct_dict[ID($_SDFF_PP0_)] = ID($_SDFFE_PP0P_);
-				if (patmatch(pattern, "$_SDFF_PP1_")) found_match = true, direct_dict[ID($_SDFF_PP1_)] = ID($_SDFFE_PP1P_);
-				if (!found_match)
-					log_cmd_error("No cell types matched pattern '%s'.\n", pattern);
-				continue;
-			}
-			break;
-		}
-		extra_args(args, argidx, design);
-
-		if (!direct_dict.empty()) {
-			log("Selected cell types for direct conversion:\n");
-			for (auto &it : direct_dict)
-				log("  %s -> %s\n", log_id(it.first), log_id(it.second));
-		}
-
-		for (auto mod : design->selected_modules())
-			if (!mod->has_processes_warn())
-			{
-				if (unmap_mode) {
-					SigMap sigmap(mod);
-					for (auto cell : mod->selected_cells()) {
-						if (cell->type == ID($dffe)) {
-							if (min_ce_use >= 0) {
-								int ce_use = 0;
-								for (auto cell_other : mod->selected_cells()) {
-									if (cell_other->type != cell->type)
-										continue;
-									if (sigmap(cell->getPort(ID::EN)) == sigmap(cell_other->getPort(ID::EN)))
-										ce_use++;
-								}
-								if (ce_use >= min_ce_use)
-									continue;
-							}
-
-							RTLIL::SigSpec tmp = mod->addWire(NEW_ID, GetSize(cell->getPort(ID::D)));
-							mod->addDff(NEW_ID, cell->getPort(ID::CLK), tmp, cell->getPort(ID::Q), cell->getParam(ID::CLK_POLARITY).as_bool());
-							if (cell->getParam(ID::EN_POLARITY).as_bool())
-								mod->addMux(NEW_ID, cell->getPort(ID::Q), cell->getPort(ID::D), cell->getPort(ID::EN), tmp);
-							else
-								mod->addMux(NEW_ID, cell->getPort(ID::D), cell->getPort(ID::Q), cell->getPort(ID::EN), tmp);
-							mod->remove(cell);
-							continue;
-						}
-						if (cell->type.begins_with("$_DFFE_")) {
-							if (min_ce_use >= 0) {
-								int ce_use = 0;
-								for (auto cell_other : mod->selected_cells()) {
-									if (cell_other->type != cell->type)
-										continue;
-									if (sigmap(cell->getPort(ID::E)) == sigmap(cell_other->getPort(ID::E)))
-										ce_use++;
-								}
-								if (ce_use >= min_ce_use)
-									continue;
-							}
-
-							bool clk_pol = cell->type.compare(7, 1, "P") == 0;
-							bool en_pol = cell->type.compare(8, 1, "P") == 0;
-							RTLIL::SigSpec tmp = mod->addWire(NEW_ID);
-							mod->addDff(NEW_ID, cell->getPort(ID::C), tmp, cell->getPort(ID::Q), clk_pol);
-							if (en_pol)
-								mod->addMux(NEW_ID, cell->getPort(ID::Q), cell->getPort(ID::D), cell->getPort(ID::E), tmp);
-							else
-								mod->addMux(NEW_ID, cell->getPort(ID::D), cell->getPort(ID::Q), cell->getPort(ID::E), tmp);
-							mod->remove(cell);
-							continue;
-						}
-					}
-					continue;
-				}
-
-				Dff2dffeWorker worker(mod, direct_dict);
-				worker.run();
-			}
-	}
-} Dff2dffePass;
-
-PRIVATE_NAMESPACE_END