I'm working on the AVR cc0 -> CCmode conversion (bug#92729). One
problem is that the cmpelim pass is currently very strict in requiring
insns of the form

(parallel [(set (reg:SI) (op:SI ... ...))
           (clobber (reg:CC REG_CC))])

when in fact AVR's insns often have the form

(parallel [(set (reg:SI) (op:SI ... ...))
           (clobber (scratch:QI))
           (clobber (reg:CC REG_CC))])

The attached patch relaxes checks in the cmpelim code to recognize
such insns, and makes it attempt to recognize

(parallel [(set (reg:CC REG_CC) (compare:CC ... ...))
           (set (reg:SI (op:SI ... ...)))
       (clobber (scratch:QI))])

as a new insn for that example. This appears to work.

I've bootstrapped and run the test suite with the patch, without differences.
From 788bf691aed9f27e1719a6c2e61b12f2a24e6b5d Mon Sep 17 00:00:00 2001
From: Pip Cet <pipcet@gmail.com>
Date: Tue, 4 Aug 2020 18:44:26 +0000
Subject: [PATCH] cmpelim: handle extra clobbers

Handle extra clobbers in CC-clobbering insns when attempting to
recognize the corresponding CC-setting insn.

This is for the AVR CCmode conversion. AVR has insns like

(define_insn "andhi3"
  [(set (match_operand:HI 0 ...)
        (and:HI (match_operand:HI 1 ...)
	        (match_operand:HI 2 ...)))
   (clobber (match_scratch:QI 3 ...))
   (clobber (reg:CC REG_CC))] ...)

which can be profitably converted into CC-setting variants.

2020-08-04  Pip Cet  <pipcet@gmail.com>

gcc/ChangeLog:

	* compare-elim.c (arithmetic_flags_clobber_p): Allow extra
        clobbers. (try_validate_parallel): (try_eliminate_compare):
        Likewise.
---
 gcc/compare-elim.c | 35 ++++++++++++++++++++++++++++++-----
 1 file changed, 30 insertions(+), 5 deletions(-)

diff --git a/gcc/compare-elim.c b/gcc/compare-elim.c
index 85f3e344074..295c32b0953 100644
--- a/gcc/compare-elim.c
+++ b/gcc/compare-elim.c
@@ -202,7 +202,7 @@ arithmetic_flags_clobber_p (rtx_insn *insn)
   if (asm_noperands (pat) >= 0)
     return false;
 
-  if (GET_CODE (pat) == PARALLEL && XVECLEN (pat, 0) == 2)
+  if (GET_CODE (pat) == PARALLEL && XVECLEN (pat, 0) >= 2)
     {
       x = XVECEXP (pat, 0, 0);
       if (GET_CODE (x) != SET)
@@ -211,7 +211,7 @@ arithmetic_flags_clobber_p (rtx_insn *insn)
       if (!REG_P (x))
 	return false;
 
-      x = XVECEXP (pat, 0, 1);
+      x = XVECEXP (pat, 0, XVECLEN (pat, 0) - 1);
       if (GET_CODE (x) == CLOBBER)
 	{
 	  x = XEXP (x, 0);
@@ -663,6 +663,16 @@ static rtx
 try_validate_parallel (rtx set_a, rtx set_b)
 {
   rtx par = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set_a, set_b));
+  if (GET_CODE (set_b) == PARALLEL)
+    {
+      int len = XVECLEN (set_b, 0);
+      rtvec v = rtvec_alloc (len);
+      RTVEC_ELT (v, 0) = set_a;
+      for (int i = 0; i < len - 1; i++)
+	RTVEC_ELT (v, i + 1) = XVECEXP (set_b, 0, i);
+
+      par = gen_rtx_PARALLEL (VOIDmode, v);
+    }
   rtx_insn *insn = make_insn_raw (par);
 
   if (insn_invalid_p (insn, false))
@@ -873,10 +883,25 @@ try_eliminate_compare (struct comparison *cmp)
      [(set (reg:CCM) (compare:CCM (operation) (immediate)))
       (set (reg) (operation)]  */
 
-  rtvec v = rtvec_alloc (2);
+  /* Rotate
+     [(set A B)
+      (clobber (scratch))
+      ...
+      (clobber (reg:CCM))]]
+
+     to
+
+     [(set (reg:CCM) (compare:CCM (operation) (immediate)))
+      (set A B)
+      (clobber (scratch))
+      ...]  */
+
+  int len = XVECLEN (PATTERN (insn), 0);
+  rtvec v = rtvec_alloc (len);
   RTVEC_ELT (v, 0) = y;
-  RTVEC_ELT (v, 1) = x;
-  
+  for (int i = 0; i < len - 1; i++)
+    RTVEC_ELT (v, i + 1) = XVECEXP (PATTERN (insn), 0, i);
+
   rtx pat = gen_rtx_PARALLEL (VOIDmode, v);
   
   /* Succeed if the new instruction is valid.  Note that we may have started
-- 
2.28.0

Reply via email to