From d9af46538c0159bcb721d602e4f864ee0d749eec Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Mon, 17 Mar 2025 04:12:06 -0700 Subject: [PATCH] opt_expand peepopt (still needs testing) --- passes/silimate/.gitignore | 1 + passes/silimate/Makefile.inc | 10 ++++ passes/silimate/opt_expand.cc | 76 ++++++++++++++++++++++++++++++ passes/silimate/peepopt_expand.pmg | 75 +++++++++++++++++++++++++++++ 4 files changed, 162 insertions(+) create mode 100644 passes/silimate/.gitignore create mode 100644 passes/silimate/opt_expand.cc create mode 100644 passes/silimate/peepopt_expand.pmg diff --git a/passes/silimate/.gitignore b/passes/silimate/.gitignore new file mode 100644 index 000000000..9342ac23b --- /dev/null +++ b/passes/silimate/.gitignore @@ -0,0 +1 @@ +/peepopt*.h \ No newline at end of file diff --git a/passes/silimate/Makefile.inc b/passes/silimate/Makefile.inc index bbf508994..c60e0693e 100644 --- a/passes/silimate/Makefile.inc +++ b/passes/silimate/Makefile.inc @@ -12,3 +12,13 @@ OBJS += passes/silimate/segv.o OBJS += passes/silimate/selectconst.o OBJS += passes/silimate/splitfanout.o OBJS += passes/silimate/splitnetlist.o + +OBJS += passes/silimate/opt_expand.o +GENFILES += passes/silimate/peepopt_expand.h +passes/silimate/opt_expand.o: passes/silimate/peepopt_expand.h +$(eval $(call add_extra_objs,passes/silimate/peepopt_expand.h)) + +PEEPOPT_PATTERN = passes/silimate/peepopt_expand.pmg + +passes/silimate/peepopt_expand.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN) + $(P) mkdir -p $(dir $@) && $(PYTHON_EXECUTABLE) $< -o $@ -p peepopt $(filter-out $<,$^) diff --git a/passes/silimate/opt_expand.cc b/passes/silimate/opt_expand.cc new file mode 100644 index 000000000..ddb13b0c1 --- /dev/null +++ b/passes/silimate/opt_expand.cc @@ -0,0 +1,76 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Claire Xenia Wolf + * Akash Levy + * + * 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 + +bool did_something; + +#include "passes/silimate/peepopt_expand.h" + +struct OptExpandPass : public Pass { + OptExpandPass() : Pass("opt_expand", "expand conjunction") { } + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" opt_expand [selection]\n"); + log("\n"); + log("This pass expands conjunction (AND) operations into disjunction (OR).\n"); + log("\n"); + log("y = (a | b) & c ===> y = (a & c) | (b & c)\n"); + log("\n"); + log(" -max_iters n\n"); + log(" max number of pass iterations to run.\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) override + { + log_header(design, "Executing OPT_EXPAND pass (expand conjunction into disjunction).\n"); + + size_t argidx; + int max_iters = 10000; + for (argidx = 1; argidx < args.size(); argidx++) { + // No extra arguments + if (args[argidx] == "-max_iters" && argidx + 1 < args.size()) { + max_iters = std::stoi(args[++argidx]); + continue; + } + break; + } + extra_args(args, argidx, design); + for (auto module : design->selected_modules()) + { + did_something = true; + for (int i = 0; did_something && i < max_iters; i++) + { + log("ITERATION OF OPT_EXPAND\n"); + did_something = false; + peepopt_pm pm(module); + pm.setup(module->selected_cells()); + pm.run_expand(); + } + } + } +} PeepoptPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/silimate/peepopt_expand.pmg b/passes/silimate/peepopt_expand.pmg new file mode 100644 index 000000000..2c1787854 --- /dev/null +++ b/passes/silimate/peepopt_expand.pmg @@ -0,0 +1,75 @@ +pattern expand +// +// Authored by Akash Levy of Silimate, Inc. under ISC license. +// +// Expand logical conjunction (&) across (|) +// +// y = (a | b) & c ===> y = (a & c) | (b & c) +// + +state and_a and_b and_y or_a or_b or_y + +match or_gate + // Select OR gate + select or_gate->type.in($or, $_OR_) + set or_a port(or_gate, \A) + set or_b port(or_gate, \B) + set or_y port(or_gate, \Y) +endmatch + +code + // Fanout of each OR gate Y bit should be 1 (no bit-split) + if (nusers(or_y) != 2) + reject; +endcode + +match and_gate + // Select AND gate + select and_gate->type.in($and, $_AND_) + + // Set ports, allowing A and B to be swapped + choice A {\A, \B} + define B (A == \A ? \B : \A) + set and_a port(and_gate, A) + set and_b port(and_gate, B) + set and_y port(and_gate, \Y) + + // Connection + index port(and_gate, A) === or_y +endmatch + +code and_a and_b and_y or_a or_b or_y + // Unset all ports + and_gate->unsetPort(\A); + and_gate->unsetPort(\B); + and_gate->unsetPort(\Y); + or_gate->unsetPort(\A); + or_gate->unsetPort(\B); + or_gate->unsetPort(\Y); + + // Create new intermediate wires + Cell *cell = and_gate; + Wire *new_or_a = module->addWire(NEW_ID2, GetSize(and_y)); + Wire *new_or_b = module->addWire(NEW_ID2, GetSize(and_y)); + + // Create new AND gates connected to the OR gate + module->addAnd(NEW_ID2, or_a, and_b, new_or_a, false, cell->get_src_attribute()); + module->addAnd(NEW_ID2, or_b, and_b, new_or_b, false, cell->get_src_attribute()); + + // Update OR gate ports + or_gate->setPort(\A, new_or_a); + or_gate->setPort(\B, new_or_b); + or_gate->setPort(\Y, and_y); + + // Rename OR gate for formal + cell = or_gate; + module->rename(or_gate, NEW_ID2); + + // Remove AND gate + autoremove(and_gate); + + // Log, fixup, accept + log("expand pattern in %s: and=%s, or=%s\n", log_id(module), log_id(and_gate), log_id(or_gate)); + did_something = true; + accept; +endcode