rx.md: Add peepholes and patterns to combine extending loads and simple arithmetic...
authorNick Clifton <nickc@redhat.com>
Wed, 30 Mar 2011 14:09:09 +0000 (14:09 +0000)
committerNick Clifton <nickc@gcc.gnu.org>
Wed, 30 Mar 2011 14:09:09 +0000 (14:09 +0000)
* config/rx/rx.md: Add peepholes and patterns to combine
extending loads and simple arithmetic instructions.
* config/rx/rx.h (ADJUST_INSN_LENGTH): Define.
        * config/rx/rx-protos.h (rx_adjust_insn_length): Prototype.
        * config/rx/rx.c (rx_is_legitimate_address): Allow QI and HI
modes to use pre-decrement and post-increment addressing.
        (rx_is_restricted_memory_address): Add range checking of REG+INT
addresses.
        (rx_print_operand): Add support for %Q.
        Fix handling of %Q.
        (rx_memory_move_cost): Adjust cost of stores.
        (rx_adjust_insn_length): New function.

From-SVN: r171724

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

index 9458d99393e4c6db6478f51be460a5a605cd60c6..fb3cc9e708b69fd910ab160521ddeb4c1c684b45 100644 (file)
@@ -1,3 +1,18 @@
+2011-03-30  Nick Clifton  <nickc@redhat.com>
+
+       * config/rx/rx.md: Add peepholes and patterns to combine
+       extending loads and simple arithmetic instructions.
+       * config/rx/rx.h (ADJUST_INSN_LENGTH): Define.
+        * config/rx/rx-protos.h (rx_adjust_insn_length): Prototype.
+        * config/rx/rx.c (rx_is_legitimate_address): Allow QI and HI
+       modes to use pre-decrement and post-increment addressing.
+        (rx_is_restricted_memory_address): Add range checking of REG+INT
+       addresses.
+        (rx_print_operand): Add support for %Q.
+        Fix handling of %Q.
+        (rx_memory_move_cost): Adjust cost of stores.
+        (rx_adjust_insn_length): New function.
+
 2011-03-30  Jakub Jelinek  <jakub@redhat.com>
 
        PR c/48305
index ab04fdd7ce0fde280ec62b984533ce47bd7bf332..17f60833e710d38d405029a3b783aae451b98b93 100644 (file)
@@ -31,16 +31,17 @@ extern void         rx_expand_prologue (void);
 extern int             rx_initial_elimination_offset (int, int);
 
 #ifdef RTX_CODE
+extern int             rx_adjust_insn_length (rtx, int);
 extern void             rx_emit_stack_popm (rtx *, bool);
 extern void             rx_emit_stack_pushm (rtx *);
 extern void            rx_expand_epilogue (bool);
 extern char *          rx_gen_move_template (rtx *, bool);
 extern bool            rx_is_legitimate_constant (rtx);
 extern bool            rx_is_restricted_memory_address (rtx, Mmode);
+extern bool            rx_match_ccmode (rtx, Mmode);
 extern void            rx_notice_update_cc (rtx body, rtx insn);
 extern void            rx_split_cbranch (Mmode, Rcode, rtx, rtx, rtx);
 extern Mmode           rx_select_cc_mode (Rcode, rtx, rtx);
-extern bool            rx_match_ccmode (rtx, Mmode);
 #endif
 
 #endif /* GCC_RX_PROTOS_H */
index a6a63ac01ab990d7d3ab37e669a467c23106f170..0ed4ee634d2be5b10c339a9b1ab2b1fe3cd9a2a7 100644 (file)
@@ -86,7 +86,7 @@ rx_is_legitimate_address (Mmode mode, rtx x, bool strict ATTRIBUTE_UNUSED)
     /* Register Indirect.  */
     return true;
 
-  if (GET_MODE_SIZE (mode) == 4
+  if (GET_MODE_SIZE (mode) <= 4
       && (GET_CODE (x) == PRE_DEC || GET_CODE (x) == POST_INC))
     /* Pre-decrement Register Indirect or
        Post-increment Register Indirect.  */
@@ -117,7 +117,7 @@ rx_is_legitimate_address (Mmode mode, rtx x, bool strict ATTRIBUTE_UNUSED)
 
            if (val < 0)
              return false;
-           
+
            switch (GET_MODE_SIZE (mode))
              {
              default: 
@@ -126,7 +126,7 @@ rx_is_legitimate_address (Mmode mode, rtx x, bool strict ATTRIBUTE_UNUSED)
              case 1: factor = 1; break;
              }
 
-           if (val > (65535 * factor))
+           if (val >= (0x10000 * factor))
              return false;
            return (val % factor) == 0;
          }
