commit 1a31d8e1d051c04df16ab22f03f4a9354c15c05b
parent a0d19a4ca73c1c2c54f9e053f6ac9983098dfbfb
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Sat,  4 Jan 2025 15:44:57 +0100
cc2: Optimize branch over jump
A branch over jump can be optimized inverting the condition of
the branch, removing the jump and branching directly to the target
of the jump. Transforming
(0)             M4[2](0,12)     M4[3](0,12)     =4(1,0) y -> L8(0,0)
(0)     L9:     j -> L6(1,0)
(0)     L8:     q0(1,0)
(0)             M4[2](0,12)     M4[4](0,12)     !4(1,0) y -> L7(0,0)
(0)     L10:    j -> L6(1,0)
(0)     L7:     #4(0,20)        h0(1,0)
into
(0)>            M4[2](0,12)     M4[3](0,12)     !4(1,0) y -> L6(0,0)
>(0)>           M4[2](0,12)     M4[4](0,12)     =4(1,0) y -> L6(0,0)
>(0)>   L7:     #4(0,20)        h0(1,0)
Diffstat:
1 file changed, 30 insertions(+), 2 deletions(-)
diff --git a/src/cmd/scc-cc/cc2/cfg.c b/src/cmd/scc-cc/cc2/cfg.c
@@ -279,22 +279,50 @@ optlabels(Node *np)
 	return np;
 }
 
+static int
+negop(int op)
+{
+	switch (op) {
+	case OEQ:  return ONE;
+	case ONE:  return OEQ;
+	case OLT:  return OGE;
+	case OGE:  return OLT;
+	case OLE:  return OGT;
+	case OGT:  return OLE;
+	default:   abort();
+	}
+	return op;
+}
+
 static Node *
 optjmps(Node *np)
 {
 	Symbol *label;
-	Node *p, *stmt, *last;
+	Node *p, *stmt, *next;
 
 	switch (np->op) {
 	case OBRANCH:
+	branch:
 		label = np->u.sym;
 		stmt = label->u.stmt;
+		next = np->next;
+
+		/* avoid branch over jump */
+		if (next->op == OJMP && next->next->label == label &&
+		    (!next->label || next->label->refcnt == 0)) {
+			Node *left = np->left;
+			np->u.sym = next->u.sym;
+			label->refcnt--;
+			left->op = negop(left->op);
+			delstmt(next);
+			goto branch;
+		}
 		goto chain_jumps;
 	case OJMP:
 		label = np->u.sym;
 		stmt = label->u.stmt;
 
-		/* Avoid jump over a set of NOPs */
+		/* avoid jump over a set of NOPs */
 		for (p = np->next; p; p = p->next) {
 			if (p == stmt) {
 				label->refcnt--;