aboutsummaryrefslogtreecommitdiffhomepage
path: root/amd64/sysv.c
diff options
context:
space:
mode:
Diffstat (limited to 'amd64/sysv.c')
-rw-r--r--amd64/sysv.c32
1 files changed, 29 insertions, 3 deletions
diff --git a/amd64/sysv.c b/amd64/sysv.c
index af0ade0..db88692 100644
--- a/amd64/sysv.c
+++ b/amd64/sysv.c
@@ -140,6 +140,30 @@ abiret(short r[2], uchar cls[2], int *ni, union irtype typ)
return ret;
}
+/* Layout of va_list:
+ * struct {
+ * ( 0) unsigned int gp_offset;
+ * ( 4) unsigned int fp_offset;
+ * ( 8) void *overflow_arg_area;
+ * (16) void *reg_save_area;
+ * }
+ * Layout of register save area (align 16):
+ * reg off
+ * rdi 0
+ * rsi 8
+ * rdx 16
+ * rcx 24
+ * r8 32
+ * r9 40
+ * xmm0 48
+ * xmm1 64
+ * ...
+ * in amd64/emit xvaprologue generates the code to save the registers to a stack slot
+ * there only needs to be one xvaprologue if there's any vastart instrs, and it has to be
+ * at the beginning of the function (before IR generated by regalloc can touch any registers)
+ * then vastart can initialize va_list.reg_save_area with a pointer to that
+ */
+
static void
vastart(struct function *fn, struct block *blk, int *curi)
{
@@ -148,9 +172,11 @@ vastart(struct function *fn, struct block *blk, int *curi)
struct instr *ins = &instrtab[blk->ins.p[*curi]];
union ref ap = ins->l, src, dst;
assert(ins->op == Ovastart);
- /* add xvaprologue if not there yet, which must be the first instruction in the function */
- if (fn->entry->ins.n > 0 && instrtab[fn->entry->ins.p[0]].op == Oxvaprologue) {
- rsave = mkref(RTMP, fn->entry->ins.p[0]);
+ /* add xvaprologue if not there yet, which must be the first
+ * real instruction in the function (following alloca) */
+ if (fn->entry->ins.n > 1 && instrtab[fn->entry->ins.p[1]].op == Oxvaprologue) {
+ rsave = mkref(RTMP, fn->entry->ins.p[0]); /* alloca instruction */
+ assert(instrtab[rsave.i].op == Oalloca16);
} else {
rsave = insertinstr(fn->entry, 0, mkalloca(192, 16));
insertinstr(fn->entry, 1, mkinstr(Oxvaprologue, 0, rsave, .keep=1));