diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 500431888..30214d6d8 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -93,14 +93,14 @@ jobs: CIBW_BEFORE_ALL: bash ./.github/workflows/wheels/cibw_before_all.sh CIBW_ENVIRONMENT: > OPTFLAGS=-O3 - PKG_CONFIG_PATH=./ffi/pfx/lib/pkgconfig - PATH="$PWD/bison/src:$PATH" + PKG_CONFIG_PATH={project}/ffi/pfx/lib/pkgconfig + PATH="{project}/bison/src:$PATH" CMAKE_ARGS="-DCMAKE_BUILD_TYPE=Release" CIBW_ENVIRONMENT_MACOS: > OPTFLAGS=-O3 - PKG_CONFIG_PATH=./ffi/pfx/lib/pkgconfig + PKG_CONFIG_PATH={project}/ffi/pfx/lib/pkgconfig MACOSX_DEPLOYMENT_TARGET=11 - PATH="$PWD/bison/src:$PATH" + PATH="{project}/bison/src:$PATH" CMAKE_ARGS="-DCMAKE_BUILD_TYPE=Release" CIBW_BEFORE_BUILD: bash ./.github/workflows/wheels/cibw_before_build.sh CIBW_TEST_COMMAND: python3 {project}/tests/pyosys/run_tests.py diff --git a/.github/workflows/wheels/cibw_before_all.sh b/.github/workflows/wheels/cibw_before_all.sh index 6450ce273..61bfb2181 100644 --- a/.github/workflows/wheels/cibw_before_all.sh +++ b/.github/workflows/wheels/cibw_before_all.sh @@ -29,9 +29,7 @@ fi set -e -x cd ffi ## Ultimate libyosys.so will be shared, so we need fPIC for the static libraries - CFLAGS=-fPIC CXXFLAGS=-fPIC ./configure --prefix=$PWD/pfx + LDFLAGS=-fPIC CFLAGS=-fPIC CXXFLAGS=-fPIC ./configure --prefix=$PWD/pfx --enable-static --disable-shared make clean make install -j$(getconf _NPROCESSORS_ONLN 2>/dev/null || sysctl -n hw.ncpu) - ## Forces static library to be used in all situations - sed -i.bak 's@-L${toolexeclibdir} -lffi@${toolexeclibdir}/libffi.a@' ./pfx/lib/pkgconfig/libffi.pc ) diff --git a/passes/opt/opt_muxtree.cc b/passes/opt/opt_muxtree.cc index 4887355b2..e1424f94e 100644 --- a/passes/opt/opt_muxtree.cc +++ b/passes/opt/opt_muxtree.cc @@ -34,7 +34,7 @@ PRIVATE_NAMESPACE_BEGIN * A multiplexer tree (mux tree) is a tree composed exclusively of muxes. * By mux, I mean $mux or $pmux. By port, I usually mean input port. * The children of a node are all the muxes driving its input ports (A, B). - * It must be rooted in a "root mux", a mux which has multiple mux users + * It must be rooted in a "root mux", a mux which has multiple mux port users * or any number of non-mux users. Only the root and leaf nodes can be * root muxes, not the internal nodes. Leaf nodes that are root muxes * are roots of "input trees". @@ -64,10 +64,17 @@ struct OptMuxtreeWorker int removed_count; int glob_evals_left = 10'000'000; + struct MuxPort { + int mux; + // Hacky: -1 is port A, if positive then indexes B port slices (of which $mux has only one) + int port; + inline Hasher hash_into(Hasher h) const { h.eat(mux); h.eat(port); return h; } + bool operator==(const MuxPort &other) const { return mux == other.mux && port == other.port; } + }; struct bitinfo_t { // Is bit directly used by non-mux cells or ports? bool seen_non_mux; - pool mux_users; + pool mux_users; std::optional mux_driver; }; @@ -94,10 +101,10 @@ struct OptMuxtreeWorker vector root_enable_muxes; pool root_mux_rerun; - portinfo_t used_port_bit(RTLIL::SigSpec& sig, int mux_idx) { + portinfo_t used_port_bit(RTLIL::SigSpec& sig, int mux_idx, int port_idx) { portinfo_t portinfo = {}; for (int bit_idx : sig2bits(sig)) { - bit2info[bit_idx].mux_users.insert(mux_idx); + bit2info[bit_idx].mux_users.insert({mux_idx, port_idx}); portinfo.input_sigs.insert(bit_idx); } return portinfo; @@ -127,7 +134,7 @@ struct OptMuxtreeWorker for (int i = 0; i < GetSize(sig_s); i++) { RTLIL::SigSpec sig = sig_b.extract(i*GetSize(sig_a), GetSize(sig_a)); RTLIL::SigSpec ctrl_sig = assign_map(SigSpec{sig_s[i]}); - portinfo_t portinfo = used_port_bit(sig, this_mux_idx); + portinfo_t portinfo = used_port_bit(sig, this_mux_idx, i); portinfo.ctrl_sig = sig2bits(ctrl_sig, false).front(); portinfo.const_activated = ctrl_sig.is_fully_const() && ctrl_sig.as_bool(); portinfo.const_deactivated = ctrl_sig.is_fully_const() && !ctrl_sig.as_bool(); @@ -135,7 +142,7 @@ struct OptMuxtreeWorker } // Analyze port A - muxinfo.ports.push_back(used_port_bit(sig_a, this_mux_idx)); + muxinfo.ports.push_back(used_port_bit(sig_a, this_mux_idx, -1)); for (int idx : sig2bits(sig_y)) { if (bit2info[idx].mux_driver) @@ -170,17 +177,18 @@ struct OptMuxtreeWorker // bit2info knows the mux users and mux drivers of bits // use this to tell mux2info ports about what muxes are driven by it for (int i = 0; i < GetSize(bit2info); i++) - for (int j : bit2info[i].mux_users) - for (auto &p : mux2info[j].ports) { - if (p.input_sigs.count(i)) - if (bit2info[i].mux_driver) - p.input_muxes.insert(*bit2info[i].mux_driver); + for (auto muxport : bit2info[i].mux_users) { + for (auto &p : mux2info[muxport.mux].ports) { + if (p.input_sigs.count(i)) + if (bit2info[i].mux_driver) + p.input_muxes.insert(*bit2info[i].mux_driver); + } } } void populate_roots() { // mux_to_users[i] means "set of muxes using output of mux i" - dict> mux_to_users; + dict> mux_to_users; // Pure root muxes (outputs seen by non-muxes) root_enable_muxes.resize(GetSize(mux2info)); // All root muxes (outputs seen by non-muxes or multiple muxes) @@ -188,8 +196,8 @@ struct OptMuxtreeWorker for (auto &bi : bit2info) { if (bi.mux_driver) - for (int j : bi.mux_users) - mux_to_users[*bi.mux_driver].insert(j); + for (auto muxport : bi.mux_users) + mux_to_users[*bi.mux_driver].insert(muxport); if (!bi.seen_non_mux) continue; if (bi.mux_driver) { diff --git a/passes/techmap/aigmap.cc b/passes/techmap/aigmap.cc index 6b7e0c377..c1ec214fd 100644 --- a/passes/techmap/aigmap.cc +++ b/passes/techmap/aigmap.cc @@ -92,7 +92,6 @@ struct AigmapPass : public Pass { } vector sigs; - dict, SigBit> and_cache; for (int node_idx = 0; node_idx < GetSize(aig.nodes); node_idx++) { @@ -115,15 +114,10 @@ struct AigmapPass : public Pass { goto skip_inverter; } else { - pair key(node.left_parent, node.right_parent); - if (and_cache.count(key)) - bit = and_cache.at(key); - else { - bit = module->addWire(NEW_ID); - auto gate = module->addAndGate(NEW_ID, A, B, bit); - if (select_mode) - new_sel.insert(gate->name); - } + bit = module->addWire(NEW_ID); + auto gate = module->addAndGate(NEW_ID, A, B, bit); + if (select_mode) + new_sel.insert(gate->name); } } diff --git a/tests/opt/opt_muxtree_port_reconverge.ys b/tests/opt/opt_muxtree_port_reconverge.ys new file mode 100644 index 000000000..592786dfc --- /dev/null +++ b/tests/opt/opt_muxtree_port_reconverge.ys @@ -0,0 +1,54 @@ +read_rtlil << EOT +module \top + wire input 1 \a + wire input 2 \b + wire output 3 \out + wire $0\out[0:0] + wire \y + wire $1\out[0:0] + wire \s + wire \q + wire \n_a + + cell $mux \mux + parameter \WIDTH 1 + connect \A 1'0 + connect \B \a + connect \S \b + connect \Y \y + end + + attribute \full_case 1 + cell $pmux \pmux + parameter \WIDTH 1 + parameter \S_WIDTH 2 + connect \A 1'x + connect \B { \y \y } + connect \S { \n_a \s } + connect \Y \q + end + + attribute \full_case 1 + cell $not \not + parameter \A_SIGNED 0 + parameter \Y_WIDTH 1 + parameter \A_WIDTH 1 + connect \A \a + connect \Y \n_a + end + + connect $0\out[0:0] $1\out[0:0] + connect \s \a + connect $1\out[0:0] \q + connect \out \q +end +EOT +# a drives out +select -assert-any i:a %co* o:out %i + +opt_muxtree +opt_reduce +opt_expr + +# a still drives out +select -assert-any o:out %ci* i:a %i