avr-protos.h (avr_out_sbxx_branch): Declare.
authorMarek Michalkiewicz <marekm@amelek.gda.pl>
Sun, 26 May 2002 20:19:32 +0000 (22:19 +0200)
committerMarek Michalkiewicz <marekm@gcc.gnu.org>
Sun, 26 May 2002 20:19:32 +0000 (20:19 +0000)
* config/avr/avr-protos.h (avr_out_sbxx_branch): Declare.
* config/avr/avr.c (jump_over_one_insn_p): Take length of the
branch insn into account, do not assume 1.
(avr_out_sbxx_branch): New function.  Optimize cases of skipping
over single word insn.  Handle upper half of I/O space too.
* config/avr/avr.md (*sbrx_branch): Use it.
(*sbrx_and_branchhi, *sbrx_and_branchsi): Likewise.
(*sbix_branch, *sbix_branch_bit7): Likewise.
(*sbix_branch_tmp, *sbix_branch_tmp_bit7): New.
Use RTL peepholes to optimize register operand sign tests.

From-SVN: r53906

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

index 800233d43db321452b05aa09000d9651f9b4626a..7b8ba2d8a75824ffa77a0b8f2fc76d0dd16f0c58 100644 (file)
        (_cpp_parse_expr, reduce): Update to handle two-integers.
        * cpplib.c (_cpp_test_assertion): Back up on CPP_EOF.
 
+2002-05-26  Marek Michalkiewicz  <marekm@amelek.gda.pl>
+
+       * config/avr/avr-protos.h (avr_out_sbxx_branch): Declare.
+       * config/avr/avr.c (jump_over_one_insn_p): Take length of the
+       branch insn into account, do not assume 1.
+       (avr_out_sbxx_branch): New function.  Optimize cases of skipping
+       over single word insn.  Handle upper half of I/O space too.
+       * config/avr/avr.md (*sbrx_branch): Use it.
+       (*sbrx_and_branchhi, *sbrx_and_branchsi): Likewise.
+       (*sbix_branch, *sbix_branch_bit7): Likewise.
+       (*sbix_branch_tmp, *sbix_branch_tmp_bit7): New.
+       Use RTL peepholes to optimize register operand sign tests.
+
 2002-05-26  Marek Michalkiewicz  <marekm@amelek.gda.pl>
 
        * config/avr/avr.c (avr_asm_only_p): New variable.
index f6dd8802e98074f5691daa57deee01587560045f..3d0be48c80728dcf5775df98aac968b805d81ed5 100644 (file)
@@ -98,6 +98,7 @@ extern const char * lshrsi3_out PARAMS ((rtx insn, rtx operands[], int *len));
 
 extern void avr_output_bld PARAMS ((rtx operands[], int bit_nr));
 extern void avr_output_addr_vec_elt PARAMS ((FILE *stream, int value));
+extern const char *avr_out_sbxx_branch PARAMS ((rtx insn, rtx operands[]));
 
 extern enum reg_class preferred_reload_class PARAMS ((rtx x,
                                                     enum reg_class class));
index 5167ee65ada31726e659adeff3244ecb77198061..67e6d52114e47a9d49829760ae42f28f2f289586 100644 (file)
@@ -5233,7 +5233,7 @@ jump_over_one_insn_p (insn, dest)
                      : dest);
   int jump_addr = INSN_ADDRESSES (INSN_UID (insn));
   int dest_addr = INSN_ADDRESSES (uid);
-  return dest_addr - jump_addr == 2;
+  return dest_addr - jump_addr == get_attr_length (insn) + 1;
 }
 
 /* Returns 1 if a value of mode MODE can be stored starting with hard
@@ -5451,3 +5451,76 @@ avr_peep2_scratch_safe (scratch)
     }
   return 1;
 }
+
+/* Output a branch that tests a single bit of a register (QI, HI or SImode)
+   or memory location in the I/O space (QImode only).
+
+   Operand 0: comparison operator (must be EQ or NE, compare bit to zero).
+   Operand 1: register operand to test, or CONST_INT memory address.
+   Operand 2: bit number (for QImode operand) or mask (HImode, SImode).
+   Operand 3: label to jump to if the test is true.  */
+
+const char *
+avr_out_sbxx_branch (insn, operands)
+     rtx insn;
+     rtx operands[];
+{
+  enum rtx_code comp = GET_CODE (operands[0]);
+  int long_jump = (get_attr_length (insn) >= 4);
+  int reverse = long_jump || jump_over_one_insn_p (insn, operands[3]);
+
+  if (comp == GE)
+    comp = EQ;
+  else if (comp == LT)
+    comp = NE;
+
+  if (reverse)
+    comp = reverse_condition (comp);
+
+  if (GET_CODE (operands[1]) == CONST_INT)
+    {
+      if (INTVAL (operands[1]) < 0x40)
+       {
+         if (comp == EQ)
+           output_asm_insn (AS2 (sbis,%1-0x20,%2), operands);
+         else
+           output_asm_insn (AS2 (sbic,%1-0x20,%2), operands);
+       }
+      else
+       {
+         output_asm_insn (AS2 (in,__tmp_reg__,%1-0x20), operands);
+         if (comp == EQ)
+           output_asm_insn (AS2 (sbrs,__tmp_reg__,%2), operands);
+         else
+           output_asm_insn (AS2 (sbrc,__tmp_reg__,%2), operands);
+       }
+    }
+  else  /* GET_CODE (operands[1]) == REG */
+    {
+      if (GET_MODE (operands[1]) == QImode)
+       {
+         if (comp == EQ)
+           output_asm_insn (AS2 (sbrs,%1,%2), operands);
+         else
+           output_asm_insn (AS2 (sbrc,%1,%2), operands);
+       }
+      else  /* HImode or SImode */
+       {
+         static char buf[] = "sbrc %A1,0";
+         int bit_nr = exact_log2 (INTVAL (operands[2])
+                                  & GET_MODE_MASK (GET_MODE (operands[1])));
+
+         buf[3] = (comp == EQ) ? 's' : 'c';
+         buf[6] = 'A' + (bit_nr >> 3);
+         buf[9] = '0' + (bit_nr & 7);
+         output_asm_insn (buf, operands);
+       }
+    }
+
+  if (long_jump)
+    return (AS1 (rjmp,_PC_+4) CR_TAB
+           AS1 (jmp,%3));
+  if (!reverse)
+    return AS1 (rjmp,%3);
+  return "";
+}
index da4c571742bbd9f62ec1d05405b0615985828def..08a468aa40bce020210e5e30e5ea30f07fa5e6e3 100644 (file)
   ""
   "")
 
+;; Test a single bit in a QI/HI/SImode register.
 (define_insn "*sbrx_branch"
   [(set (pc)
         (if_then_else
                         [(zero_extract
                           (match_operand:QI 1 "register_operand" "r")
                           (const_int 1)
-                          (match_operand 2 "immediate_operand" "n"))
+                          (match_operand 2 "const_int_operand" "n"))
                          (const_int 0)])
         (label_ref (match_operand 3 "" ""))
         (pc)))]
-  "(GET_CODE (operands[0]) == EQ || GET_CODE (operands[0]) == NE)"
-  "* {
-       int comp = ((get_attr_length (insn) == 4)
-                   ? reverse_condition (GET_CODE (operands[0]))
-                   : GET_CODE (operands[0]));
-       if (comp == EQ)
-         output_asm_insn (AS2 (sbrs,%1,%2), operands);
-       else
-         output_asm_insn (AS2 (sbrc,%1,%2), operands);
-       if (get_attr_length (insn) != 4)
-         return AS1 (rjmp,%3);
-       return (AS1 (rjmp,_PC_+4) CR_TAB
-               AS1 (jmp,%3));
-     }"
+  "GET_CODE (operands[0]) == EQ || GET_CODE (operands[0]) == NE"
+  "* return avr_out_sbxx_branch (insn, operands);"
   [(set (attr "length")
        (if_then_else (and (ge (minus (pc) (match_dup 3)) (const_int -2046))
                           (le (minus (pc) (match_dup 3)) (const_int 2046)))
                                    (const_int 4))))
    (set_attr "cc" "clobber")])
 
-(define_insn "*sbrx_and_branchsi"
+(define_insn "*sbrx_and_branchhi"
   [(set (pc)
         (if_then_else
         (match_operator 0 "comparison_operator"
-                        [(and:SI
-                          (match_operand:SI 1 "register_operand" "r")
-                          (match_operand:SI 2 "immediate_operand" "n"))
+                        [(and:HI
+                          (match_operand:HI 1 "register_operand" "r")
+                          (match_operand:HI 2 "const_int_operand" "n"))
                          (const_int 0)])
         (label_ref (match_operand 3 "" ""))
         (pc)))]
   "(GET_CODE (operands[0]) == EQ || GET_CODE (operands[0]) == NE)
-   && mask_one_bit_p(INTVAL (operands[2]))"
-  "* {
-       int comp = ((get_attr_length (insn) == 4)
-                   ? reverse_condition (GET_CODE (operands[0]))
-                   : GET_CODE (operands[0]));
-       int bit = mask_one_bit_p(INTVAL (operands[2])) - 1;
-       static char buf[] = \"sbrc %A1,0\";
-       buf[3] = (comp == EQ ? 's' : 'c');
-       buf[6] = bit / 8 + 'A';
-       buf[9] = bit % 8 + '0';
-       output_asm_insn (buf, operands);
-
-       if (get_attr_length (insn) != 4)
-         return AS1 (rjmp,%3);
-       return (AS1 (rjmp,_PC_+4) CR_TAB
-               AS1 (jmp,%3));
-     }"
+   && exact_log2 (INTVAL (operands[2]) & 0xffff) >= 0"
+  "* return avr_out_sbxx_branch (insn, operands);"
   [(set (attr "length")
        (if_then_else (and (ge (minus (pc) (match_dup 3)) (const_int -2046))
                           (le (minus (pc) (match_dup 3)) (const_int 2046)))
                                    (const_int 4))))
    (set_attr "cc" "clobber")])
 
-(define_insn "*sbrx_and_branchhi"
+(define_insn "*sbrx_and_branchsi"
   [(set (pc)
         (if_then_else
         (match_operator 0 "comparison_operator"
-                        [(and:HI
-                          (match_operand:HI 1 "register_operand" "r")
-                          (match_operand:HI 2 "immediate_operand" "n"))
+                        [(and:SI
+                          (match_operand:SI 1 "register_operand" "r")
+                          (match_operand:SI 2 "const_int_operand" "n"))
                          (const_int 0)])
         (label_ref (match_operand 3 "" ""))
         (pc)))]
   "(GET_CODE (operands[0]) == EQ || GET_CODE (operands[0]) == NE)
-   && mask_one_bit_p(INTVAL (operands[2]))"
-  "* {
-       int comp = ((get_attr_length (insn) == 4)
-                   ? reverse_condition (GET_CODE (operands[0]))
-                   : GET_CODE (operands[0]));
-       int bit = mask_one_bit_p(INTVAL (operands[2])) - 1;
-       static char buf[] = \"sbrc %A1,0\";
-       buf[3] = (comp == EQ ? 's' : 'c');
-       buf[6] = bit / 8 + 'A';
-       buf[9] = bit % 8 + '0';
-       output_asm_insn (buf, operands);
-
-       if (get_attr_length (insn) != 4)
-         return AS1 (rjmp,%3);
-       return (AS1 (rjmp,_PC_+4) CR_TAB
-               AS1 (jmp,%3));
-     }"
+   && exact_log2 (INTVAL (operands[2]) & 0xffffffff) >= 0"
+  "* return avr_out_sbxx_branch (insn, operands);"
   [(set (attr "length")
        (if_then_else (and (ge (minus (pc) (match_dup 3)) (const_int -2046))
                           (le (minus (pc) (match_dup 3)) (const_int 2046)))
                                    (const_int 4))))
    (set_attr "cc" "clobber")])
 
