Browse Source

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.
Quentin Carbonneaux 8 years ago
parent
commit
2b64b75c84
4 changed files with 41 additions and 4 deletions
  1. 1 0
      all.h
  2. 12 4
      amd64/emit.c
  3. 1 0
      amd64/isel.c
  4. 27 0
      test/dynalloc.ssa

+ 1 - 0
all.h

@@ -342,6 +342,7 @@ struct Fn {
 	int slot;
 	char export;
 	char vararg;
+	char dynalloc;
 	char name[NString];
 };
 

+ 12 - 4
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);

+ 1 - 0
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)

+ 27 - 0
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
+}