rtlil: Disallow 0-width chunks in SigSpec.

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.
This commit is contained in:
Marcelina Kościelnicka 2021-03-09 02:54:56 +01:00
parent e178d0367a
commit f965b3fa54
2 changed files with 63 additions and 18 deletions

View File

@ -3276,8 +3276,12 @@ RTLIL::SigSpec::SigSpec(const RTLIL::Const &value)
{ {
cover("kernel.rtlil.sigspec.init.const"); cover("kernel.rtlil.sigspec.init.const");
if (GetSize(value) != 0) {
chunks_.emplace_back(value); chunks_.emplace_back(value);
width_ = chunks_.back().width; width_ = chunks_.back().width;
} else {
width_ = 0;
}
hash_ = 0; hash_ = 0;
check(); check();
} }
@ -3286,8 +3290,12 @@ RTLIL::SigSpec::SigSpec(const RTLIL::SigChunk &chunk)
{ {
cover("kernel.rtlil.sigspec.init.chunk"); cover("kernel.rtlil.sigspec.init.chunk");
if (chunk.width != 0) {
chunks_.emplace_back(chunk); chunks_.emplace_back(chunk);
width_ = chunks_.back().width; width_ = chunks_.back().width;
} else {
width_ = 0;
}
hash_ = 0; hash_ = 0;
check(); check();
} }
@ -3296,8 +3304,12 @@ RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire)
{ {
cover("kernel.rtlil.sigspec.init.wire"); cover("kernel.rtlil.sigspec.init.wire");
if (wire->width != 0) {
chunks_.emplace_back(wire); chunks_.emplace_back(wire);
width_ = chunks_.back().width; width_ = chunks_.back().width;
} else {
width_ = 0;
}
hash_ = 0; hash_ = 0;
check(); check();
} }
@ -3306,8 +3318,12 @@ RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire, int offset, int width)
{ {
cover("kernel.rtlil.sigspec.init.wire_part"); cover("kernel.rtlil.sigspec.init.wire_part");
if (width != 0) {
chunks_.emplace_back(wire, offset, width); chunks_.emplace_back(wire, offset, width);
width_ = chunks_.back().width; width_ = chunks_.back().width;
} else {
width_ = 0;
}
hash_ = 0; hash_ = 0;
check(); check();
} }
@ -3316,8 +3332,12 @@ RTLIL::SigSpec::SigSpec(const std::string &str)
{ {
cover("kernel.rtlil.sigspec.init.str"); cover("kernel.rtlil.sigspec.init.str");
if (str.size() != 0) {
chunks_.emplace_back(str); chunks_.emplace_back(str);
width_ = chunks_.back().width; width_ = chunks_.back().width;
} else {
width_ = 0;
}
hash_ = 0; hash_ = 0;
check(); check();
} }
@ -3326,6 +3346,7 @@ RTLIL::SigSpec::SigSpec(int val, int width)
{ {
cover("kernel.rtlil.sigspec.init.int"); cover("kernel.rtlil.sigspec.init.int");
if (width != 0)
chunks_.emplace_back(val, width); chunks_.emplace_back(val, width);
width_ = width; width_ = width;
hash_ = 0; hash_ = 0;
@ -3336,6 +3357,7 @@ RTLIL::SigSpec::SigSpec(RTLIL::State bit, int width)
{ {
cover("kernel.rtlil.sigspec.init.state"); cover("kernel.rtlil.sigspec.init.state");
if (width != 0)
chunks_.emplace_back(bit, width); chunks_.emplace_back(bit, width);
width_ = width; width_ = width;
hash_ = 0; hash_ = 0;
@ -3346,11 +3368,13 @@ RTLIL::SigSpec::SigSpec(const RTLIL::SigBit &bit, int width)
{ {
cover("kernel.rtlil.sigspec.init.bit"); cover("kernel.rtlil.sigspec.init.bit");
if (width != 0) {
if (bit.wire == NULL) if (bit.wire == NULL)
chunks_.emplace_back(bit.data, width); chunks_.emplace_back(bit.data, width);
else else
for (int i = 0; i < width; i++) for (int i = 0; i < width; i++)
chunks_.push_back(bit); chunks_.push_back(bit);
}
width_ = width; width_ = width;
hash_ = 0; hash_ = 0;
check(); check();
@ -3795,7 +3819,13 @@ void RTLIL::SigSpec::remove_const()
width_ = 0; width_ = 0;
for (auto &chunk : chunks_) for (auto &chunk : chunks_)
if (chunk.wire != NULL) { if (chunk.wire != NULL) {
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); new_chunks.push_back(chunk);
}
width_ += chunk.width; width_ += chunk.width;
} }
@ -3955,6 +3985,7 @@ void RTLIL::SigSpec::check() const
int w = 0; int w = 0;
for (size_t i = 0; i < chunks_.size(); i++) { for (size_t i = 0; i < chunks_.size(); i++) {
const RTLIL::SigChunk &chunk = chunks_[i]; const RTLIL::SigChunk &chunk = chunks_[i];
log_assert(chunk.width != 0);
if (chunk.wire == NULL) { if (chunk.wire == NULL) {
if (i > 0) if (i > 0)
log_assert(chunks_[i-1].wire != NULL); log_assert(chunks_[i-1].wire != NULL);

14
tests/opt/bug2623.ys Normal file
View File

@ -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