OSDN Git Service

* config/xtensa/xtensa.md (adddi3): Don't clobber source operand used
[pf3gnuchains/gcc-fork.git] / gcc / config / xtensa / xtensa.md
index e261b77..cc722b9 100644 (file)
@@ -34,6 +34,7 @@
   (UNSPEC_NSAU         1)
   (UNSPEC_NOP          2)
   (UNSPEC_PLT          3)
+  (UNSPEC_RET_ADDR     4)
   (UNSPECV_SET_FP      1)
 ])
 
@@ -96,6 +97,7 @@
   ""
   "
 {
+  rtx srclo;
   rtx dstlo = gen_lowpart (SImode, operands[0]);
   rtx src1lo = gen_lowpart (SImode, operands[1]);
   rtx src2lo = gen_lowpart (SImode, operands[2]);
   rtx src1hi = gen_highpart (SImode, operands[1]);
   rtx src2hi = gen_highpart (SImode, operands[2]);
 
+  /* Either source can be used for overflow checking, as long as it's
+     not clobbered by the first addition.  */
+  if (!rtx_equal_p (dstlo, src1lo))
+    srclo = src1lo;
+  else if (!rtx_equal_p (dstlo, src2lo))
+    srclo = src2lo;
+  else
+    {
+      srclo = gen_reg_rtx (SImode);
+      emit_move_insn (srclo, src1lo);
+    }
+
   emit_insn (gen_addsi3 (dstlo, src1lo, src2lo));
   emit_insn (gen_addsi3 (dsthi, src1hi, src2hi));
-  emit_insn (gen_adddi_carry (dsthi, dstlo, src2lo));
+  emit_insn (gen_adddi_carry (dsthi, dstlo, srclo));
   DONE;
 }")
 
    (set_attr "mode"    "SI")
    (set_attr "length"  "2,2,3,3,3")])
 
