aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2025-11-23 12:02:27 +0100
committerlemon <lsof@mailbox.org>2025-11-23 15:29:55 +0100
commit1f72464c6451fcff16180d00af537225acc9b83c (patch)
tree3ea1d99164f990fb2ce331abbf44de2a0db48f25
parentf4488e9153a4ead6f427902237cca93c67fec2bd (diff)
implement float varargs, and some other fixes
-rw-r--r--amd64/isel.c6
-rw-r--r--amd64/sysv.c91
-rw-r--r--c/c.c3
-rw-r--r--ir/abi0.c4
-rw-r--r--ir/ir.c3
-rw-r--r--ir/regalloc.c17
-rw-r--r--test/10-varargs.c22
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");
}
diff --git a/c/c.c b/c/c.c
index 05308e1..2b2688d 100644
--- a/c/c.c
+++ b/c/c.c
@@ -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 */
diff --git a/ir/abi0.c b/ir/abi0.c
index fe1a7e3..4462be9 100644
--- a/ir/abi0.c
+++ b/ir/abi0.c
@@ -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) {
diff --git a/ir/ir.c b/ir/ir.c
index 3b37405..412d0f9 100644
--- a/ir/ir.c
+++ b/ir/ir.c
@@ -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));
}