+;; Convert sign tests to bit 7/15/31 tests that match the above insns.
+(define_peephole2
+  [(set (cc0) (match_operand:QI 0 "register_operand" ""))
+   (set (pc) (if_then_else (ge (cc0) (const_int 0))
+                          (label_ref (match_operand 1 "" ""))
+                          (pc)))]
+  ""
+  [(set (pc) (if_then_else (eq (zero_extract (match_dup 0)
+                                            (const_int 1)
+                                            (const_int 7))
+                              (const_int 0))
+                          (label_ref (match_dup 1))
+                          (pc)))]
+  "")
+
+(define_peephole2
+  [(set (cc0) (match_operand:QI 0 "register_operand" ""))
+   (set (pc) (if_then_else (lt (cc0) (const_int 0))
+                          (label_ref (match_operand 1 "" ""))
+                          (pc)))]
+  ""
+  [(set (pc) (if_then_else (ne (zero_extract (match_dup 0)
+                                            (const_int 1)
+                                            (const_int 7))
+                              (const_int 0))
+                          (label_ref (match_dup 1))
+                          (pc)))]
+  "")
+
+(define_peephole2
+  [(set (cc0) (match_operand:HI 0 "register_operand" ""))
+   (set (pc) (if_then_else (ge (cc0) (const_int 0))
+                          (label_ref (match_operand 1 "" ""))
+                          (pc)))]
+  ""
+  [(set (pc) (if_then_else (eq (and:HI (match_dup 0) (const_int -32768))
+                              (const_int 0))
+                          (label_ref (match_dup 1))
+                          (pc)))]
+  "")
+
+(define_peephole2
+  [(set (cc0) (match_operand:HI 0 "register_operand" ""))
+   (set (pc) (if_then_else (lt (cc0) (const_int 0))
+                          (label_ref (match_operand 1 "" ""))
+                          (pc)))]
+  ""
+  [(set (pc) (if_then_else (ne (and:HI (match_dup 0) (const_int -32768))
+                              (const_int 0))
+                          (label_ref (match_dup 1))
+                          (pc)))]
+  "")
+
+(define_peephole2
+  [(set (cc0) (match_operand:SI 0 "register_operand" ""))
+   (set (pc) (if_then_else (ge (cc0) (const_int 0))
+                          (label_ref (match_operand 1 "" ""))
+                          (pc)))]
+  ""
+  [(set (pc) (if_then_else (eq (and:SI (match_dup 0) (match_dup 2))
+                              (const_int 0))
+                          (label_ref (match_dup 1))
+                          (pc)))]
+  "operands[2] = GEN_INT (0x80000000);")
+
+(define_peephole2
+  [(set (cc0) (match_operand:SI 0 "register_operand" ""))
+   (set (pc) (if_then_else (lt (cc0) (const_int 0))
+                          (label_ref (match_operand 1 "" ""))
+                          (pc)))]
+  ""
+  [(set (pc) (if_then_else (ne (and:SI (match_dup 0) (match_dup 2))
+                              (const_int 0))
+                          (label_ref (match_dup 1))
+                          (pc)))]
+  "operands[2] = GEN_INT (0x80000000);")
+
 ;; ************************************************************************
 ;; Implementation of conditional jumps here.
 ;;  Compare with 0 (test) jumps
   [(set_attr "length" "1")
    (set_attr "cc" "none")])
 
