OSDN Git Service

gcc/ada/
[pf3gnuchains/gcc-fork.git] / gcc / config / mips / mips.md
index cad5920..76dde25 100644 (file)
@@ -11,7 +11,7 @@
 
 ;; GCC is free software; you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
+;; the Free Software Foundation; either version 3, or (at your option)
 ;; any later version.
 
 ;; GCC is distributed in the hope that it will be useful,
@@ -20,9 +20,8 @@
 ;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
-;; along with GCC; see the file COPYING.  If not, write to
-;; the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
 
 (define_constants
   [(UNSPEC_LOAD_DF_LOW          0)
    (UNSPEC_RDHWR               34)
    (UNSPEC_SYNCI               35)
    (UNSPEC_SYNC                        36)
-
+   (UNSPEC_COMPARE_AND_SWAP    37)
+   (UNSPEC_SYNC_OLD_OP         38)
+   (UNSPEC_SYNC_NEW_OP         39)
+   (UNSPEC_SYNC_EXCHANGE       40)
+   
    (UNSPEC_ADDRESS_FIRST       100)
 
    (FAKE_CALL_REGNO            79)
          (eq_attr "type" "const")
          (symbol_ref "mips_const_insns (operands[1]) * 4")
          (eq_attr "type" "load,fpload")
-         (symbol_ref "mips_fetch_insns (operands[1]) * 4")
+         (symbol_ref "mips_load_store_insns (operands[1], insn) * 4")
          (eq_attr "type" "store,fpstore")
-         (symbol_ref "mips_fetch_insns (operands[0]) * 4")
+         (symbol_ref "mips_load_store_insns (operands[0], insn) * 4")
 
          ;; In the worst case, a call macro will take 8 instructions:
          ;;
   [(set_attr "type" "multi")
    (set_attr "can_delay" "no")])
 \f
-;; This mode macro allows 32-bit and 64-bit GPR patterns to be generated
+;; This mode iterator allows 32-bit and 64-bit GPR patterns to be generated
 ;; from the same template.
-(define_mode_macro GPR [SI (DI "TARGET_64BIT")])
+(define_mode_iterator GPR [SI (DI "TARGET_64BIT")])
 
-;; This mode macro allows :P to be used for patterns that operate on
+;; This mode iterator allows :P to be used for patterns that operate on
 ;; pointer-sized quantities.  Exactly one of the two alternatives will match.
-(define_mode_macro P [(SI "Pmode == SImode") (DI "Pmode == DImode")])
+(define_mode_iterator P [(SI "Pmode == SImode") (DI "Pmode == DImode")])
 
-;; This mode macro allows :MOVECC to be used anywhere that a
+;; This mode iterator allows :MOVECC to be used anywhere that a
 ;; conditional-move-type condition is needed.
-(define_mode_macro MOVECC [SI (DI "TARGET_64BIT") (CC "TARGET_HARD_FLOAT")])
+(define_mode_iterator MOVECC [SI (DI "TARGET_64BIT") (CC "TARGET_HARD_FLOAT")])
 
-;; This mode macro allows the QI and HI extension patterns to be defined from
+;; This mode iterator allows the QI and HI extension patterns to be defined from
 ;; the same template.
-(define_mode_macro SHORT [QI HI])
+(define_mode_iterator SHORT [QI HI])
 
-;; This mode macro allows :ANYF to be used wherever a scalar or vector
+;; This mode iterator allows :ANYF to be used wherever a scalar or vector
 ;; floating-point mode is allowed.
-(define_mode_macro ANYF [(SF "TARGET_HARD_FLOAT")
-                        (DF "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT")
-                        (V2SF "TARGET_PAIRED_SINGLE_FLOAT")])
+(define_mode_iterator ANYF [(SF "TARGET_HARD_FLOAT")
+                           (DF "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT")
+                           (V2SF "TARGET_PAIRED_SINGLE_FLOAT")])
 
 ;; Like ANYF, but only applies to scalar modes.
-(define_mode_macro SCALARF [(SF "TARGET_HARD_FLOAT")
-                           (DF "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT")])
+(define_mode_iterator SCALARF [(SF "TARGET_HARD_FLOAT")
+                              (DF "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT")])
 
 ;; In GPR templates, a string like "<d>subu" will expand to "subu" in the
 ;; 32-bit version and "dsubu" in the 64-bit version.
 (define_mode_attr recip_condition
   [(SF "ISA_HAS_FP4") (DF "ISA_HAS_FP4") (V2SF "TARGET_SB1")])
 
-;; This code macro allows all branch instructions to be generated from
+;; This code iterator allows all branch instructions to be generated from
 ;; a single define_expand template.
-(define_code_macro any_cond [unordered ordered unlt unge uneq ltgt unle ungt
-                            eq ne gt ge lt le gtu geu ltu leu])
+(define_code_iterator any_cond [unordered ordered unlt unge uneq ltgt unle ungt
+                               eq ne gt ge lt le gtu geu ltu leu])
 
-;; This code macro allows signed and unsigned widening multiplications
+;; This code iterator allows signed and unsigned widening multiplications
 ;; to use the same template.
-(define_code_macro any_extend [sign_extend zero_extend])
+(define_code_iterator any_extend [sign_extend zero_extend])
 
-;; This code macro allows the three shift instructions to be generated
+;; This code iterator allows the three shift instructions to be generated
 ;; from the same template.
-(define_code_macro any_shift [ashift ashiftrt lshiftrt])
+(define_code_iterator any_shift [ashift ashiftrt lshiftrt])
 
-;; This code macro allows all native floating-point comparisons to be
+;; This code iterator allows all native floating-point comparisons to be
 ;; generated from the same template.
-(define_code_macro fcond [unordered uneq unlt unle eq lt le])
+(define_code_iterator fcond [unordered uneq unlt unle eq lt le])
 
-;; This code macro is used for comparisons that can be implemented
+;; This code iterator is used for comparisons that can be implemented
 ;; by swapping the operands.
-(define_code_macro swapped_fcond [ge gt unge ungt])
+(define_code_iterator swapped_fcond [ge gt unge ungt])
 
 ;; <u> expands to an empty string when doing a signed operation and
 ;; "u" when doing an unsigned operation.
 ;; <optab> expands to the name of the optab for a particular code.
 (define_code_attr optab [(ashift "ashl")
                         (ashiftrt "ashr")
-                        (lshiftrt "lshr")])
+                        (lshiftrt "lshr")
+                        (ior "ior")
+                        (xor "xor")
+                        (and "and")])
 
 ;; <insn> expands to the name of the insn that implements a particular code.
 (define_code_attr insn [(ashift "sll")
                        (ashiftrt "sra")
-                       (lshiftrt "srl")])
+                       (lshiftrt "srl")
+                       (ior "or")
+                       (xor "xor")
+                       (and "and")])
 
 ;; <fcond> is the c.cond.fmt condition associated with a particular code.
 (define_code_attr fcond [(unordered "un")
                                 (gt "lt")
                                 (unge "ule")
                                 (ungt "ult")])
