diff options
Diffstat (limited to 'amd64')
| -rw-r--r-- | amd64/sysv.c | 32 |
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)); |