rx: Rewrite the bit manipulation patterns.
authorRichard Henderson <rth@redhat.com>
Mon, 17 Jan 2011 18:16:39 +0000 (10:16 -0800)
committerRichard Henderson <rth@gcc.gnu.org>
Mon, 17 Jan 2011 18:16:39 +0000 (10:16 -0800)
The patterns represented with ashift 1 canonically need to have
the ashift as the first operand of the logical operation.

Leave insv represented as a zero_extract store.
Implement a variable store to a 1 bit field as tst+bmne.
Implement a variable store of a condition into a 1 bit field with bmcc.

From-SVN: r168927

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

index a58c1eb58284cca4a52e19f77452ab4fa6460080..4b6aa41acd784a7084400bd5feedfd785ff35a3e 100644 (file)
@@ -1,5 +1,15 @@
 2011-01-17  Richard Henderson  <rth@redhat.com>
 
+       * config/rx/predicates.md (rshift_operator): New.
+       * config/rx/rx.c (rx_expand_insv): Remove.
+       * config/rx/rx-protos.h: Update.
+       * config/rx/rx.md (*bitset): Rename from bitset.  Swap the ashift
+       operand to the canonical position.
+       (*bitset_in_memory, *bitinvert, *bitinvert_in_memory): Similarly.
+       (*bitclr, *bitclr_in_memory): Similarly.
+       (*insv_imm, rx_insv_reg, *insv_cond, *bmcc, *insv_cond_lt): New.
+       (insv): Retain the zero_extract in the expansion.
+
        * config/rx/rx.md (bswapsi2): Use = not + for output reload.
        (bswaphi2, bitinvert, revw): Likewise.
 
index 0ab4df3aac9768a440cfff9d9ff44da5f918a235..5ae5d2220e0c6a6420a2dbf4f9f2d450694b9024 100644 (file)
 (define_predicate "rx_fp_comparison_operator"
   (match_code "eq,ne,lt,ge,ordered,unordered,uneq,unlt,unge,ltgt")
 )
+
+(define_predicate "rshift_operator"
+  (match_code "ashiftrt,lshiftrt")
+)
index 9bb76b2afe74b979d60815fc33e5920ebec7d2b0..3c3f2d471247a6594cb78098b676feff4546e6ea 100644 (file)
@@ -33,7 +33,6 @@ extern int            rx_initial_elimination_offset (int, int);
 extern void             rx_emit_stack_popm (rtx *, bool);
 extern void             rx_emit_stack_pushm (rtx *);
 extern void            rx_expand_epilogue (bool);
-extern bool            rx_expand_insv (rtx *);
 extern char *          rx_gen_move_template (rtx *, bool);
 extern bool            rx_is_legitimate_constant (rtx);
 extern bool            rx_is_mode_dependent_addr (rtx);
index 16646aeb4f24fb66e0a7ce1b7fb3e1b544e444cf..8cc46e7af68caeae4e3508c29d4bcc8af8c1dbd4 100644 (file)
@@ -2339,48 +2339,6 @@ rx_is_ms_bitfield_layout (const_tree record_type ATTRIBUTE_UNUSED)
   /* The packed attribute overrides the MS behaviour.  */
   return ! TYPE_PACKED (record_type);
 }
-
-/* Try to generate code for the "isnv" pattern which inserts bits
-   into a word.
-     operands[0] => Location to be altered.
-     operands[1] => Number of bits to change.
-     operands[2] => Starting bit.
-     operands[3] => Value to insert.
-   Returns TRUE if successful, FALSE otherwise.  */
-
-bool
-rx_expand_insv (rtx * operands)
-{
-  if (INTVAL (operands[1]) != 1
-      || ! CONST_INT_P (operands[3]))
-    return false;
-
-  if (MEM_P (operands[0])
-      && INTVAL (operands[2]) > 7)
-    return false;
-
-  switch (INTVAL (operands[3]))
-    {
-    case 0:
-      if (MEM_P (operands[0]))
-       emit_insn (gen_bitclr_in_memory (operands[0], operands[0],
-                                        operands[2]));
-      else
-       emit_insn (gen_bitclr (operands[0], operands[0], operands[2]));
-      break;
-    case 1:
-    case -1:
-      if (MEM_P (operands[0]))
-       emit_insn (gen_bitset_in_memory (operands[0], operands[0],
-                                        operands[2]));
-      else
-       emit_insn (gen_bitset (operands[0], operands[0], operands[2]));
-      break;
-   default:
-      return false;
-    }
-  return true;
-}
 \f
 /* Returns true if X a legitimate constant for an immediate
    operand on the RX.  X is already known to satisfy CONSTANT_P.  */
index 864b4a5a808c101bf242e6391718ead65d3aa3f5..7fa8668e46c8ebdc369ff8f8634dc9b6f08f2bb5 100644 (file)
 )
 \f
 ;; Bit manipulation instructions.
-;; Note - there are two versions of each pattern because the memory
-;; accessing versions use QImode whilst the register accessing
-;; versions use SImode.
-;; The peephole are here because the combiner only looks at a maximum
-;; of three instructions at a time.
 