+
+;; Atomic fetch bitwise operations.
+(define_code_iterator fetchop_bit [ior xor and])
+
+;; <immediate_insn> expands to the name of the insn that implements
+;; a particular code to operate in immediate values.
+(define_code_attr immediate_insn [(ior "ori") (xor "xori") (and "andi")])
+
 \f
 ;; .........................
 ;;
   [(set_attr "type" "arith")
    (set_attr "mode" "<MODE>")])
 
-;; We need to recognize MIPS16 stack pointer additions explicitly, since
-;; we don't have a constraint for $sp.  These insns will be generated by
-;; the save_restore_insns functions.
-
-(define_insn "*add<mode>3_sp1"
-  [(set (reg:GPR 29)
-       (plus:GPR (reg:GPR 29)
-                 (match_operand:GPR 0 "const_arith_operand" "")))]
-  "TARGET_MIPS16"
-  "<d>addiu\t%$,%$,%0"
-  [(set_attr "type" "arith")
-   (set_attr "mode" "<MODE>")
-   (set (attr "length") (if_then_else (match_operand 0 "m16_simm8_8")
-                                     (const_int 4)
-                                     (const_int 8)))])
-
-(define_insn "*add<mode>3_sp2"
-  [(set (match_operand:GPR 0 "register_operand" "=d")
-       (plus:GPR (reg:GPR 29)
-                 (match_operand:GPR 1 "const_arith_operand" "")))]
-  "TARGET_MIPS16"
-  "<d>addiu\t%0,%$,%1"
-  [(set_attr "type" "arith")
-   (set_attr "mode" "<MODE>")
-   (set (attr "length") (if_then_else (match_operand 1 "m16_uimm<si8_di5>_4")
-                                     (const_int 4)
-                                     (const_int 8)))])
-
 (define_insn "*add<mode>3_mips16"
-  [(set (match_operand:GPR 0 "register_operand" "=d,d,d")
-       (plus:GPR (match_operand:GPR 1 "register_operand" "0,d,d")
-                 (match_operand:GPR 2 "arith_operand" "Q,O,d")))]
+  [(set (match_operand:GPR 0 "register_operand" "=ks,d,d,d,d")
+       (plus:GPR (match_operand:GPR 1 "register_operand" "ks,ks,0,d,d")
+                 (match_operand:GPR 2 "arith_operand" "Q,Q,Q,O,d")))]
   "TARGET_MIPS16"
   "@
     <d>addiu\t%0,%2
     <d>addiu\t%0,%1,%2
+    <d>addiu\t%0,%2
+    <d>addiu\t%0,%1,%2
     <d>addu\t%0,%1,%2"
   [(set_attr "type" "arith")
    (set_attr "mode" "<MODE>")
    (set_attr_alternative "length"
-               [(if_then_else (match_operand 2 "m16_simm<si8_di5>_1")
+               [(if_then_else (match_operand 2 "m16_simm8_8")
+                              (const_int 4)
+                              (const_int 8))
+                (if_then_else (match_operand 2 "m16_uimm<si8_di5>_4")
+                              (const_int 4)
+                              (const_int 8))
+                (if_then_else (match_operand 2 "m16_simm<si8_di5>_1")
                               (const_int 4)
                               (const_int 8))
                 (if_then_else (match_operand 2 "m16_simm4_1")
                               (const_int 8))
                 (const_int 4)])])
 
-
 ;; On the mips16, we can sometimes split an add of a constant which is
 ;; a 4 byte instruction into two adds which are both 2 byte
 ;; instructions.  There are two cases: one where we are adding a
   rtx label2 = gen_label_rtx ();
   REAL_VALUE_TYPE offset;
 
-  real_2expN (&offset, 31);
+  real_2expN (&offset, 31, DFmode);
 
   if (reg1)                    /* Turn off complaints about unreached code.  */
     {
-      emit_move_insn (reg1, CONST_DOUBLE_FROM_REAL_VALUE (offset, DFmode));
+      mips_emit_move (reg1, CONST_DOUBLE_FROM_REAL_VALUE (offset, DFmode));
       do_pending_stack_adjust ();
 
       emit_insn (gen_cmpdf (operands[1], reg1));
       emit_barrier ();
 
       emit_label (label1);
-      emit_move_insn (reg2, gen_rtx_MINUS (DFmode, operands[1], reg1));
-      emit_move_insn (reg3, GEN_INT (trunc_int_for_mode
+      mips_emit_move (reg2, gen_rtx_MINUS (DFmode, operands[1], reg1));
+      mips_emit_move (reg3, GEN_INT (trunc_int_for_mode
                                     (BITMASK_HIGH, SImode)));
 
       emit_insn (gen_fix_truncdfsi2 (operands[0], reg2));
   rtx label2 = gen_label_rtx ();
   REAL_VALUE_TYPE offset;
 
-  real_2expN (&offset, 63);
+  real_2expN (&offset, 63, DFmode);
 
-  emit_move_insn (reg1, CONST_DOUBLE_FROM_REAL_VALUE (offset, DFmode));
+  mips_emit_move (reg1, CONST_DOUBLE_FROM_REAL_VALUE (offset, DFmode));
   do_pending_stack_adjust ();
 
   emit_insn (gen_cmpdf (operands[1], reg1));
   emit_barrier ();
 
   emit_label (label1);
-  emit_move_insn (reg2, gen_rtx_MINUS (DFmode, operands[1], reg1));
-  emit_move_insn (reg3, GEN_INT (BITMASK_HIGH));
+  mips_emit_move (reg2, gen_rtx_MINUS (DFmode, operands[1], reg1));
+  mips_emit_move (reg3, GEN_INT (BITMASK_HIGH));
   emit_insn (gen_ashldi3 (reg3, reg3, GEN_INT (32)));
 
   emit_insn (gen_fix_truncdfdi2 (operands[0], reg2));
   rtx label2 = gen_label_rtx ();
   REAL_VALUE_TYPE offset;
 
-  real_2expN (&offset, 31);
+  real_2expN (&offset, 31, SFmode);
 
-  emit_move_insn (reg1, CONST_DOUBLE_FROM_REAL_VALUE (offset, SFmode));
+  mips_emit_move (reg1, CONST_DOUBLE_FROM_REAL_VALUE (offset, SFmode));
   do_pending_stack_adjust ();
 
   emit_insn (gen_cmpsf (operands[1], reg1));
   emit_barrier ();
 
   emit_label (label1);
-  emit_move_insn (reg2, gen_rtx_MINUS (SFmode, operands[1], reg1));
-  emit_move_insn (reg3, GEN_INT (trunc_int_for_mode
+  mips_emit_move (reg2, gen_rtx_MINUS (SFmode, operands[1], reg1));
+  mips_emit_move (reg3, GEN_INT (trunc_int_for_mode
                                 (BITMASK_HIGH, SImode)));
 
   emit_insn (gen_fix_truncsfsi2 (operands[0], reg2));
   rtx label2 = gen_label_rtx ();
   REAL_VALUE_TYPE offset;
 
-  real_2expN (&offset, 63);
+  real_2expN (&offset, 63, SFmode);
 
-  emit_move_insn (reg1, CONST_DOUBLE_FROM_REAL_VALUE (offset, SFmode));
+  mips_emit_move (reg1, CONST_DOUBLE_FROM_REAL_VALUE (offset, SFmode));
   do_pending_stack_adjust ();
 
   emit_insn (gen_cmpsf (operands[1], reg1));
   emit_barrier ();
 
   emit_label (label1);
-  emit_move_insn (reg2, gen_rtx_MINUS (SFmode, operands[1], reg1));
-  emit_move_insn (reg3, GEN_INT (BITMASK_HIGH));
+  mips_emit_move (reg2, gen_rtx_MINUS (SFmode, operands[1], reg1));
+  mips_emit_move (reg3, GEN_INT (BITMASK_HIGH));
   emit_insn (gen_ashldi3 (reg3, reg3, GEN_INT (32)));
 
   emit_insn (gen_fix_truncsfdi2 (operands[0], reg2));
   [(set_attr "type" "store")
    (set_attr "mode" "<MODE>")])
 
-;; An instruction to calculate the high part of a 64-bit SYMBOL_GENERAL.
+;; An instruction to calculate the high part of a 64-bit SYMBOL_ABSOLUTE.
 ;; The required value is:
 ;;
 ;;     (%highest(op1) << 48) + (%higher(op1) << 32) + (%hi(op1) << 16)
 ;; to take effect.
 (define_insn_and_split "*lea_high64"
   [(set (match_operand:DI 0 "register_operand" "=d")
-       (high:DI (match_operand:DI 1 "general_symbolic_operand" "")))]
+       (high:DI (match_operand:DI 1 "absolute_symbolic_operand" "")))]
   "TARGET_EXPLICIT_RELOCS && ABI_HAS_64BIT_SYMBOLS"
   "#"
   "&& epilogue_completed"
 ;;     daddu   op1,op1,op0
 (define_peephole2
   [(set (match_operand:DI 1 "register_operand")
-       (high:DI (match_operand:DI 2 "general_symbolic_operand")))
+       (high:DI (match_operand:DI 2 "absolute_symbolic_operand")))
    (match_scratch:DI 0 "d")]
   "TARGET_EXPLICIT_RELOCS && ABI_HAS_64BIT_SYMBOLS"
   [(set (match_dup 1) (high:DI (match_dup 3)))
 })
 
 ;; On most targets, the expansion of (lo_sum (high X) X) for a 64-bit
-;; SYMBOL_GENERAL X will take 6 cycles.  This next pattern allows combine
+;; SYMBOL_ABSOLUTE X will take 6 cycles.  This next pattern allows combine
 ;; to merge the HIGH and LO_SUM parts of a move if the HIGH part is only
 ;; used once.  We can then use the sequence:
 ;;
 ;; which takes 4 cycles on most superscalar targets.
 (define_insn_and_split "*lea64"
   [(set (match_operand:DI 0 "register_operand" "=d")
-       (match_operand:DI 1 "general_symbolic_operand" ""))
+       (match_operand:DI 1 "absolute_symbolic_operand" ""))
    (clobber (match_scratch:DI 2 "=&d"))]
   "TARGET_EXPLICIT_RELOCS && ABI_HAS_64BIT_SYMBOLS && cse_not_expected"
   "#"
 }
   [(set_attr "length" "24")])
 
+;; Split HIGHs into:
+;;
+;;     li op0,%hi(sym)
+;;     sll op0,16
+;;
+;; on MIPS16 targets.
+(define_split
+  [(set (match_operand:SI 0 "register_operand" "=d")
+       (high:SI (match_operand:SI 1 "absolute_symbolic_operand" "")))]
+  "TARGET_MIPS16 && reload_completed"
+  [(set (match_dup 0) (match_dup 2))
+   (set (match_dup 0) (ashift:SI (match_dup 0) (const_int 16)))]
+{
+  operands[2] = mips_unspec_address (operands[1], SYMBOL_32_HIGH);
+})
+
 ;; Insns to fetch a symbol from a big GOT.
 
 (define_insn_and_split "*xgot_hi<mode>"
 ;; Likewise, for symbolic operands.
 (define_split
   [(set (match_operand:P 0 "register_operand")
-       (match_operand:P 1 "splittable_symbolic_operand"))
+       (match_operand:P 1))
    (clobber (match_operand:P 2 "register_operand"))]
-  ""
-  [(set (match_dup 0) (match_dup 1))]
-  { operands[1] = mips_split_symbol (operands[2], operands[1]); })
+  "mips_split_symbol (operands[2], operands[1], MAX_MACHINE_MODE, NULL)"
+  [(set (match_dup 0) (match_dup 3))]
+{
+  mips_split_symbol (operands[2], operands[1],
+                    MAX_MACHINE_MODE, &operands[3]);
+})
 
 ;; 64-bit integer moves
 
                     (match_operand:GPR 2 "register_operand" "l,h")]
                    UNSPEC_MFHILO))]
   "ISA_HAS_MACCHI"
-{
-  if (REGNO (operands[1]) == HI_REGNUM)
-    return "<d>macchi\t%0,%.,%.";
-  else
-    return "<d>macc\t%0,%.,%.";
-}
+  "@
+   <d>macchi\t%0,%.,%.
+   <d>macc\t%0,%.,%."
   [(set_attr "type" "mfhilo")
    (set_attr "mode" "<MODE>")])
 
   ""
   [(const_int 0)]
 {
-  emit_move_insn (pic_offset_table_rtx, operands[0]);
+  mips_emit_move (pic_offset_table_rtx, operands[0]);
   DONE;
 }
   [(set_attr "length" "8")])
                                 (match_dup 4)] UNSPEC_LOAD_GOT))]
 {
   operands[2] = pic_offset_table_rtx;
-  operands[3] = mips_unspec_address (operands[0], SYMBOL_GENERAL);
+  operands[3] = mips_unspec_address (operands[0], SYMBOL_ABSOLUTE);
   operands[4] = mips_unspec_address (operands[1], SYMBOL_HALF);
 })
 
       /* Flush both caches.  We need to flush the data cache in case
          the system has a write-back cache.  */
       emit_library_call (gen_rtx_SYMBOL_REF (Pmode, mips_cache_flush_func),
-                         0, VOIDmode, 3, operands[0], Pmode,
-                         len, TYPE_MODE (integer_type_node),
+                         0, VOIDmode, 3, operands[0], Pmode, len, Pmode,
                          GEN_INT (3), TYPE_MODE (integer_type_node));
    }
   DONE;
 
 (define_insn "sync"
   [(unspec_volatile [(const_int 0)] UNSPEC_SYNC)]
-  "ISA_HAS_SYNCI"
+  "ISA_HAS_SYNC"
   "sync")
 
 (define_insn "synci"
   "synci\t0(%0)")
 
 (define_insn "rdhwr"
-  [(set (match_operand:SI 0 "general_operand" "=d")
+  [(set (match_operand:SI 0 "register_operand" "=d")
         (unspec_volatile [(match_operand:SI 1 "const_int_operand" "n")]
         UNSPEC_RDHWR))]
   "ISA_HAS_SYNCI"
          "\t.set\tpop";
 }
   [(set_attr "length" "20")])
+
+;; Atomic memory operations.
+
+(define_expand "memory_barrier"
+  [(unspec_volatile [(const_int 0)] UNSPEC_SYNC)]
+  "ISA_HAS_SYNC"
+  "")
+
+(define_insn "sync_compare_and_swap<mode>"
+  [(set (match_operand:GPR 0 "register_operand" "=&d,d")
+       (match_operand:GPR 1 "memory_operand" "+R,R"))
+   (set (match_dup 1)
+       (unspec_volatile:GPR [(match_operand:GPR 2 "register_operand" "d,d")
+                             (match_operand:GPR 3 "arith_operand" "I,d")]
+        UNSPEC_COMPARE_AND_SWAP))]
+  "ISA_HAS_LL_SC"
+{
+  if (which_alternative == 0)
+    return MIPS_COMPARE_AND_SWAP ("<d>", "li");
+  else
+    return MIPS_COMPARE_AND_SWAP ("<d>", "move");
+}
+  [(set_attr "length" "28")])
+
+(define_insn "sync_add<mode>"
+  [(set (match_operand:GPR 0 "memory_operand" "+R,R")
+       (unspec_volatile:GPR
+          [(plus:GPR (match_dup 0)
+                             (match_operand:GPR 1 "arith_operand" "I,d"))]
+        UNSPEC_SYNC_OLD_OP))]
+  "ISA_HAS_LL_SC"
+{
+  if (which_alternative == 0)
+    return MIPS_SYNC_OP ("<d>", "<d>addiu");   
+  else
+    return MIPS_SYNC_OP ("<d>", "<d>addu");    
+}
+  [(set_attr "length" "24")])
+
+(define_insn "sync_sub<mode>"
+  [(set (match_operand:GPR 0 "memory_operand" "+R")
+       (unspec_volatile:GPR
+          [(minus:GPR (match_dup 0)
+                             (match_operand:GPR 1 "register_operand" "d"))]
+        UNSPEC_SYNC_OLD_OP))]
+  "ISA_HAS_LL_SC"
+{
+    return MIPS_SYNC_OP ("<d>", "<d>subu");    
+}
+  [(set_attr "length" "24")])
+
+(define_insn "sync_old_add<mode>"
+  [(set (match_operand:GPR 0 "register_operand" "=&d,d")
+       (match_operand:GPR 1 "memory_operand" "+R,R"))
+   (set (match_dup 1)
+       (unspec_volatile:GPR
+          [(plus:GPR (match_dup 1)
+                    (match_operand:GPR 2 "arith_operand" "I,d"))]
+        UNSPEC_SYNC_OLD_OP))]
+  "ISA_HAS_LL_SC"
+{
+  if (which_alternative == 0)
+    return MIPS_SYNC_OLD_OP ("<d>", "<d>addiu");       
+  else
+    return MIPS_SYNC_OLD_OP ("<d>", "<d>addu");        
+}
+  [(set_attr "length" "24")])
+
+(define_insn "sync_old_sub<mode>"
+  [(set (match_operand:GPR 0 "register_operand" "=&d")
+       (match_operand:GPR 1 "memory_operand" "+R"))
+   (set (match_dup 1)
+       (unspec_volatile:GPR
+          [(minus:GPR (match_dup 1)
+                     (match_operand:GPR 2 "register_operand" "d"))]
+        UNSPEC_SYNC_OLD_OP))]
+  "ISA_HAS_LL_SC"
+{
+  return MIPS_SYNC_OLD_OP ("<d>", "<d>subu");  
+}
+  [(set_attr "length" "24")])
+
+(define_insn "sync_new_add<mode>"
+  [(set (match_operand:GPR 0 "register_operand" "=&d,d")
+        (plus:GPR (match_operand:GPR 1 "memory_operand" "+R,R")
+                 (match_operand:GPR 2 "arith_operand" "I,d")))
+   (set (match_dup 1)
+       (unspec_volatile:GPR
+         [(plus:GPR (match_dup 1) (match_dup 2))]
+        UNSPEC_SYNC_NEW_OP))]
+  "ISA_HAS_LL_SC"
+{
+  if (which_alternative == 0)
+    return MIPS_SYNC_NEW_OP ("<d>", "<d>addiu");       
+  else
+    return MIPS_SYNC_NEW_OP ("<d>", "<d>addu");        
+}
+  [(set_attr "length" "24")])
+
+(define_insn "sync_new_sub<mode>"
+  [(set (match_operand:GPR 0 "register_operand" "=&d")
+        (minus:GPR (match_operand:GPR 1 "memory_operand" "+R")
+                  (match_operand:GPR 2 "register_operand" "d")))
+   (set (match_dup 1)
+       (unspec_volatile:GPR
+         [(minus:GPR (match_dup 1) (match_dup 2))]
+        UNSPEC_SYNC_NEW_OP))]
+  "ISA_HAS_LL_SC"
+{
+  return MIPS_SYNC_NEW_OP ("<d>", "<d>subu");  
+}
+  [(set_attr "length" "24")])
+
+(define_insn "sync_<optab><mode>"
+  [(set (match_operand:GPR 0 "memory_operand" "+R,R")
+       (unspec_volatile:GPR
+          [(fetchop_bit:GPR (match_operand:GPR 1 "uns_arith_operand" "K,d")
+                             (match_dup 0))]
+        UNSPEC_SYNC_OLD_OP))]
+  "ISA_HAS_LL_SC"
+{
+  if (which_alternative == 0)
+    return MIPS_SYNC_OP ("<d>", "<immediate_insn>");   
+  else
+    return MIPS_SYNC_OP ("<d>", "<insn>");     
+}
+  [(set_attr "length" "24")])
+
+(define_insn "sync_old_<optab><mode>"
+  [(set (match_operand:GPR 0 "register_operand" "=&d,d")
+       (match_operand:GPR 1 "memory_operand" "+R,R"))
+   (set (match_dup 1)
+       (unspec_volatile:GPR
+          [(fetchop_bit:GPR (match_operand:GPR 2 "uns_arith_operand" "K,d")
+                           (match_dup 1))]
+        UNSPEC_SYNC_OLD_OP))]
+  "ISA_HAS_LL_SC"
+{
+  if (which_alternative == 0)
+    return MIPS_SYNC_OLD_OP ("<d>", "<immediate_insn>");       
+  else
+    return MIPS_SYNC_OLD_OP ("<d>", "<insn>"); 
+}
+  [(set_attr "length" "24")])
+
+(define_insn "sync_new_<optab><mode>"
+  [(set (match_operand:GPR 0 "register_operand" "=&d,d")
+       (match_operand:GPR 1 "memory_operand" "+R,R"))
+   (set (match_dup 1)
+       (unspec_volatile:GPR
+          [(fetchop_bit:GPR (match_operand:GPR 2 "uns_arith_operand" "K,d")
+                           (match_dup 1))]
+        UNSPEC_SYNC_NEW_OP))]
+  "ISA_HAS_LL_SC"
+{
+  if (which_alternative == 0)
+    return MIPS_SYNC_NEW_OP ("<d>", "<immediate_insn>");       
+  else
+    return MIPS_SYNC_NEW_OP ("<d>", "<insn>"); 
+}
+  [(set_attr "length" "24")])
+
+(define_insn "sync_nand<mode>"
+  [(set (match_operand:GPR 0 "memory_operand" "+R,R")
+       (unspec_volatile:GPR [(match_operand:GPR 1 "uns_arith_operand" "K,d")]
+        UNSPEC_SYNC_OLD_OP))]
+  "ISA_HAS_LL_SC"
+{
+  if (which_alternative == 0)
+    return MIPS_SYNC_NAND ("<d>", "andi");     
+  else
+    return MIPS_SYNC_NAND ("<d>", "and");      
+}
+  [(set_attr "length" "28")])
+
+(define_insn "sync_old_nand<mode>"
+  [(set (match_operand:GPR 0 "register_operand" "=&d,d")
+       (match_operand:GPR 1 "memory_operand" "+R,R"))
+   (set (match_dup 1)
+        (unspec_volatile:GPR [(match_operand:GPR 2 "uns_arith_operand" "K,d")]
+        UNSPEC_SYNC_OLD_OP))]
+  "ISA_HAS_LL_SC"
+{
+  if (which_alternative == 0)
+    return MIPS_SYNC_OLD_NAND ("<d>", "andi"); 
+  else
+    return MIPS_SYNC_OLD_NAND ("<d>", "and");  
+}
+  [(set_attr "length" "28")])
+
+(define_insn "sync_new_nand<mode>"
+  [(set (match_operand:GPR 0 "register_operand" "=&d,d")
+       (match_operand:GPR 1 "memory_operand" "+R,R"))
+   (set (match_dup 1)
+       (unspec_volatile:GPR [(match_operand:GPR 2 "uns_arith_operand" "K,d")]
+        UNSPEC_SYNC_NEW_OP))]
+  "ISA_HAS_LL_SC"
+{
+  if (which_alternative == 0)
+    return MIPS_SYNC_NEW_NAND ("<d>", "andi"); 
+  else
+    return MIPS_SYNC_NEW_NAND ("<d>", "and");  
+}
+  [(set_attr "length" "28")])
+
+(define_insn "sync_lock_test_and_set<mode>"
+  [(set (match_operand:GPR 0 "register_operand" "=&d,d")
+       (match_operand:GPR 1 "memory_operand" "+R,R"))
+   (set (match_dup 1)
+       (unspec_volatile:GPR [(match_operand:GPR 2 "arith_operand" "I,d")]
+        UNSPEC_SYNC_EXCHANGE))]
+  "ISA_HAS_LL_SC"
+{
+  if (which_alternative == 0)
+    return MIPS_SYNC_EXCHANGE ("<d>", "li");
+  else
+    return MIPS_SYNC_EXCHANGE ("<d>", "move");
+}
+  [(set_attr "length" "24")])
 \f
 ;; Block moves, see mips.c for more details.
 ;; Argument 0 is the destination
    (use (label_ref (match_operand 1 "")))]
   ""
 {
-  if (TARGET_MIPS16)
+  if (TARGET_MIPS16_SHORT_JUMP_TABLES)
     operands[0] = expand_binop (Pmode, add_optab,
                                convert_to_mode (Pmode, operands[0], false),
                                gen_rtx_LABEL_REF (Pmode, operands[1]),
   rtx addr;
 
   addr = plus_constant (operands[0], GET_MODE_SIZE (Pmode) * 3);
-  emit_move_insn (gen_rtx_MEM (Pmode, addr), pic_offset_table_rtx);
+  mips_emit_move (gen_rtx_MEM (Pmode, addr), pic_offset_table_rtx);
   DONE;
 })
 
 
   /* This bit is similar to expand_builtin_longjmp except that it
      restores $gp as well.  */
