Calling `throw dst_end_of_data_exception()` when the desired number of cycles has been reached means that the fst reader can't tidy up after itself and leads to memory leaks.
This doesn't happen when the `-stop` flag is used because the `Yosys::FstData` struct tracks the end time and skips the outer callback if the simulation has gone past the desired end time.
Move cycle checking into the inner callback along with the time checking means that the outer callback no longer needs to throw an exception in order to stop checking further values, while still allowing the fst reader to finish reading and deallocate memory.
When building `WITH_PYTHON`, where a global list of modules is maintained, deleting a module also erases the entry in said global list. This can lead to memory corruption if the global list is destructed before the module.
Using `on_shutdown()` instead means the module destructor is explicitly called before the global list can be destructed, preventing the issue.
Also add a comment to `Pass::~Pass()` to suggest the same for future passes that might try to use that (and see this commit in the blame if they need a reason why).
The lexer for liberty files was using istream's `get` and `unget` which
are notorious for bad performance and that showed up during profiling.
This replaces the direct `istream` use with a custom LibertyInputStream
that does its own buffering to provide `get` and `unget` that behave the
same way but are implemented with a fast path that is easy to inline and
optimize.
Instead, change the default `Design::selected_modules()` to match the behaviour (i.e. `selected_unboxed_modules_warn()`) because it's a lot of files to touch and they don't really _need_ to be updated.
Also change `Design::selected_whole_modules()` users over to `Design::selected_unboxed_whole_modules()`, except `attrmap` because I'm not convinced it should be ignoring boxes. So instead, leave the deprecation warning for that one use and come back to the pass another time.