diff options
| -rw-r--r-- | amd64/isel.c | 6 | ||||
| -rw-r--r-- | amd64/sysv.c | 91 | ||||
| -rw-r--r-- | c/c.c | 3 | ||||
| -rw-r--r-- | ir/abi0.c | 4 | ||||
| -rw-r--r-- | ir/ir.c | 3 | ||||
| -rw-r--r-- | ir/regalloc.c | 17 | ||||
| -rw-r--r-- | test/10-varargs.c | 22 |
7 files changed, 93 insertions, 53 deletions
diff --git a/amd64/isel.c b/amd64/isel.c index 9606c87..51a58db 100644 --- a/amd64/isel.c +++ b/amd64/isel.c @@ -141,6 +141,12 @@ selcall(struct function *fn, struct instr *ins, struct block *blk, int *curi) } else { union ref adr = mkaddr((struct addr){mkref(RREG, RSP), .disp = abi.stk}); *arg = mkinstr(Ostore8+ilog2(cls2siz[abi.ty.cls]), 0, adr, arg->r); + int iargsave = iarg; + if (isaddrcon(arg->r,1) || arg->r.t == RADDR) + arg->r = insertinstr(blk, iarg++, mkinstr(Ocopy, abi.ty.cls, arg->r)); + else + fixarg(&ins->r, ins, blk, &iarg); + *curi += iarg - iargsave; } } if (call->argstksiz) { diff --git a/amd64/sysv.c b/amd64/sysv.c index 9d97b86..9d356a1 100644 --- a/amd64/sysv.c +++ b/amd64/sysv.c @@ -74,7 +74,7 @@ abiarg(short r[2], uchar cls[2], int *ni, int *nf, int *ns, union irtype typ) if (!typ.isagg) { if (kisflt(cls[0] = typ.cls) && *nf < NFLT) { r[0] = XMM0 + (*nf)++; - } else if (*ni < NINT) { + } else if (kisint(cls[0]) && *ni < NINT) { r[0] = intregs[(*ni)++]; } else { r[0] = *ns; @@ -204,7 +204,7 @@ vastart(struct function *fn, struct block *blk, int *curi) insertinstr(blk, i++, mkinstr(Ostore32, 0, ap, mkref(RICON, gpr0*8))); /* set ap->fp_offset */ dst = insertinstr(blk, i++, mkinstr(Oadd, KPTR, ap, mkref(RICON, 4))); - insertinstr(blk, i++, mkinstr(Ostore32, 0, dst, mkref(RICON, 6*8 + fpr0*8))); + insertinstr(blk, i++, mkinstr(Ostore32, 0, dst, mkref(RICON, 6*8 + fpr0*16))); *curi = i; } @@ -228,51 +228,50 @@ vaarg(struct function *fn, struct block *blk, int *curi) else if (ret == 1) { struct block *merge; union ref phi, phiargs[2]; - if (ni) { - /* l->gp_offset < 48 - num_gp * 8 */ - tmp = insertinstr(blk, (*curi)++, mkinstr(Oloadu32, KI32, ap)); - tmp = insertinstr(blk, (*curi)++, mkinstr(Oulte, KI32, tmp, mkref(RICON, 48 - ni*8))); - merge = blksplitafter(fn, blk, *curi); - blk->jmp.t = 0; - useblk(fn, blk); - putcondbranch(fn, tmp, newblk(fn), newblk(fn)); - useblk(fn, blk->s1); - { - /* phi0: &l->reg_save_area[l->gp_offset] */ - union ref sav = addinstr(fn, mkinstr(Oloadi64, KPTR, irbinop(fn, Oadd, KPTR, ap, mkref(RICON, 16)))); - union ref gpoff = addinstr(fn, mkinstr(Oloadu32, KI32, ap)); - phiargs[0] = irbinop(fn, Oadd, KPTR, sav, gpoff); - /* l->gp_offset += num_gp * 8 */ - gpoff = irbinop(fn, Oadd, KI32, gpoff, mkref(RICON, ni * 8)); - addinstr(fn, mkinstr(Ostore32, 0, ap, gpoff)); - assert(merge->npred == 1); - blkpred(merge, 0) = blk->s1; - blk->s1->jmp.t = Jb; - blk->s1->s1 = merge; - } - useblk(fn, blk->s2); - { - /* phi1: l->overflow_arg_area */ - union ref adr = irbinop(fn, Oadd, KPTR, ap, mkref(RICON, 8)); - union ref ovf = addinstr(fn, mkinstr(Oloadi64, KPTR, adr)); - /* align no-op */ - - phiargs[1] = ovf; - /* update l->overflow_arg_area += num_gp*8 */ - int siz = 8; - addinstr(fn, mkinstr(Ostore64, 0, adr, irbinop(fn, Oadd, KPTR, ovf, mkref(RICON, siz)))); - putbranch(fn, merge); - } - assert(merge->npred == 2); - vpush(&merge->ins, 0); - memmove(merge->ins.p+1, merge->ins.p, (merge->ins.n-1)*sizeof *merge->ins.p); - merge->ins.p[0] = var; - phi = insertphi(merge, KPTR); - memcpy(phitab.p[instrtab[phi.i].l.i], phiargs, sizeof phiargs); - instrtab[var] = mkinstr(cls[0] == KI32 ? Oloads32 : Oloadi64, cls[0], phi); - } else { - assert(0&&nf); + /* int: l->gp_offset < 48 - num_gp * 8 */ + /* sse: l->fp_offset < 304 - num_gp * 16 (why 304? ... 176) */ + tmp = ni ? ap : insertinstr(blk, (*curi)++, mkinstr(Oadd, KPTR, ap, mkref(RICON, 4))); + tmp = insertinstr(blk, (*curi)++, mkinstr(Oloadu32, KI32, tmp)); + tmp = insertinstr(blk, (*curi)++, mkinstr(Oulte, KI32, tmp, mkref(RICON, ni ? 48 - ni*8 : 176 - nf*16))); + merge = blksplitafter(fn, blk, *curi); + blk->jmp.t = 0; + useblk(fn, blk); + putcondbranch(fn, tmp, newblk(fn), newblk(fn)); + useblk(fn, blk->s1); + { + /* phi0: &l->reg_save_area[l->gp/fp_offset] */ + union ref sav = addinstr(fn, mkinstr(Oloadi64, KPTR, irbinop(fn, Oadd, KPTR, ap, mkref(RICON, 16)))); + union ref roff = addinstr(fn, mkinstr(Oloadu32, KI32, irbinop(fn, Oadd, KPTR, ap, mkref(RICON, ni ? 0 : 4)))); + phiargs[0] = irbinop(fn, Oadd, KPTR, sav, roff); + /* l->gp/fp_offset += num_gp/fp * 8(16) */ + roff = irbinop(fn, Oadd, KI32, roff, mkref(RICON, ni ? ni * 8 : nf * 16)); + addinstr(fn, mkinstr(Ostore32, 0, irbinop(fn, Oadd, KPTR, ap, mkref(RICON, ni ? 0 : 4)), roff)); + assert(merge->npred == 1); + blkpred(merge, 0) = blk->s1; + blk->s1->jmp.t = Jb; + blk->s1->s1 = merge; + } + useblk(fn, blk->s2); + { + /* phi1: l->overflow_arg_area */ + union ref adr = irbinop(fn, Oadd, KPTR, ap, mkref(RICON, 8)); + union ref ovf = addinstr(fn, mkinstr(Oloadi64, KPTR, adr)); + /* align no-op */ + + phiargs[1] = ovf; + /* update l->overflow_arg_area += size */ + int siz = 8; + addinstr(fn, mkinstr(Ostore64, 0, adr, irbinop(fn, Oadd, KPTR, ovf, mkref(RICON, siz)))); + putbranch(fn, merge); } + assert(merge->npred == 2); + vpush(&merge->ins, 0); + memmove(merge->ins.p+1, merge->ins.p, (merge->ins.n-1)*sizeof *merge->ins.p); + merge->ins.p[0] = var; + phi = insertphi(merge, KPTR); + memcpy(phitab.p[instrtab[phi.i].l.i], phiargs, sizeof phiargs); + instrtab[var] = mkinstr(cls[0] == KI32 ? Oloads32 : Oloadi64, cls[0], phi); + fn->prop &= ~FNUSE; } else { assert(!"nyi"); } @@ -2677,6 +2677,9 @@ expraddr(struct function *fn, const struct expr *ex) case ECALL: assert(isagg(ex->ty)); return compilecall(fn, ex); + case EVAARG: + assert(isagg(ex->ty)); + return builtin_va_arg_comp(fn, ex, 0); case EINIT: if (fn) { /* compound literal, allocate temp */ @@ -437,7 +437,9 @@ abi0(struct function *fn) blk->id = id++; } while ((blk = blk->lnext) != fn->entry); - /* vaargs might break */ + + /* vaargs might break these */ + if (!(fn->prop & FNUSE)) filluses(fn); fn->prop &= ~(FNBLKID | FNRPO); if (ccopt.dbg.a) { @@ -326,7 +326,7 @@ blksplitafter(struct function *fn, struct block *blk, int idx) memset(blk->jmp.arg, 0, sizeof blk->jmp.arg); for (int i = 0; i < 2; ++i) { struct block *s = (&blk->s1)[i]; - for (int i = 0; i < s->npred; ++i) { + if (s) for (int i = 0; i < s->npred; ++i) { if (blkpred(s, i) == blk) blkpred(s, i) = new; } @@ -334,6 +334,7 @@ blksplitafter(struct function *fn, struct block *blk, int idx) new->s1 = blk->s1, new->s2 = blk->s2; blk->s1 = new, blk->s2 = NULL; addpred(new, blk); + fn->prop &= ~FNUSE; return new; } diff --git a/ir/regalloc.c b/ir/regalloc.c index d3c1ee0..e060ebf 100644 --- a/ir/regalloc.c +++ b/ir/regalloc.c @@ -517,11 +517,18 @@ usereg(struct rega *ra, int reg, struct block *blk, int pos) { struct fixinterval *fxit; if (rstest(mctarg->rglob, reg)) return; /* regalloc never allocates globally live regs, so don't need intervals for those */ - 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->range.from > pos) break; if (fxit->rs == 1<<reg && fxit->range.from <= pos && pos < fxit->range.to) { /* contained by existing interval */ fxit->range.from = blk->inumstart; + /* insert at head */ + //DBG(">>>extend REG %s range %d-%d\n", mctarg->rnames[reg], fxit->range.from, fxit->range.to); + if (prev) { + prev->next = fxit->next; + fxit->next = ra->intervals.fixed; + ra->intervals.fixed = fxit; + } return; } } @@ -539,7 +546,7 @@ defreg(struct rega *ra, int reg, int pos) { if (fxit->rs == 1<<reg) { assert(fxit->range.from <= pos); fxit->range.from = pos; - // DBG(">>>REG %s range @%d: %d-%d\n", mctarg->rnames[reg], fxit->range.from.blk, fxit->range.from.ins, fxit->range.to.ins); + //DBG(">>>def REG %s range %d-%d\n", mctarg->rnames[reg], fxit->range.from, fxit->range.to); return; } } @@ -643,9 +650,9 @@ buildintervals(struct rega *ra) ra->intervals.fixed = fxit; } for (int j = call->narg - 1; j >= 0; --j) { - int reg = call->abiarg[j].reg; - if (reg >= 0) { - usereg(ra, reg, blk, pos); + struct abiarg abi = call->abiarg[j]; + if (!abi.isstk) { + usereg(ra, abi.reg, blk, pos); } } } diff --git a/test/10-varargs.c b/test/10-varargs.c index c15b887..a3715ab 100644 --- a/test/10-varargs.c +++ b/test/10-varargs.c @@ -1,5 +1,7 @@ /* EXPECT: 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 = 36 +<1.5> +1.1 + 2.1 + 3.1 + 5.1 + 1.5 + -1.5 + 1.5 + -1.5 + 1.5 + -1 = 11.9 */ @@ -18,6 +20,26 @@ int sum(int x, ...) { return x; } +double stkarg(double a, double b, double c, double d, double e, double f, double g, double h, double x) { + printf(""); + return x; +} + +double sumf(double x, ...) { + va_list ap; + va_start(ap, x); + printf("%g", x); + for (double y; (y = va_arg(ap, double));) { + printf(" + %g",y); + x += y; + } + va_end(ap); + return x; +} + + int main() { printf(" = %d\n", sum(1,2,3,4,5,6,7,8,0,0)); + printf("<%g>\n", stkarg(0,0,0,0,0,0,0,0,1.5)); + printf(" = %g\n", sumf(1.1, 2.1, 3.1, 5.1, 1.5, -1.5, 1.5, -1.5, 1.5, -1.0, 0.0)); } |