rx: Split adddi3 and subdi3 after reload.
authorRichard Henderson <rth@redhat.com>
Mon, 17 Jan 2011 18:22:04 +0000 (10:22 -0800)
committerRichard Henderson <rth@gcc.gnu.org>
Mon, 17 Jan 2011 18:22:04 +0000 (10:22 -0800)
The formulation of the pre-reload pattern allows the lower_subreg
pass to properly split the patterns.  This also required re-writing
rx_source_operand and related predicates to accept subregs.

From-SVN: r168929

gcc/ChangeLog
gcc/config/rx/predicates.md
gcc/config/rx/rx.md

index 8683ed3291d9b7ef9b36c6cd07b0be239742fdf5..e7f9d749eef3c2e0e295a747392ec5aba60e231c 100644 (file)
@@ -1,5 +1,16 @@
 2011-01-17  Richard Henderson  <rth@redhat.com>
 
+       * config/rx/predicates.md (rx_constshift_operand): Use match_test.
+       (rx_restricted_mem_operand): New.
+       (rx_shift_operand): Use register_operand.
+       (rx_source_operand, rx_compare_operand): Likewise.
+       * config/rx/rx.md (addsi3_flags): New expander.
+       (adddi3): Rewrite as expander.
+       (adc_internal, *adc_flags, adddi3_internal): New patterns.
+       (subsi3_flags): New expander.
+       (subdi3): Rewrite as expander.
+       (sbb_internal, *sbb_flags, subdi3_internal): New patterns.
+
        * config/rx/rx.c (RX_BUILTIN_SAT): Remove.
        (rx_init_builtins): Remove sat builtin.
        (rx_expand_builtin): Likewise.
index 5ae5d2220e0c6a6420a2dbf4f9f2d450694b9024..608fca5f9255123385aafe8d0e1f8355cdb4699e 100644 (file)
 ;; Only small integers or a value in a register are permitted.
 
 (define_predicate "rx_shift_operand"
-  (match_code "const_int,reg")
-  {
-    if (CONST_INT_P (op))
-      return IN_RANGE (INTVAL (op), 0, 31);
-    return true;
-  }
+  (ior (match_operand 0 "register_operand")
+       (and (match_code "const_int")
+           (match_test "IN_RANGE (INTVAL (op), 0, 31)")))
 )
 
 (define_predicate "rx_constshift_operand"
-  (match_code "const_int")
-  {
-    return IN_RANGE (INTVAL (op), 0, 31);
-  }
+  (and (match_code "const_int")
+       (match_test "IN_RANGE (INTVAL (op), 0, 31)"))
+)
+
+(define_predicate "rx_restricted_mem_operand"
+  (and (match_code "mem")
+       (match_test "rx_is_restricted_memory_address (XEXP (op, 0), mode)"))
 )
 
 ;; Check that the operand is suitable as the source operand
 ;; and a restricted subset of memory addresses are allowed.
 
 (define_predicate "rx_source_operand"
-  (match_code "const_int,const_double,const,symbol_ref,label_ref,reg,mem")
-  {
-    if (CONSTANT_P (op))
-      return rx_is_legitimate_constant (op);
-
-    if (! MEM_P (op))
-      return true;
-      
-    /* Do not allow size conversions whilst accessing memory.  */
-    if (GET_MODE (op) != mode)
-      return false;
-
-    return rx_is_restricted_memory_address (XEXP (op, 0), mode);
-  }
+  (ior (match_operand 0 "register_operand")
+       (match_operand 0 "immediate_operand")
+       (match_operand 0 "rx_restricted_mem_operand"))
 )
 
 ;; Check that the operand is suitable as the source operand
 ;; CONST_INTs are not.
 
 (define_predicate "rx_compare_operand"
-  (match_code "subreg,reg,mem")
-  {
-    if (GET_CODE (op) == SUBREG)
-      return REG_P (XEXP (op, 0));
-    
-    if (! MEM_P (op))
-      return true;
-
-    return rx_is_restricted_memory_address (XEXP (op, 0), mode);
-  }
+  (ior (match_operand 0 "register_operand")
+       (match_operand 0 "rx_restricted_mem_operand"))
 )
 
 ;; Return true if OP is a store multiple operation.  This looks like:
index a3db92c0ad5034e18ce99582f88b231c3fe5489d..d8cd66d63de0f21d50fba46b238c568ae131bd43 100644 (file)
    (set_attr "length"   "2,2,2,3,4,5,6,2,3,3,4,5,6,5")]
 )
 
