OSDN Git Service

* arm.md (cmpsi2_addneg): New ARM pattern. Add peephole2 to generate
authorrearnsha <rearnsha@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 7 Oct 2003 08:49:36 +0000 (08:49 +0000)
committerrearnsha <rearnsha@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 7 Oct 2003 08:49:36 +0000 (08:49 +0000)
it.
(cbranchne_decr1): New Thumb pattern.
* arm.c (arm_addimm_operand): New insn predicate.
* arm-protos.h: Add a prototype for it.
* arm.h (PREDICATE_CODES): Add it.

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

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

index 3298828..f8e3e05 100644 (file)
@@ -1,3 +1,12 @@
+2003-10-07  Richard Earnshaw  <rearnsha@arm.com>
+
+       * arm.md (cmpsi2_addneg): New ARM pattern. Add peephole2 to generate
+       it.
+       (cbranchne_decr1): New Thumb pattern.
+       * arm.c (arm_addimm_operand): New insn predicate.
+       * arm-protos.h: Add a prototype for it.
+       * arm.h (PREDICATE_CODES): Add it.
+
 2003-10-07  Dorit Naishlos <dorit@il.ibm.com>
 
        * sched-int.h (sched_info): New field 
index fe424d7..c16deb6 100644 (file)
@@ -65,6 +65,7 @@ extern int arm_reload_memory_operand (rtx, enum machine_mode);
 extern int arm_rhs_operand (rtx, enum machine_mode);
 extern int arm_rhsm_operand (rtx, enum machine_mode);
 extern int arm_add_operand (rtx, enum machine_mode);
+extern int arm_addimm_operand (rtx, enum machine_mode);
 extern int arm_not_operand (rtx, enum machine_mode);
 extern int offsettable_memory_operand (rtx, enum machine_mode);
 extern int alignable_memory_operand (rtx, enum machine_mode);
index a810791..f2441a0 100644 (file)
@@ -3750,6 +3750,15 @@ arm_add_operand (rtx op, enum machine_mode mode)
                  || const_ok_for_arm (-INTVAL (op)))));
 }
 
+/* Return TRUE for valid ARM constants (or when valid if negated).  */
+int
+arm_addimm_operand (rtx op, enum machine_mode mode)
+{
+  return (GET_CODE (op) == CONST_INT
+         && (const_ok_for_arm (INTVAL (op))
+             || const_ok_for_arm (-INTVAL (op))));
+}
+
 int
 arm_not_operand (rtx op, enum machine_mode mode)
 {
index dc21b53..77debec 100644 (file)
@@ -2681,6 +2681,7 @@ extern int making_const_table;
   {"arm_hard_register_operand", {REG}},                                        \
   {"f_register_operand", {SUBREG, REG}},                               \
   {"arm_add_operand",    {SUBREG, REG, CONST_INT}},                    \
+  {"arm_addimm_operand", {CONST_INT}},                                 \
   {"fpa_add_operand",    {SUBREG, REG, CONST_DOUBLE}},                 \
   {"fpa_rhs_operand",    {SUBREG, REG, CONST_DOUBLE}},                 \
   {"arm_rhs_operand",    {SUBREG, REG, CONST_INT}},                    \
index 4a72c69..177d54b 100644 (file)
   [(set_attr "conds" "set")]
 )
 
+;; This is the canonicalization of addsi3_compare0_for_combiner when the
+;; addend is a constant.
+(define_insn "*cmpsi2_addneg"
+  [(set (reg:CC CC_REGNUM)
+       (compare:CC
+        (match_operand:SI 1 "s_register_operand" "r,r")
+        (match_operand:SI 2 "arm_addimm_operand" "I,L")))
+   (set (match_operand:SI 0 "s_register_operand" "=r,r")
+       (plus:SI (match_dup 1)
+                (match_operand:SI 3 "arm_addimm_operand" "L,I")))]
+  "TARGET_ARM && INTVAL (operands[2]) == -INTVAL (operands[3])"
+  "@
+   sub%?s\\t%0, %1, %2
+   add%?s\\t%0, %1, #%n2"
+  [(set_attr "conds" "set")]
+)
+
+;; Convert the sequence
+;;  sub  rd, rn, #1
+;;  cmn  rd, #1        (equivalent to cmp rd, #-1)
+;;  bne  dest
+;; into
+;;  subs rd, rn, #1
+;;  bcs  dest  ((unsigned)rn >= 1)
+;; similarly for the beq variant using bcc.
+;; This is a common looping idiom (while (n--))
+(define_peephole2
+  [(set (match_operand:SI 0 "s_register_operand" "")
+       (plus:SI (match_operand:SI 1 "s_register_operand" "")
+                (const_int -1)))
+   (set (match_operand 2 "cc_register" "")
+       (compare (match_dup 0) (const_int -1)))
+   (set (pc)
+       (if_then_else (match_operator 3 "equality_operator"
+                      [(match_dup 2) (const_int 0)])
+                     (match_operand 4 "" "")
+                     (match_operand 5 "" "")))]
+  "TARGET_ARM && peep2_reg_dead_p (3, operands[2])"
+  [(parallel[
+    (set (match_dup 2)
+        (compare:CC
+         (match_dup 1) (const_int 1)))
+    (set (match_dup 0) (plus:SI (match_dup 1) (const_int -1)))])
+   (set (pc)
+       (if_then_else (match_op_dup 3 [(match_dup 2) (const_int 0)])
+                     (match_dup 4)
+                     (match_dup 5)))]
+  "operands[2] = gen_rtx_REG (CCmode, CC_REGNUM);
+   operands[3] = gen_rtx_fmt_ee ((GET_CODE (operands[3]) == NE
+                                 ? GEU : LTU),
+                                VOIDmode, 
+                                operands[2], const0_rtx);"
+)
+
 ;; The next four insns work because they compare the result with one of
 ;; the operands, and we know that the use of the condition code is
 ;; either GEU or LTU, so we can use the carry flag from the addition
                (const_int 8))))]
 )
 
