Combine consecutive assertOn() checks into one, and hoist past enclosing
'if' statements if possible. This enables combining a lot of them, which
can be worth 10% performance on some assertion heavy designs depending
on how the assertions are written.
Add an overload that takes `const char*` format string. This avoids
having to construct/destruct a temporary `std::string` at the call site
when calling these functions with a string literal, which is fairly
common. This is worth 25% code size on some assertion heavy design.
Also use `std::string::clear()` instead of assigning an empty string
which is more efficient.
Turn `x = $sformatf(...)` into `$sformat(x, ...)`. The former requires
checking and running a destructor for `x` at the call site, the later
does it in the callee VL_SFORMAT. This reduces the size of the call
site, which can be significant e.g. in the presence of many assertions.
Also added a rewrite of `$sformat(x, "const-string")` back into `x =
"const-string"` for the cases where the `$sformatf` would have been
folded into a constant string.
Treat AstSFormat as a special form of assignment in V3Life. This allows
eliminating earlier redundant assignments to strings when an $sformat
later sets the string. UVM has lot of these.
V3Premit extracts wide sub-expressions via temporaries, which is needed
for emitting wide operations to C++ (calls to `VL_*_W`). The previous
version used to extract both branches of an AstCond unconditionally,
meaning both branches were fully evaluated. Rewriting the AstCond into
an AstIf instead enables evaluating only the required branch. While
this does limit V3Subst, overall the resulting code is ~3% faster,
and contains ~25% fewer branches on a large design.
If the same statements appears in both branches of an 'if', put a single
copy after the 'if', apply recursively. This also has the effect of
getting rid of conditionals with identical branches, but is more widely
applicable.