decrement and branch on m68k

Herman ten Brugge herman@htbrug.net.HCC.nl
Mon Dec 29 11:42:00 GMT 1997


Hello,

I found a bug in the define_peephole construct for decrement and branch
until zero. The bug shows itself when a wile loop is inside a for loop.
The program below shows the problem:

int a[10];
int z = 1;

void update()
{
	z--;
}

int main()
{
	int i;

	for (i = 10 ; i >= 0 ; i--) {
		z = i;
		do {
			update();
		} while (a[z]);
	}
	return(0);
}

Compiled with gcc (2.7.2.1). The peephole is the same in egcs so we have the
same problem here.

#NO_APP
gcc2_compiled.:
___gnu_compiled_c:
.globl _z
.data
	.even
_z:
	.long 1
.text
	.even
.globl _main
_main:
	link a6,#0
	movel a2,sp@-
	movel d2,sp@-
	jbsr ___main
	moveq #10,d2
	lea _a,a2
L15:
	movel d2,_z
L16:
	jbsr _update
	movel _z,d0
	tstl a2@(d0:l:4)
	dbne d2,L15			<---- ERROR
	jne L16				<---- ERROR
	clrw d2
	subql #1,d2
	jpl L15
	movel a6@(-8),d2
	movel a6@(-4),a2
	unlk a6
	rts
	.even
.globl _update
_update:
	link a6,#0
	subql #1,_z
	unlk a6
	rts
.comm _a,40

The problem is that the dbne and jne switched due to the peephole. This is
certainly wrong in this case. I made the following patch to solve this
problem.

	Herman.


--- m68k.md.org	Mon Dec 29 20:24:24 1997
+++ m68k.md	Mon Dec 29 20:25:59 1997
@@ -7087,7 +7087,8 @@
      (set (match_dup 0)
 	  (plus:HI (match_dup 0)
 		   (const_int -1)))])]
-  "!TARGET_5200 && DATA_REG_P (operands[0]) && ! flags_in_68881 ()"
+  "!TARGET_5200 && DATA_REG_P (operands[0]) && ! flags_in_68881 ()
+   && !dbcc_label_conflict (insn, operands[2], operands[1])"
   "*
 {
   CC_STATUS_INIT;
@@ -7111,7 +7112,8 @@
      (set (match_dup 0)
 	  (plus:SI (match_dup 0)
 		   (const_int -1)))])]
-  "!TARGET_5200 && DATA_REG_P (operands[0]) && ! flags_in_68881 ()"
+  "!TARGET_5200 && DATA_REG_P (operands[0]) && ! flags_in_68881 ()
+   && !dbcc_label_conflict (insn, operands[2], operands[1])"
   "*
 {
   CC_STATUS_INIT;
--- m68k.c.org	Mon Dec 29 20:24:27 1997
+++ m68k.c	Mon Dec 29 20:27:22 1997
@@ -878,6 +878,28 @@
     }
 }
 
+/* check for while loop inside a decrement and branch loop */
+
+int
+dbcc_label_conflict (insn, jump, db)
+     rtx insn;
+     rtx jump;
+     rtx db;
+{
+  while (insn)
+    {
+      if (GET_CODE (insn) == CODE_LABEL)
+	{
+          if (CODE_LABEL_NUMBER(jump) == CODE_LABEL_NUMBER(insn))
+	    return 1;
+          if (CODE_LABEL_NUMBER(db) == CODE_LABEL_NUMBER(insn))
+	    return 0;
+	}
+      insn = PREV_INSN (insn);
+    }
+  return 1;
+}
+
 /* Return non-zero if flags are currently in the 68881 flag register.  */
 int
 flags_in_68881 ()

-- 
-------------------------------------------------------------------------
Herman ten Brugge			Email:	Haj.Ten.Brugge@net.HCC.nl



More information about the Gcc-bugs mailing list