Skip to content

Commit

Permalink
rtlil: Add packed extract implementation for SigSpec
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
jix committed Apr 22, 2024
1 parent 171577f commit 0d30a4d
Showing 1 changed file with 32 additions and 1 deletion.
33 changes: 32 additions & 1 deletion kernel/rtlil.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4435,8 +4435,39 @@ RTLIL::SigSpec RTLIL::SigSpec::extract(int offset, int length) const
log_assert(offset >= 0);
log_assert(length >= 0);
log_assert(offset + length <= width_);
unpack();

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);
}

Expand Down

0 comments on commit 0d30a4d

Please sign in to comment.