-(define_insn "adddi3"
-  [(set (match_operand:DI          0 "register_operand" "=r,r,r,r,r,r")
-       (plus:DI (match_operand:DI 1 "register_operand" "%0,0,0,0,0,0")
-                (match_operand:DI 2 "rx_source_operand"
-                                  "r,Sint08,Sint16,Sint24,i,Q")))
+;; A helper to expand the above with the CC_MODE filled in.
+(define_expand "addsi3_flags"
+  [(parallel [(set (match_operand:SI 0 "register_operand")
+                  (plus:SI (match_operand:SI 1 "register_operand")
+                           (match_operand:SI 2 "rx_source_operand")))
+             (set (reg:CC_ZSC CC_REG)
+                  (compare:CC_ZSC (plus:SI (match_dup 1) (match_dup 2))
+                                  (const_int 0)))])]
+)
+
+(define_insn "adc_internal"
+  [(set (match_operand:SI     0 "register_operand"  "=r,r,r,r,r,r")
+       (plus:SI
+         (plus:SI
+           (ltu:SI (reg:CC CC_REG) (const_int 0))
+           (match_operand:SI 1 "register_operand"  "%0,0,0,0,0,0"))
+         (match_operand:SI   2 "rx_source_operand" "r,Sint08,Sint16,Sint24,i,Q")))
+    (clobber (reg:CC CC_REG))]
+  "reload_completed"
+  "adc %2,%0"
+  [(set_attr "timings" "11,11,11,11,11,33")
+   (set_attr "length"   "3,4,5,6,7,6")]
+)
+
+(define_insn "*adc_flags"
+  [(set (match_operand:SI     0 "register_operand"  "=r,r,r,r,r,r")
+       (plus:SI
+         (plus:SI
+           (ltu:SI (reg:CC CC_REG) (const_int 0))
+           (match_operand:SI 1 "register_operand"  "%0,0,0,0,0,0"))
+         (match_operand:SI   2 "rx_source_operand" "r,Sint08,Sint16,Sint24,i,Q")))
+   (set (reg CC_REG)
+       (compare 
+         (plus:SI
+           (plus:SI
+             (ltu:SI (reg:CC CC_REG) (const_int 0))
+             (match_dup 1))
+           (match_dup 2))
+         (const_int 0)))]
+  "reload_completed && rx_match_ccmode (insn, CC_ZSCmode)"
+  "adc %2,%0"
+  [(set_attr "timings" "11,11,11,11,11,33")
+   (set_attr "length"   "3,4,5,6,7,6")]
+)
+
+(define_expand "adddi3"
+  [(set (match_operand:DI          0 "register_operand" "")
+       (plus:DI (match_operand:DI 1 "register_operand" "")
+                (match_operand:DI 2 "rx_source_operand" "")))]
+  ""
+{
+  rtx op0l, op0h, op1l, op1h, op2l, op2h;
+
+  op0l = gen_lowpart (SImode, operands[0]);
+  op1l = gen_lowpart (SImode, operands[1]);
+  op2l = gen_lowpart (SImode, operands[2]);
+  op0h = gen_highpart (SImode, operands[0]);
+  op1h = gen_highpart (SImode, operands[1]);
+  op2h = gen_highpart_mode (SImode, DImode, operands[2]);
+
+  emit_insn (gen_adddi3_internal (op0l, op0h, op1l, op2l, op1h, op2h));
+  DONE;
+})
+
+(define_insn_and_split "adddi3_internal"
+  [(set (match_operand:SI          0 "register_operand"  "=r")
+       (plus:SI (match_operand:SI 2 "register_operand"  "r")
+                (match_operand:SI 3 "rx_source_operand" "riQ")))
+   (set (match_operand:SI          1 "register_operand"  "=r")
+       (plus:SI
+         (plus:SI
+           (ltu:SI (plus:SI (match_dup 2) (match_dup 3)) (match_dup 2))
+           (match_operand:SI      4 "register_operand"  "%1"))
+         (match_operand:SI        5 "rx_source_operand" "riQ")))
+   (clobber (match_scratch:SI      6                     "=&r"))
    (clobber (reg:CC CC_REG))]
   ""
-  "add\t%L2, %L0\n\tadc\t%H2, %H0"
-  [(set_attr "timings" "22,22,22,22,22,44")
-   (set_attr "length" "5,7,9,11,13,11")]
-)
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+{
+  rtx op0l = operands[0];
+  rtx op0h = operands[1];
+  rtx op1l = operands[2];
+  rtx op2l = operands[3];
+  rtx op1h = operands[4];
+  rtx op2h = operands[5];
+  rtx scratch = operands[6];
+  rtx x;
+
+  if (reg_overlap_mentioned_p (op0l, op1h))
+    {
+      emit_move_insn (scratch, op0l);
+      op1h = scratch;
+      if (reg_overlap_mentioned_p (op0l, op2h))
+       op2h = scratch;
+    }
+  else if (reg_overlap_mentioned_p (op0l, op2h))
+    {
+      emit_move_insn (scratch, op0l);
+      op2h = scratch;
+    }
+
+  if (rtx_equal_p (op0l, op1l))
+    ;
+  else if (rtx_equal_p (op0l, op2l))
+    x = op1l, op1l = op2l, op2l = x;
+  emit_insn (gen_addsi3_flags (op0l, op1l, op2l));
+
+  if (rtx_equal_p (op0h, op1h))
+    ;
+  else if (rtx_equal_p (op0h, op2h))
+    x = op1h, op1h = op2h, op2h = x;
+  else
+    {
+      emit_move_insn (op0h, op1h);
+      op1h = op0h;
+    }
+  emit_insn (gen_adc_internal (op0h, op1h, op2h));
+  DONE;
+})
 
 (define_insn "andsi3"
   [(set (match_operand:SI         0 "register_operand"  "=r,r,r,r,r,r,r,r,r")
    (set_attr "length" "2,2,6,3,5")]
 )
 
-(define_insn "subdi3"
-  [(set (match_operand:DI           0 "register_operand" "=r,r")
-       (minus:DI (match_operand:DI 1 "register_operand"  "0,0")
-                 (match_operand:DI 2 "rx_source_operand" "r,Q")))
+;; A helper to expand the above with the CC_MODE filled in.
+(define_expand "subsi3_flags"
+  [(parallel [(set (match_operand:SI 0 "register_operand")
+                  (minus:SI (match_operand:SI 1 "register_operand")
+                            (match_operand:SI 2 "rx_source_operand")))
+             (set (reg:CC_ZSC CC_REG)
+                  (compare:CC_ZSC (minus:SI (match_dup 1) (match_dup 2))
+                                  (const_int 0)))])]
+)
+
+(define_insn "sbb_internal"
+  [(set (match_operand:SI     0 "register_operand"   "=r,r")
+       (minus:SI
+         (minus:SI
+           (match_operand:SI 1 "register_operand"   " 0,0")
+           (match_operand:SI 2 "rx_compare_operand" " r,Q"))
+         (geu:SI (reg:CC CC_REG) (const_int 0))))
+    (clobber (reg:CC CC_REG))]
+  "reload_completed"
+  "sbb\t%2, %0"
+  [(set_attr "timings" "11,33")
+   (set_attr "length"  "3,6")]
+)
+
+(define_insn "*sbb_flags"
+  [(set (match_operand:SI     0 "register_operand"   "=r,r")
+       (minus:SI
+         (minus:SI
+           (match_operand:SI 1 "register_operand"   " 0,0")
+           (match_operand:SI 2 "rx_compare_operand" " r,Q"))
+         (geu:SI (reg:CC CC_REG) (const_int 0))))
+   (set (reg CC_REG)
+       (compare
+         (minus:SI
+           (minus:SI (match_dup 1) (match_dup 2))
+           (geu:SI (reg:CC CC_REG) (const_int 0)))
+         (const_int 0)))]
+  "reload_completed"
+  "sbb\t%2, %0"
+  [(set_attr "timings" "11,33")
+   (set_attr "length"  "3,6")]
+)
+
+(define_expand "subdi3"
+  [(set (match_operand:DI           0 "register_operand" "")
+       (minus:DI (match_operand:DI 1 "register_operand" "")
+                 (match_operand:DI 2 "rx_source_operand" "")))]
+  ""
+{
+  rtx op0l, op0h, op1l, op1h, op2l, op2h;
+
+  op0l = gen_lowpart (SImode, operands[0]);
+  op1l = gen_lowpart (SImode, operands[1]);
+  op2l = gen_lowpart (SImode, operands[2]);
+  op0h = gen_highpart (SImode, operands[0]);
+  op1h = gen_highpart (SImode, operands[1]);
+  op2h = gen_highpart_mode (SImode, DImode, operands[2]);
+
+  emit_insn (gen_subdi3_internal (op0l, op0h, op1l, op2l, op1h, op2h));
+  DONE;
+})
+
+(define_insn_and_split "subdi3_internal"
+  [(set (match_operand:SI          0 "register_operand"   "=&r,&r")
+       (minus:SI (match_operand:SI 2 "register_operand"  "  0, r")
+                 (match_operand:SI 3 "rx_source_operand" "rnQ, r")))
+   (set (match_operand:SI          1 "register_operand"   "= r, r")
+       (minus:SI
+         (minus:SI
+           (match_operand:SI      4 "register_operand"   "  1, 1")
+           (match_operand:SI      5 "rx_compare_operand" " rQ,rQ"))
+         (geu:SI (match_dup 2) (match_dup 3))))
    (clobber (reg:CC CC_REG))]
   ""
-  "sub\t%L2, %L0\n\tsbb\t%H2, %H0"
-  [(set_attr "timings" "22,44")
-   (set_attr "length" "5,11")]
-)
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+{
+  emit_insn (gen_subsi3_flags (operands[0], operands[2], operands[3]));
+  emit_insn (gen_sbb_internal (operands[1], operands[4], operands[5]));
+  DONE;
+})
 
 (define_insn "xorsi3"
   [(set (match_operand:SI         0 "register_operand" "=r,r,r,r,r,r")