mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-04 05:19:11 +00:00 
			
		
		
		
	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
This commit is contained in:
		
							parent
							
								
									a02d1720a7
								
							
						
					
					
						commit
						07c4a7d438
					
				
					 6 changed files with 383 additions and 1 deletions
				
			
		| 
						 | 
					@ -4,6 +4,7 @@ OBJS += passes/opt/opt_merge.o
 | 
				
			||||||
OBJS += passes/opt/opt_muxtree.o
 | 
					OBJS += passes/opt/opt_muxtree.o
 | 
				
			||||||
OBJS += passes/opt/opt_reduce.o
 | 
					OBJS += passes/opt/opt_reduce.o
 | 
				
			||||||
OBJS += passes/opt/opt_rmdff.o
 | 
					OBJS += passes/opt/opt_rmdff.o
 | 
				
			||||||
 | 
					OBJS += passes/opt/opt_share.o
 | 
				
			||||||
OBJS += passes/opt/opt_clean.o
 | 
					OBJS += passes/opt/opt_clean.o
 | 
				
			||||||
OBJS += passes/opt/opt_expr.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/pmux2shiftx.o
 | 
				
			||||||
OBJS += passes/opt/muxpack.o
 | 
					OBJS += passes/opt/muxpack.o
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										329
									
								
								passes/opt/opt_share.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										329
									
								
								passes/opt/opt_share.cc
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
							
								
								
									
										15
									
								
								tests/opt/opt_share_cat.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								tests/opt/opt_share_cat.v
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
							
								
								
									
										9
									
								
								tests/opt/opt_share_cat.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								tests/opt/opt_share_cat.ys
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
							
								
								
									
										19
									
								
								tests/opt/opt_share_mux_tree.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								tests/opt/opt_share_mux_tree.v
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
							
								
								
									
										10
									
								
								tests/opt/opt_share_mux_tree.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								tests/opt/opt_share_mux_tree.ys
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue