diff mbox

[AVR] : Fix PR50447 (4/n)

Message ID 4E9434EB.9010204@gjlay.de
State New
Headers show

Commit Message

Georg-Johann Lay Oct. 11, 2011, 12:22 p.m. UTC
This is a small addendum to PR50447.

It's a change to addsi3 insn; the actual insn sequence printed is still the
same (except for adding +/-1 to l-reg) but the effect on cc0 is worked out so
that it can be used to cancel out comparisons like in long loops.

cc insn attribute gets one more alternative and notice_update_cc calls
respective output function that works out the effect on cc0.

Passed without regressions. Ok for trunk?

Johann

	PR target/50447
	* config/avr/avr.md (cc): Add out_plus attribute alternative.
	(addsi3): Use it.  Adapt avr_out_plus to new prototype.  Use
	avr_out_plus for all CONST_INT addends.
	* config/avr/avr-protos.h (avr_out_plus): Change prototype.
	* config/avr/avr.c (notice_update_cc): Call avr_out_plus on
	CC_OUT_PLUS.
	(avr_out_plus_1): Change prototype and report effect on cc0.
	(avr_out_plus): Ditto.
	(adjust_insn_length): Adapt call to avr_out_plus to new prototype.

Comments

Denis Chertykov Oct. 11, 2011, 3:55 p.m. UTC | #1
2011/10/11 Georg-Johann Lay <avr@gjlay.de>:
> This is a small addendum to PR50447.
>
> It's a change to addsi3 insn; the actual insn sequence printed is still the
> same (except for adding +/-1 to l-reg) but the effect on cc0 is worked out so
> that it can be used to cancel out comparisons like in long loops.
>
> cc insn attribute gets one more alternative and notice_update_cc calls
> respective output function that works out the effect on cc0.
>
> Passed without regressions. Ok for trunk?

Ok.

Denis.
diff mbox

Patch

Index: config/avr/avr.md
===================================================================
--- config/avr/avr.md	(revision 179765)
+++ config/avr/avr.md	(working copy)
@@ -77,7 +77,8 @@  (define_c_enum "unspecv"
 (include "constraints.md")
   
 ;; Condition code settings.
-(define_attr "cc" "none,set_czn,set_zn,set_n,compare,clobber"
+(define_attr "cc" "none,set_czn,set_zn,set_n,compare,clobber,
+                   out_plus"
   (const_string "none"))
 
 (define_attr "type" "branch,branch1,arith,xcall"
@@ -786,30 +787,28 @@  (define_insn "*addhi3"
    (set_attr "cc" "set_n,set_czn,set_czn,set_czn,set_n,set_n")])
 
 (define_insn "addsi3"
-  [(set (match_operand:SI 0 "register_operand"          "=r,!w,!w,d,l,l ,d,r")
-        (plus:SI (match_operand:SI 1 "register_operand" "%0,0 ,0 ,0,0,0 ,0,0")
-                 (match_operand:SI 2 "nonmemory_operand" "r,I ,J ,s,P,N ,n,n")))
-   (clobber (match_scratch:QI 3                         "=X,X ,X ,X,X,X ,X,&d"))]
+  [(set (match_operand:SI 0 "register_operand"          "=r,d ,d,r")
+        (plus:SI (match_operand:SI 1 "register_operand" "%0,0 ,0,0")
+                 (match_operand:SI 2 "nonmemory_operand" "r,s ,n,n")))
+   (clobber (match_scratch:QI 3                         "=X,X ,X,&d"))]
   ""
   {
     static const char * const asm_code[] =
       {
         "add %A0,%A2\;adc %B0,%B2\;adc %C0,%C2\;adc %D0,%D2",
-        "adiw %0,%2\;adc %C0,__zero_reg__\;adc %D0,__zero_reg__",
-        "sbiw %0,%n2\;sbc %C0,__zero_reg__\;sbc %D0,__zero_reg__",
         "subi %0,lo8(-(%2))\;sbci %B0,hi8(-(%2))\;sbci %C0,hlo8(-(%2))\;sbci %D0,hhi8(-(%2))",
-        "sec\;adc %A0,__zero_reg__\;adc %B0,__zero_reg__\;adc %C0,__zero_reg__\;adc %D0,__zero_reg__",
-        "sec\;sbc %A0,__zero_reg__\;sbc %B0,__zero_reg__\;sbc %C0,__zero_reg__\;sbc %D0,__zero_reg__"
+        "",
+        ""
       };
 
-    if (which_alternative >= (signed) (sizeof (asm_code) / sizeof (*asm_code)))
-      return avr_out_plus (operands, NULL);
+    if (*asm_code[which_alternative])
+      return asm_code [which_alternative];
 
-    return asm_code [which_alternative];
+    return avr_out_plus (operands, NULL, NULL);
   }
-  [(set_attr "length" "4,3,3,4,5,5,8,8")
-   (set_attr "adjust_len" "*,*,*,*,*,*,out_plus,out_plus")
-   (set_attr "cc" "set_n,set_n,set_czn,set_czn,set_n,set_n,clobber,clobber")])
+  [(set_attr "length" "4,4,4,8")
+   (set_attr "adjust_len" "*,*,out_plus,out_plus")
+   (set_attr "cc" "set_n,set_czn,out_plus,out_plus")])
 
 (define_insn "*addsi3_zero_extend"
   [(set (match_operand:SI 0 "register_operand"                         "=r")
Index: config/avr/avr-protos.h
===================================================================
--- config/avr/avr-protos.h	(revision 179765)
+++ config/avr/avr-protos.h	(working copy)
@@ -82,7 +82,7 @@  extern void avr_output_bld (rtx operands
 extern void avr_output_addr_vec_elt (FILE *stream, int value);
 extern const char *avr_out_sbxx_branch (rtx insn, rtx operands[]);
 extern const char* avr_out_bitop (rtx, rtx*, int*);
-extern const char* avr_out_plus (rtx*, int*);
+extern const char* avr_out_plus (rtx*, int*, int*);
 extern const char* avr_out_addto_sp (rtx*, int*);
 extern bool avr_popcount_each_byte (rtx, int, int);
 
Index: config/avr/avr.c
===================================================================
--- config/avr/avr.c	(revision 179765)
+++ config/avr/avr.c	(working copy)
@@ -1630,9 +1630,37 @@  void
 notice_update_cc (rtx body ATTRIBUTE_UNUSED, rtx insn)
 {
   rtx set;
+  enum attr_cc cc = get_attr_cc (insn);
   
-  switch (get_attr_cc (insn))
+  switch (cc)
     {
+    default:
+      break;
+
+    case CC_OUT_PLUS:
+      {
+        rtx *op = recog_data.operand;
+        int len_dummy, icc;
+        
+        /* Extract insn's operands.  */
+        extract_constrain_insn_cached (insn);
+        
+        avr_out_plus (op, &len_dummy, &icc);
+        cc = (enum attr_cc) icc;
+        
+        break;
+      }
+    }
+
+  switch (cc)
+    {
+    default:
+      /* Special values like CC_OUT_PLUS from above have been
+         mapped to "standard" CC_* values so we never come here.  */
+      
+      gcc_unreachable();
+      break;
+      
     case CC_NONE:
       /* Insn does not affect CC at all.  */
       break;
@@ -4673,10 +4701,11 @@  lshrsi3_out (rtx insn, rtx operands[], i
    addition; otherwise, set *PLEN to the length of the instruction sequence (in
    words) printed with PLEN == NULL.  XOP[3] is an 8-bit scratch register.
    CODE == PLUS:  perform addition by using ADD instructions.
-   CODE == MINUS: perform addition by using SUB instructions.  */
+   CODE == MINUS: perform addition by using SUB instructions.
+   Set *PCC to effect on cc0 according to respective CC_* insn attribute.  */
 
 static void
-avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code)
+avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc)
 {
   /* MODE of the operation.  */
   enum machine_mode mode = GET_MODE (xop[0]);
@@ -4700,6 +4729,10 @@  avr_out_plus_1 (rtx *xop, int *plen, enu
   /* Value to add.  There are two ways to add VAL: R += VAL and R -= -VAL.  */
   rtx xval = xop[2];
 
+  /* Addition does not set cc0 in a usable way.  */
+  
+  *pcc = (MINUS == code) ? CC_SET_CZN : CC_CLOBBER;
+
   if (MINUS == code)
     xval = gen_int_mode (-UINTVAL (xval), mode);
 
@@ -4722,6 +4755,11 @@  avr_out_plus_1 (rtx *xop, int *plen, enu
 
       op[0] = reg8;
       op[1] = GEN_INT (val8);
+
+      /* To get usable cc0 no low-bytes must have been skipped.  */
+      
+      if (i && !started)
+        *pcc = CC_CLOBBER;
       
       if (!started && i % 2 == 0
           && test_hard_reg_class (ADDW_REGS, reg8))
@@ -4794,6 +4832,11 @@  avr_out_plus_1 (rtx *xop, int *plen, enu
       started = true;
 
     } /* for all sub-bytes */
+
+  /* No output doesn't change cc0.  */
+  
+  if (plen && *plen == 0)
+    *pcc = CC_NONE;
 }
 
 
@@ -4803,24 +4846,35 @@  avr_out_plus_1 (rtx *xop, int *plen, enu
 
    and return "".  If PLEN == NULL, print assembler instructions to perform the
    addition; otherwise, set *PLEN to the length of the instruction sequence (in
-   words) printed with PLEN == NULL.  */
+   words) printed with PLEN == NULL.
+   If PCC != 0 then set *PCC to the the instruction sequence's effect on the
+   condition code (with respect to XOP[0]).  */
 
 const char*
-avr_out_plus (rtx *xop, int *plen)
+avr_out_plus (rtx *xop, int *plen, int *pcc)
 {
   int len_plus, len_minus;
+  int cc_plus, cc_minus, cc_dummy;
 
+  if (!pcc)
+    pcc = &cc_dummy;
+                                   
   /* Work out if  XOP[0] += XOP[2]  is better or  XOP[0] -= -XOP[2].  */
   
-  avr_out_plus_1 (xop, &len_plus, PLUS);
-  avr_out_plus_1 (xop, &len_minus, MINUS);
+  avr_out_plus_1 (xop, &len_plus, PLUS, &cc_plus);
+  avr_out_plus_1 (xop, &len_minus, MINUS, &cc_minus);
 
+  /* Prefer MINUS over PLUS if size is equal because it sets cc0.  */
+  
   if (plen)
-    *plen = (len_minus <= len_plus) ? len_minus : len_plus;
+    {
+      *plen = (len_minus <= len_plus) ? len_minus : len_plus;
+      *pcc  = (len_minus <= len_plus) ? cc_minus : cc_plus;
+    }
   else if (len_minus <= len_plus)
-    avr_out_plus_1 (xop, NULL, MINUS);
+    avr_out_plus_1 (xop, NULL, MINUS, pcc);
   else
-    avr_out_plus_1 (xop, NULL, PLUS);
+    avr_out_plus_1 (xop, NULL, PLUS, pcc);
 
   return "";
 }
@@ -5209,7 +5263,7 @@  adjust_insn_length (rtx insn, int len)
       
     case ADJUST_LEN_OUT_BITOP: avr_out_bitop (insn, op, &len); break;
       
-    case ADJUST_LEN_OUT_PLUS: avr_out_plus (op, &len); break;
+    case ADJUST_LEN_OUT_PLUS: avr_out_plus (op, &len, NULL); break;
 
     case ADJUST_LEN_ADDTO_SP: avr_out_addto_sp (op, &len); break;