diff options
| author | 2026-03-08 18:04:29 +0100 | |
|---|---|---|
| committer | 2026-03-08 18:04:29 +0100 | |
| commit | 18304d695eb69e6e8776e82c305c6798d42ca1f7 (patch) | |
| tree | 7d4f2ed1f066b8c00b8ba68905265251c3bf40e9 /ir/inliner.c | |
| parent | 0a9b4736ca028e1637311a6cc0753bbb9351e951 (diff) | |
ir: fix inlining getting stuck on complex recursive call sequences
By maintaining a proper stack of inline expansions and refusing to
expand callers already present in the stack.
Diffstat (limited to 'ir/inliner.c')
| -rw-r--r-- | ir/inliner.c | 25 |
1 files changed, 17 insertions, 8 deletions
diff --git a/ir/inliner.c b/ir/inliner.c index 80e6081..b99d3dc 100644 --- a/ir/inliner.c +++ b/ir/inliner.c @@ -1,7 +1,6 @@ #include "ir.h" struct savedfunc { - int mark; uint ninstr; struct instr *instrtab; struct xcon *contab; @@ -255,16 +254,22 @@ inlcall(struct function *fn, struct block *blk, int curi, struct savedfunc *sv) return exit; } +enum { MAX_REC_INLINE = 16 }; void doinline(struct function *fn) { if (calltab.n == 0) return; struct block *b = fn->entry; - static int visitmark = 1; /* stops infinite recursion */ - struct block *vnext = NULL; + struct stack { /* stack of callees being inline expanded */ + struct block *b; /* block after the end of expansion */ + struct savedfunc *sv; + } stkbuf[MAX_REC_INLINE], *stk = stkbuf + MAX_REC_INLINE, *stkend = stk; bool dumpbefore = 0; do { - if (b == vnext) ++visitmark; + if (stk != stkend && b == stk->b) + ++stk; /* pop */ + else if (stk == stkbuf) /* stack full? */ + continue; for (int i = 0; i < b->ins.n; ++i) { struct instr *ins = &instrtab[b->ins.p[i]]; if (ins->op != Ocall) continue; @@ -274,11 +279,12 @@ doinline(struct function *fn) struct savedfunc **pcallee, *sv; if ((pcallee = pmap_get(&savedfns, fname)) && (sv = *pcallee)->nabiarg == call->narg && call->vararg == -1 - && sv->mark != visitmark && call->narg == sv->nabiarg && (!call->narg || !memcmp(sv->abiarg, call->abiarg, sizeof *sv->abiarg * sv->nabiarg)) && !memcmp(sv->abiret, call->abiret, sizeof sv->abiret)) { - sv->mark = visitmark; + for (struct stack *s = stk; s != stkend; ++s) { + if (s->sv == sv) goto Skip; /* recursion encountered */ + } if (ccopt.dbg.y) { if (!dumpbefore) { bfmt(ccopt.dbgout, "<< Before inlining >>\n"); @@ -286,13 +292,16 @@ doinline(struct function *fn) dumpbefore = 1; } } - vnext = inlcall(fn, b, i, *pcallee); + + (--stk)->b = inlcall(fn, b, i, *pcallee); + stk->sv = sv; if (ccopt.dbg.y) { - bfmt(ccopt.dbgout, "<< After inlining '%s' >>\n", fname); + bfmt(ccopt.dbgout, "<< After inlining '%s' (@%d-@%d) >>\n", fname, b->lnext->id, stk->b->id); irdump(fn); } break; } + Skip:; } } while ((b = b->lnext) != fn->entry); } |