-(define_insn ""
+(define_insn "*addx2"
   [(set (match_operand:SI 0 "register_operand" "=a")
        (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "r")
                          (const_int 2))
    (set_attr "mode"    "SI")
    (set_attr "length"  "3")])
 
-(define_insn ""
+(define_insn "*addx4"
   [(set (match_operand:SI 0 "register_operand" "=a")
        (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "r")
                          (const_int 4))
    (set_attr "mode"    "SI")
    (set_attr "length"  "3")])
 
-(define_insn ""
+(define_insn "*addx8"
   [(set (match_operand:SI 0 "register_operand" "=a")
        (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "r")
                          (const_int 8))
   rtx src1hi = gen_highpart (SImode, operands[1]);
   rtx src2hi = gen_highpart (SImode, operands[2]);
 
-  emit_insn (gen_subsi3 (dstlo, src1lo, src2lo));
   emit_insn (gen_subsi3 (dsthi, src1hi, src2hi));
   emit_insn (gen_subdi_carry (dsthi, src1lo, src2lo));
+  emit_insn (gen_subsi3 (dstlo, src1lo, src2lo));
   DONE;
 }")
 
    (set_attr "mode"    "SI")
    (set_attr "length"  "3")])
 
-(define_insn ""
+(define_insn "*subx2"
   [(set (match_operand:SI 0 "register_operand" "=a")
        (minus:SI (mult:SI (match_operand:SI 1 "register_operand" "r")
                           (const_int 2))
    (set_attr "mode"    "SI")
    (set_attr "length"  "3")])
 
-(define_insn ""
+(define_insn "*subx4"
   [(set (match_operand:SI 0 "register_operand" "=a")
        (minus:SI (mult:SI (match_operand:SI 1 "register_operand" "r")
                           (const_int 4))
    (set_attr "mode"    "SI")
    (set_attr "length"  "3")])
 
-(define_insn ""
+(define_insn "*subx8"
   [(set (match_operand:SI 0 "register_operand" "=a")
        (minus:SI (mult:SI (match_operand:SI 1 "register_operand" "r")
                           (const_int 8))
    (set_attr "mode"    "SF")
    (set_attr "length"  "3")])
 
-(define_insn ""
+(define_insn "*recipsf2"
   [(set (match_operand:SF 0 "register_operand" "=f")
        (div:SF (match_operand:SF 1 "const_float_1_operand" "")
                (match_operand:SF 2 "register_operand" "f")))]
    (set_attr "mode"    "SF")
    (set_attr "length"  "3")])
 
-(define_insn ""
+(define_insn "*rsqrtsf2"
   [(set (match_operand:SF 0 "register_operand" "=f")
        (div:SF (match_operand:SF 1 "const_float_1_operand" "")
                (sqrt:SF (match_operand:SF 2 "register_operand" "f"))))]
          && !register_operand (operands[1], DImode))
        operands[1] = force_reg (DImode, operands[1]);
 
-      if (a7_overlap_mentioned_p (operands[1]))
-       {
-         emit_insn (gen_movdi_internal (operands[0], operands[1]));
-         emit_insn (gen_set_frame_ptr ());
-         DONE;
-       }
+      if (xtensa_copy_incoming_a7 (operands, DImode))
+       DONE;
     }
 }")
 
 (define_insn "movsi_internal"
   [(set (match_operand:SI 0 "nonimmed_operand" "=D,D,D,D,R,R,a,q,a,a,a,U,*a,*A")
        (match_operand:SI 1 "move_operand" "M,D,d,R,D,d,r,r,I,T,U,r,*A,*r"))]
-  "non_acc_reg_operand (operands[0], SImode)
-   || non_acc_reg_operand (operands[1], SImode)"
+  "xtensa_valid_move (SImode, operands)"
   "@
    movi.n\\t%0, %x1
    mov.n\\t%0, %1
 (define_insn "movhi_internal"
   [(set (match_operand:HI 0 "nonimmed_operand" "=D,D,a,a,a,U,*a,*A")
        (match_operand:HI 1 "move_operand" "M,d,r,I,U,r,*A,*r"))]
-  "non_acc_reg_operand (operands[0], HImode)
-   || non_acc_reg_operand (operands[1], HImode)"
+  "xtensa_valid_move (HImode, operands)"
   "@
    movi.n\\t%0, %x1
    mov.n\\t%0, %1
 (define_insn "movqi_internal"
   [(set (match_operand:QI 0 "nonimmed_operand" "=D,D,a,a,a,U,*a,*A")
        (match_operand:QI 1 "move_operand" "M,d,r,I,U,r,*A,*r"))]
-  "non_acc_reg_operand (operands[0], QImode)
-   || non_acc_reg_operand (operands[1], QImode)"
+  "xtensa_valid_move (QImode, operands)"
   "@
    movi.n\\t%0, %x1
    mov.n\\t%0, %1
              && constantpool_mem_p (operands[1]))))
        operands[1] = force_reg (SFmode, operands[1]);
 
-      if (a7_overlap_mentioned_p (operands[1]))
-       {
-         emit_insn (gen_movsf_internal (operands[0], operands[1]));
-         emit_insn (gen_set_frame_ptr ());
-         DONE;
-       }
+      if (xtensa_copy_incoming_a7 (operands, SFmode))
+       DONE;
     }
 }")
 
    (set_attr "mode"    "SF")
    (set_attr "length"  "3,3,3,2,2,2,3,3,3,3,3,3")])
 
-(define_insn ""
-  [(parallel
-    [(set (match_operand:SF 0 "register_operand" "=f")
-         (mem:SF (plus:SI (match_operand:SI 1 "register_operand" "+a")
-                          (match_operand:SI 2 "fpmem_offset_operand" "i"))))
-     (set (match_dup 1)
-         (plus:SI (match_dup 1) (match_dup 2)))])]
+(define_insn "*lsiu"
+  [(set (match_operand:SF 0 "register_operand" "=f")
+       (mem:SF (plus:SI (match_operand:SI 1 "register_operand" "+a")
+                        (match_operand:SI 2 "fpmem_offset_operand" "i"))))
+   (set (match_dup 1)
+       (plus:SI (match_dup 1) (match_dup 2)))]
   "TARGET_HARD_FLOAT"
   "*
 {
    (set_attr "mode"    "SF")
    (set_attr "length"  "3")])
 
-(define_insn ""
-  [(parallel
-    [(set (mem:SF (plus:SI (match_operand:SI 0 "register_operand" "+a")
-                          (match_operand:SI 1 "fpmem_offset_operand" "i")))
-         (match_operand:SF 2 "register_operand" "f"))
-     (set (match_dup 0)
-         (plus:SI (match_dup 0) (match_dup 1)))])]
+(define_insn "*ssiu"
+  [(set (mem:SF (plus:SI (match_operand:SI 0 "register_operand" "+a")
+                        (match_operand:SI 1 "fpmem_offset_operand" "i")))
+       (match_operand:SF 2 "register_operand" "f"))
+   (set (match_dup 0)
+       (plus:SI (match_dup 0) (match_dup 1)))]
   "TARGET_HARD_FLOAT"
   "*
 {
          && !register_operand (operands[1], DFmode))
        operands[1] = force_reg (DFmode, operands[1]);
 
-      if (a7_overlap_mentioned_p (operands[1]))
-       {
-         emit_insn (gen_movdf_internal (operands[0], operands[1]));
-         emit_insn (gen_set_frame_ptr ());
-         DONE;
-       }
+      if (xtensa_copy_incoming_a7 (operands, DFmode))
+       DONE;
     }
 }")
 
 }")
 
 (define_insn "movstrsi_internal"
-  [(parallel [(set (match_operand:BLK 0 "memory_operand" "=U")
-                  (match_operand:BLK 1 "memory_operand" "U"))
-             (use (match_operand:SI 2 "arith_operand" ""))
-             (use (match_operand:SI 3 "const_int_operand" ""))
-             (clobber (match_scratch:SI 4 "=&r"))
-             (clobber (match_scratch:SI 5 "=&r"))])]
+  [(set (match_operand:BLK 0 "memory_operand" "=U")
+       (match_operand:BLK 1 "memory_operand" "U"))
+   (use (match_operand:SI 2 "arith_operand" ""))
+   (use (match_operand:SI 3 "const_int_operand" ""))
+   (clobber (match_scratch:SI 4 "=&r"))
+   (clobber (match_scratch:SI 5 "=&r"))]
   ""
   "*
 {
    (set_attr "mode"    "SI")
    (set_attr "length"  "6,6")])
 
+
 ;;
 ;;  ....................
 ;;
 
 ;; Branch patterns for standard integer comparisons
 
-(define_insn ""
+(define_insn "*btrue"
   [(set (pc)
        (if_then_else (match_operator 3 "branch_operator"
                         [(match_operand:SI 0 "register_operand" "r,r")
    (set_attr "mode"    "none")
    (set_attr "length"  "3,3")])
 
-(define_insn ""
+(define_insn "*bfalse"
   [(set (pc)
        (if_then_else (match_operator 3 "branch_operator"
                         [(match_operand:SI 0 "register_operand" "r,r")
    (set_attr "mode"    "none")
    (set_attr "length"  "3,3")])
 
-(define_insn ""
+(define_insn "*ubtrue"
   [(set (pc)
        (if_then_else (match_operator 3 "ubranch_operator"
                         [(match_operand:SI 0 "register_operand" "r,r")
    (set_attr "mode"    "none")
    (set_attr "length"  "3,3")])
 
-(define_insn ""
+(define_insn "*ubfalse"
   [(set (pc)
        (if_then_else (match_operator 3 "ubranch_operator"
                         [(match_operand:SI 0 "register_operand" "r,r")
 
 ;; Branch patterns for bit testing
 
-(define_insn ""
+(define_insn "*bittrue"
   [(set (pc)
        (if_then_else (match_operator 3 "boolean_operator"
                        [(zero_extract:SI
    (set_attr "mode"    "none")
    (set_attr "length"  "3")])
 
-(define_insn ""
+(define_insn "*bitfalse"
   [(set (pc)
        (if_then_else (match_operator 3 "boolean_operator"
                        [(zero_extract:SI
    (set_attr "mode"    "none")
    (set_attr "length"  "3")])
 
-(define_insn ""
+(define_insn "*masktrue"
   [(set (pc)
        (if_then_else (match_operator 3 "boolean_operator"
                 [(and:SI (match_operand:SI 0 "register_operand" "r")
    (set_attr "mode"    "none")
    (set_attr "length"  "3")])
 
-(define_insn ""
+(define_insn "*maskfalse"
   [(set (pc)
        (if_then_else (match_operator 3 "boolean_operator"
                 [(and:SI (match_operand:SI 0 "register_operand" "r")
 ;; since since loop end is handled in hardware.
 
 (define_insn "zero_cost_loop_start"
-  [(parallel [(set (pc) (if_then_else (eq (match_operand:SI 0 "register_operand" "a")
-                                         (const_int 0))
-                                     (label_ref (match_operand 1 "" ""))
-                                     (pc)))
-             (set (reg:SI 19)
-                  (plus:SI (match_dup 0)
-                           (const_int -1)))])]
+  [(set (pc) (if_then_else (eq (match_operand:SI 0 "register_operand" "a")
+                              (const_int 0))
+                          (label_ref (match_operand 1 "" ""))
+                          (pc)))
+   (set (reg:SI 19)
+       (plus:SI (match_dup 0) (const_int -1)))]
   ""
   "loopnez %0, %l1"
   [(set_attr "type"    "jump")
    (set_attr "length"  "3")])
 
 (define_insn "zero_cost_loop_end"
-  [(parallel [(set (pc) (if_then_else (ne (reg:SI 19)
-                                         (const_int 0))
-                                     (label_ref (match_operand 0 "" ""))
-                                     (pc)))
-             (set (reg:SI 19)
-                  (plus:SI (reg:SI 19)
-                           (const_int -1)))])]
+  [(set (pc) (if_then_else (ne (reg:SI 19) (const_int 0))
+                          (label_ref (match_operand 0 "" ""))
+                          (pc)))
+   (set (reg:SI 19)
+       (plus:SI (reg:SI 19) (const_int -1)))]
   ""
   "*
     xtensa_emit_loop_end (insn, operands);
 ;; to set up the frame pointer.
 
 (define_insn "set_frame_ptr"
-  [(unspec_volatile [(const_int 0)] UNSPECV_SET_FP)]
+  [(set (reg:SI A7_REG) (unspec_volatile [(const_int 0)] UNSPECV_SET_FP))]
   ""
   "*
 {
 
 ;; Post-reload splitter to remove fp assignment when it's not needed.
 (define_split
-  [(unspec_volatile [(const_int 0)] UNSPECV_SET_FP)]
+  [(set (reg:SI A7_REG) (unspec_volatile [(const_int 0)] UNSPECV_SET_FP))]
   "reload_completed && !frame_pointer_needed"
   [(unspec [(const_int 0)] UNSPEC_NOP)]
   "")
 ;; The preceding splitter needs something to split the insn into;
 ;; things start breaking if the result is just a "use" so instead we
 ;; generate the following insn.
-(define_insn ""
+(define_insn "*unspec_nop"
   [(unspec [(const_int 0)] UNSPEC_NOP)]
   ""
   ""
    (set_attr "mode"    "none")
    (set_attr "length"  "0")])
 
+;; The fix_return_addr pattern sets the high 2 bits of an address in a
+;; register to match the high bits of the current PC.
+
+(define_insn "fix_return_addr"
+  [(set (match_operand:SI 0 "register_operand" "=a")
+       (unspec:SI [(match_operand:SI 1 "register_operand" "r")]
+                  UNSPEC_RET_ADDR))
+   (clobber (match_scratch:SI 2 "=r"))
+   (clobber (match_scratch:SI 3 "=r"))]
+  ""
+  "mov\\t%2, a0\;call0\\t0f\;.align\\t4\;0:\;mov\\t%3, a0\;mov\\ta0, %2\;\
+srli\\t%3, %3, 30\;slli\\t%0, %1, 2\;ssai\\t2\;src\\t%0, %3, %0"
+  [(set_attr "type"    "multi")
+   (set_attr "mode"    "SI")
+   (set_attr "length"  "24")])
+
+
 ;;
 ;;  ....................
 ;;
 
 ;; branch patterns
 
-(define_insn ""
+(define_insn "*booltrue"
   [(set (pc)
        (if_then_else (match_operator 2 "boolean_operator"
                         [(match_operand:CC 0 "register_operand" "b")
    (set_attr "mode"    "none")
    (set_attr "length"  "3")])
 
-(define_insn ""
+(define_insn "*boolfalse"
   [(set (pc)
        (if_then_else (match_operator 2 "boolean_operator"
                         [(match_operand:CC 0 "register_operand" "b")