code: plan9front

Download patch

ref: 313e4bf78ea365ad29ef9c42b359b7994c566b6d
parent: a3b95d3e567c0ef60f9f1ead26124fb706dec20d
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)