rtlil: Disallow 0-width chunks in SigSpec.
authorMarcelina Kościelnicka <mwk@0x04.net>
Tue, 9 Mar 2021 01:54:56 +0000 (02:54 +0100)
committerMarcelina Kościelnicka <mwk@0x04.net>
Mon, 15 Mar 2021 16:16:24 +0000 (17:16 +0100)
Among other problems, this also fixes equality comparisons between
SigSpec by enforcing a canonical form.

Also fix another minor issue with possible non-canonical SigSpec.

Fixes #2623.

kernel/rtlil.cc
tests/opt/bug2623.ys [new file with mode: 0644]

index c3ae5d2438ea62610e0fab41e78b3f756277b732..32069ce036519b7ee9df9d51d43c837d2024ff7c 100644 (file)
@@ -3276,8 +3276,12 @@ RTLIL::SigSpec::SigSpec(const RTLIL::Const &value)
 {
        cover("kernel.rtlil.sigspec.init.const");
 
-       chunks_.emplace_back(value);
-       width_ = chunks_.back().width;
+       if (GetSize(value) != 0) {
+               chunks_.emplace_back(value);
+               width_ = chunks_.back().width;
+       } else {
+               width_ = 0;
+       }
        hash_ = 0;
        check();
 }
@@ -3286,8 +3290,12 @@ RTLIL::SigSpec::SigSpec(const RTLIL::SigChunk &chunk)
 {
        cover("kernel.rtlil.sigspec.init.chunk");
 
-       chunks_.emplace_back(chunk);
-       width_ = chunks_.back().width;
+       if (chunk.width != 0) {
+               chunks_.emplace_back(chunk);
+               width_ = chunks_.back().width;
+       } else {
+               width_ = 0;
+       }
        hash_ = 0;
        check();
 }
@@ -3296,8 +3304,12 @@ RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire)
 {
        cover("kernel.rtlil.sigspec.init.wire");
 
-       chunks_.emplace_back(wire);
-       width_ = chunks_.back().width;
+       if (wire->width != 0) {
+               chunks_.emplace_back(wire);
+               width_ = chunks_.back().width;
+       } else {
+               width_ = 0;
+       }
        hash_ = 0;
        check();
 }
@@ -3306,8 +3318,12 @@ RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire, int offset, int width)
 {
        cover("kernel.rtlil.sigspec.init.wire_part");
 
-       chunks_.emplace_back(wire, offset, width);
-       width_ = chunks_.back().width;
+       if (width != 0) {
+               chunks_.emplace_back(wire, offset, width);
+               width_ = chunks_.back().width;
+       } else {
+               width_ = 0;
+       }
        hash_ = 0;
        check();
 }
@@ -3316,8 +3332,12 @@ RTLIL::SigSpec::SigSpec(const std::string &str)
 {
        cover("kernel.rtlil.sigspec.init.str");
 
-       chunks_.emplace_back(str);
-       width_ = chunks_.back().width;
+       if (str.size() != 0) {
+               chunks_.emplace_back(str);
+               width_ = chunks_.back().width;
+       } else {
+               width_ = 0;
+       }
        hash_ = 0;
        check();
 }
@@ -3326,7 +3346,8 @@ RTLIL::SigSpec::SigSpec(int val, int width)
 {
        cover("kernel.rtlil.sigspec.init.int");
 
-       chunks_.emplace_back(val, width);
+       if (width != 0)
+               chunks_.emplace_back(val, width);
        width_ = width;
        hash_ = 0;
        check();
@@ -3336,7 +3357,8 @@ RTLIL::SigSpec::SigSpec(RTLIL::State bit, int width)
 {
        cover("kernel.rtlil.sigspec.init.state");
 
-       chunks_.emplace_back(bit, width);
+       if (width != 0)
+               chunks_.emplace_back(bit, width);
        width_ = width;
        hash_ = 0;
        check();
@@ -3346,11 +3368,13 @@ RTLIL::SigSpec::SigSpec(const RTLIL::SigBit &bit, int width)
 {
        cover("kernel.rtlil.sigspec.init.bit");
 
-       if (bit.wire == NULL)
-               chunks_.emplace_back(bit.data, width);
-       else
-               for (int i = 0; i < width; i++)
-                       chunks_.push_back(bit);
+       if (width != 0) {
+               if (bit.wire == NULL)
+                       chunks_.emplace_back(bit.data, width);
+               else
+                       for (int i = 0; i < width; i++)
+                               chunks_.push_back(bit);
+       }
        width_ = width;
        hash_ = 0;
        check();
@@ -3795,7 +3819,13 @@ void RTLIL::SigSpec::remove_const()
                width_ = 0;
                for (auto &chunk : chunks_)
                        if (chunk.wire != NULL) {
-                               new_chunks.push_back(chunk);
+                               if (!new_chunks.empty() &&
+                                       new_chunks.back().wire == chunk.wire &&
+                                       new_chunks.back().offset + new_chunks.back().width == chunk.offset) {
+                                       new_chunks.back().width += chunk.width;
+                               } else {
+                                       new_chunks.push_back(chunk);
+                               }
                                width_ += chunk.width;
                        }
 
@@ -3955,6 +3985,7 @@ void RTLIL::SigSpec::check() const
                int w = 0;
                for (size_t i = 0; i < chunks_.size(); i++) {
                        const RTLIL::SigChunk &chunk = chunks_[i];
+                       log_assert(chunk.width != 0);
                        if (chunk.wire == NULL) {
                                if (i > 0)
                                        log_assert(chunks_[i-1].wire != NULL);
diff --git a/tests/opt/bug2623.ys b/tests/opt/bug2623.ys
new file mode 100644 (file)
index 0000000..2ff23ea
--- /dev/null
@@ -0,0 +1,14 @@
+read_rtlil << EOT
+
+module \top
+  wire output 1 \a
+  wire width 0 $dummy
+  cell \abc \abc
+    connect \a \a
+    connect \b $dummy
+  end
+end
+
+EOT
+
+opt_clean