git: 9front

Download patch

ref: 3813637061f6c8b2e187fe767714e13aa84bd3cb
parent: 711750a7c5673dbd343b8daa89398e7cdf414f9b
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Mon Jun 12 15:10:12 EDT 2023

7c: elide type converting moves, registerize loads after store from local variables

To elide type converting modes, we used findpre() to
find the previous instruction generating the source
register (to check if type conversion is needed).
But findpre() will return nil if it encounters
the instruction to be used. What we want is find the
instruction that sets/modifies the source regiser for
the type converting move. Add a findset() function for
this and use instead.

The code generator can emit sequences like:

MOV reg1, v(SP)
MOV v(SP), reg2

We rather get rid of the second load here and convert to:

MOV reg1, v(SP)
MOV reg1, reg2

And then have copyprop deal with getting rid of the
second move.

This is what storeprop() does.

--- a/sys/src/cmd/7c/peep.c
+++ b/sys/src/cmd/7c/peep.c
@@ -2,8 +2,11 @@
 
 int xtramodes(Reg*, Adr*);
 
+Reg* findset(Reg *r, Adr *v);
 Reg* findpre(Reg *r, Adr *v);
 Reg* findinc(Reg *r, Reg *r2, Adr *v);
+static void
+storeprop(int as, Adr *a, Adr *v, Reg *r);
 
 static int
 isu32op(Prog *p)
@@ -142,8 +145,14 @@
 	t = 0;
 	for(r=firstr; r!=R; r=r->link) {
 		p = r->prog;
-		if(p->as == ALSL || p->as == ALSR || p->as == AASR ||
-		   p->as == ALSLW || p->as == ALSRW || p->as == AASRW) {
+
+		/* registerize local loads following stores */
+		if(p->as == AMOV || p->as == AMOVW || p->as == AMOVWU || p->as == AFMOVS || p->as == AFMOVD)
+			if(p->from.type == D_REG && p->to.type == D_OREG && (p->to.name == D_AUTO || p->to.name == D_PARAM))
+				storeprop(p->as, &p->from, &p->to, r->s1);
+
+		if(p->as == ALSL || p->as == ALSR || p->as == AASR
+		|| p->as == ALSLW || p->as == ALSRW || p->as == AASRW) {
 			/*
 			 * elide shift into D_SHIFT operand of subsequent instruction
 			 */
@@ -153,8 +162,7 @@
 			}
 		} else
 		if(p->as == ASXTW && p->from.type == D_REG && p->to.type == D_REG){
-			r1 = findpre(r, &p->from);
-			if(r1 != R){
+			if((r1 = findset(r, &p->from)) != R){
 				p1 = r1->prog;
 				switch(p1->as){
 				case AMOVB:
@@ -170,8 +178,7 @@
 		} else
 		if((p->as == AMOVB || p->as == AMOVBU || p->as == AMOVH || p->as == AMOVHU || p->as == AMOVWU)
 		&& (p->from.type == D_REG && p->to.type == D_REG)){
-			r1 = findpre(r, &p->from);
-			if(r1 != R){
+			if((r1 = findset(r, &p->from)) != R){
 				p1 = r1->prog;
 				if(p1->to.type == p->from.type && p1->to.reg == p->from.reg){
 					if(p1->as == p->as || p->as == AMOVWU && isu32op(p1))
@@ -745,6 +752,48 @@
 }
 
 /*
+ * Registerize loads from local variables:
+ *
+ * MOV a, v
+ * ... (a and v not touched)
+ * MOV v, b
+ * ----
+ * MOV a, v
+ * ... (a and v not touched)
+ * MOV a, b
+ */
+static void
+storeprop(int as, Adr *a, Adr *v, Reg *r)
+{
+	Prog *p;
+
+	for(; r != R; r = r->s1) {
+		if(uniqp(r) == R)
+			return;
+
+		p = r->prog;
+		if((as == p->as
+		|| (as == AMOV && (p->as == AMOVW || p->as == AMOVWU))
+		|| (as == AMOVW && p->as == AMOVWU)
+		|| (as == AMOVWU && p->as == AMOVW))
+		&& copyas(&p->from, v)){
+			p->from = *a;
+			continue;
+		}
+
+		if(copyu(p, a, A) > 1)
+			return;
+
+		if(p->to.type == D_OREG || p->to.type == D_XPRE || p->to.type == D_XPOST)
+			if(p->to.name == D_NONE || copyas(&p->to, v))
+				return;
+
+		if(r->s2)
+			storeprop(as, a, v, r->s2);
+	}
+}
+
+/*
  * ALSL x,y,w
  * .. (not use w, not set x y w)
  * AXXX w,a,b (a != w)
@@ -865,6 +914,21 @@
 }
 
 Reg*
+findset(Reg *r, Adr *v)
+{
+
+	Reg *r1;
+
+	for(r1=uniqp(r); r1!=R; r=r1,r1=uniqp(r)) {
+		if(uniqs(r1) != r)
+			return R;
+		if(copyu(r1->prog, v, A) > 1)
+			return r1;
+	}
+	return R;
+}
+
+Reg*
 findpre(Reg *r, Adr *v)
 {
 	Reg *r1;
@@ -1387,7 +1451,7 @@
 		if(a->type == v->type)
 		if(a->reg == v->reg)
 			return 1;
-	} else if(v->type == D_CONST) {		/* for constprop */
+	} else {
 		if(a->type == v->type)
 		if(a->name == v->name)
 		if(a->sym == v->sym)
--