qbe

Internal scc patchset buffer for QBE
Log | Files | Refs | README | LICENSE

commit 2b64b75c845d0491c7a701e44485d2856eeb686d
parent 64c79edda0bc29d11b7efaffa9d051f64ea431d0
Author: Quentin Carbonneaux <quentin@c9x.me>
Date:   Thu, 27 Jul 2017 19:48:54 -0400

fix dynamic stack allocs for amd64

The arm64 might have the same problem but it
is currently unable to handle them even in
instruction selection.

Thanks to Jean Dao for reporting the bug.

Diffstat:
Mall.h | 1+
Mamd64/emit.c | 16++++++++++++----
Mamd64/isel.c | 1+
Atest/dynalloc.ssa | 27+++++++++++++++++++++++++++
4 files changed, 41 insertions(+), 4 deletions(-)

diff --git a/all.h b/all.h @@ -342,6 +342,7 @@ struct Fn { int slot; char export; char vararg; + char dynalloc; char name[NString]; }; diff --git a/amd64/emit.c b/amd64/emit.c @@ -488,10 +488,10 @@ emitins(Ins i, Fn *fn, FILE *f) } } -static int +static uint64_t framesz(Fn *fn) { - int i, o, f; + uint64_t i, o, f; /* specific to NAlign == 3 */ for (i=0, o=0; i<NCLR; i++) @@ -512,7 +512,8 @@ amd64_emitfn(Fn *fn, FILE *f) static int id0; Blk *b, *s; Ins *i, itmp; - int *r, c, fs, o, n, lbl; + int *r, c, o, n, lbl; + uint64_t fs; fprintf(f, ".text\n"); if (fn->export) @@ -525,7 +526,7 @@ amd64_emitfn(Fn *fn, FILE *f) ); fs = framesz(fn); if (fs) - fprintf(f, "\tsub $%d, %%rsp\n", fs); + fprintf(f, "\tsub $%"PRIu64", %%rsp\n", fs); if (fn->vararg) { o = -176; for (r=amd64_sysv_rsave; r<&amd64_sysv_rsave[6]; r++, o+=8) @@ -537,6 +538,7 @@ amd64_emitfn(Fn *fn, FILE *f) if (fn->reg & BIT(*r)) { itmp.arg[0] = TMP(*r); emitf("pushq %L0", &itmp, fn, f); + fs += 8; } for (lbl=0, b=fn->start; b; b=b->link) { @@ -547,6 +549,12 @@ amd64_emitfn(Fn *fn, FILE *f) lbl = 1; switch (b->jmp.type) { case Jret0: + if (fn->dynalloc) + fprintf(f, + "\tmovq %%rbp, %%rsp\n" + "\tsubq $%"PRIu64", %%rsp\n", + fs + ); for (r=&amd64_sysv_rclob[NCLR]; r>amd64_sysv_rclob;) if (fn->reg & BIT(*--r)) { itmp.arg[0] = TMP(*r); diff --git a/amd64/isel.c b/amd64/isel.c @@ -291,6 +291,7 @@ Emit: * the stack remains aligned * (rsp = 0) mod 16 */ + fn->dynalloc = 1; if (rtype(i.arg[0]) == RCon) { sz = fn->con[i.arg[0].val].bits.i; if (sz < 0 || sz >= INT_MAX-15) diff --git a/test/dynalloc.ssa b/test/dynalloc.ssa @@ -0,0 +1,27 @@ +# make sure dynamic allocations +# and caller-save regs interact +# soundly + +function $g() { +@start + ret +} + +function w $f(w %arg) { +@start + call $g() +@alloc + %r =l alloc8 16 + storel 180388626474, %r + %r8 =l add 8, %r + storel 180388626474, %r8 + ret %arg +} + +export +function w $main() { +@start + %a =w call $f(w 0) + %b =w call $f(w 0) + ret %a +}