@@ -167,8 +167,6 @@ rx_is_legitimate_address (Mmode mode, rtx x, bool strict ATTRIBUTE_UNUSED)
 bool
 rx_is_restricted_memory_address (rtx mem, enum machine_mode mode)
 {
-  rtx base, index;
-
   if (! rx_is_legitimate_address
       (mode, mem, reload_in_progress || reload_completed))
     return false;
@@ -184,11 +182,18 @@ rx_is_restricted_memory_address (rtx mem, enum machine_mode mode)
       return false;
 
     case PLUS:
-      /* Only allow REG+INT addressing.  */
-      base = XEXP (mem, 0);
-      index = XEXP (mem, 1);
+      {
+       rtx base, index;
+       
+       /* Only allow REG+INT addressing.  */
+       base = XEXP (mem, 0);
+       index = XEXP (mem, 1);
 
-      return RX_REG_P (base) && CONST_INT_P (index);
+       if (! RX_REG_P (base) || ! CONST_INT_P (index))
+         return false;
+
+       return IN_RANGE (INTVAL (index), 0, (0x10000 * GET_MODE_SIZE (mode)) - 1);
+      }
 
     case SYMBOL_REF:
       /* Can happen when small data is being supported.
@@ -387,11 +392,14 @@ rx_assemble_integer (rtx x, unsigned int size, int is_aligned)
      %L  Print low part of a DImode register, integer or address.
      %N  Print the negation of the immediate value.
      %Q  If the operand is a MEM, then correctly generate
-         register indirect or register relative addressing.  */
+         register indirect or register relative addressing.
+     %R  Like %Q but for zero-extending loads.  */
 
 static void
 rx_print_operand (FILE * file, rtx op, int letter)
 {
+  bool unsigned_load = false;
+
   switch (letter)
     {
     case 'A':
@@ -451,6 +459,7 @@ rx_print_operand (FILE * file, rtx op, int letter)
        else
          {
            unsigned int flags = flags_from_mode (mode);
+
            switch (code)
              {
              case LT:
@@ -589,10 +598,15 @@ rx_print_operand (FILE * file, rtx op, int letter)
       rx_print_integer (file, - INTVAL (op));
       break;
 
+    case 'R':
+      gcc_assert (GET_MODE_SIZE (GET_MODE (op)) < 4);
+      unsigned_load = true;
+      /* Fall through.  */
     case 'Q':
       if (MEM_P (op))
        {
          HOST_WIDE_INT offset;
+         rtx mem = op;
 
          op = XEXP (op, 0);
 
@@ -627,22 +641,24 @@ rx_print_operand (FILE * file, rtx op, int letter)
          rx_print_operand (file, op, 0);
          fprintf (file, "].");
 
-         switch (GET_MODE_SIZE (GET_MODE (op)))
+         switch (GET_MODE_SIZE (GET_MODE (mem)))
            {
            case 1:
-             gcc_assert (offset < 65535 * 1);
-             fprintf (file, "B");
+             gcc_assert (offset <= 65535 * 1);
+             fprintf (file, unsigned_load ? "UB" : "B");
              break;
            case 2:
              gcc_assert (offset % 2 == 0);
-             gcc_assert (offset < 65535 * 2);
-             fprintf (file, "W");
+             gcc_assert (offset <= 65535 * 2);
+             fprintf (file, unsigned_load ? "UW" : "W");
              break;
-           default:
+           case 4:
              gcc_assert (offset % 4 == 0);
-             gcc_assert (offset < 65535 * 4);
+             gcc_assert (offset <= 65535 * 4);
              fprintf (file, "L");
              break;
+           default:
+             gcc_unreachable ();
            }
          break;
        }
@@ -2449,8 +2465,7 @@ rx_is_legitimate_constant (rtx x)
 
        default:
          /* FIXME: Can this ever happen ?  */
-         abort ();
-         return false;
+         gcc_unreachable ();
        }
       break;
       
@@ -2593,7 +2608,7 @@ rx_trampoline_init (rtx tramp, tree fndecl, rtx chain)
 static int
 rx_memory_move_cost (enum machine_mode mode, reg_class_t regclass, bool in)
 {
-  return 2 + memory_move_secondary_cost (mode, regclass, in);
+  return (in ? 2 : 0) + memory_move_secondary_cost (mode, regclass, in);
 }
 
 /* Convert a CC_MODE to the set of flags that it represents.  */
@@ -2778,6 +2793,113 @@ rx_max_skip_for_label (rtx lab)
     return opsize - 1;
   return 0;
 }
+
+/* Compute the real length of the extending load-and-op instructions.  */
+
+int
+rx_adjust_insn_length (rtx insn, int current_length)
+{
+  rtx extend, mem, offset;
+  bool zero;
+  int factor;
+
+  switch (INSN_CODE (insn))
+    {
+    default:
+      return current_length;
+
+    case CODE_FOR_plussi3_zero_extendhi:
+    case CODE_FOR_andsi3_zero_extendhi:
+    case CODE_FOR_iorsi3_zero_extendhi:
+    case CODE_FOR_xorsi3_zero_extendhi:
+    case CODE_FOR_divsi3_zero_extendhi:
+    case CODE_FOR_udivsi3_zero_extendhi:
+    case CODE_FOR_minussi3_zero_extendhi:
+    case CODE_FOR_smaxsi3_zero_extendhi:
+    case CODE_FOR_sminsi3_zero_extendhi:
+    case CODE_FOR_multsi3_zero_extendhi:
+    case CODE_FOR_comparesi3_zero_extendqi:
+      zero = true;
+      factor = 2;
+      break;
+
+    case CODE_FOR_plussi3_sign_extendhi:
+    case CODE_FOR_andsi3_sign_extendhi:
+    case CODE_FOR_iorsi3_sign_extendhi:
+    case CODE_FOR_xorsi3_sign_extendhi:
+    case CODE_FOR_divsi3_sign_extendhi:
+    case CODE_FOR_udivsi3_sign_extendhi:
+    case CODE_FOR_minussi3_sign_extendhi:
+    case CODE_FOR_smaxsi3_sign_extendhi:
+    case CODE_FOR_sminsi3_sign_extendhi:
+    case CODE_FOR_multsi3_sign_extendhi:
+    case CODE_FOR_comparesi3_zero_extendhi:
+      zero = false;
+      factor = 2;
+      break;
+      
+    case CODE_FOR_plussi3_zero_extendqi:
+    case CODE_FOR_andsi3_zero_extendqi:
+    case CODE_FOR_iorsi3_zero_extendqi:
+    case CODE_FOR_xorsi3_zero_extendqi:
+    case CODE_FOR_divsi3_zero_extendqi:
+    case CODE_FOR_udivsi3_zero_extendqi:
+    case CODE_FOR_minussi3_zero_extendqi:
+    case CODE_FOR_smaxsi3_zero_extendqi:
+    case CODE_FOR_sminsi3_zero_extendqi:
+    case CODE_FOR_multsi3_zero_extendqi:
+    case CODE_FOR_comparesi3_sign_extendqi:
+      zero = true;
+      factor = 1;
+      break;
+      
+    case CODE_FOR_plussi3_sign_extendqi:
+    case CODE_FOR_andsi3_sign_extendqi:
+    case CODE_FOR_iorsi3_sign_extendqi:
+    case CODE_FOR_xorsi3_sign_extendqi:
+    case CODE_FOR_divsi3_sign_extendqi:
+    case CODE_FOR_udivsi3_sign_extendqi:
+    case CODE_FOR_minussi3_sign_extendqi:
+    case CODE_FOR_smaxsi3_sign_extendqi:
+    case CODE_FOR_sminsi3_sign_extendqi:
+    case CODE_FOR_multsi3_sign_extendqi:
+    case CODE_FOR_comparesi3_sign_extendhi:
+      zero = false;
+      factor = 1;
+      break;
+    }      
+
+  /* We are expecting: (SET (REG) (<OP> (REG) (<EXTEND> (MEM)))).  */
+  extend = single_set (insn);
+  gcc_assert (extend != NULL_RTX);
+
+  extend = SET_SRC (extend);
+  if (GET_CODE (XEXP (extend, 0)) == ZERO_EXTEND
+      || GET_CODE (XEXP (extend, 0)) == SIGN_EXTEND)
+    extend = XEXP (extend, 0);
+  else
+    extend = XEXP (extend, 1);
+
+  gcc_assert ((zero && (GET_CODE (extend) == ZERO_EXTEND))
+             || (! zero && (GET_CODE (extend) == SIGN_EXTEND)));
+    
+  mem = XEXP (extend, 0);
+  gcc_checking_assert (MEM_P (mem));
+  if (REG_P (XEXP (mem, 0)))
+    return (zero && factor == 1) ? 2 : 3;
+
+  /* We are expecting: (MEM (PLUS (REG) (CONST_INT))).  */
+  gcc_checking_assert (GET_CODE (XEXP (mem, 0)) == PLUS);
+  gcc_checking_assert (REG_P (XEXP (XEXP (mem, 0), 0)));
+
+  offset = XEXP (XEXP (mem, 0), 1);
+  gcc_checking_assert (GET_CODE (offset) == CONST_INT);
+
+  if (IN_RANGE (INTVAL (offset), 0, 255 * factor))
+    return (zero && factor == 1) ? 3 : 4;
+
+  return (zero && factor == 1) ? 4 : 5;
+}
 \f
 #undef  TARGET_ASM_JUMP_ALIGN_MAX_SKIP
 #define TARGET_ASM_JUMP_ALIGN_MAX_SKIP                 rx_max_skip_for_label
index f9ea20930078a9a094e35bd36123c59eff1fb7c3..14b13d955598220675e0f9598a19e03ee1c3450b 100644 (file)
@@ -630,3 +630,10 @@ typedef unsigned int CUMULATIVE_ARGS;
 #define REGISTER_MOVE_COST(MODE,FROM,TO) 2
 
 #define SELECT_CC_MODE(OP,X,Y)  rx_select_cc_mode(OP, X, Y)
+
+#define ADJUST_INSN_LENGTH(INSN,LENGTH)                                \
+  do                                                           \
+    {                                                          \
+      (LENGTH) = rx_adjust_insn_length ((INSN), (LENGTH));     \
+    }                                                          \
+  while (0)
index cd5b571dd3ad4a909be9d0ab51a085647029c08d..6ff3a1e7e2ab6dc5fb89c6dd14706113823b508a 100644 (file)
    (set_attr "length" "3,4,5,6,7,6")]
 )
 \f
+;; A set of peepholes to catch extending loads followed by arithmetic operations.
+;; We use iterators where possible to reduce the amount of typing and hence the
+;; possibilities for typos.
+
+(define_code_iterator extend_types [(zero_extend "") (sign_extend "")])
+(define_code_attr     letter       [(zero_extend "R") (sign_extend "Q")])
+
+(define_code_iterator memex_commutative [(plus "") (and "") (ior "") (xor "")])
+(define_code_iterator memex_noncomm     [(div "") (udiv "") (minus "")])
+(define_code_iterator memex_nocc        [(smax "") (smin "") (mult "")])
+
+(define_code_attr     op                [(plus "add") (and "and") (div "div") (udiv "divu") (smax "max") (smin "min") (mult "mul") (ior "or") (minus "sub") (xor "xor")])
+
+(define_peephole2
+  [(set (match_operand:SI                               0 "register_operand")
+       (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand")))
+   (parallel [(set (match_operand:SI                    2 "register_operand")
+                  (memex_commutative:SI (match_dup 0)
+                                        (match_dup 2)))
+             (clobber (reg:CC CC_REG))])]
+  "peep2_regno_dead_p (2, REGNO (operands[0]))"
+  [(parallel [(set:SI (match_dup 2)
+                     (memex_commutative:SI (match_dup 2)
+                                           (extend_types:SI (match_dup 1))))
+             (clobber (reg:CC CC_REG))])]
+)
+
+(define_peephole2
+  [(set (match_operand:SI                               0 "register_operand")
+       (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand")))
+   (parallel [(set (match_operand:SI                    2 "register_operand")
+                  (memex_commutative:SI (match_dup 2)
+                                        (match_dup 0)))
+             (clobber (reg:CC CC_REG))])]
+  "peep2_regno_dead_p (2, REGNO (operands[0]))"
+  [(parallel [(set:SI (match_dup 2)
+                     (memex_commutative:SI (match_dup 2)
+                                           (extend_types:SI (match_dup 1))))
+             (clobber (reg:CC CC_REG))])]
+)
+
+(define_peephole2
+  [(set (match_operand:SI                               0 "register_operand")
+       (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand")))
+   (parallel [(set (match_operand:SI                    2 "register_operand")
+                  (memex_noncomm:SI (match_dup 2)
+                                    (match_dup 0)))
+             (clobber (reg:CC CC_REG))])]
+  "peep2_regno_dead_p (2, REGNO (operands[0]))"
+  [(parallel [(set:SI (match_dup 2)
+                     (memex_noncomm:SI (match_dup 2)
+                                       (extend_types:SI (match_dup 1))))
+             (clobber (reg:CC CC_REG))])]
+)
+
+(define_peephole2
+  [(set (match_operand:SI                               0 "register_operand")
+       (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand")))
+   (set (match_operand:SI                               2 "register_operand")
+       (memex_nocc:SI (match_dup 0)
+                      (match_dup 2)))]
+  "peep2_regno_dead_p (2, REGNO (operands[0]))"
+  [(set:SI (match_dup 2)
+          (memex_nocc:SI (match_dup 2)
+                         (extend_types:SI (match_dup 1))))]
+)
+
+(define_peephole2
+  [(set (match_operand:SI                               0 "register_operand")
+       (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand")))
+   (set (match_operand:SI                               2 "register_operand")
+       (memex_nocc:SI (match_dup 2)
+                      (match_dup 0)))]
+  "peep2_regno_dead_p (2, REGNO (operands[0]))"
+  [(set:SI (match_dup 2)
+          (memex_nocc:SI (match_dup 2)
+                         (extend_types:SI (match_dup 1))))]
+)
+
+(define_insn "<memex_commutative:code>si3_<extend_types:code><small_int_modes:mode>"
+  [(set (match_operand:SI                                                     0 "register_operand" "=r")
+       (memex_commutative:SI (match_operand:SI                               1 "register_operand" "%0")
+                             (extend_types:SI (match_operand:small_int_modes 2 "rx_restricted_mem_operand" "Q"))))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "<memex_commutative:op>\t%<extend_types:letter>2, %0"
+  [(set_attr "timings" "33")
+   (set_attr "length"  "5")] ;; This length is corrected in rx_adjust_insn_length
+)
+
+(define_insn "<memex_noncomm:code>si3_<extend_types:code><small_int_modes:mode>"
+  [(set (match_operand:SI                                                 0 "register_operand" "=r")
+       (memex_noncomm:SI (match_operand:SI                               1 "register_operand" "0")
+                          (extend_types:SI (match_operand:small_int_modes 2 "rx_restricted_mem_operand" "Q"))))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "<memex_noncomm:op>\t%<extend_types:letter>2, %0"
+  [(set_attr "timings" "33")
+   (set_attr "length"  "5")] ;; This length is corrected in rx_adjust_insn_length
+)
+
+(define_insn "<memex_nocc:code>si3_<extend_types:code><small_int_modes:mode>"
+  [(set (match_operand:SI                                              0 "register_operand" "=r")
+       (memex_nocc:SI (match_operand:SI                               1 "register_operand" "%0")
+                      (extend_types:SI (match_operand:small_int_modes 2 "rx_restricted_mem_operand" "Q"))))]
+  ""
+  "<memex_nocc:op>\t%<extend_types:letter>2, %0"
+  [(set_attr "timings" "33")
+   (set_attr "length"  "5")] ;; This length is corrected in rx_adjust_insn_length
+)
+
+(define_peephole2
+  [(set (match_operand:SI                               0 "register_operand")
+       (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand")))
+   (set (reg:CC CC_REG)
+       (compare:CC (match_operand:SI                   2 "register_operand")
+                   (match_dup 0)))]
+  "peep2_regno_dead_p (2, REGNO (operands[0]))"
+  [(set (reg:CC CC_REG)
+       (compare:CC (match_dup 2)
+                   (extend_types:SI (match_dup 1))))]
+)
+
+(define_insn "comparesi3_<extend_types:code><small_int_modes:mode>"
+  [(set (reg:CC CC_REG)
+       (compare:CC (match_operand:SI                               0 "register_operand" "=r")
+                   (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand" "Q"))))]
+  ""
+  "cmp\t%<extend_types:letter>1, %0"
+  [(set_attr "timings" "33")
+   (set_attr "length"  "5")] ;; This length is corrected in rx_adjust_insn_length
+)
+\f
 ;; Floating Point Instructions
 
 (define_insn "addsf3"
     rtx addr2 = gen_rtx_REG (SImode, 2);
     rtx len   = gen_rtx_REG (SImode, 3);
 
-    /* Do not use when the source or destination are volatile - the SMOVF
-       instruction will read and write in word sized blocks, which may be
-       outside of the valid address range.  */
-    if (MEM_P (operands[0]) && MEM_VOLATILE_P (operands[0]))
-      FAIL;
-    if (MEM_P (operands[1]) && MEM_VOLATILE_P (operands[1]))
-      FAIL;
-
     if (REG_P (operands[0]) && (REGNO (operands[0]) == 2
                                      || REGNO (operands[0]) == 3))
       FAIL;