-(define_insn "bitset"
+;; ??? The *_in_memory patterns will not be matched without further help.
+;; At one time we had the insv expander generate them, but I suspect that
+;; in general we get better performance by exposing the register load to
+;; the optimizers.
+;;
+;; An alternate solution would be to re-organize these patterns such
+;; that allow both register and memory operands.  This would allow the
+;; register allocator to spill and not load the register operand.  This
+;; would be possible only for operations for which we have a constant
+;; bit offset, so that we can adjust the address by ofs/8 and replace
+;; the offset in the insn by ofs%8.
+
+(define_insn "*bitset"
   [(set (match_operand:SI                    0 "register_operand" "=r")
-       (ior:SI (match_operand:SI            1 "register_operand" "0")
-               (ashift:SI (const_int 1)
-                          (match_operand:SI 2 "nonmemory_operand" "ri"))))]
+       (ior:SI (ashift:SI (const_int 1)
+                          (match_operand:SI 1 "rx_shift_operand" "ri"))
+               (match_operand:SI            2 "register_operand" "0")))]
   ""
-  "bset\t%2, %0"
+  "bset\t%1, %0"
   [(set_attr "length" "3")]
 )
 
-(define_insn "bitset_in_memory"
-  [(set (match_operand:QI                    0 "memory_operand" "=m")
-       (ior:QI (match_operand:QI            1 "memory_operand" "0")
-               (ashift:QI (const_int 1)
-                          (match_operand:QI 2 "nonmemory_operand" "ri"))))]
+(define_insn "*bitset_in_memory"
+  [(set (match_operand:QI                    0 "memory_operand" "+Q")
+       (ior:QI (ashift:QI (const_int 1)
+                          (match_operand:QI 1 "nonmemory_operand" "ri"))
+               (match_dup 0)))]
   ""
-  "bset\t%2, %0.B"
+  "bset\t%1, %0.B"
   [(set_attr "length" "3")
    (set_attr "timings" "34")]
 )
 
 (define_insn "*bitinvert"
   [(set (match_operand:SI 0 "register_operand" "=r")
-       (xor:SI (match_operand:SI 1 "register_operand" "0")
-               (ashift:SI (const_int 1)
-                          (match_operand:SI 2 "nonmemory_operand" "ri"))))]
+       (xor:SI (ashift:SI (const_int 1)
+                          (match_operand:SI 1 "rx_shift_operand" "ri"))
+               (match_operand:SI 2 "register_operand" "0")))]
   ""
-  "bnot\t%2, %0"
+  "bnot\t%1, %0"
   [(set_attr "length" "3")]
 )
 
-(define_insn "bitinvert_in_memory"
-  [(set (match_operand:QI 0 "memory_operand" "+m")
-       (xor:QI (match_operand:QI 1 "register_operand" "0")
-               (ashift:QI (const_int 1)
-                          (match_operand:QI 2 "nonmemory_operand" "ri"))))]
+(define_insn "*bitinvert_in_memory"
+  [(set (match_operand:QI 0 "memory_operand" "+Q")
+       (xor:QI (ashift:QI (const_int 1)
+                          (match_operand:QI 1 "nonmemory_operand" "ri"))
+               (match_dup 0)))]
   ""
-  "bnot\t%2, %0.B"
+  "bnot\t%1, %0.B"
   [(set_attr "length" "5")
    (set_attr "timings" "33")]
 )
 
-(define_insn "bitclr"
+(define_insn "*bitclr"
   [(set (match_operand:SI 0 "register_operand" "=r")
-       (and:SI (match_operand:SI 1 "register_operand" "0")
-               (not:SI
+       (and:SI (not:SI
                  (ashift:SI
                    (const_int 1)
-                   (match_operand:SI 2 "nonmemory_operand" "ri")))))]
+                   (match_operand:SI 1 "rx_shift_operand" "ri")))
+               (match_operand:SI 2 "register_operand" "0")))]
   ""
-  "bclr\t%2, %0"
+  "bclr\t%1, %0"
   [(set_attr "length" "3")]
 )
 
-(define_insn "bitclr_in_memory"
-  [(set (match_operand:QI 0 "memory_operand" "=m")
-       (and:QI (match_operand:QI 1 "memory_operand" "0")
-               (not:QI
+(define_insn "*bitclr_in_memory"
+  [(set (match_operand:QI 0 "memory_operand" "+Q")
+       (and:QI (not:QI
                  (ashift:QI
                    (const_int 1)
-                   (match_operand:QI 2 "nonmemory_operand" "ri")))))]
+                   (match_operand:QI 1 "nonmemory_operand" "ri")))
+               (match_dup 0)))]
   ""
-  "bclr\t%2, %0.B"
+  "bclr\t%1, %0.B"
   [(set_attr "length" "3")
    (set_attr "timings" "34")]
 )
 
