mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-04 13:29:12 +00:00 
			
		
		
		
	opt_dff: Don't mutate muxes while ModWalker is active.
This commit is contained in:
		
							parent
							
								
									bac750fb99
								
							
						
					
					
						commit
						db33b1e535
					
				
					 1 changed files with 112 additions and 98 deletions
				
			
		| 
						 | 
				
			
			@ -58,13 +58,10 @@ struct OptDffWorker
 | 
			
		|||
	typedef std::pair<RTLIL::SigBit, bool> ctrl_t;
 | 
			
		||||
	typedef std::set<ctrl_t> ctrls_t;
 | 
			
		||||
 | 
			
		||||
	ModWalker modwalker;
 | 
			
		||||
	QuickConeSat qcsat;
 | 
			
		||||
 | 
			
		||||
	// Used as a queue.
 | 
			
		||||
	std::vector<Cell *> dff_cells;
 | 
			
		||||
 | 
			
		||||
	OptDffWorker(const OptDffOptions &opt, Module *mod) : opt(opt), module(mod), sigmap(mod), initvals(&sigmap, mod), modwalker(module->design, module), qcsat(modwalker) {
 | 
			
		||||
	OptDffWorker(const OptDffOptions &opt, Module *mod) : opt(opt), module(mod), sigmap(mod), initvals(&sigmap, mod) {
 | 
			
		||||
		// Gathering two kinds of information here for every sigmapped SigBit:
 | 
			
		||||
		//
 | 
			
		||||
		// - bitusers: how many users it has (muxes will only be merged into FFs if this is 1, making the FF the only user)
 | 
			
		||||
| 
						 | 
				
			
			@ -569,100 +566,6 @@ struct OptDffWorker
 | 
			
		|||
				changed = true;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Now check if any bit can be replaced by a constant.
 | 
			
		||||
			pool<int> removed_sigbits;
 | 
			
		||||
			for (int i = 0; i < ff.width; i++) {
 | 
			
		||||
				State val = ff.val_init[i];
 | 
			
		||||
				if (ff.has_arst)
 | 
			
		||||
					val = combine_const(val, ff.val_arst[i]);
 | 
			
		||||
				if (ff.has_srst)
 | 
			
		||||
					val = combine_const(val, ff.val_srst[i]);
 | 
			
		||||
				if (ff.has_sr) {
 | 
			
		||||
					if (ff.sig_clr[i] != (ff.pol_clr ? State::S0 : State::S1))
 | 
			
		||||
						val = combine_const(val, State::S0);
 | 
			
		||||
					if (ff.sig_set[i] != (ff.pol_set ? State::S0 : State::S1))
 | 
			
		||||
						val = combine_const(val, State::S1);
 | 
			
		||||
				}
 | 
			
		||||
				if (val == State::Sm)
 | 
			
		||||
					continue;
 | 
			
		||||
				if (ff.has_clk || ff.has_gclk) {
 | 
			
		||||
					if (!ff.sig_d[i].wire) {
 | 
			
		||||
						val = combine_const(val, ff.sig_d[i].data);
 | 
			
		||||
						if (val == State::Sm)
 | 
			
		||||
							continue;
 | 
			
		||||
					} else {
 | 
			
		||||
						if (!opt.sat)
 | 
			
		||||
							continue;
 | 
			
		||||
						// For each register bit, try to prove that it cannot change from the initial value. If so, remove it
 | 
			
		||||
						if (!modwalker.has_drivers(ff.sig_d.extract(i)))
 | 
			
		||||
							continue;
 | 
			
		||||
						if (val != State::S0 && val != State::S1)
 | 
			
		||||
							continue;
 | 
			
		||||
 | 
			
		||||
						int init_sat_pi = qcsat.importSigBit(val);
 | 
			
		||||
						int q_sat_pi = qcsat.importSigBit(ff.sig_q[i]);
 | 
			
		||||
						int d_sat_pi = qcsat.importSigBit(ff.sig_d[i]);
 | 
			
		||||
 | 
			
		||||
						qcsat.prepare();
 | 
			
		||||
 | 
			
		||||
						// Try to find out whether the register bit can change under some circumstances
 | 
			
		||||
						bool counter_example_found = qcsat.ez->solve(qcsat.ez->IFF(q_sat_pi, init_sat_pi), qcsat.ez->NOT(qcsat.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)
 | 
			
		||||
							continue;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				if (ff.has_aload) {
 | 
			
		||||
					if (!ff.sig_ad[i].wire) {
 | 
			
		||||
						val = combine_const(val, ff.sig_ad[i].data);
 | 
			
		||||
						if (val == State::Sm)
 | 
			
		||||
							continue;
 | 
			
		||||
					} else {
 | 
			
		||||
						if (!opt.sat)
 | 
			
		||||
							continue;
 | 
			
		||||
						// For each register bit, try to prove that it cannot change from the initial value. If so, remove it
 | 
			
		||||
						if (!modwalker.has_drivers(ff.sig_ad.extract(i)))
 | 
			
		||||
							continue;
 | 
			
		||||
						if (val != State::S0 && val != State::S1)
 | 
			
		||||
							continue;
 | 
			
		||||
 | 
			
		||||
						int init_sat_pi = qcsat.importSigBit(val);
 | 
			
		||||
						int q_sat_pi = qcsat.importSigBit(ff.sig_q[i]);
 | 
			
		||||
						int d_sat_pi = qcsat.importSigBit(ff.sig_ad[i]);
 | 
			
		||||
 | 
			
		||||
						qcsat.prepare();
 | 
			
		||||
 | 
			
		||||
						// Try to find out whether the register bit can change under some circumstances
 | 
			
		||||
						bool counter_example_found = qcsat.ez->solve(qcsat.ez->IFF(q_sat_pi, init_sat_pi), qcsat.ez->NOT(qcsat.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)
 | 
			
		||||
							continue;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				log("Setting constant %d-bit at position %d on %s (%s) from module %s.\n", val ? 1 : 0,
 | 
			
		||||
						i, log_id(cell), log_id(cell->type), log_id(module));
 | 
			
		||||
 | 
			
		||||
				initvals.remove_init(ff.sig_q[i]);
 | 
			
		||||
				module->connect(ff.sig_q[i], val);
 | 
			
		||||
				removed_sigbits.insert(i);
 | 
			
		||||
			}
 | 
			
		||||
			if (!removed_sigbits.empty()) {
 | 
			
		||||
				std::vector<int> keep_bits;
 | 
			
		||||
				for (int i = 0; i < ff.width; i++)
 | 
			
		||||
					if (!removed_sigbits.count(i))
 | 
			
		||||
						keep_bits.push_back(i);
 | 
			
		||||
				if (keep_bits.empty()) {
 | 
			
		||||
					module->remove(cell);
 | 
			
		||||
					did_something = true;
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
				ff = ff.slice(keep_bits);
 | 
			
		||||
				ff.cell = cell;
 | 
			
		||||
				changed = true;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// The cell has been simplified as much as possible already.  Now try to spice it up with enables / sync resets.
 | 
			
		||||
			if (ff.has_clk) {
 | 
			
		||||
				if (!ff.has_arst && !ff.has_sr && (!ff.has_srst || !ff.has_ce || ff.ce_over_srst) && !opt.nosdff) {
 | 
			
		||||
| 
						 | 
				
			
			@ -818,6 +721,115 @@ struct OptDffWorker
 | 
			
		|||
		}
 | 
			
		||||
		return did_something;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool run_constbits() {
 | 
			
		||||
		ModWalker modwalker(module->design, module);
 | 
			
		||||
		QuickConeSat qcsat(modwalker);
 | 
			
		||||
 | 
			
		||||
		// Run as a separate sub-pass, so that we don't mutate (non-FF) cells under ModWalker.
 | 
			
		||||
		bool did_something = false;
 | 
			
		||||
		for (auto cell : module->selected_cells()) {
 | 
			
		||||
			if (!RTLIL::builtin_ff_cell_types().count(cell->type))
 | 
			
		||||
				continue;
 | 
			
		||||
			FfData ff(&initvals, cell);
 | 
			
		||||
 | 
			
		||||
			// Now check if any bit can be replaced by a constant.
 | 
			
		||||
			pool<int> removed_sigbits;
 | 
			
		||||
			for (int i = 0; i < ff.width; i++) {
 | 
			
		||||
				State val = ff.val_init[i];
 | 
			
		||||
				if (ff.has_arst)
 | 
			
		||||
					val = combine_const(val, ff.val_arst[i]);
 | 
			
		||||
				if (ff.has_srst)
 | 
			
		||||
					val = combine_const(val, ff.val_srst[i]);
 | 
			
		||||
				if (ff.has_sr) {
 | 
			
		||||
					if (ff.sig_clr[i] != (ff.pol_clr ? State::S0 : State::S1))
 | 
			
		||||
						val = combine_const(val, State::S0);
 | 
			
		||||
					if (ff.sig_set[i] != (ff.pol_set ? State::S0 : State::S1))
 | 
			
		||||
						val = combine_const(val, State::S1);
 | 
			
		||||
				}
 | 
			
		||||
				if (val == State::Sm)
 | 
			
		||||
					continue;
 | 
			
		||||
				if (ff.has_clk || ff.has_gclk) {
 | 
			
		||||
					if (!ff.sig_d[i].wire) {
 | 
			
		||||
						val = combine_const(val, ff.sig_d[i].data);
 | 
			
		||||
						if (val == State::Sm)
 | 
			
		||||
							continue;
 | 
			
		||||
					} else {
 | 
			
		||||
						if (!opt.sat)
 | 
			
		||||
							continue;
 | 
			
		||||
						// For each register bit, try to prove that it cannot change from the initial value. If so, remove it
 | 
			
		||||
						if (!modwalker.has_drivers(ff.sig_d.extract(i)))
 | 
			
		||||
							continue;
 | 
			
		||||
						if (val != State::S0 && val != State::S1)
 | 
			
		||||
							continue;
 | 
			
		||||
 | 
			
		||||
						int init_sat_pi = qcsat.importSigBit(val);
 | 
			
		||||
						int q_sat_pi = qcsat.importSigBit(ff.sig_q[i]);
 | 
			
		||||
						int d_sat_pi = qcsat.importSigBit(ff.sig_d[i]);
 | 
			
		||||
 | 
			
		||||
						qcsat.prepare();
 | 
			
		||||
 | 
			
		||||
						// Try to find out whether the register bit can change under some circumstances
 | 
			
		||||
						bool counter_example_found = qcsat.ez->solve(qcsat.ez->IFF(q_sat_pi, init_sat_pi), qcsat.ez->NOT(qcsat.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)
 | 
			
		||||
							continue;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				if (ff.has_aload) {
 | 
			
		||||
					if (!ff.sig_ad[i].wire) {
 | 
			
		||||
						val = combine_const(val, ff.sig_ad[i].data);
 | 
			
		||||
						if (val == State::Sm)
 | 
			
		||||
							continue;
 | 
			
		||||
					} else {
 | 
			
		||||
						if (!opt.sat)
 | 
			
		||||
							continue;
 | 
			
		||||
						// For each register bit, try to prove that it cannot change from the initial value. If so, remove it
 | 
			
		||||
						if (!modwalker.has_drivers(ff.sig_ad.extract(i)))
 | 
			
		||||
							continue;
 | 
			
		||||
						if (val != State::S0 && val != State::S1)
 | 
			
		||||
							continue;
 | 
			
		||||
 | 
			
		||||
						int init_sat_pi = qcsat.importSigBit(val);
 | 
			
		||||
						int q_sat_pi = qcsat.importSigBit(ff.sig_q[i]);
 | 
			
		||||
						int d_sat_pi = qcsat.importSigBit(ff.sig_ad[i]);
 | 
			
		||||
 | 
			
		||||
						qcsat.prepare();
 | 
			
		||||
 | 
			
		||||
						// Try to find out whether the register bit can change under some circumstances
 | 
			
		||||
						bool counter_example_found = qcsat.ez->solve(qcsat.ez->IFF(q_sat_pi, init_sat_pi), qcsat.ez->NOT(qcsat.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)
 | 
			
		||||
							continue;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				log("Setting constant %d-bit at position %d on %s (%s) from module %s.\n", val ? 1 : 0,
 | 
			
		||||
						i, log_id(cell), log_id(cell->type), log_id(module));
 | 
			
		||||
 | 
			
		||||
				initvals.remove_init(ff.sig_q[i]);
 | 
			
		||||
				module->connect(ff.sig_q[i], val);
 | 
			
		||||
				removed_sigbits.insert(i);
 | 
			
		||||
			}
 | 
			
		||||
			if (!removed_sigbits.empty()) {
 | 
			
		||||
				std::vector<int> keep_bits;
 | 
			
		||||
				for (int i = 0; i < ff.width; i++)
 | 
			
		||||
					if (!removed_sigbits.count(i))
 | 
			
		||||
						keep_bits.push_back(i);
 | 
			
		||||
				if (keep_bits.empty()) {
 | 
			
		||||
					module->remove(cell);
 | 
			
		||||
					did_something = true;
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
				ff = ff.slice(keep_bits);
 | 
			
		||||
				ff.cell = cell;
 | 
			
		||||
				ff.emit();
 | 
			
		||||
				did_something = true;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return did_something;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct OptDffPass : public Pass {
 | 
			
		||||
| 
						 | 
				
			
			@ -894,6 +906,8 @@ struct OptDffPass : public Pass {
 | 
			
		|||
			OptDffWorker worker(opt, mod);
 | 
			
		||||
			if (worker.run())
 | 
			
		||||
				did_something = true;
 | 
			
		||||
			if (worker.run_constbits())
 | 
			
		||||
				did_something = true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (did_something)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue