From d43993dfaa1cf9b684583a0c9266e18ea61abb4d Mon Sep 17 00:00:00 2001 From: lemon Date: Thu, 18 Dec 2025 08:50:47 +0100 Subject: x86_64: for vararg calls, write to EAX in isel Also, in regalloc ensure fixed intervals are sorted --- ir/regalloc.c | 33 +++++++++++++++++++++++++-------- x86_64/emit.c | 10 ---------- x86_64/isel.c | 9 +++++---- 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/ir/regalloc.c b/ir/regalloc.c index 794cdd6..7056dfd 100644 --- a/ir/regalloc.c +++ b/ir/regalloc.c @@ -560,10 +560,19 @@ usereg(struct rega *ra, int reg, struct block *blk, int pos) static bool defreg(struct rega *ra, int reg, int pos) { if (rstest(mctarg->rglob, reg)) return 1; - for (struct fixinterval *fxit = ra->intervals.fixed; fxit; fxit = fxit->next) { + for (struct fixinterval *prev = NULL, *fxit = ra->intervals.fixed; fxit; prev = fxit, fxit = fxit->next) { if (fxit->rs == 1<range.from <= pos) { fxit->range.from = pos; + struct fixinterval **at = &ra->intervals.fixed; + if ((*at)->range.from > pos) { + /* keep sorted */ + //DBG("moved %s\n", mctarg->rnames[reg]); + if (prev) prev->next = fxit->next; + while ((*at)->range.from < pos) at = &(*at)->next; + fxit->next = *at; + *at = fxit; + } //DBG(">>>def REG %s range %d-%d\n", mctarg->rnames[reg], fxit->range.from, fxit->range.to); return 1; } @@ -649,14 +658,21 @@ buildintervals(struct rega *ra) /* gather fixed intervals */ if (ins->op == Omove) { assert(ins->l.t == RREG); - if (ins->l.bits == ins->r.bits) /* special case `move Rx,Rx`: clobber reg, not a real use */ + if (ins->l.bits == ins->r.bits) {/* special case `move Rx,Rx`: clobber reg, not a real use */ usereg(ra, ins->l.i, blk, pos); + //DBG("@ %d clob %s\n", pos, mctarg->rnames[ins->l.i]); + } if (!defreg(ra, ins->l.i, pos)) { - /* dead register use. for example if - * move RCX, %1 - * %2 = shl 1, RCX - * and %2 is dead, the move to RCX can be killed */ - *ins = mkinstr(Onop,0,); + if (ins->keep) { /* clobber here */ + usereg(ra, ins->l.i, blk, pos); + assert(defreg(ra, ins->l.i, pos)); + } else { + /* dead register use. for example if + * move RCX, %1 + * %2 = shl 1, RCX + * and %2 is dead, the move to RCX can be killed */ + *ins = mkinstr(Onop,0,); + } } if (ins->l.bits == ins->r.bits) continue; @@ -917,7 +933,8 @@ linearscan(struct rega *ra) int end = itrange(current, current->nrange-1).to; /* exclude regs from overlapping fixed intervals */ - for (struct fixinterval *fxit = intervals->fixed; fxit; fxit = fxit->next) { + for (struct fixinterval *last = NULL, *fxit = intervals->fixed; fxit; last = fxit, fxit = fxit->next) { + if (last) assert(last->range.from <= fxit->range.from && "unsorted fixintervals"); if (fxit->range.to <= pos) { intervals->fixed = fxit->next; continue; diff --git a/x86_64/emit.c b/x86_64/emit.c index 13121b3..89585b8 100644 --- a/x86_64/emit.c +++ b/x86_64/emit.c @@ -1171,16 +1171,6 @@ emitinstr(uchar **pcode, struct function *fn, struct block *blk, int curi, struc Xpop(pcode, mkregoper(ins->l).reg); break; case Ocall: - if (calltab.p[ins->r.i].vararg >= 0) { - struct call *call = &calltab.p[ins->r.i]; - /* variadic functions need the caller to write num of args in sse regs to %al */ - int n = 0; - for (int i = 0; i < call->narg; ++i) - if (!call->abiarg[i].isstk && call->abiarg[i].reg >= XMM0) - ++n; - if (!n) DS("\x31\xC0"); /* XOR EAX, EAX */ - else B(0xB0), B(n); /* MOV AL, n */ - } Xcall(pcode, KPTR, ref2oper(ins->l)); break; case Oxvaprologue: diff --git a/x86_64/isel.c b/x86_64/isel.c index 67a4358..22a1290 100644 --- a/x86_64/isel.c +++ b/x86_64/isel.c @@ -126,6 +126,7 @@ selcall(struct function *fn, struct instr *ins, struct block *blk, int *curi) int iarg = *curi - 1; enum irclass cls; uint argstksiz = alignup(call->argstksiz, 16); + int nsse = 0; for (int i = call->narg - 1; i >= 0; --i) { struct abiarg abi = call->abiarg[i]; @@ -139,6 +140,7 @@ selcall(struct function *fn, struct instr *ins, struct block *blk, int *curi) if (!abi.isstk) { assert(!abi.ty.isagg); *arg = mkinstr(Omove, call->abiarg[i].ty.cls, mkref(RREG, abi.reg), arg->r); + if (abi.reg >= XMM0) ++nsse; } else { union ref adr = mkaddr((struct addr){mkref(RREG, RSP), .disp = abi.stk}); int iargsave = iarg; @@ -165,10 +167,9 @@ selcall(struct function *fn, struct instr *ins, struct block *blk, int *curi) else if (isintcon(ins->l)) ins->l = insertinstr(blk, (*curi)++, mkinstr(Ocopy, KPTR, ins->l)); - if (call->vararg >= 0 && ins->l.t == RTMP) { - /* variadic calls write number of sse regs used to AL, so mark it as clobbered such that - * the function pointer of an indirect calls does not get allocated to RAX by regalloc */ - insertinstr(blk, (*curi)++, mkinstr(Omove, KPTR, mkref(RREG, RAX), mkref(RREG, RAX))); + if (call->vararg >= 0) { + /* variadic calls write number of sse regs used to AL */ + insertinstr(blk, (*curi)++, mkinstr(Omove, KI32, mkref(RREG, RAX), mkref(RICON, nsse), .keep=1)); } cls = ins->cls; ins->cls = 0; -- cgit v1.2.3