ref: 14aeadb41737f1765b6f3489f3b8da330aeccf39
parent: 0bd2678722f5f70a063190d54d12e62420f02b05
author: Ori Bernstein <ori@eigenstate.org>
date: Fri Aug 21 14:54:53 EDT 2015
Get closer to the C ABI
--- a/6/asm.h
+++ b/6/asm.h
@@ -130,10 +130,14 @@
struct Func {
char *name; /* function name */
int isexport; /* is this exported from the asm? */
- size_t stksz; /* stack size */
Type *type; /* type of function */
+
+ Node **args; /* argument list */
+ size_t nargs; /* number of args, including hidden ones */
Htab *stkoff; /* Loc* -> int stackoff map */
+ size_t stksz; /* stack size */
Node *ret; /* return value */
+
Cfg *cfg; /* flow graph */
};
--- a/6/insns.def
+++ b/6/insns.def
@@ -304,7 +304,11 @@
Insn(Icall,
"\tcall %v\n",
"\tCALL %V\n",
- Use(.l={1}),
+ Use(.l={1}, .r={
+ Rrdi, Rrsi, Rrdx, Rrcx, Rr8, Rr9,
+ Rxmm0d, Rxmm1d, Rxmm2d, Rxmm3d,
+ Rxmm4d, Rxmm5d, Rxmm6d, Rxmm7d,
+ }),
Def(.r={Rrax, Rrbx, Rrcx, Rrdx, Rrsi,
Rrdi, Rr8,Rr9,Rr10,Rr11,
Rxmm0d, Rxmm1d, Rxmm2d, Rxmm3d,
@@ -315,7 +319,11 @@
Insn(Icallind,
"\tcall *%v\n",
"\tCALL *%V\n",
- Use(.l={1}),
+ Use(.l={1}, .r={
+ Rrdi, Rrsi, Rrdx, Rrcx, Rr8, Rr9,
+ Rxmm0d, Rxmm1d, Rxmm2d, Rxmm3d,
+ Rxmm4d, Rxmm5d, Rxmm6d, Rxmm7d,
+ }),
Def(.r={Rrax, Rrbx, Rrcx, Rrdx, Rrsi,
Rrdi, Rr8,Rr9,Rr10,Rr11,
Rxmm0d, Rxmm1d, Rxmm2d, Rxmm3d,
--- a/6/isel.c
+++ b/6/isel.c
@@ -19,6 +19,14 @@
/* forward decls */
Loc *selexpr(Isel *s, Node *n);
+#define Nfloatregargs 8
+#define Nintregargs 6
+regid floatargregs[] = {
+ Rxmm0d, Rxmm1d, Rxmm2d, Rxmm3d,
+ Rxmm4d, Rxmm5d, Rxmm6d, Rxmm7d,
+};
+regid intargregs[] = {Rrdi, Rrsi, Rrdx, Rrcx, Rr8, Rr9};
+
/* used to decide which operator is appropriate
* for implementing various conditional operators */
struct {
@@ -50,14 +58,12 @@
[Ofle] = {Icomis, Ijbe, Isetbe},
};
-static Mode mode(Node *n)
+static Mode tymode(Type *t)
{
- Type *t;
-
- t = tybase(exprtype(n));
/* FIXME: What should the mode for, say, structs be when we have no
* intention of loading /through/ the pointer? For now, we'll just say it's
* the pointer mode, since we expect to address through the pointer */
+ t = tybase(t);
switch (t->type) {
case Tyflt32: return ModeF; break;
case Tyflt64: return ModeD; break;
@@ -64,7 +70,7 @@
default:
if (stacktype(t))
return ModeQ;
- switch (size(n)) {
+ switch (tysize(t)) {
case 1: return ModeB; break;
case 2: return ModeW; break;
case 4: return ModeL; break;
@@ -75,6 +81,16 @@
return ModeQ;
}
+static Mode mode(Node *n)
+{
+ if (n->type == Nexpr)
+ return tymode(exprtype(n));
+ else if (n->type == Ndecl)
+ return tymode(n->decl.type);
+ else
+ die("invalid node type");
+}
+
static Loc *loc(Isel *s, Node *n)
{
ssize_t stkoff;
@@ -90,9 +106,11 @@
stkoff = ptoi(htget(s->stkoff, n));
l = locmem(-stkoff, locphysreg(Rrbp), NULL, mode(n));
} else {
- if (!hthas(s->reglocs, n))
- htput(s->reglocs, n, locreg(mode(n)));
- return htget(s->reglocs, n);
+ l = htget(s->reglocs, n);
+ if (!l) {
+ l = locreg(mode(n));
+ htput(s->reglocs, n, l);
+ }
}
break;
case Olit:
@@ -471,14 +489,31 @@
g(s, op, f, NULL);
}
+static size_t countargs(Type *t)
+{
+ size_t nargs;
+
+ t = tybase(t);
+ nargs = t->nsub - 1;
+ if (stacktype(t->sub[0]))
+ nargs++;
+ /* valists are replaced with hidden type parameter,
+ * which we want on the stack for ease of ABI */
+ if (tybase(t->sub[t->nsub - 1])->type == Tyvalist)
+ nargs--;
+ return nargs;
+}
+
static Loc *gencall(Isel *s, Node *n)
{
Loc *src, *dst, *arg; /* values we reduced */
+ size_t argsz, argoff, nargs;
+ size_t nfloats, nints;
Loc *retloc, *rsp, *ret; /* hard-coded registers */
Loc *stkbump; /* calculated stack offset */
- int argsz, argoff;
size_t i, a;
- Type *t;
+ int vararg;
+ Type *t, *fn;
rsp = locphysreg(Rrsp);
t = exprtype(n);
@@ -492,6 +527,10 @@
retloc = coreg(Rrax, mode(n));
ret = locreg(mode(n));
}
+ fn = tybase(exprtype(n->expr.args[0]));
+ /* calculate the number of args we expect to see, adjust
+ * for a hidden return argument. */
+ nargs = countargs(fn);
argsz = 0;
/* Have to calculate the amount to bump the stack
* pointer by in one pass first, otherwise if we push
@@ -510,20 +549,36 @@
/* Now, we can evaluate the arguments */
argoff = 0;
+ nfloats = 0;
+ nints = 0;
+ vararg = 0;
for (i = 1; i < n->expr.nargs; i++) {
arg = selexpr(s, n->expr.args[i]);
argoff = align(argoff, min(size(n->expr.args[i]), Ptrsz));
+ if (i > nargs)
+ vararg = 1;
if (stacknode(n->expr.args[i])) {
src = locreg(ModeQ);
g(s, Ilea, arg, src, NULL);
a = alignto(1, n->expr.args[i]->expr.type);
blit(s, rsp, src, argoff, 0, size(n->expr.args[i]), a);
+ argoff += size(n->expr.args[i]);
+ } else if (!vararg && isfloatmode(arg->mode) && nfloats < Nfloatregargs) {
+ dst = coreg(floatargregs[nfloats], arg->mode);
+ arg = inri(s, arg);
+ g(s, Imovs, arg, dst, NULL);
+ nfloats++;
+ } else if (!vararg && isintmode(arg->mode) && nints < Nintregargs) {
+ dst = coreg(intargregs[nints], arg->mode);
+ arg = inri(s, arg);
+ g(s, Imov, arg, dst, NULL);
+ nints++;
} else {
dst = locmem(argoff, rsp, NULL, arg->mode);
arg = inri(s, arg);
stor(s, arg, dst);
+ argoff += size(n->expr.args[i]);
}
- argoff += size(n->expr.args[i]);
}
call(s, n->expr.args[0]);
if (argsz)
@@ -842,8 +897,48 @@
Rnone
};
-static void prologue(Isel *s, size_t sz)
+void addarglocs(Isel *s, Func *fn)
{
+ size_t i, nints, nfloats, nargs;
+ size_t argoff;
+ int vararg;
+ Node *arg;
+ Loc *a, *l;
+
+ argoff = 0;
+ nfloats = 0;
+ nints = 0;
+ vararg = 0;
+ nargs = countargs(fn->type);
+ for (i = 0; i < fn->nargs; i++) {
+ arg = fn->args[i];
+ argoff = align(argoff, min(size(arg), Ptrsz));
+ if (i >= nargs)
+ vararg = 1;
+ if (stacknode(arg)) {
+ htput(s->stkoff, arg, itop(-(argoff + 2*Ptrsz)));
+ argoff += size(arg);
+ } else if (!vararg && isfloatmode(mode(arg)) && nfloats < Nfloatregargs) {
+ a = coreg(floatargregs[nfloats], mode(arg));
+ l = locreg(mode(arg));
+ g(s, Imovs, a, l, NULL);
+ htput(s->reglocs, arg, l);
+ nfloats++;
+ } else if (!vararg && isintmode(mode(arg)) && nints < Nintregargs) {
+ a = coreg(intargregs[nints], mode(arg));
+ l = locreg(mode(arg));
+ g(s, Imov, a, l, NULL);
+ htput(s->reglocs, arg, l);
+ nints++;
+ } else {
+ htput(s->stkoff, arg, itop(-(argoff + 2*Ptrsz)));
+ argoff += size(arg);
+ }
+ }
+}
+
+static void prologue(Isel *s, Func *fn, size_t sz)
+{
Loc *rsp;
Loc *rbp;
Loc *stksz;
@@ -867,6 +962,7 @@
g(s, Imov, phys, s->calleesave[i], NULL);
}
}
+ addarglocs(s, fn);
s->nsaved = i;
s->stksz = stksz; /* need to update if we spill */
}
@@ -927,7 +1023,7 @@
lappend(&is->bb, &is->nbb, mkasmbb(fn->cfg->bb[i]));
is->curbb = is->bb[0];
- prologue(is, fn->stksz);
+ prologue(is, fn, fn->stksz);
for (j = 0; j < fn->cfg->nbb - 1; j++) {
is->curbb = is->bb[j];
if (!is->bb[j])
@@ -945,4 +1041,5 @@
is->curbb = is->bb[is->nbb - 1];
epilogue(is);
regalloc(is);
+ is->stksz->lit = align(is->stksz->lit, 16);
}
--- a/6/ra.c
+++ b/6/ra.c
@@ -919,6 +919,8 @@
{
if (s->nuses[r] == 0)
return -1;
+ if (bshas(s->neverspill, r))
+ return -10000;
return s->degree[r] * 100 / s->nuses[r];
}
@@ -953,7 +955,6 @@
if (!m) {
for (i = 0; i < s->nwlspill; i++) {
if (bshas(s->neverspill, s->wlspill[i]->reg.id)) {
- printf("Not spilling %zd\n", s->wlspill[i]->reg.id);
continue;
}
m = s->wlspill[i];
--- a/6/simp.c
+++ b/6/simp.c
@@ -47,10 +47,13 @@
/* location handling */
Node **blobs;
size_t nblobs;
- size_t stksz;
- size_t argsz;
Htab *globls;
- Htab *stkoff;
+
+ Htab *_stkoff;
+ size_t stksz;
+
+ Node **args;
+ size_t nargs;
};
static Node *simp(Simp *s, Node *n);
@@ -166,7 +169,7 @@
static int addressable(Simp *s, Node *a)
{
if (a->type == Ndecl || (a->type == Nexpr && exprop(a) == Ovar))
- return hthas(s->stkoff, a) || hthas(s->globls, a);
+ return hthas(s->_stkoff, a) || hthas(s->globls, a);
else
return stacknode(a);
}
@@ -209,7 +212,7 @@
dump(n, stdout);
printf("declared at %zd, size = %zd\n", s->stksz, size(n));
}
- htput(s->stkoff, n, itop(s->stksz));
+ htput(s->_stkoff, n, itop(s->stksz));
}
static void declarelocal(Simp *s, Node *n)
@@ -1565,13 +1568,7 @@
static void declarearg(Simp *s, Node *n)
{
assert(n->type == Ndecl || (n->type == Nexpr && exprop(n) == Ovar));
- s->argsz = align(s->argsz, min(size(n), Ptrsz));
- htput(s->stkoff, n, itop(-(s->argsz + 2*Ptrsz)));
- if (debugopt['i']) {
- dump(n, stdout);
- printf("declared at %zd\n", -(s->argsz + 2*Ptrsz));
- }
- s->argsz += size(n);
+ lappend(&s->args, &s->nargs, n);
}
static int islbl(Node *n)
@@ -1724,10 +1721,13 @@
fn = zalloc(sizeof(Func));
fn->name = strdup(name);
+ fn->type = dcl->decl.type;
fn->isexport = isexport(dcl);
fn->stksz = align(s->stksz, 8);
- fn->stkoff = s->stkoff;
+ fn->stkoff = s->_stkoff;
fn->ret = s->ret;
+ fn->args = s->args;
+ fn->nargs = s->nargs;
fn->cfg = cfg;
return fn;
}
@@ -1800,7 +1800,7 @@
if (ismain(dcl))
dcl->decl.vis = Vishidden;
- s.stkoff = mkht(varhash, vareq);
+ s._stkoff = mkht(varhash, vareq);
s.globls = globls;
s.blobs = *blob;
s.nblobs = *nblob;
--- a/libstd/syscall+freebsd-x64.s
+++ b/libstd/syscall+freebsd-x64.s
@@ -1,14 +1,5 @@
.globl sys$syscall
sys$syscall:
- pushq %rbp
- pushq %rdi
- pushq %rsi
- pushq %rdx
- pushq %r10
- pushq %r8
- pushq %r9
- pushq %rcx
- pushq %r11
/*
hack: We load 6 args regardless of
how many we actually have. This may
@@ -16,24 +7,15 @@
doesn't use them, it's going to be
harmless.
*/
- movq 80 (%rsp),%rax
- movq 88 (%rsp),%rdi
- movq 96 (%rsp),%rsi
- movq 104(%rsp),%rdx
- movq 112(%rsp),%r10
- movq 120(%rsp),%r8
- movq 128(%rsp),%r9
+ movq %rdi,%rax
+ movq %rsi,%rdi
+ movq %rdx,%rsi
+ movq %rcx,%rdx
+ movq %r8,%r10
+ movq %r9,%r8
+ movq 8(%rsp),%r9
syscall
- popq %r11
- popq %rcx
- popq %r9
- popq %r8
- popq %r10
- popq %rdx
- popq %rsi
- popq %rdi
- popq %rbp
ret
--- a/libstd/syscall+linux-x64.s
+++ b/libstd/syscall+linux-x64.s
@@ -1,15 +1,5 @@
.globl sys$syscall
sys$syscall:
- pushq %rbp
- pushq %rdi
- pushq %rsi
- pushq %rdx
- pushq %r10
- pushq %r8
- pushq %r9
- pushq %rcx
- pushq %r11
-
/*
hack: We load 6 args regardless of
how many we actually have. This may
@@ -17,25 +7,16 @@
doesn't use them, it's going to be
harmless.
*/
- movq 80 (%rsp),%rax
- /* 88: hidden type arg */
- movq 96 (%rsp),%rdi
- movq 104(%rsp),%rsi
- movq 112(%rsp),%rdx
- movq 120(%rsp),%r10
- movq 128(%rsp),%r8
- movq 136(%rsp),%r9
+ movq %rdi,%rax
+ /* 8(%rsp): hidden type arg */
+ movq 16(%rsp),%rdi
+ movq 24(%rsp),%rsi
+ movq 32(%rsp),%rdx
+ movq 40(%rsp),%r10
+ movq 48(%rsp),%r8
+ movq 56(%rsp),%r9
syscall
- popq %r11
- popq %rcx
- popq %r9
- popq %r8
- popq %r10
- popq %rdx
- popq %rsi
- popq %rdi
- popq %rbp
ret
--- a/libstd/syscall+osx-x64.s
+++ b/libstd/syscall+osx-x64.s
@@ -1,14 +1,6 @@
.globl _sys$syscall
_sys$syscall:
- pushq %rbp
- pushq %rdi
- pushq %rsi
- pushq %rdx
- pushq %r10
- pushq %r8
- pushq %r9
- pushq %rcx
- pushq %r11
+
/*
hack: We load 6 args regardless of
how many we actually have. This may
@@ -16,14 +8,14 @@
doesn't use them, it's going to be
harmless.
*/
- movq 80 (%rsp),%rax
- /* 88: hidden type arg */
- movq 96 (%rsp),%rdi
- movq 104(%rsp),%rsi
- movq 112(%rsp),%rdx
- movq 120(%rsp),%r10
- movq 128(%rsp),%r8
- movq 136(%rsp),%r9
+ movq %rdi,%rax
+ /* 8(%rsp): hidden type arg */
+ movq 16(%rsp),%rdi
+ movq 24(%rsp),%rsi
+ movq 32(%rsp),%rdx
+ movq 40(%rsp),%r10
+ movq 48(%rsp),%r8
+ movq 56(%rsp),%r9
syscall
jae .success
@@ -30,15 +22,6 @@
negq %rax
.success:
- popq %r11
- popq %rcx
- popq %r9
- popq %r8
- popq %r10
- popq %rdx
- popq %rsi
- popq %rdi
- popq %rbp
ret
/*
@@ -51,16 +34,6 @@
*/
.globl _sys$__osx_fork
_sys$__osx_fork:
- pushq %rbp
- pushq %rdi
- pushq %rsi
- pushq %rdx
- pushq %r10
- pushq %r8
- pushq %r9
- pushq %rcx
- pushq %r11
-
movq $0x2000002,%rax
syscall
@@ -72,16 +45,6 @@
jz .isparent
xorq %rax,%rax
.isparent:
-
- popq %r11
- popq %rcx
- popq %r9
- popq %r8
- popq %r10
- popq %rdx
- popq %rsi
- popq %rdi
- popq %rbp
ret
/*
@@ -91,16 +54,6 @@
*/
.globl _sys$__osx_pipe
_sys$__osx_pipe:
- pushq %rbp
- pushq %rdi
- pushq %rsi
- pushq %rdx
- pushq %r10
- pushq %r8
- pushq %r9
- pushq %rcx
- pushq %r11
-
movq $0x200002a,%rax
syscall
@@ -112,30 +65,10 @@
movl %eax,(%rdi)
movl %edx,4(%rdi)
xorq %rax,%rax
-
- popq %r11
- popq %rcx
- popq %r9
- popq %r8
- popq %r10
- popq %rdx
- popq %rsi
- popq %rdi
- popq %rbp
ret
.globl _sys$__osx_lseek
_sys$__osx_lseek:
- pushq %rbp
- pushq %rdi
- pushq %rsi
- pushq %rdx
- pushq %r10
- pushq %r8
- pushq %r9
- pushq %rcx
- pushq %r11
-
movq $0x20000C7,%rax
syscall
@@ -146,31 +79,11 @@
movq 80(%rsp),%rdi
shlq $32,%rdx
orq %rdx,%rax
-
- popq %r11
- popq %rcx
- popq %r9
- popq %r8
- popq %r10
- popq %rdx
- popq %rsi
- popq %rdi
- popq %rbp
ret
.globl _sys$__osx_gettimeofday
_sys$__osx_gettimeofday:
- pushq %rbp
- pushq %rdi
- pushq %rsi
- pushq %rdx
- pushq %r10
- pushq %r8
- pushq %r9
- pushq %rcx
- pushq %r11
-
movq $0x2000074,%rax
syscall
@@ -182,15 +95,5 @@
movq %rax, (%rdi)
movl %edx,8(%rdi)
xorq %rax,%rax
-
- popq %r11
- popq %rcx
- popq %r9
- popq %r8
- popq %r10
- popq %rdx
- popq %rsi
- popq %rdi
- popq %rbp
ret
--- a/libstd/util+posixy-x64.s
+++ b/libstd/util+posixy-x64.s
@@ -56,10 +56,9 @@
pushq %rbx
movq 8(%rbp),%r15 /* ret addr */
- movq 16(%rbp),%rbx /* len */
/* get stack space */
- subq %rbx,%rsp /* get stack space */
+ subq %rdi,%rsp /* get stack space */
movq %rsp,%rax /* top of stack (return value) */
subq $31,%rsp /* "unpop" the args for return */
andq $(~15),%rsp /* align */
--- a/libstd/varargs.myr
+++ b/libstd/varargs.myr
@@ -77,6 +77,9 @@
-> sl
}
+const inspectarg = {x
+}
+
generic vanext = {ap -> @a
var v : @a
var ti
@@ -87,6 +90,7 @@
/* apply the alignment to the arg pointer */
align = ti.align castto(intptr)
+ inspectarg(align)
p = ap.args castto(intptr)
p = (p + align - 1) & ~(align - 1)
ap.args = p castto(byte#)
--- a/mbld/deps.myr
+++ b/mbld/deps.myr
@@ -14,6 +14,7 @@
var usepat : regex.regex#
;;
+const Abiversion = 5
var usepat : regex.regex#
type dep = union
@@ -234,12 +235,13 @@
| `std.None: std.fatal("library {}: could not read usefile\n", lib)
;;
match bio.getbe32(f)
- | `std.Some 4: /* nothing: version matches. */
- | `std.Some 3: std.fput(1, "library {}: warning: old usefile version\n", lib)
- | `std.Some 2: std.fput(1, "library {}: warning: old usefile version\n", lib)
- | `std.Some 1: std.fput(1, "library {}: warning: old usefile version\n", lib)
- | `std.Some 0: std.fput(1, "library {}: warning: old usefile version\n", lib)
- | `std.Some _: std.fatal("library {}: usefile version unknown\n", lib)
+ | `std.Some Abiversion: /* nothing: version matches. */
+ | `std.Some v:
+ if v < Abiversion
+ std.fput(1, "library {}: warning: old abi version\n", lib)
+ else
+ std.fatal("library {}: usefile version unknown\n", lib)
+ ;;
| `std.None: std.fatal("library {}: corrutpt or invalid usefile\n", lib)
;;
std.slfree(rdstr(f))
--- a/muse/Makefile
+++ b/muse/Makefile
@@ -5,3 +5,4 @@
DEPS=../parse/libparse.a
include ../mk/c.mk
+include ../config.mk
--- a/muse/muse.c
+++ b/muse/muse.c
@@ -81,7 +81,7 @@
lappend(&incpaths, &nincpaths, Instroot "/lib/myr");
if (!outfile) {
- fprintf(stderr, "Output file needed when merging usefiles.");
+ fprintf(stderr, "output file needed when merging usefiles.\n");
exit(1);
}
--- a/parse/parse.h
+++ b/parse/parse.h
@@ -4,7 +4,7 @@
# define FATAL
#endif
-#define Abiversion 4
+#define Abiversion 5
typedef uint8_t byte;
typedef unsigned int uint;
--- a/test/runtest.sh
+++ b/test/runtest.sh
@@ -10,7 +10,7 @@
function build {
rm -f $1 $1.o $1.s $1.use
- ../mbld/mbld -b $1 -C../6/6m -M../muse/muse -I../libstd -r../rt/_myrrt.o $1.myr
+ mbld -b $1 -C../6/6m -M../muse/muse -I../libstd -r../rt/_myrrt.o $1.myr
}
function pass {