summary refs log tree commit diff
diff options
context:
space:
mode:
authorQuentin Carbonneaux <quentin@c9x.me>2019-02-21 14:42:01 +0100
committerQuentin Carbonneaux <quentin@c9x.me>2019-02-21 14:46:18 +0100
commita877ba986b4c5b24ee07d59b3001d45fd5b3f834 (patch)
tree64ea16f84451b2e7dd1ce16de68a25acf1b5f61e
parentcf9f2e8ef7e775bcedf74b70a3dd35962484f1f1 (diff)
downloadroux-a877ba986b4c5b24ee07d59b3001d45fd5b3f834.tar.gz
fix amd64 addressing mode matcher
The numberer made some arranging choices when
numbering arguments of an instruction, but these
decisions were ignored when matching.  The fix
is to reconcile numbering and matching.
-rw-r--r--amd64/isel.c35
-rw-r--r--test/isel1.ssa24
2 files changed, 39 insertions, 20 deletions
diff --git a/amd64/isel.c b/amd64/isel.c
index 2519ae5..6aea850 100644
--- a/amd64/isel.c
+++ b/amd64/isel.c
@@ -25,7 +25,7 @@ struct ANum {
 	Ins *i;
 };
 
-static void amatch(Addr *, Ref, ANum *, Fn *, int);
+static int amatch(Addr *, Ref, int, ANum *, Fn *);
 
 static int
 noimm(Ref r, Fn *fn)
@@ -131,8 +131,8 @@ seladdr(Ref *r, ANum *an, Fn *fn)
 
 	r0 = *r;
 	if (rtype(r0) == RTmp) {
-		amatch(&a, r0, an, fn, 1);
-		if (req(a.base, r0))
+		memset(&a, 0, sizeof a);
+		if (!amatch(&a, r0, an[r0.val].n, an, fn))
 			return;
 		if (a.offset.type == CAddr)
 		if (!req(a.base, R)) {
@@ -488,18 +488,16 @@ anumber(ANum *ai, Blk *b, Con *con)
 	}
 }
 
-static void
-amatch(Addr *a, Ref r, ANum *ai, Fn *fn, int top)
+static int
+amatch(Addr *a, Ref r, int n, ANum *ai, Fn *fn)
 {
 	Ins *i;
 	int nl, nr, t, s;
 	Ref al, ar;
 
-	if (top)
-		memset(a, 0, sizeof *a);
 	if (rtype(r) == RCon) {
 		addcon(&a->offset, &fn->con[r.val]);
-		return;
+		return 1;
 	}
 	assert(rtype(r) == RTmp);
 	i = ai[r.val].i;
@@ -515,14 +513,11 @@ amatch(Addr *a, Ref r, ANum *ai, Fn *fn, int top)
 			ar = i->arg[1];
 		}
 	}
-	switch (ai[r.val].n) {
+	switch (n) {
 	case 3: /* s * i */
-		if (!top) {
-			a->index = al;
-			a->scale = fn->con[ar.val].bits.i;
-		} else
-			a->base = r;
-		break;
+		a->index = al;
+		a->scale = fn->con[ar.val].bits.i;
+		return 0;
 	case 4: /* b + s * i */
 		switch (nr) {
 		case 0:
@@ -534,7 +529,7 @@ amatch(Addr *a, Ref r, ANum *ai, Fn *fn, int top)
 			a->scale = 1;
 			break;
 		case 3:
-			amatch(a, ar, ai, fn, 0);
+			amatch(a, ar, nr, ai, fn);
 			break;
 		}
 		r = al;
@@ -544,14 +539,14 @@ amatch(Addr *a, Ref r, ANum *ai, Fn *fn, int top)
 		if (s != -1)
 			r = SLOT(s);
 		a->base = r;
-		break;
+		return n || s != -1;
 	case 2: /* constants */
 	case 5: /* o + s * i */
 	case 6: /* o + b */
 	case 7: /* o + b + s * i */
-		amatch(a, ar, ai, fn, 0);
-		amatch(a, al, ai, fn, 0);
-		break;
+		amatch(a, ar, nr, ai, fn);
+		amatch(a, al, nl, ai, fn);
+		return 1;
 	default:
 		die("unreachable");
 	}
diff --git a/test/isel1.ssa b/test/isel1.ssa
new file mode 100644
index 0000000..879a871
--- /dev/null
+++ b/test/isel1.ssa
@@ -0,0 +1,24 @@
+# tests that the address matcher is not
+# confused by the two multiplications
+
+# note: the code handling apple asm fixes
+# ruins the good work of the matcher here,
+# I should revisit these fixes
+
+export function w $f(l %i, l %j) {
+@start
+	%off1 =l mul %i, 8
+	%a_i =l add $a, %off1
+	%off2 =l mul %j, 4
+	%a_ij =l add %a_i, %off2
+	%x =w loadsw %a_ij
+	ret %x
+}
+
+# >>> driver
+# int a[] = {1, 2, 3, 4};
+# extern int f(long long, long long);
+# int main() {
+# 	return !(f(0, 0) == 1 && f(0, 1) == 2 && f(1, 0) == 3 && f(1, 1) == 4);
+# }
+# <<<