-  emit_move_insn (hard_frame_pointer_rtx, fp);
-  emit_move_insn (pv, lab);
+  mips_emit_move (hard_frame_pointer_rtx, fp);
+  mips_emit_move (pv, lab);
   emit_stack_restore (SAVE_NONLOCAL, stack, NULL_RTX);
-  emit_move_insn (gp, gpv);
+  mips_emit_move (gp, gpv);
   emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx));
   emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx));
   emit_insn (gen_rtx_USE (VOIDmode, gp));
   [(set_attr "jal" "indirect,direct")
    (set_attr "extended_mips16" "no,yes")])
 
+;; A pattern for calls that must be made directly.  It is used for
+;; MIPS16 calls that the linker may need to redirect to a hard-float
+;; stub; the linker relies on the call relocation type to detect when
+;; such redirection is needed.
+(define_insn "call_internal_direct"
+  [(call (mem:SI (match_operand 0 "const_call_insn_operand"))
+        (match_operand 1))
+   (const_int 1)
+   (clobber (reg:SI 31))]
+  ""
+  { return MIPS_CALL ("jal", operands, 0); })
+
 (define_insn "call_split"
   [(call (mem:SI (match_operand 0 "call_insn_operand" "cS"))
         (match_operand 1 "" ""))
   { return MIPS_CALL ("jal", operands, 1); }
   [(set_attr "type" "call")])
 
+;; See call_internal_direct.
+(define_insn "call_value_internal_direct"
+  [(set (match_operand 0 "register_operand")
+        (call (mem:SI (match_operand 1 "const_call_insn_operand"))
+              (match_operand 2)))
+   (const_int 1)
+   (clobber (reg:SI 31))]
+  ""
+  { return MIPS_CALL ("jal", operands, 1); })
+
 ;; See comment for call_internal.
 (define_insn_and_split "call_value_multiple_internal"
   [(set (match_operand 0 "register_operand" "")
   for (i = 0; i < XVECLEN (operands[2], 0); i++)
     {
       rtx set = XVECEXP (operands[2], 0, i);
-      emit_move_insn (SET_DEST (set), SET_SRC (set));
+      mips_emit_move (SET_DEST (set), SET_SRC (set));
     }
 
   emit_insn (gen_blockage ());