summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--all.h1
-rw-r--r--amd64/emit.c16
-rw-r--r--amd64/isel.c1
-rw-r--r--test/dynalloc.ssa27
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
+}