commit 8dddb971d923fa19dced39013e6d4a39676e065a
parent 5490268683c82ad07eac6d2e8296a45702a8381e
Author: Quentin Carbonneaux <quentin@c9x.me>
Date: Mon, 29 Aug 2022 18:45:52 +0200
drop -G flag and add target amd64_apple
apple support is more than assembly syntax
in case of arm64 machines, and apple syntax
is currently useless in all cases but amd64;
rather than having a -G option that only
makes sense with amd64, we add a new target
amd64_apple
Diffstat:
15 files changed, 266 insertions(+), 246 deletions(-)
diff --git a/Makefile b/Makefile
@@ -5,7 +5,7 @@ PREFIX = /usr/local
BINDIR = $(PREFIX)/bin
COMMOBJ = main.o util.o parse.o cfg.o mem.o ssa.o alias.o load.o copy.o \
- fold.o live.o spill.o rega.o gas.o
+ fold.o live.o spill.o rega.o emit.o
AMD64OBJ = amd64/targ.o amd64/sysv.o amd64/isel.o amd64/emit.o
ARM64OBJ = arm64/targ.o arm64/abi.o arm64/isel.o arm64/emit.o
RV64OBJ = rv64/targ.o rv64/abi.o rv64/isel.o rv64/emit.o
@@ -30,11 +30,9 @@ main.o: config.h
config.h:
@case `uname` in \
*Darwin*) \
- echo "#define Defasm Gasmacho"; \
- echo "#define Deftgt T_amd64_sysv"; \
+ echo "#define Deftgt T_amd64_apple"; \
;; \
*) \
- echo "#define Defasm Gaself"; \
case `uname -m` in \
*aarch64*) \
echo "#define Deftgt T_arm64"; \
diff --git a/all.h b/all.h
@@ -55,6 +55,9 @@ struct Target {
void (*abi)(Fn *);
void (*isel)(Fn *);
void (*emitfn)(Fn *, FILE *);
+ void (*emitfin)(FILE *);
+ char asloc[4];
+ char assym[4];
};
#define BIT(n) ((bits)1 << (n))
@@ -524,16 +527,10 @@ void spill(Fn *);
/* rega.c */
void rega(Fn *);
-/* gas.c */
-enum Asm {
- Gasmacho,
- Gaself,
-};
-extern char *gasloc;
-extern char *gassym;
-void gasinit(enum Asm);
-void gasemitlnk(char *, Lnk *, char *, FILE *);
-void gasemitfntail(char *, FILE *);
-void gasemitdat(Dat *, FILE *);
-int gasstash(void *, int);
-void gasemitfin(FILE *);
+/* emit.c */
+void emitlnk(char *, Lnk *, char *, FILE *);
+void emitdat(Dat *, FILE *);
+int stashbits(void *, int);
+void elf_emitfnfin(char *, FILE *);
+void elf_emitfin(FILE *);
+void macho_emitfin(FILE *);
diff --git a/amd64/all.h b/amd64/all.h
@@ -67,4 +67,5 @@ void amd64_sysv_abi(Fn *);
void amd64_isel(Fn *);
/* emit.c */
-void amd64_emitfn(Fn *, FILE *);
+void amd64_sysv_emitfn(Fn *, FILE *);
+void amd64_apple_emitfn(Fn *, FILE *);
diff --git a/amd64/emit.c b/amd64/emit.c
@@ -166,7 +166,7 @@ emitcon(Con *con, FILE *f)
switch (con->type) {
case CAddr:
l = str(con->label);
- p = con->local ? gasloc : l[0] == '"' ? "" : gassym;
+ p = con->local ? T.asloc : l[0] == '"' ? "" : T.assym;
fprintf(f, "%s%s", p, l);
if (con->bits.i)
fprintf(f, "%+"PRId64, con->bits.i);
@@ -425,8 +425,8 @@ emitins(Ins i, Fn *fn, FILE *f)
fprintf(f,
"\txorp%c %sfp%d(%%rip), %%%s\n",
"xxsd"[i.cls],
- gasloc,
- gasstash(negmask[i.cls], 16),
+ T.asloc,
+ stashbits(negmask[i.cls], 16),
regtoa(i.to.val, SLong)
);
break;
@@ -535,8 +535,8 @@ framesz(Fn *fn)
return 4*f + 8*o + 176*fn->vararg;
}
-void
-amd64_emitfn(Fn *fn, FILE *f)
+static void
+emitfn(Fn *fn, FILE *f)
{
static char *ctoa[] = {
#define X(c, s) [c] = s,
@@ -549,7 +549,7 @@ amd64_emitfn(Fn *fn, FILE *f)
int *r, c, o, n, lbl;
uint64_t fs;
- gasemitlnk(fn->name, &fn->lnk, ".text", f);
+ emitlnk(fn->name, &fn->lnk, ".text", f);
fputs("\tpushq %rbp\n\tmovq %rsp, %rbp\n", f);
fs = framesz(fn);
if (fs)
@@ -570,7 +570,7 @@ amd64_emitfn(Fn *fn, FILE *f)
for (lbl=0, b=fn->start; b; b=b->link) {
if (lbl || b->npred > 1)
- fprintf(f, "%sbb%d:\n", gasloc, id0+b->id);
+ fprintf(f, "%sbb%d:\n", T.asloc, id0+b->id);
for (i=b->ins; i!=&b->ins[b->nins]; i++)
emitins(*i, fn, f);
lbl = 1;
@@ -596,7 +596,7 @@ amd64_emitfn(Fn *fn, FILE *f)
Jmp:
if (b->s1 != b->link)
fprintf(f, "\tjmp %sbb%d\n",
- gasloc, id0+b->s1->id);
+ T.asloc, id0+b->s1->id);
else
lbl = 0;
break;
@@ -610,7 +610,7 @@ amd64_emitfn(Fn *fn, FILE *f)
} else
c = cmpneg(c);
fprintf(f, "\tj%s %sbb%d\n", ctoa[c],
- gasloc, id0+b->s2->id);
+ T.asloc, id0+b->s2->id);
goto Jmp;
}
die("unhandled jump %d", b->jmp.type);
@@ -618,3 +618,16 @@ amd64_emitfn(Fn *fn, FILE *f)
}
id0 += fn->nblk;
}
+
+void
+amd64_sysv_emitfn(Fn *fn, FILE *f)
+{
+ emitfn(fn, f);
+ elf_emitfnfin(fn->name, f);
+}
+
+void
+amd64_apple_emitfn(Fn *fn, FILE *f)
+{
+ emitfn(fn, f);
+}
diff --git a/amd64/isel.c b/amd64/isel.c
@@ -79,7 +79,7 @@ fixarg(Ref *r, int k, Ins *i, Fn *fn)
memset(&a, 0, sizeof a);
a.offset.type = CAddr;
a.offset.local = 1;
- n = gasstash(&fn->con[r0.val].bits, KWIDE(k) ? 8 : 4);
+ n = stashbits(&fn->con[r0.val].bits, KWIDE(k) ? 8 : 4);
sprintf(buf, "fp%d", n);
a.offset.label = intern(buf);
fn->mem[fn->nmem-1] = a;
diff --git a/amd64/targ.c b/amd64/targ.c
@@ -12,20 +12,34 @@ amd64_memargs(int op)
return amd64_op[op].nmem;
}
+#define AMD64_COMMON \
+ .gpr0 = RAX, \
+ .ngpr = NGPR, \
+ .fpr0 = XMM0, \
+ .nfpr = NFPR, \
+ .rglob = BIT(RBP) | BIT(RSP), \
+ .nrglob = 2, \
+ .rsave = amd64_sysv_rsave, \
+ .nrsave = {NGPS, NFPS}, \
+ .retregs = amd64_sysv_retregs, \
+ .argregs = amd64_sysv_argregs, \
+ .memargs = amd64_memargs, \
+ .abi = amd64_sysv_abi, \
+ .isel = amd64_isel, \
+
Target T_amd64_sysv = {
.name = "amd64_sysv",
- .gpr0 = RAX,
- .ngpr = NGPR,
- .fpr0 = XMM0,
- .nfpr = NFPR,
- .rglob = BIT(RBP) | BIT(RSP),
- .nrglob = 2,
- .rsave = amd64_sysv_rsave,
- .nrsave = {NGPS, NFPS},
- .retregs = amd64_sysv_retregs,
- .argregs = amd64_sysv_argregs,
- .memargs = amd64_memargs,
- .abi = amd64_sysv_abi,
- .isel = amd64_isel,
- .emitfn = amd64_emitfn,
+ .emitfn = amd64_sysv_emitfn,
+ .emitfin = elf_emitfin,
+ .asloc = ".L",
+ AMD64_COMMON
+};
+
+Target T_amd64_apple = {
+ .name = "amd64_apple",
+ .emitfn = amd64_apple_emitfn,
+ .emitfin = macho_emitfin,
+ .asloc = "L",
+ .assym = "_",
+ AMD64_COMMON
};
diff --git a/arm64/emit.c b/arm64/emit.c
@@ -245,7 +245,7 @@ emitf(char *s, Ins *i, E *e)
static void
loadcon(Con *c, int r, int k, FILE *f)
{
- char *rn, *p, off[32];
+ char *rn, *l, *p, off[32];
int64_t n;
int w, sh;
@@ -258,11 +258,12 @@ loadcon(Con *c, int r, int k, FILE *f)
sprintf(off, "+%"PRIi64, n);
else
off[0] = 0;
- p = c->local ? ".L" : "";
+ l = str(c->label);
+ p = c->local ? T.asloc : l[0] == '"' ? "" : T.assym;
fprintf(f, "\tadrp\t%s, %s%s%s\n",
- rn, p, str(c->label), off);
+ rn, p, l, off);
fprintf(f, "\tadd\t%s, %s, #:lo12:%s%s%s\n",
- rn, rn, p, str(c->label), off);
+ rn, rn, p, l, off);
return;
}
assert(c->type == CBits);
@@ -451,7 +452,7 @@ arm64_emitfn(Fn *fn, FILE *out)
Ins *i;
E *e;
- gasemitlnk(fn->name, &fn->lnk, ".text", out);
+ emitlnk(fn->name, &fn->lnk, ".text", out);
e = &(E){.f = out, .fn = fn};
framelayout(e);
@@ -500,7 +501,7 @@ arm64_emitfn(Fn *fn, FILE *out)
for (lbl=0, b=e->fn->start; b; b=b->link) {
if (lbl || b->npred > 1)
- fprintf(e->f, ".L%d:\n", id0+b->id);
+ fprintf(e->f, "%s%d:\n", T.asloc, id0+b->id);
for (i=b->ins; i!=&b->ins[b->nins]; i++)
emitins(i, e);
lbl = 1;
@@ -550,7 +551,10 @@ arm64_emitfn(Fn *fn, FILE *out)
case Jjmp:
Jmp:
if (b->s1 != b->link)
- fprintf(e->f, "\tb\t.L%d\n", id0+b->s1->id);
+ fprintf(e->f,
+ "\tb\t%s%d\n",
+ T.asloc, id0+b->s1->id
+ );
else
lbl = 0;
break;
@@ -564,9 +568,13 @@ arm64_emitfn(Fn *fn, FILE *out)
b->s2 = t;
} else
c = cmpneg(c);
- fprintf(e->f, "\tb%s\t.L%d\n", ctoa[c], id0+b->s2->id);
+ fprintf(e->f,
+ "\tb%s\t%s%d\n",
+ ctoa[c], T.asloc, id0+b->s2->id
+ );
goto Jmp;
}
}
id0 += e->fn->nblk;
+ elf_emitfnfin(e->fn->name, e->f);
}
diff --git a/arm64/isel.c b/arm64/isel.c
@@ -84,7 +84,7 @@ fixarg(Ref *pr, int k, int phi, Fn *fn)
emit(Ocopy, k, r1, r0, R);
} else {
c = &fn->con[r0.val];
- n = gasstash(&c->bits, KWIDE(k) ? 8 : 4);
+ n = stashbits(&c->bits, KWIDE(k) ? 8 : 4);
vgrow(&fn->con, ++fn->ncon);
c = &fn->con[fn->ncon-1];
sprintf(buf, "fp%d", n);
diff --git a/arm64/targ.c b/arm64/targ.c
@@ -41,6 +41,8 @@ Target T_arm64 = {
.abi = arm64_abi,
.isel = arm64_isel,
.emitfn = arm64_emitfn,
+ .emitfin = elf_emitfin,
+ .asloc = ".L",
};
MAKESURE(globals_are_not_arguments,
diff --git a/emit.c b/emit.c
@@ -0,0 +1,172 @@
+#include "all.h"
+
+void
+emitlnk(char *n, Lnk *l, char *s, FILE *f)
+{
+ char *p;
+
+ if (l->sec) {
+ fprintf(f, ".section %s", l->sec);
+ if (l->secf)
+ fprintf(f, ", %s", l->secf);
+ } else {
+ fputs(s, f);
+ }
+ fputc('\n', f);
+ if (l->align)
+ fprintf(f, ".balign %d\n", l->align);
+ p = n[0] == '"' ? "" : T.assym;
+ if (l->export)
+ fprintf(f, ".globl %s%s\n", p, n);
+ fprintf(f, "%s%s:\n", p, n);
+}
+
+void
+emitdat(Dat *d, FILE *f)
+{
+ static char *dtoa[] = {
+ [DB] = "\t.byte",
+ [DH] = "\t.short",
+ [DW] = "\t.int",
+ [DL] = "\t.quad"
+ };
+ static int64_t zero;
+ char *p;
+
+ switch (d->type) {
+ case DStart:
+ zero = 0;
+ break;
+ case DEnd:
+ if (zero != -1) {
+ emitlnk(d->name, d->lnk, ".bss", f);
+ fprintf(f, "\t.fill %"PRId64",1,0\n", zero);
+ }
+ break;
+ case DZ:
+ if (zero != -1)
+ zero += d->u.num;
+ else
+ fprintf(f, "\t.fill %"PRId64",1,0\n", d->u.num);
+ break;
+ default:
+ if (zero != -1) {
+ emitlnk(d->name, d->lnk, ".data", f);
+ if (zero > 0)
+ fprintf(f, "\t.fill %"PRId64",1,0\n", zero);
+ zero = -1;
+ }
+ if (d->isstr) {
+ if (d->type != DB)
+ err("strings only supported for 'b' currently");
+ fprintf(f, "\t.ascii %s\n", d->u.str);
+ }
+ else if (d->isref) {
+ p = d->u.ref.name[0] == '"' ? "" : T.assym;
+ fprintf(f, "%s %s%s%+"PRId64"\n",
+ dtoa[d->type], p, d->u.ref.name,
+ d->u.ref.off);
+ }
+ else {
+ fprintf(f, "%s %"PRId64"\n",
+ dtoa[d->type], d->u.num);
+ }
+ break;
+ }
+}
+
+typedef struct Asmbits Asmbits;
+
+struct Asmbits {
+ char bits[16];
+ int size;
+ Asmbits *link;
+};
+
+static Asmbits *stash;
+
+int
+stashbits(void *bits, int size)
+{
+ Asmbits **pb, *b;
+ int i;
+
+ assert(size == 4 || size == 8 || size == 16);
+ for (pb=&stash, i=0; (b=*pb); pb=&b->link, i++)
+ if (size <= b->size)
+ if (memcmp(bits, b->bits, size) == 0)
+ return i;
+ b = emalloc(sizeof *b);
+ memcpy(b->bits, bits, size);
+ b->size = size;
+ b->link = 0;
+ *pb = b;
+ return i;
+}
+
+static void
+emitfin(FILE *f, char *sec[3])
+{
+ Asmbits *b;
+ char *p;
+ int lg, i;
+ double d;
+
+ if (!stash)
+ return;
+ fprintf(f, "/* floating point constants */\n");
+ for (lg=4; lg>=2; lg--)
+ for (b=stash, i=0; b; b=b->link, i++) {
+ if (b->size == (1<<lg)) {
+ fprintf(f,
+ ".section %s\n"
+ ".p2align %d\n"
+ "%sfp%d:",
+ sec[lg-2], lg, T.asloc, i
+ );
+ for (p=b->bits; p<&b->bits[b->size]; p+=4)
+ fprintf(f, "\n\t.int %"PRId32,
+ *(int32_t *)p);
+ if (lg <= 3) {
+ if (lg == 2)
+ d = *(float *)b->bits;
+ else
+ d = *(double *)b->bits;
+ fprintf(f, " /* %f */\n\n", d);
+ } else
+ fprintf(f, "\n\n");
+ }
+ }
+ while ((b=stash)) {
+ stash = b->link;
+ free(b);
+ }
+}
+
+void
+elf_emitfin(FILE *f)
+{
+ static char *sec[3] = { ".rodata", ".rodata", ".rodata" };
+
+ emitfin(f ,sec);
+ fprintf(f, ".section .note.GNU-stack,\"\",@progbits\n");
+}
+
+void
+elf_emitfnfin(char *fn, FILE *f)
+{
+ fprintf(f, ".type %s, @function\n", fn);
+ fprintf(f, ".size %s, .-%s\n", fn, fn);
+}
+
+void
+macho_emitfin(FILE *f)
+{
+ static char *sec[3] = {
+ "__TEXT,__literal4,4byte_literals",
+ "__TEXT,__literal8,8byte_literals",
+ ".rodata", /* should not happen */
+ };
+
+ emitfin(f, sec);
+}
diff --git a/gas.c b/gas.c
@@ -1,174 +0,0 @@
-#include "all.h"
-
-
-char *gasloc, *gassym;
-static int gasasm;
-
-void
-gasinit(enum Asm asmmode)
-{
- gasasm = asmmode;
- switch (gasasm) {
- case Gaself:
- gasloc = ".L";
- gassym = "";
- break;
- case Gasmacho:
- gasloc = "L";
- gassym = "_";
- break;
- }
-}
-
-void
-gasemitlnk(char *n, Lnk *l, char *s, FILE *f)
-{
- char *p;
-
- if (l->sec) {
- fprintf(f, ".section %s", l->sec);
- if (l->secf)
- fprintf(f, ", %s", l->secf);
- } else {
- fputs(s, f);
- }
- fputc('\n', f);
- if (l->align)
- fprintf(f, ".balign %d\n", l->align);
- p = n[0] == '"' ? "" : gassym;
- if (l->export)
- fprintf(f, ".globl %s%s\n", p, n);
- fprintf(f, "%s%s:\n", p, n);
-}
-
-void
-gasemitfntail(char *fn, FILE *f)
-{
- if (gasasm == Gaself) {
- fprintf(f, ".type %s, @function\n", fn);
- fprintf(f, ".size %s, .-%s\n", fn, fn);
- }
-}
-
-void
-gasemitdat(Dat *d, FILE *f)
-{
- static char *dtoa[] = {
- [DB] = "\t.byte",
- [DH] = "\t.short",
- [DW] = "\t.int",
- [DL] = "\t.quad"
- };
- static int64_t zero;
- char *p;
-
- switch (d->type) {
- case DStart:
- zero = 0;
- break;
- case DEnd:
- if (zero != -1) {
- gasemitlnk(d->name, d->lnk, ".bss", f);
- fprintf(f, "\t.fill %"PRId64",1,0\n", zero);
- }
- break;
- case DZ:
- if (zero != -1)
- zero += d->u.num;
- else
- fprintf(f, "\t.fill %"PRId64",1,0\n", d->u.num);
- break;
- default:
- if (zero != -1) {
- gasemitlnk(d->name, d->lnk, ".data", f);
- if (zero > 0)
- fprintf(f, "\t.fill %"PRId64",1,0\n", zero);
- zero = -1;
- }
- if (d->isstr) {
- if (d->type != DB)
- err("strings only supported for 'b' currently");
- fprintf(f, "\t.ascii %s\n", d->u.str);
- }
- else if (d->isref) {
- p = d->u.ref.name[0] == '"' ? "" : gassym;
- fprintf(f, "%s %s%s%+"PRId64"\n",
- dtoa[d->type], p, d->u.ref.name,
- d->u.ref.off);
- }
- else {
- fprintf(f, "%s %"PRId64"\n",
- dtoa[d->type], d->u.num);
- }
- break;
- }
-}
-
-typedef struct Asmbits Asmbits;
-
-struct Asmbits {
- char bits[16];
- int size;
- Asmbits *link;
-};
-
-static Asmbits *stash;
-
-int
-gasstash(void *bits, int size)
-{
- Asmbits **pb, *b;
- int i;
-
- assert(size == 4 || size == 8 || size == 16);
- for (pb=&stash, i=0; (b=*pb); pb=&b->link, i++)
- if (size <= b->size)
- if (memcmp(bits, b->bits, size) == 0)
- return i;
- b = emalloc(sizeof *b);
- memcpy(b->bits, bits, size);
- b->size = size;
- b->link = 0;
- *pb = b;
- return i;
-}
-
-void
-gasemitfin(FILE *f)
-{
- Asmbits *b;
- char *p;
- int sz, i;
- double d;
-
- if (gasasm == Gaself)
- fprintf(f, ".section .note.GNU-stack,\"\",@progbits\n\n");
- if (!stash)
- return;
- fprintf(f, "/* floating point constants */\n.data\n");
- for (sz=16; sz>=4; sz/=2)
- for (b=stash, i=0; b; b=b->link, i++) {
- if (b->size == sz) {
- fprintf(f,
- ".balign %d\n"
- "%sfp%d:",
- sz, gasloc, i
- );
- for (p=b->bits; p<&b->bits[sz]; p+=4)
- fprintf(f, "\n\t.int %"PRId32,
- *(int32_t *)p);
- if (sz <= 8) {
- if (sz == 4)
- d = *(float *)b->bits;
- else
- d = *(double *)b->bits;
- fprintf(f, " /* %f */\n", d);
- } else
- fprintf(f, "\n");
- }
- }
- while ((b=stash)) {
- stash = b->link;
- free(b);
- }
-}
diff --git a/main.c b/main.c
@@ -19,11 +19,13 @@ char debug['Z'+1] = {
};
extern Target T_amd64_sysv;
+extern Target T_amd64_apple;
extern Target T_arm64;
extern Target T_rv64;
static Target *tlist[] = {
&T_amd64_sysv,
+ &T_amd64_apple,
&T_arm64,
&T_rv64,
0
@@ -40,7 +42,7 @@ data(Dat *d)
fputs("/* end data */\n\n", outf);
freeall();
}
- gasemitdat(d, outf);
+ emitdat(d, outf);
}
static void
@@ -92,7 +94,6 @@ func(Fn *fn)
fn->rpo[n]->link = fn->rpo[n+1];
if (!dbg) {
T.emitfn(fn, outf);
- gasemitfntail(fn->name, outf);
fprintf(outf, "/* end function %s */\n\n", fn->name);
} else
fprintf(stderr, "\n");
@@ -105,12 +106,11 @@ main(int ac, char *av[])
Target **t;
FILE *inf, *hf;
char *f, *sep;
- int c, asmmode;
+ int c;
- asmmode = Defasm;
T = Deftgt;
outf = stdout;
- while ((c = getopt(ac, av, "hd:o:G:t:")) != -1)
+ while ((c = getopt(ac, av, "hd:o:t:")) != -1)
switch (c) {
case 'd':
for (; *optarg; optarg++)
@@ -144,16 +144,6 @@ main(int ac, char *av[])
}
}
break;
- case 'G':
- if (strcmp(optarg, "e") == 0)
- asmmode = Gaself;
- else if (strcmp(optarg, "m") == 0)
- asmmode = Gasmacho;
- else {
- fprintf(stderr, "unknown gas flavor '%s'\n", optarg);
- exit(1);
- }
- break;
case 'h':
default:
hf = c != 'h' ? stderr : stdout;
@@ -168,13 +158,10 @@ main(int ac, char *av[])
fputs(" (default)", hf);
}
fprintf(hf, "\n");
- fprintf(hf, "\t%-11s generate gas (e) or osx (m) asm\n", "-G {e,m}");
fprintf(hf, "\t%-11s dump debug information\n", "-d <flags>");
exit(c != 'h');
}
- gasinit(asmmode);
-
do {
f = av[optind];
if (!f || strcmp(f, "-") == 0) {
@@ -192,7 +179,7 @@ main(int ac, char *av[])
} while (++optind < ac);
if (!dbg)
- gasemitfin(outf);
+ T.emitfin(outf);
exit(0);
}
diff --git a/rv64/emit.c b/rv64/emit.c
@@ -415,7 +415,7 @@ rv64_emitfn(Fn *fn, FILE *f)
Blk *b, *s;
Ins *i;
- gasemitlnk(fn->name, &fn->lnk, ".text", f);
+ emitlnk(fn->name, &fn->lnk, ".text", f);
if (fn->vararg) {
/* TODO: only need space for registers
diff --git a/rv64/isel.c b/rv64/isel.c
@@ -41,7 +41,7 @@ fixarg(Ref *r, int k, Ins *i, Fn *fn)
* immediates
*/
assert(c->type == CBits);
- n = gasstash(&c->bits, KWIDE(k) ? 8 : 4);
+ n = stashbits(&c->bits, KWIDE(k) ? 8 : 4);
vgrow(&fn->con, ++fn->ncon);
c = &fn->con[fn->ncon-1];
sprintf(buf, "fp%d", n);
diff --git a/rv64/targ.c b/rv64/targ.c
@@ -47,6 +47,8 @@ Target T_rv64 = {
.abi = rv64_abi,
.isel = rv64_isel,
.emitfn = rv64_emitfn,
+ .emitfin = elf_emitfin,
+ .asloc = ".L",
};
MAKESURE(rsave_size_ok, sizeof rv64_rsave == (NGPS+NFPS+1) * sizeof(int));