+;; Lower half of the I/O space - use sbic/sbis directly.
 (define_insn "*sbix_branch"
   [(set (pc)
        (if_then_else
         (pc)))]
   "(GET_CODE (operands[0]) == EQ || GET_CODE (operands[0]) == NE)
    && avr_io_address_p (operands[1], 1 + 0x20)"
-{
-  enum rtx_code comp = GET_CODE (operands[0]);
-  int reverse = (get_attr_length (insn) == 4);
-
-  if (reverse)
-    comp = reverse_condition (comp);
-  if (comp == EQ)
-    output_asm_insn (AS2 (sbis,%1-0x20,%2), operands);
-  else
-    output_asm_insn (AS2 (sbic,%1-0x20,%2), operands);
-  if (!reverse)
-    return AS1 (rjmp,%3);
-  return (AS1 (rjmp,_PC_+4) CR_TAB
-         AS1 (jmp,%3));
-}
+  "* return avr_out_sbxx_branch (insn, operands);"
   [(set (attr "length")
        (if_then_else (and (ge (minus (pc) (match_dup 3)) (const_int -2046))
                           (le (minus (pc) (match_dup 3)) (const_int 2046)))
   "(GET_CODE (operands[0]) == GE || GET_CODE (operands[0]) == LT)
    && avr_io_address_p (operands[1], 1 + 0x20)"
 {
-  enum rtx_code comp = GET_CODE (operands[0]);
-  int reverse = (get_attr_length (insn) == 4);
-
-  if (reverse)
-    comp = reverse_condition (comp);
-  if (comp == GE)
-    output_asm_insn (AS2 (sbis,%1-0x20,7), operands);
-  else
-    output_asm_insn (AS2 (sbic,%1-0x20,7), operands);
-  if (!reverse)
-    return AS1 (rjmp,%2);
-  return (AS1 (rjmp,_PC_+4) CR_TAB
-         AS1 (jmp,%2));
+  operands[3] = operands[2];
+  operands[2] = GEN_INT (7);
+  return avr_out_sbxx_branch (insn, operands);
 }
   [(set (attr "length")
        (if_then_else (and (ge (minus (pc) (match_dup 2)) (const_int -2046))
                                    (const_int 4))))
    (set_attr "cc" "clobber")])
 
+;; Upper half of the I/O space - read port to __tmp_reg__ and use sbrc/sbrs.
+(define_insn "*sbix_branch_tmp"
+  [(set (pc)
+       (if_then_else
+        (match_operator 0 "comparison_operator"
+                        [(zero_extract
+                          (mem:QI (match_operand 1 "const_int_operand" "n"))
+                          (const_int 1)
+                          (match_operand 2 "const_int_operand" "n"))
+                         (const_int 0)])
+        (label_ref (match_operand 3 "" ""))
+        (pc)))]
+  "(GET_CODE (operands[0]) == EQ || GET_CODE (operands[0]) == NE)
+   && avr_io_address_p (operands[1], 1) && INTVAL (operands[1]) >= 0x40"
+  "* return avr_out_sbxx_branch (insn, operands);"
+  [(set (attr "length")
+       (if_then_else (and (ge (minus (pc) (match_dup 3)) (const_int -2046))
+                          (le (minus (pc) (match_dup 3)) (const_int 2045)))
+                     (const_int 3)
+                     (if_then_else (eq_attr "mcu_mega" "no")
+                                   (const_int 3)
+                                   (const_int 5))))
+   (set_attr "cc" "clobber")])
+
+(define_insn "*sbix_branch_tmp_bit7"
+  [(set (pc)
+       (if_then_else
+        (match_operator 0 "comparison_operator"
+                        [(mem:QI (match_operand 1 "const_int_operand" "n"))
+                         (const_int 0)])
+        (label_ref (match_operand 2 "" ""))
+        (pc)))]
+  "(GET_CODE (operands[0]) == GE || GET_CODE (operands[0]) == LT)
+   && avr_io_address_p (operands[1], 1) && INTVAL (operands[1]) >= 0x40"
+{
+  operands[3] = operands[2];
+  operands[2] = GEN_INT (7);
+  return avr_out_sbxx_branch (insn, operands);
+}
+  [(set (attr "length")
+       (if_then_else (and (ge (minus (pc) (match_dup 2)) (const_int -2046))
+                          (le (minus (pc) (match_dup 2)) (const_int 2045)))
+                     (const_int 3)
+                     (if_then_else (eq_attr "mcu_mega" "no")
+                                   (const_int 3)
+                                   (const_int 5))))
+   (set_attr "cc" "clobber")])
+
 ;; ************************* Peepholes ********************************
 
 (define_peephole
   return (AS1 (brcs,_PC_+4) CR_TAB
           AS1 (jmp,%1));
 }")
-                                       
-(define_peephole
-  [(set (cc0) (match_operand:QI 0 "register_operand" ""))
-   (set (pc)
-       (if_then_else (lt (cc0) (const_int 0))
-                     (label_ref (match_operand 1 "" ""))
-                     (pc)))]
-  "jump_over_one_insn_p (insn, operands[1])"
-  "sbrs %0,7")
-
-(define_peephole
-  [(set (cc0) (match_operand:QI 0 "register_operand" ""))
-   (set (pc)
-       (if_then_else (ge (cc0) (const_int 0))
-                     (label_ref (match_operand 1 "" ""))
-                     (pc)))]
-  "jump_over_one_insn_p (insn, operands[1])"
-  "sbrc %0,7")
-                                       
-(define_peephole
-  [(set (cc0) (match_operand:HI 0 "register_operand" ""))
-   (set (pc)
-       (if_then_else (lt (cc0) (const_int 0))
-                     (label_ref (match_operand 1 "" ""))
-                     (pc)))]
-  "jump_over_one_insn_p (insn, operands[1])"
-  "sbrs %B0,7")
-
-(define_peephole
-  [(set (cc0) (match_operand:HI 0 "register_operand" ""))
-   (set (pc)
-       (if_then_else (ge (cc0) (const_int 0))
-                     (label_ref (match_operand 1 "" ""))
-                     (pc)))]
-  "jump_over_one_insn_p (insn, operands[1])"
-  "sbrc %B0,7")
-
-(define_peephole
-  [(set (cc0) (match_operand:SI 0 "register_operand" ""))
-   (set (pc)
-       (if_then_else (lt (cc0) (const_int 0))
-                     (label_ref (match_operand 1 "" ""))
-                     (pc)))]
-  "jump_over_one_insn_p (insn, operands[1])"
-  "sbrs %D0,7")
-
-(define_peephole
-  [(set (cc0) (match_operand:SI 0 "register_operand" ""))
-   (set (pc)
-       (if_then_else (ge (cc0) (const_int 0))
-                     (label_ref (match_operand 1 "" ""))
-                     (pc)))]
-  "jump_over_one_insn_p (insn, operands[1])"
-  "sbrc %D0,7")
 
 (define_peephole
   [(set (cc0) (match_operand:QI 0 "register_operand" ""))