+(define_insn "*insv_imm"
+  [(set (zero_extract:SI
+         (match_operand:SI 0 "register_operand" "+r")
+         (const_int 1)
+         (match_operand:SI 1 "rx_shift_operand" "ri"))
+       (match_operand:SI 2 "const_int_operand" ""))]
+  ""
+{
+  if (INTVAL (operands[2]) & 1)
+    return "bset\t%1, %0";
+  else
+    return "bclr\t%1, %0";
+}
+  [(set_attr "length" "3")]
+)
+
+(define_insn_and_split "rx_insv_reg"
+  [(set (zero_extract:SI
+         (match_operand:SI 0 "register_operand" "+r")
+         (const_int 1)
+         (match_operand:SI 1 "const_int_operand" ""))
+       (match_operand:SI 2 "register_operand" "r"))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "#"
+  "reload_completed"
+  [(set (zero_extract:SI (match_dup 0) (const_int 1) (match_dup 1))
+       (match_dup 3))]
+{
+  rtx flags, x;
+
+  /* Emit tst #1, op2.  */
+  flags = gen_rtx_REG (CC_ZSmode, CC_REG);
+  x = gen_rtx_AND (SImode, operands[2], const1_rtx);
+  x = gen_rtx_COMPARE (CC_ZSmode, x, const0_rtx);
+  x = gen_rtx_SET (VOIDmode, flags, x);
+  emit_insn (x);
+
+  /* Emit bmne.  */
+  operands[3] = gen_rtx_NE (SImode, flags, const0_rtx);
+})
+
+(define_insn_and_split "*insv_cond"
+  [(set (zero_extract:SI
+         (match_operand:SI 0 "register_operand" "+r")
+         (const_int 1)
+         (match_operand:SI 1 "const_int_operand" ""))
+       (match_operator:SI 4 "comparison_operator"
+         [(match_operand:SI 2 "register_operand" "r")
+          (match_operand:SI 3 "rx_source_operand" "riQ")]))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "#"
+  "reload_completed"
+  [(set (zero_extract:SI (match_dup 0) (const_int 1) (match_dup 1))
+       (match_dup 4))]
+{
+  rtx flags, x;
+
+  flags = gen_rtx_REG (CCmode, CC_REG);
+  x = gen_rtx_COMPARE (CCmode, operands[2], operands[3]);
+  x = gen_rtx_SET (VOIDmode, flags, x);
+  emit_insn (x);
+
+  operands[4] = gen_rtx_fmt_ee (GET_CODE (operands[4]), SImode,
+                               flags, const0_rtx);
+})
+
+(define_insn "*bmcc"
+  [(set (zero_extract:SI
+         (match_operand:SI 0 "register_operand" "+r")
+         (const_int 1)
+         (match_operand:SI 1 "const_int_operand" ""))
+       (match_operator:SI 2 "comparison_operator"
+         [(reg CC_REG) (const_int 0)]))]
+  "reload_completed"
+  "bm%B2\t%1, %0"
+  [(set_attr "length" "3")]
+)
+
+;; Work around the fact that X=Y<0 is preferentially expanded as a shift.
+(define_insn_and_split "*insv_cond_lt"
+  [(set (zero_extract:SI
+         (match_operand:SI 0 "register_operand" "+r")
+         (const_int 1)
+         (match_operand:SI 1 "const_int_operand" ""))
+       (match_operator:SI 3 "rshift_operator"
+         [(match_operand:SI 2 "register_operand" "r")
+          (const_int 31)]))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "#"
+  ""
+  [(parallel [(set (zero_extract:SI (match_dup 0) (const_int 1) (match_dup 1))
+                  (lt:SI (match_dup 2) (const_int 0)))
+             (clobber (reg:CC CC_REG))])]
+  ""
+)
+
 (define_expand "insv"
-  [(set (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand") ;; Destination
-                        (match_operand    1 "immediate_operand")    ;; # of bits to set
-                        (match_operand    2 "immediate_operand"))   ;; Starting bit
-       (match_operand                3 "immediate_operand"))]       ;; Bits to insert
+  [(set (zero_extract:SI
+         (match_operand:SI 0 "register_operand")       ;; Destination
+         (match_operand:SI 1 "const_int_operand")      ;; # of bits to set
+         (match_operand:SI 2 "nonmemory_operand"))     ;; Starting bit
+       (match_operand:SI   3 "nonmemory_operand"))]    ;; Bits to insert
   ""
-  {
-    if (rx_expand_insv (operands))
+{
+  /* We only handle single-bit inserts.  */
+  if (!CONST_INT_P (operands[1]) || INTVAL (operands[1]) != 1)
+    FAIL;
+
+  /* Either the bit to insert or the position must be constant.  */
+  if (CONST_INT_P (operands[3]))
+    operands[3] = GEN_INT (INTVAL (operands[3]) & 1);
+  else if (CONST_INT_P (operands[2]))
+    {
+      emit_insn (gen_rx_insv_reg (operands[0], operands[2], operands[3]));
       DONE;
+    }
+  else
     FAIL;
-  }
-)
+})
 \f
 ;; Atomic exchange operation.