Optimize $sformatf into $sformat (#7701)
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.
This commit is contained in:
parent
efb83c55de
commit
715f5f0c13
|
|
@ -2352,7 +2352,7 @@ class AstSFormatF final : public AstNodeExpr {
|
|||
// @astgen op1 := exprsp : List[AstNodeExpr]
|
||||
// @astgen op2 := scopeNamep : Optional[AstScopeName]
|
||||
string m_text;
|
||||
const bool m_hidden; // Under display, etc
|
||||
bool m_hidden; // Under display, etc
|
||||
bool m_exprFormat
|
||||
= false; // Runtime Node* format, false = text() format code, false = possibly r
|
||||
bool m_optionalFormat
|
||||
|
|
@ -2411,6 +2411,7 @@ public:
|
|||
return false;
|
||||
}
|
||||
bool hidden() const { return m_hidden; }
|
||||
void hidden(bool flag) { m_hidden = flag; }
|
||||
bool exprFormat() const { return m_exprFormat; }
|
||||
void exprFormat(bool flag) { m_exprFormat = flag; }
|
||||
bool optionalFormat() const { return m_optionalFormat; }
|
||||
|
|
|
|||
|
|
@ -1137,6 +1137,12 @@ public:
|
|||
fmtp(newp);
|
||||
this->lhsp(lhsp);
|
||||
}
|
||||
AstSFormat(FileLine* fl, AstSFormatF* fmtp, AstNodeExpr* lhsp)
|
||||
: ASTGEN_SUPER_SFormat(fl) {
|
||||
this->fmtp(fmtp);
|
||||
this->lhsp(lhsp);
|
||||
fmtp->hidden(true);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstSFormat;
|
||||
const char* broken() const override {
|
||||
BROKEN_RTN(!fmtp());
|
||||
|
|
|
|||
|
|
@ -2233,6 +2233,22 @@ class ConstVisitor final : public VNVisitor {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool replaceAssignSFormatF(AstNodeAssign* nodep) {
|
||||
// Rewrite 'x = sformatf(...)' into 'sformat(x, ...)', which is more efficient
|
||||
// at the call site as it does not need to check if 'x' needs to be freed first.
|
||||
// This is a somewhat common pattern after lowering assertions.
|
||||
if (!VN_IS(nodep, Assign)) return false;
|
||||
AstVarRef* const lhsp = VN_CAST(nodep->lhsp(), VarRef);
|
||||
if (!lhsp) return false;
|
||||
AstSFormatF* const fmtp = VN_CAST(nodep->rhsp(), SFormatF);
|
||||
if (!fmtp) return false;
|
||||
lhsp->unlinkFrBack();
|
||||
fmtp->unlinkFrBack();
|
||||
nodep->replaceWith(new AstSFormat{nodep->fileline(), fmtp, lhsp});
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool varNotReferenced(AstNode* nodep, AstVar* varp, int level = 0) {
|
||||
// Return true if varp never referenced under node.
|
||||
// Return false if referenced, or tree too deep to be worth it, or side effects
|
||||
|
|
@ -2607,6 +2623,8 @@ class ConstVisitor final : public VNVisitor {
|
|||
}
|
||||
} else if (m_doV && replaceAssignMultiSel(nodep)) {
|
||||
return true;
|
||||
} else if (replaceAssignSFormatF(nodep)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -3822,6 +3840,25 @@ class ConstVisitor final : public VNVisitor {
|
|||
return;
|
||||
}
|
||||
}
|
||||
void visit(AstSFormat* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (!m_doNConst) return;
|
||||
if (m_doNConst) {
|
||||
// If it's a constant string written to a string variable, inline it as an assignment
|
||||
AstSFormatF* const fmtp = nodep->fmtp();
|
||||
AstNodeExpr* const lhsp = nodep->lhsp();
|
||||
AstBasicDType* const basicp = VN_CAST(lhsp->dtypep()->skipRefp(), BasicDType);
|
||||
if (basicp && basicp->isString() && !fmtp->exprsp()
|
||||
&& fmtp->text().find('%') == string::npos) {
|
||||
AstConst* const strp
|
||||
= new AstConst{fmtp->fileline(), AstConst::String{}, fmtp->text()};
|
||||
lhsp->unlinkFrBack();
|
||||
nodep->replaceWith(new AstAssign{nodep->fileline(), lhsp, strp});
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
void visit(AstNodeFTask* nodep) override {
|
||||
VL_RESTORER(m_underRecFunc);
|
||||
if (nodep->recursive()) m_underRecFunc = true;
|
||||
|
|
|
|||
Loading…
Reference in New Issue