diff options
author | Quentin Carbonneaux <quentin@c9x.me> | 2017-07-27 19:48:54 -0400 |
---|---|---|
committer | Quentin Carbonneaux <quentin@c9x.me> | 2017-07-30 11:13:56 -0400 |
commit | 2b64b75c845d0491c7a701e44485d2856eeb686d (patch) | |
tree | 9a0b8819cadaf31a81e534be7a8c6041eff4793d | |
parent | 64c79edda0bc29d11b7efaffa9d051f64ea431d0 (diff) | |
download | roux-2b64b75c845d0491c7a701e44485d2856eeb686d.tar.gz |
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.
-rw-r--r-- | all.h | 1 | ||||
-rw-r--r-- | amd64/emit.c | 16 | ||||
-rw-r--r-- | amd64/isel.c | 1 | ||||
-rw-r--r-- | test/dynalloc.ssa | 27 |
4 files changed, 41 insertions, 4 deletions
diff --git a/all.h b/all.h index 629fea3..24a1755 100644 --- 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 index 51833b4..b8fa655 100644 --- 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 index 4202610..46ed259 100644 --- 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 new file mode 100644 index 0000000..7c54e88 --- /dev/null +++ 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 +} |