summary refs log tree commit diff
diff options
context:
space:
mode:
authorQuentin Carbonneaux <quentin@c9x.me>2019-04-30 11:02:42 +0200
committerQuentin Carbonneaux <quentin@c9x.me>2019-04-30 11:21:45 +0200
commit4b7f02c09710b379a706708ae5880a1811519539 (patch)
treefa13857c28209bf6ecc837a6532adc176720e66e
parent660a8d9dfa44050897b2f5ead823554893d79f24 (diff)
downloadroux-4b7f02c09710b379a706708ae5880a1811519539.tar.gz
isel fix for amd64 memory stores
The value argument of store instructions was
handled incorrectly.
-rw-r--r--amd64/isel.c37
-rw-r--r--test/conaddr.ssa14
2 files changed, 31 insertions, 20 deletions
diff --git a/amd64/isel.c b/amd64/isel.c
index 22e1e14..56e4cf3 100644
--- a/amd64/isel.c
+++ b/amd64/isel.c
@@ -59,17 +59,16 @@ rslot(Ref r, Fn *fn)
 }
 
 static void
-fixarg(Ref *r, int k, int op, Fn *fn)
+fixarg(Ref *r, int k, Ins *i, Fn *fn)
 {
 	char buf[32];
 	Addr a, *m;
 	Ref r0, r1;
-	int s, n, cpy, mem;
+	int s, n, op;
 
 	r1 = r0 = *r;
 	s = rslot(r0, fn);
-	cpy = op == Ocopy || op == -1;
-	mem = isstore(op) || isload(op) || op == Ocall;
+	op = i ? i->op : Ocopy;
 	if (KBASE(k) == 1 && rtype(r0) == RCon) {
 		/* load floating points from memory
 		 * slots, they can't be used as
@@ -85,7 +84,7 @@ fixarg(Ref *r, int k, int op, Fn *fn)
 		a.offset.label = intern(buf);
 		fn->mem[fn->nmem-1] = a;
 	}
-	else if (!cpy && k == Kl && noimm(r0, fn)) {
+	else if (op != Ocopy && k == Kl && noimm(r0, fn)) {
 		/* load constants that do not fit in
 		 * a 32bit signed integer into a
 		 * long temporary
@@ -101,7 +100,8 @@ fixarg(Ref *r, int k, int op, Fn *fn)
 		r1 = newtmp("isel", Kl, fn);
 		emit(Oaddr, Kl, r1, SLOT(s), R);
 	}
-	else if (!mem && rtype(r0) == RCon
+	else if (!(isstore(op) && r == &i->arg[1])
+	&& !isload(op) && op != Ocall && rtype(r0) == RCon
 	&& fn->con[r0.val].type == CAddr) {
 		/* apple as does not support 32-bit
 		 * absolute addressing, use a rip-
@@ -168,7 +168,8 @@ static int
 selcmp(Ref arg[2], int k, Fn *fn)
 {
 	int swap;
-	Ref r, *iarg;
+	Ref r;
+	Ins *icmp;
 
 	swap = rtype(arg[0]) == RCon;
 	if (swap) {
@@ -177,21 +178,21 @@ selcmp(Ref arg[2], int k, Fn *fn)
 		arg[0] = r;
 	}
 	emit(Oxcmp, k, R, arg[1], arg[0]);
-	iarg = curi->arg;
+	icmp = curi;
 	if (rtype(arg[0]) == RCon) {
 		assert(k == Kl);
-		iarg[1] = newtmp("isel", k, fn);
-		emit(Ocopy, k, iarg[1], arg[0], R);
+		icmp->arg[1] = newtmp("isel", k, fn);
+		emit(Ocopy, k, icmp->arg[1], arg[0], R);
 	}
-	fixarg(&iarg[0], k, Oxcmp, fn);
-	fixarg(&iarg[1], k, Oxcmp, fn);
+	fixarg(&icmp->arg[0], k, icmp, fn);
+	fixarg(&icmp->arg[1], k, icmp, fn);
 	return swap;
 }
 
 static void
 sel(Ins i, ANum *an, Fn *fn)
 {
-	Ref r0, r1, *iarg;
+	Ref r0, r1;
 	int x, k, kc;
 	int64_t sz;
 	Ins *i0, *i1;
@@ -236,7 +237,7 @@ sel(Ins i, ANum *an, Fn *fn)
 			emit(Ocopy, k, TMP(RDX), CON_Z, R);
 		}
 		emit(Ocopy, k, TMP(RAX), i.arg[0], R);
-		fixarg(&curi->arg[0], k, Ocopy, fn);
+		fixarg(&curi->arg[0], k, curi, fn);
 		if (rtype(i.arg[1]) == RCon)
 			emit(Ocopy, k, r0, i.arg[1], R);
 		break;
@@ -290,9 +291,9 @@ sel(Ins i, ANum *an, Fn *fn)
 	case_OExt:
 Emit:
 		emiti(i);
-		iarg = curi->arg; /* fixarg() can change curi */
-		fixarg(&iarg[0], argcls(&i, 0), i.op, fn);
-		fixarg(&iarg[1], argcls(&i, 1), i.op, fn);
+		i1 = curi; /* fixarg() can change curi */
+		fixarg(&i1->arg[0], argcls(&i, 0), i1, fn);
+		fixarg(&i1->arg[1], argcls(&i, 1), i1, fn);
 		break;
 	case Oalloc:
 	case Oalloc+1:
@@ -604,7 +605,7 @@ amd64_isel(Fn *fn)
 			for (p=(*sb)->phi; p; p=p->link) {
 				for (a=0; p->blk[a] != b; a++)
 					assert(a+1 < p->narg);
-				fixarg(&p->arg[a], p->cls, -1, fn);
+				fixarg(&p->arg[a], p->cls, 0, fn);
 			}
 		memset(ainfo, 0, n * sizeof ainfo[0]);
 		anumber(ainfo, b, fn->con);
diff --git a/test/conaddr.ssa b/test/conaddr.ssa
index 43177ba..9e24d49 100644
--- a/test/conaddr.ssa
+++ b/test/conaddr.ssa
@@ -35,6 +35,13 @@ function l $f3(l %o) {
 }
 
 export
+function $f4() {
+@start
+	storel $p, $p
+	ret
+}
+
+export
 function $writeto0() {
 @start
 	storel 0, 0
@@ -45,13 +52,14 @@ function $writeto0() {
 # #include <stdlib.h>
 # #include <signal.h>
 # char a[] = "qbe rocks";
+# void *p;
 # int ok;
 # extern unsigned f0(long), f1(long), f2(long, long);
 # extern char *f3(long);
-# extern void writeto0();
+# extern void f4(), writeto0();
 # void h(int sig, siginfo_t *si, void *unused) {
 # 	ok += si->si_addr == 0;
-# 	exit(!(ok == 5));
+# 	exit(!(ok == 6));
 # }
 # int main() {
 # 	struct sigaction sa = {.sa_flags=SA_SIGINFO, .sa_sigaction=h};
@@ -60,6 +68,8 @@ function $writeto0() {
 # 	ok += f1((long)a-5) == 'o';
 # 	ok += f2(4, 2) == 's';
 # 	ok += *f3(0) == 'q';
+# 	f4();
+# 	ok += p == &p;
 # 	writeto0(); /* will segfault */
 # }
 # <<<