+(define_insn "*cbranchne_decr1"
+  [(set (pc)
+       (if_then_else (match_operator 3 "equality_operator"
+                      [(match_operand:SI 2 "s_register_operand" "l,l,1,l")
+                       (const_int 0)])
+                     (label_ref (match_operand 4 "" ""))
+                     (pc)))
+   (set (match_operand:SI 0 "s_register_operand" "=l,?h,?m,?m")
+       (plus:SI (match_dup 2) (const_int -1)))
+   (clobber (match_scratch:SI 1 "=X,l,&l,&l"))]
+  "TARGET_THUMB"
+  "*
+   {
+     rtx cond[2];
+     cond[0] = gen_rtx_fmt_ee ((GET_CODE (operands[3]) == NE
+                               ? GEU : LTU),
+                              VOIDmode, NULL, NULL);
+     cond[1] = operands[4];
+
+     if (which_alternative == 0)
+       output_asm_insn (\"sub\\t%0, %2, #1\", operands);
+     else if (which_alternative == 1)
+       {
+        /* We must provide an alternative for a hi reg because reload 
+           cannot handle output reloads on a jump instruction, but we
+           can't subtract into that.  Fortunately a mov from lo to hi
+           does not clobber the condition codes.  */
+        output_asm_insn (\"sub\\t%1, %2, #1\", operands);
+        output_asm_insn (\"mov\\t%0, %1\", operands);
+       }
+     else
+       {
+        /* Similarly, but the target is memory.  */
+        output_asm_insn (\"sub\\t%1, %2, #1\", operands);
+        output_asm_insn (\"str\\t%1, %0\", operands);
+       }
+
+     switch (get_attr_length (insn) - (which_alternative ? 2 : 0))
+       {
+        case 4:
+          output_asm_insn (\"b%d0\\t%l1\", &cond);
+          return \"\";
+        case 6:
+          output_asm_insn (\"b%D0\\t.LCB%=\", &cond);
+          return \"b\\t%l4\\t%@long jump\\n.LCB%=:\";
+        default:
+          output_asm_insn (\"b%D0\\t.LCB%=\", &cond);
+          return \"bl\\t%l4\\t%@far jump\\n.LCB%=:\";
+       }
+   }
+  "
+  [(set (attr "far_jump")
+        (if_then_else
+           (ior (and (eq (symbol_ref ("which_alternative"))
+                         (const_int 0))
+                     (eq_attr "length" "8"))
+                (eq_attr "length" "10"))
+           (const_string "yes")
+            (const_string "no")))
+   (set_attr_alternative "length"
+      [
+       ;; Alternative 0
+       (if_then_else
+        (and (ge (minus (match_dup 4) (pc)) (const_int -250))
+             (le (minus (match_dup 4) (pc)) (const_int 256)))
+        (const_int 4)
+        (if_then_else
+          (and (ge (minus (match_dup 4) (pc)) (const_int -2040))
+               (le (minus (match_dup 4) (pc)) (const_int 2048)))
+          (const_int 6)
+          (const_int 8)))
+       ;; Alternative 1
+       (if_then_else
+        (and (ge (minus (match_dup 4) (pc)) (const_int -248))
+             (le (minus (match_dup 4) (pc)) (const_int 256)))
+        (const_int 6)
+        (if_then_else
+          (and (ge (minus (match_dup 4) (pc)) (const_int -2038))
+               (le (minus (match_dup 4) (pc)) (const_int 2048)))
+          (const_int 8)
+          (const_int 10)))
+       ;; Alternative 2
+       (if_then_else
+        (and (ge (minus (match_dup 4) (pc)) (const_int -248))
+             (le (minus (match_dup 4) (pc)) (const_int 256)))
+        (const_int 6)
+        (if_then_else
+          (and (ge (minus (match_dup 4) (pc)) (const_int -2038))
+               (le (minus (match_dup 4) (pc)) (const_int 2048)))
+          (const_int 8)
+          (const_int 10)))
+       ;; Alternative 3
+       (if_then_else
+        (and (ge (minus (match_dup 4) (pc)) (const_int -248))
+             (le (minus (match_dup 4) (pc)) (const_int 256)))
+        (const_int 6)
+        (if_then_else
+          (and (ge (minus (match_dup 4) (pc)) (const_int -2038))
+               (le (minus (match_dup 4) (pc)) (const_int 2048)))
+          (const_int 8)
+          (const_int 10)))])]
+)
 
 ;; Comparison and test insns