rtlil: Improve performance of SigSpec::extract(SigSpec, SigSpec*)
authorRick Altherr <kc8apf@kc8apf.net>
Sun, 31 Jan 2016 17:07:21 +0000 (09:07 -0800)
committerRick Altherr <kc8apf@kc8apf.net>
Sun, 31 Jan 2016 17:20:16 +0000 (09:20 -0800)
Converting to a pool<SigBit> is fairly expensive due to inserts somewhat
frequently causing rehashing.  Instead, walk through the pattern SigSpec
directly on a chunk-by-chunk basis and apply it to this SigSpec's
individual bits.  Using chunks for the pattern minimizes the number of
iterations in the outer loop.

kernel/rtlil.cc

index ee0f44a38a3d8bd4a2496a5495f6f2d0de921253..1f3f789990ba7648bb753b0a6b76b65d2370020f 100644 (file)
@@ -2777,8 +2777,37 @@ void RTLIL::SigSpec::remove2(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigS
 
 RTLIL::SigSpec RTLIL::SigSpec::extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other) const
 {
-       pool<RTLIL::SigBit> pattern_bits = pattern.to_sigbit_pool();
-       return extract(pattern_bits, other);
+       if (other)
+               cover("kernel.rtlil.sigspec.extract_other");
+       else
+               cover("kernel.rtlil.sigspec.extract");
+
+       log_assert(other == NULL || width_ == other->width_);
+
+       RTLIL::SigSpec ret;
+       std::vector<RTLIL::SigBit> bits_match = to_sigbit_vector();
+
+       for (auto& pattern_chunk : pattern.chunks()) {
+               if (other) {
+                       std::vector<RTLIL::SigBit> bits_other = other->to_sigbit_vector();
+                       for (int i = 0; i < width_; i++)
+                               if (bits_match[i].wire &&
+                                       bits_match[i].wire == pattern_chunk.wire &&
+                                       bits_match[i].offset >= pattern_chunk.offset &&
+                                       bits_match[i].offset < pattern_chunk.offset + pattern_chunk.width)
+                                       ret.append_bit(bits_other[i]);
+               } else {
+                       for (int i = 0; i < width_; i++)
+                               if (bits_match[i].wire &&
+                                       bits_match[i].wire == pattern_chunk.wire &&
+                                       bits_match[i].offset >= pattern_chunk.offset &&
+                                       bits_match[i].offset < pattern_chunk.offset + pattern_chunk.width)
+                                       ret.append_bit(bits_match[i]);
+               }
+       }
+
+       ret.check();
+       return ret;
 }
 
 RTLIL::SigSpec RTLIL::SigSpec::extract(const pool<RTLIL::SigBit> &pattern, const RTLIL::SigSpec *other) const