mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 03:32:29 +00:00 
			
		
		
		
	Various cleanups and improvements in opt_muxtree
This commit is contained in:
		
							parent
							
								
									279a18c9a3
								
							
						
					
					
						commit
						61192514e3
					
				
					 1 changed files with 71 additions and 87 deletions
				
			
		|  | @ -37,39 +37,33 @@ struct OptMuxtreeWorker | ||||||
| 	SigMap assign_map; | 	SigMap assign_map; | ||||||
| 	int removed_count; | 	int removed_count; | ||||||
| 
 | 
 | ||||||
|         struct bitDef_t : public std::pair<RTLIL::Wire*, int> { |  | ||||||
| 		bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { } |  | ||||||
| 		bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { } |  | ||||||
| 	}; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 	struct bitinfo_t { | 	struct bitinfo_t { | ||||||
| 		int num; | 		int num; | ||||||
| 		bitDef_t bit; | 		SigBit bit; | ||||||
| 		bool seen_non_mux; | 		bool seen_non_mux; | ||||||
| 		std::vector<int> mux_users; | 		vector<int> mux_users; | ||||||
| 		std::vector<int> mux_drivers; | 		vector<int> mux_drivers; | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	std::map<bitDef_t, int> bit2num; | 	dict<SigBit, int> bit2num; | ||||||
| 	std::vector<bitinfo_t> bit2info; | 	vector<bitinfo_t> bit2info; | ||||||
| 
 | 
 | ||||||
| 	struct portinfo_t { | 	struct portinfo_t { | ||||||
| 		std::vector<int> ctrl_sigs; | 		int ctrl_sig; | ||||||
| 		std::vector<int> input_sigs; | 		vector<int> input_sigs; | ||||||
| 		std::vector<int> input_muxes; | 		vector<int> input_muxes; | ||||||
| 		bool const_activated; | 		bool const_activated; | ||||||
|  | 		bool const_deactivated; | ||||||
| 		bool enabled; | 		bool enabled; | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	struct muxinfo_t { | 	struct muxinfo_t { | ||||||
| 		RTLIL::Cell *cell; | 		RTLIL::Cell *cell; | ||||||
| 		std::vector<portinfo_t> ports; | 		vector<portinfo_t> ports; | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	std::vector<muxinfo_t> mux2info; | 	vector<muxinfo_t> mux2info; | ||||||
| 
 | 	vector<bool> root_muxes; | ||||||
| 	std::set<int> root_muxes; |  | ||||||
| 
 | 
 | ||||||
| 	OptMuxtreeWorker(RTLIL::Design *design, RTLIL::Module *module) : | 	OptMuxtreeWorker(RTLIL::Design *design, RTLIL::Module *module) : | ||||||
| 			design(design), module(module), assign_map(module), removed_count(0) | 			design(design), module(module), assign_map(module), removed_count(0) | ||||||
|  | @ -83,9 +77,10 @@ struct OptMuxtreeWorker | ||||||
| 		//	.mux_users
 | 		//	.mux_users
 | ||||||
| 		//	.mux_drivers
 | 		//	.mux_drivers
 | ||||||
| 		// Populate mux2info[].ports[]:
 | 		// Populate mux2info[].ports[]:
 | ||||||
| 		//	.ctrl_sigs
 | 		//	.ctrl_sig
 | ||||||
| 		//	.input_sigs
 | 		//	.input_sigs
 | ||||||
| 		//	.const_activated
 | 		//	.const_activated
 | ||||||
|  | 		//	.const_deactivated
 | ||||||
| 		for (auto cell : module->cells()) | 		for (auto cell : module->cells()) | ||||||
| 		{ | 		{ | ||||||
| 			if (cell->type == "$mux" || cell->type == "$pmux") | 			if (cell->type == "$mux" || cell->type == "$pmux") | ||||||
|  | @ -102,13 +97,13 @@ struct OptMuxtreeWorker | ||||||
| 					RTLIL::SigSpec sig = sig_b.extract(i*sig_a.size(), sig_a.size()); | 					RTLIL::SigSpec sig = sig_b.extract(i*sig_a.size(), sig_a.size()); | ||||||
| 					RTLIL::SigSpec ctrl_sig = assign_map(sig_s.extract(i, 1)); | 					RTLIL::SigSpec ctrl_sig = assign_map(sig_s.extract(i, 1)); | ||||||
| 					portinfo_t portinfo; | 					portinfo_t portinfo; | ||||||
|  | 					portinfo.ctrl_sig = sig2bits(ctrl_sig, false).front(); | ||||||
| 					for (int idx : sig2bits(sig)) { | 					for (int idx : sig2bits(sig)) { | ||||||
| 						add_to_list(bit2info[idx].mux_users, mux2info.size()); | 						add_to_list(bit2info[idx].mux_users, mux2info.size()); | ||||||
| 						add_to_list(portinfo.input_sigs, idx); | 						add_to_list(portinfo.input_sigs, idx); | ||||||
| 					} | 					} | ||||||
| 					for (int idx : sig2bits(ctrl_sig)) |  | ||||||
| 						add_to_list(portinfo.ctrl_sigs, idx); |  | ||||||
| 					portinfo.const_activated = ctrl_sig.is_fully_const() && ctrl_sig.as_bool(); | 					portinfo.const_activated = ctrl_sig.is_fully_const() && ctrl_sig.as_bool(); | ||||||
|  | 					portinfo.const_deactivated = ctrl_sig.is_fully_const() && !ctrl_sig.as_bool(); | ||||||
| 					portinfo.enabled = false; | 					portinfo.enabled = false; | ||||||
| 					muxinfo.ports.push_back(portinfo); | 					muxinfo.ports.push_back(portinfo); | ||||||
| 				} | 				} | ||||||
|  | @ -118,7 +113,9 @@ struct OptMuxtreeWorker | ||||||
| 					add_to_list(bit2info[idx].mux_users, mux2info.size()); | 					add_to_list(bit2info[idx].mux_users, mux2info.size()); | ||||||
| 					add_to_list(portinfo.input_sigs, idx); | 					add_to_list(portinfo.input_sigs, idx); | ||||||
| 				} | 				} | ||||||
|  | 				portinfo.ctrl_sig = -1; | ||||||
| 				portinfo.const_activated = false; | 				portinfo.const_activated = false; | ||||||
|  | 				portinfo.const_deactivated = false; | ||||||
| 				portinfo.enabled = false; | 				portinfo.enabled = false; | ||||||
| 				muxinfo.ports.push_back(portinfo); | 				muxinfo.ports.push_back(portinfo); | ||||||
| 
 | 
 | ||||||
|  | @ -162,6 +159,7 @@ struct OptMuxtreeWorker | ||||||
| 		log("  Evaluating internal representation of mux trees.\n"); | 		log("  Evaluating internal representation of mux trees.\n"); | ||||||
| 
 | 
 | ||||||
| 		dict<int, pool<int>> mux_to_users; | 		dict<int, pool<int>> mux_to_users; | ||||||
|  | 		root_muxes.resize(mux2info.size()); | ||||||
| 
 | 
 | ||||||
| 		for (auto &bi : bit2info) { | 		for (auto &bi : bit2info) { | ||||||
| 			for (int i : bi.mux_drivers) | 			for (int i : bi.mux_drivers) | ||||||
|  | @ -170,23 +168,24 @@ struct OptMuxtreeWorker | ||||||
| 			if (!bi.seen_non_mux) | 			if (!bi.seen_non_mux) | ||||||
| 				continue; | 				continue; | ||||||
| 			for (int mux_idx : bi.mux_drivers) | 			for (int mux_idx : bi.mux_drivers) | ||||||
| 				root_muxes.insert(mux_idx); | 				root_muxes.at(mux_idx) = true; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		for (auto &it : mux_to_users) | 		for (auto &it : mux_to_users) | ||||||
| 			if (GetSize(it.second) > 1) | 			if (GetSize(it.second) > 1) | ||||||
| 				root_muxes.insert(it.first); | 				root_muxes.at(it.first) = true; | ||||||
| 
 | 
 | ||||||
| 		for (int mux_idx : root_muxes) { | 		for (int mux_idx = 0; mux_idx < GetSize(root_muxes); mux_idx++) | ||||||
| 			log("    Root of a mux tree: %s\n", log_id(mux2info[mux_idx].cell)); | 			if (root_muxes.at(mux_idx)) { | ||||||
| 			eval_root_mux(mux_idx); | 				log("    Root of a mux tree: %s\n", log_id(mux2info[mux_idx].cell)); | ||||||
| 		} | 				eval_root_mux(mux_idx); | ||||||
|  | 			} | ||||||
| 
 | 
 | ||||||
| 		log("  Analyzing evaluation results.\n"); | 		log("  Analyzing evaluation results.\n"); | ||||||
| 
 | 
 | ||||||
| 		for (auto &mi : mux2info) | 		for (auto &mi : mux2info) | ||||||
| 		{ | 		{ | ||||||
| 			std::vector<int> live_ports; | 			vector<int> live_ports; | ||||||
| 			for (int port_idx = 0; port_idx < GetSize(mi.ports); port_idx++) { | 			for (int port_idx = 0; port_idx < GetSize(mi.ports); port_idx++) { | ||||||
| 				portinfo_t &pi = mi.ports[port_idx]; | 				portinfo_t &pi = mi.ports[port_idx]; | ||||||
| 				if (pi.enabled) { | 				if (pi.enabled) { | ||||||
|  | @ -247,15 +246,7 @@ struct OptMuxtreeWorker | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	bool list_is_subset(const std::vector<int> &sub, const std::vector<int> &super) | 	bool is_in_list(const vector<int> &list, int value) | ||||||
| 	{ |  | ||||||
| 		for (int v : sub) |  | ||||||
| 			if (!is_in_list(super, v)) |  | ||||||
| 				return false; |  | ||||||
| 		return true; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	bool is_in_list(const std::vector<int> &list, int value) |  | ||||||
| 	{ | 	{ | ||||||
| 		for (int v : list) | 		for (int v : list) | ||||||
| 			if (v == value) | 			if (v == value) | ||||||
|  | @ -263,15 +254,15 @@ struct OptMuxtreeWorker | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void add_to_list(std::vector<int> &list, int value) | 	void add_to_list(vector<int> &list, int value) | ||||||
| 	{ | 	{ | ||||||
| 		if (!is_in_list(list, value)) | 		if (!is_in_list(list, value)) | ||||||
| 			list.push_back(value); | 			list.push_back(value); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	std::vector<int> sig2bits(RTLIL::SigSpec sig, bool skip_non_wires = true) | 	vector<int> sig2bits(RTLIL::SigSpec sig, bool skip_non_wires = true) | ||||||
| 	{ | 	{ | ||||||
| 		std::vector<int> results; | 		vector<int> results; | ||||||
| 		assign_map.apply(sig); | 		assign_map.apply(sig); | ||||||
| 		for (auto &bit : sig) | 		for (auto &bit : sig) | ||||||
| 			if (bit.wire != NULL) { | 			if (bit.wire != NULL) { | ||||||
|  | @ -292,57 +283,58 @@ struct OptMuxtreeWorker | ||||||
| 	struct knowledge_t | 	struct knowledge_t | ||||||
| 	{ | 	{ | ||||||
| 		// database of known inactive signals
 | 		// database of known inactive signals
 | ||||||
| 		// the 2nd integer is a reference counter used to manage the
 | 		// the payload is a reference counter used to manage the
 | ||||||
| 		// list. when it is non-zero the signal in known to be inactive
 | 		// list. when it is non-zero the signal in known to be inactive
 | ||||||
| 		std::map<int, int> known_inactive; | 		vector<int> known_inactive; | ||||||
| 
 | 
 | ||||||
| 		// database of known active signals
 | 		// database of known active signals
 | ||||||
| 		// the 2nd dimension is the list of or-ed signals. so we know that
 | 		vector<int> known_active; | ||||||
| 		// for each i there is a j so that known_active[i][j] points to an
 |  | ||||||
| 		// active control signal.
 |  | ||||||
| 		std::vector<std::vector<int>> known_active; |  | ||||||
| 
 | 
 | ||||||
| 		// this is just used to keep track of visited muxes in order to prohibit
 | 		// this is just used to keep track of visited muxes in order to prohibit
 | ||||||
| 		// endless recursion in mux loops
 | 		// endless recursion in mux loops
 | ||||||
| 		std::set<int> visited_muxes; | 		vector<bool> visited_muxes; | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	void eval_mux_port(knowledge_t &knowledge, int mux_idx, int port_idx) | 	void eval_mux_port(knowledge_t &knowledge, int mux_idx, int port_idx) | ||||||
| 	{ | 	{ | ||||||
| 		muxinfo_t &muxinfo = mux2info[mux_idx]; | 		muxinfo_t &muxinfo = mux2info[mux_idx]; | ||||||
|  | 
 | ||||||
|  | 		if (muxinfo.ports[port_idx].const_deactivated) | ||||||
|  | 			return; | ||||||
|  | 
 | ||||||
| 		muxinfo.ports[port_idx].enabled = true; | 		muxinfo.ports[port_idx].enabled = true; | ||||||
| 
 | 
 | ||||||
| 		for (size_t i = 0; i < muxinfo.ports.size(); i++) { | 		for (int i = 0; i < GetSize(muxinfo.ports); i++) { | ||||||
| 			if (int(i) == port_idx) | 			if (i == port_idx) | ||||||
| 				continue; | 				continue; | ||||||
| 			for (int b : muxinfo.ports[i].ctrl_sigs) | 			if (muxinfo.ports[i].ctrl_sig >= 0) | ||||||
| 				knowledge.known_inactive[b]++; | 				knowledge.known_inactive.at(muxinfo.ports[i].ctrl_sig)++; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (port_idx < int(muxinfo.ports.size())-1 && !muxinfo.ports[port_idx].const_activated) | 		if (port_idx < int(muxinfo.ports.size())-1 && !muxinfo.ports[port_idx].const_activated) | ||||||
| 			knowledge.known_active.push_back(muxinfo.ports[port_idx].ctrl_sigs); | 			knowledge.known_active.at(muxinfo.ports[port_idx].ctrl_sig)++; | ||||||
| 
 | 
 | ||||||
| 		std::vector<int> parent_muxes; | 		vector<int> parent_muxes; | ||||||
| 		for (int m : muxinfo.ports[port_idx].input_muxes) { | 		for (int m : muxinfo.ports[port_idx].input_muxes) { | ||||||
| 			if (knowledge.visited_muxes.count(m) > 0) | 			if (knowledge.visited_muxes[m]) | ||||||
| 				continue; | 				continue; | ||||||
| 			knowledge.visited_muxes.insert(m); | 			knowledge.visited_muxes[m] = true; | ||||||
| 			parent_muxes.push_back(m); | 			parent_muxes.push_back(m); | ||||||
| 		} | 		} | ||||||
| 		for (int m : parent_muxes) | 		for (int m : parent_muxes) | ||||||
| 			if (!root_muxes.count(m)) | 			if (!root_muxes.at(m)) | ||||||
| 				eval_mux(knowledge, m); | 				eval_mux(knowledge, m); | ||||||
| 		for (int m : parent_muxes) | 		for (int m : parent_muxes) | ||||||
| 			knowledge.visited_muxes.erase(m); | 			knowledge.visited_muxes[m] = false; | ||||||
| 
 | 
 | ||||||
| 		if (port_idx < int(muxinfo.ports.size())-1 && !muxinfo.ports[port_idx].const_activated) | 		if (port_idx < int(muxinfo.ports.size())-1 && !muxinfo.ports[port_idx].const_activated) | ||||||
| 			knowledge.known_active.pop_back(); | 			knowledge.known_active.at(muxinfo.ports[port_idx].ctrl_sig)--; | ||||||
| 
 | 
 | ||||||
| 		for (size_t i = 0; i < muxinfo.ports.size(); i++) { | 		for (size_t i = 0; i < muxinfo.ports.size(); i++) { | ||||||
| 			if (int(i) == port_idx) | 			if (int(i) == port_idx) | ||||||
| 				continue; | 				continue; | ||||||
| 			for (int b : muxinfo.ports[i].ctrl_sigs) | 			if (muxinfo.ports[i].ctrl_sig >= 0) | ||||||
| 				knowledge.known_inactive[b]--; | 				knowledge.known_inactive.at(muxinfo.ports[i].ctrl_sig)--; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -351,20 +343,17 @@ struct OptMuxtreeWorker | ||||||
| 		SigSpec sig = muxinfo.cell->getPort(portname); | 		SigSpec sig = muxinfo.cell->getPort(portname); | ||||||
| 		bool did_something = false; | 		bool did_something = false; | ||||||
| 
 | 
 | ||||||
| 		std::vector<int> bits = sig2bits(sig, false); | 		vector<int> bits = sig2bits(sig, false); | ||||||
| 		for (int i = 0; i < GetSize(bits); i++) { | 		for (int i = 0; i < GetSize(bits); i++) { | ||||||
| 			if (bits[i] < 0) | 			if (bits[i] < 0) | ||||||
| 				continue; | 				continue; | ||||||
| 			if (knowledge.known_inactive[bits[i]]) { | 			if (knowledge.known_inactive.at(bits[i])) { | ||||||
| 				sig[i] = State::S0; | 				sig[i] = State::S0; | ||||||
| 				did_something = true; | 				did_something = true; | ||||||
| 			} else { | 			} else | ||||||
| 				for (auto &it : knowledge.known_active) | 			if (knowledge.known_active.at(bits[i])) { | ||||||
| 					if (GetSize(it) == 1 && it.front() == bits[i]) { | 				sig[i] = State::S1; | ||||||
| 						sig[i] = State::S1; | 				did_something = true; | ||||||
| 						did_something = true; |  | ||||||
| 						break; |  | ||||||
| 					} |  | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | @ -399,16 +388,14 @@ struct OptMuxtreeWorker | ||||||
| 		for (size_t port_idx = 0; port_idx < muxinfo.ports.size()-1; port_idx++) | 		for (size_t port_idx = 0; port_idx < muxinfo.ports.size()-1; port_idx++) | ||||||
| 		{ | 		{ | ||||||
| 			portinfo_t &portinfo = muxinfo.ports[port_idx]; | 			portinfo_t &portinfo = muxinfo.ports[port_idx]; | ||||||
| 			for (size_t i = 0; i < knowledge.known_active.size(); i++) { | 			if (knowledge.known_active.at(portinfo.ctrl_sig)) { | ||||||
| 				if (list_is_subset(knowledge.known_active[i], portinfo.ctrl_sigs)) { | 				eval_mux_port(knowledge, mux_idx, port_idx); | ||||||
| 					eval_mux_port(knowledge, mux_idx, port_idx); | 				return; | ||||||
| 					return; |  | ||||||
| 				} |  | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		// compare ports with known_inactive and known_active signals. If all control
 | 		// compare ports with known_inactive and known_active signals. If the control
 | ||||||
| 		// signals of the port are known_inactive or if the control signals of all other
 | 		// signal of the port is known_inactive or if the control signals of all other
 | ||||||
| 		// ports are known_active this port can't be activated. this loop includes the
 | 		// ports are known_active this port can't be activated. this loop includes the
 | ||||||
| 		// default port but no known_inactive match is performed on the default port.
 | 		// default port but no known_inactive match is performed on the default port.
 | ||||||
| 		for (size_t port_idx = 0; port_idx < muxinfo.ports.size(); port_idx++) | 		for (size_t port_idx = 0; port_idx < muxinfo.ports.size(); port_idx++) | ||||||
|  | @ -417,23 +404,17 @@ struct OptMuxtreeWorker | ||||||
| 
 | 
 | ||||||
| 			if (port_idx < muxinfo.ports.size()-1) { | 			if (port_idx < muxinfo.ports.size()-1) { | ||||||
| 				bool found_non_known_inactive = false; | 				bool found_non_known_inactive = false; | ||||||
| 				for (int i : portinfo.ctrl_sigs) | 				if (knowledge.known_inactive.at(portinfo.ctrl_sig) == 0) | ||||||
| 					if (knowledge.known_inactive[i] == 0) | 					found_non_known_inactive = true; | ||||||
| 						found_non_known_inactive = true; |  | ||||||
| 				if (!found_non_known_inactive) | 				if (!found_non_known_inactive) | ||||||
| 					continue; | 					continue; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			bool port_active = true; | 			bool port_active = true; | ||||||
| 			std::vector<int> other_ctrl_sig; |  | ||||||
| 			for (size_t i = 0; i < muxinfo.ports.size()-1; i++) { | 			for (size_t i = 0; i < muxinfo.ports.size()-1; i++) { | ||||||
| 				if (i == port_idx) | 				if (i == port_idx) | ||||||
| 					continue; | 					continue; | ||||||
| 				other_ctrl_sig.insert(other_ctrl_sig.end(), | 				if (knowledge.known_active.at(muxinfo.ports[i].ctrl_sig)) | ||||||
| 						muxinfo.ports[i].ctrl_sigs.begin(), muxinfo.ports[i].ctrl_sigs.end()); |  | ||||||
| 			} |  | ||||||
| 			for (size_t i = 0; i < knowledge.known_active.size(); i++) { |  | ||||||
| 				if (list_is_subset(knowledge.known_active[i], other_ctrl_sig)) |  | ||||||
| 					port_active = false; | 					port_active = false; | ||||||
| 			} | 			} | ||||||
| 			if (port_active) | 			if (port_active) | ||||||
|  | @ -444,7 +425,10 @@ struct OptMuxtreeWorker | ||||||
| 	void eval_root_mux(int mux_idx) | 	void eval_root_mux(int mux_idx) | ||||||
| 	{ | 	{ | ||||||
| 		knowledge_t knowledge; | 		knowledge_t knowledge; | ||||||
| 		knowledge.visited_muxes.insert(mux_idx); | 		knowledge.known_inactive.resize(bit2info.size()); | ||||||
|  | 		knowledge.known_active.resize(bit2info.size()); | ||||||
|  | 		knowledge.visited_muxes.resize(mux2info.size()); | ||||||
|  | 		knowledge.visited_muxes[mux_idx] = true; | ||||||
| 		eval_mux(knowledge, mux_idx); | 		eval_mux(knowledge, mux_idx); | ||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
|  | @ -464,7 +448,7 @@ struct OptMuxtreePass : public Pass { | ||||||
| 		log("This pass only operates on completely selected modules without processes.\n"); | 		log("This pass only operates on completely selected modules without processes.\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
| 	} | 	} | ||||||
| 	virtual void execute(std::vector<std::string> args, RTLIL::Design *design) | 	virtual void execute(vector<std::string> args, RTLIL::Design *design) | ||||||
| 	{ | 	{ | ||||||
| 		log_header("Executing OPT_MUXTREE pass (detect dead branches in mux trees).\n"); | 		log_header("Executing OPT_MUXTREE pass (detect dead branches in mux trees).\n"); | ||||||
| 		extra_args(args, 1, design); | 		extra_args(args, 1, design); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue