PR target/50447
authorgjl <gjl@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 11 Oct 2011 18:28:49 +0000 (18:28 +0000)
committergjl <gjl@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 11 Oct 2011 18:28:49 +0000 (18:28 +0000)
* 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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@179816 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/avr/avr-protos.h
gcc/config/avr/avr.c
gcc/config/avr/avr.md

index 8c9f7ec..2fabe68 100644 (file)
@@ -1,3 +1,16 @@
+2011-10-11  Georg-Johann Lay  <avr@gjlay.de>
+
+       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.
+
 2011-10-11  H.J. Lu  <hongjiu.lu@intel.com>
 
        * config/i386/i386.c (ix86_expand_special_args_builtin): Remove
index a2a5dd0..06e412c 100644 (file)
@@ -82,7 +82,7 @@ extern void avr_output_bld (rtx operands[], int bit_nr);
 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 d8cc84a..afc3d61 100644 (file)
@@ -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[], int *len)
    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, enum rtx_code code)
   /* 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, enum rtx_code code)
 
       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, enum rtx_code code)
       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, enum rtx_code code)
 
    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;
       
index 23541bf..b7fe770 100644 (file)
@@ -77,7 +77,8 @@
 (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"
    (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")