mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-12 20:18:20 +00:00
rtlil: Add packed extract
implementation for SigSpec
Previously `extract` on a `SigSpec` would always unpack it. Since a significant amount of `SigSpec`s have one or few chunks, it's worth having a dedicated implementation. This is especially true, since the RTLIL frontend calls into this for every `wire [lhs:rhs]` slice, making this `extract` take up 40% when profiling `read_rtlil` with one of the largest coarse grained RTLIL designs I had on hand. With this change the `read_rtlil` profile looks like I would expect it to look like, but I noticed that a lot of the other core RTLIL methods also are a bit too eager with unpacking or implementing `SigChunk`/`Const` overloads that just convert to a single chunk `SigSpec` and forward to the implementation for that, when a direct implementation would avoid temporary std::vector allocations. While not relevant for `read_rtlil`, to me it looks like there might be a few easy overall performance gains to be had by addressing this more generally.
This commit is contained in:
parent
171577f909
commit
0d30a4d479
|
@ -4435,8 +4435,39 @@ RTLIL::SigSpec RTLIL::SigSpec::extract(int offset, int length) const
|
||||||
log_assert(offset >= 0);
|
log_assert(offset >= 0);
|
||||||
log_assert(length >= 0);
|
log_assert(length >= 0);
|
||||||
log_assert(offset + length <= width_);
|
log_assert(offset + length <= width_);
|
||||||
unpack();
|
|
||||||
cover("kernel.rtlil.sigspec.extract_pos");
|
cover("kernel.rtlil.sigspec.extract_pos");
|
||||||
|
|
||||||
|
if (packed())
|
||||||
|
{
|
||||||
|
if (chunks_.size() == 1)
|
||||||
|
return chunks_[0].extract(offset, length);
|
||||||
|
|
||||||
|
SigSpec extracted;
|
||||||
|
int end = offset + length;
|
||||||
|
int chunk_end = 0;
|
||||||
|
|
||||||
|
for (auto const &chunk : chunks_)
|
||||||
|
{
|
||||||
|
int chunk_begin = chunk_end;
|
||||||
|
chunk_end += chunk.width;
|
||||||
|
int extract_begin = std::max(chunk_begin, offset);
|
||||||
|
int extract_end = std::min(chunk_end, end);
|
||||||
|
if (extract_begin >= extract_end)
|
||||||
|
continue;
|
||||||
|
int extract_offset = extract_begin - chunk_begin;
|
||||||
|
int extract_len = extract_end - extract_begin;
|
||||||
|
if (extract_offset == 0 && extract_len == chunk.width)
|
||||||
|
extracted.chunks_.emplace_back(chunk);
|
||||||
|
else
|
||||||
|
extracted.chunks_.emplace_back(
|
||||||
|
chunk.extract(extract_offset, extract_len));
|
||||||
|
}
|
||||||
|
|
||||||
|
extracted.width_ = length;
|
||||||
|
return extracted;
|
||||||
|
}
|
||||||
|
|
||||||
return std::vector<RTLIL::SigBit>(bits_.begin() + offset, bits_.begin() + offset + length);
|
return std::vector<RTLIL::SigBit>(bits_.begin() + offset, bits_.begin() + offset + length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue