Improve Loop unrolling (#6480) (#6493)

This patch implements #6480. All loop statements are represented using
AstLoop and AstLoopTest.

This necessitates rework of the loop unroller to handle loops of
arbitrary form. To enable this, I have split the old unroller used for
'generate for' statements and moved it into V3Param, and subsequently
rewrote V3Unroll to handle the new representation. V3Unroll can now
unroll more complex loops, including with loop conditions containing
multiple variable references or inlined functions.

Handling the more generic code also requires some restrictions. If a
loop contains any of the following, it cannot be unrolled:
- A timing control that might suspend the loop
- A non-inlined call to a non-pure function

These constructs can change the values of variables in the loop, so are
generally not safe to unroll if they are present. (We could still unroll
if all the variables needed for unrolling are automatic, however we
don't do that right now.)

These restrictions seem ok in the benchmark suite, where the new
unroller can generally unroll many more loops than before.
This commit is contained in:
Geza Lore
2025-09-29 15:25:25 +01:00
committed by GitHub
parent 5c72b45975
commit 603f4c615a
59 changed files with 3151 additions and 2891 deletions
+1 -21
View File
@@ -52,7 +52,6 @@ class PremitVisitor final : public VNVisitor {
AstCFunc* m_cfuncp = nullptr; // Current block
size_t m_tmpVarCnt = 0; // Number of temporary variables created inside a function
AstNode* m_stmtp = nullptr; // Current statement
AstWhile* m_inWhileCondp = nullptr; // Inside condition of this while loop
bool m_assignLhs = false; // Inside assignment lhs, don't breakup extracts
// METHODS
@@ -100,10 +99,6 @@ class PremitVisitor final : public VNVisitor {
= new AstAssign{flp, new AstVarRef{flp, varp, VAccess::WRITE}, nodep};
// Insert before the statement
m_stmtp->addHereThisAsNext(assignp);
// Statements that are needed for the 'condition' in a while also
// need to be inserted on the back-edge to the loop header.
// 'incsp' is just right palce to do this
if (m_inWhileCondp) m_inWhileCondp->addIncsp(assignp->cloneTree(false));
}
// Replace node with VarRef to new Var
@@ -173,24 +168,9 @@ class PremitVisitor final : public VNVisitor {
if (stmtp->user1SetOnce()) return; \
VL_RESTORER(m_assignLhs); \
VL_RESTORER(m_stmtp); \
VL_RESTORER(m_inWhileCondp); \
m_assignLhs = false; \
m_stmtp = stmtp; \
m_inWhileCondp = nullptr
m_stmtp = stmtp;
void visit(AstWhile* nodep) override {
UINFO(4, " WHILE " << nodep);
// cppcheck-suppress shadowVariable // Also restored below
START_STATEMENT_OR_RETURN(nodep);
{
// cppcheck-suppress shadowVariable // Also restored above
VL_RESTORER(m_inWhileCondp);
m_inWhileCondp = nodep;
iterateAndNextNull(nodep->condp());
}
iterateAndNextNull(nodep->stmtsp());
iterateAndNextNull(nodep->incsp());
}
void visit(AstNodeAssign* nodep) override {
START_STATEMENT_OR_RETURN(nodep);