proc_prune: Make assign removal and promotion per-bit, remember promoted bits.
authorMarcelina Kościelnicka <mwk@0x04.net>
Sat, 14 Aug 2021 12:23:12 +0000 (14:23 +0200)
committerMarcelina Kościelnicka <mwk@0x04.net>
Sat, 14 Aug 2021 13:26:11 +0000 (15:26 +0200)
Fixes #2962.

passes/proc/proc_prune.cc
tests/proc/bug2962.ys [new file with mode: 0644]

index bd122b91fff737d2f42a57cc9dd79c764d170c3f..9f1080ef6354650e9ed22694c6df0895c2d293b1 100644 (file)
@@ -67,51 +67,36 @@ struct PruneWorker
                }
                for (auto it = cs->actions.rbegin(); it != cs->actions.rend(); ) {
                        RTLIL::SigSpec lhs = sigmap(it->first);
-                       bool redundant = true;
-                       for (auto &bit : lhs) {
+                       RTLIL::SigSpec rhs = sigmap(it->second);
+                       SigSpec new_lhs, new_rhs;
+                       SigSpec conn_lhs, conn_rhs;
+                       for (int i = 0; i < GetSize(lhs); i++) {
+                               SigBit bit = lhs[i];
                                if (bit.wire && !assigned[bit]) {
-                                       redundant = false;
-                                       break;
-                               }
-                       }
-                       bool remove = false;
-                       if (redundant) {
-                               removed_count++;
-                               remove = true;
-                       } else {
-                               if (root) {
-                                       bool promotable = true;
-                                       for (auto &bit : lhs) {
-                                               if (bit.wire && affected[bit] && !assigned[bit]) {
-                                                       promotable = false;
-                                                       break;
-                                               }
-                                       }
-                                       if (promotable) {
-                                               RTLIL::SigSpec rhs = sigmap(it->second);
-                                               RTLIL::SigSig conn;
-                                               for (int i = 0; i < GetSize(lhs); i++) {
-                                                       RTLIL::SigBit lhs_bit = lhs[i];
-                                                       if (lhs_bit.wire && !assigned[lhs_bit]) {
-                                                               conn.first.append(lhs_bit);
-                                                               conn.second.append(rhs.extract(i));
-                                                       }
-                                               }
-                                               promoted_count++;
-                                               module->connect(conn);
-                                               remove = true;
+                                       if (!affected[bit] && root) {
+                                               conn_lhs.append(bit);
+                                               conn_rhs.append(rhs[i]);
+                                       } else {
+                                               new_lhs.append(bit);
+                                               new_rhs.append(rhs[i]);
                                        }
+                                       assigned.insert(bit);
+                                       affected.insert(bit);
                                }
-                               for (auto &bit : lhs)
-                                       if (bit.wire)
-                                               assigned.insert(bit);
-                               for (auto &bit : lhs)
-                                       if (bit.wire)
-                                               affected.insert(bit);
                        }
-                       if (remove)
+                       if (GetSize(conn_lhs)) {
+                               promoted_count++;
+                               module->connect(conn_lhs, conn_rhs);
+                       }
+                       if (GetSize(new_lhs) == 0) {
+                               if (GetSize(conn_lhs) == 0)
+                                       removed_count++;
                                cs->actions.erase((it++).base() - 1);
-                       else it++;
+                       } else {
+                               it->first = new_lhs;
+                               it->second = new_rhs;
+                               it++;
+                       }
                }
                return assigned;
        }
diff --git a/tests/proc/bug2962.ys b/tests/proc/bug2962.ys
new file mode 100644 (file)
index 0000000..99da8db
--- /dev/null
@@ -0,0 +1,22 @@
+read_ilang << EOT
+module \top
+   wire width 4 input 1 \a
+   wire width 2 input 2 \b
+   wire input 3 \clk
+   wire width 4 output 4 \q
+   wire input 5 \en
+   wire width 4 \nq
+   process \p
+     assign \nq \a
+     assign \nq [1:0] \b
+     switch \en
+       case 1'1
+         assign \nq [3] 1'0
+     end
+     sync posedge \clk
+       update \q \nq
+   end
+end
+EOT
+proc
+check -assert