OSDN Git Service

* config/mips/mips.h (ISA_HAS_SEQ_SNE): New macro.
[pf3gnuchains/gcc-fork.git] / gcc / config / mips / mips.md
index 4204ec1..0512a70 100644 (file)
                (const_string "yes")
                (const_string "no")))
 
-;; Attribute defining whether or not we can use the branch-likely instructions
+;; Attribute defining whether or not we can use the branch-likely
+;; instructions.
 (define_attr "branch_likely" "no,yes"
-  (const
-   (if_then_else (ne (symbol_ref "GENERATE_BRANCHLIKELY") (const_int 0))
-                (const_string "yes")
-                (const_string "no"))))
+  (if_then_else (ne (symbol_ref "GENERATE_BRANCHLIKELY") (const_int 0))
+               (const_string "yes")
+               (const_string "no")))
 
 ;; True if an instruction might assign to hi or lo when reloaded.
 ;; This is used by the TUNE_MACC_CHAINS code.
                     (HA "") (SA "") (DA "d")
                     (UHA "") (USA "") (UDA "d")])
 
+;; Same as d but upper-case.
+(define_mode_attr D [(SI "") (DI "D")
+                    (QQ "") (HQ "") (SQ "") (DQ "D")
+                    (UQQ "") (UHQ "") (USQ "") (UDQ "D")
+                    (HA "") (SA "") (DA "D")
+                    (UHA "") (USA "") (UDA "D")])
+
 ;; This attribute gives the length suffix for a sign- or zero-extension
 ;; instruction.
 (define_mode_attr size [(QI "b") (HI "h")])
 ;; to use the same template.
 (define_code_iterator any_extend [sign_extend zero_extend])
 
+;; This code iterator allows the two right shift instructions to be
+;; generated from the same template.
+(define_code_iterator any_shiftrt [ashiftrt lshiftrt])
+
 ;; This code iterator allows the three shift instructions to be generated
 ;; from the same template.
 (define_code_iterator any_shift [ashift ashiftrt lshiftrt])
 ;; by swapping the operands.
 (define_code_iterator swapped_fcond [ge gt unge ungt])
 
+;; Equality operators.
+(define_code_iterator equality_op [eq ne])
+
 ;; These code iterators allow the signed and unsigned scc operations to use
 ;; the same template.
 (define_code_iterator any_gt [gt gtu])
                        (plus "addu")
                        (minus "subu")])
 
+;; <immediate_insn> expands to the name of the insn that implements
+;; a particular code to operate on immediate values.
+(define_code_attr immediate_insn [(ior "ori")
+                                 (xor "xori")
+                                 (and "andi")])
+
 ;; <fcond> is the c.cond.fmt condition associated with a particular code.
 (define_code_attr fcond [(unordered "un")
                         (uneq "ueq")
                                 (unge "ule")
                                 (ungt "ult")])
 
-;; Atomic fetch bitwise operations.
-(define_code_iterator fetchop_bit [ior xor and])
+;; The value of the bit when the branch is taken for branch_bit patterns.
+;; Comparison is always against zero so this depends on the operator.
+(define_code_attr bbv [(eq "0") (ne "1")])
 
-;; <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")])
-
-;; Atomic HI and QI operations
-(define_code_iterator atomic_hiqi_op [plus minus ior xor and])
+;; This is the inverse value of bbv.
+(define_code_attr bbinv [(eq "1") (ne "0")])
 \f
 ;; .........................
 ;;
 ;; .........................
 
 (define_delay (and (eq_attr "type" "branch")
-                  (eq (symbol_ref "TARGET_MIPS16") (const_int 0)))
+                  (eq (symbol_ref "TARGET_MIPS16") (const_int 0))
+                  (eq_attr "branch_likely" "yes"))
+  [(eq_attr "can_delay" "yes")
+   (nil)
+   (eq_attr "can_delay" "yes")])
+
+;; Branches that don't have likely variants do not annul on false.
+(define_delay (and (eq_attr "type" "branch")
+                  (eq (symbol_ref "TARGET_MIPS16") (const_int 0))
+                  (eq_attr "branch_likely" "no"))
   [(eq_attr "can_delay" "yes")
    (nil)
-   (and (eq_attr "branch_likely" "yes")
-       (eq_attr "can_delay" "yes"))])
+   (nil)])
 
 (define_delay (eq_attr "type" "jump")
   [(eq_attr "can_delay" "yes")
 ;; These processors have PRId values of 0x00004220 and 0x00004300,
 ;; respectively.
 
-(define_expand "mulsi3"
-  [(set (match_operand:SI 0 "register_operand")
-       (mult:SI (match_operand:SI 1 "register_operand")
-                (match_operand:SI 2 "register_operand")))]
+(define_expand "mul<mode>3"
+  [(set (match_operand:GPR 0 "register_operand")
+       (mult:GPR (match_operand:GPR 1 "register_operand")
+                 (match_operand:GPR 2 "register_operand")))]
   ""
 {
-  if (ISA_HAS_MUL3)
-    emit_insn (gen_mulsi3_mult3 (operands[0], operands[1], operands[2]));
+  if (ISA_HAS_<D>MUL3)
+    emit_insn (gen_mul<mode>3_mul3 (operands[0], operands[1], operands[2]));
   else if (TARGET_FIX_R4000)
-    emit_insn (gen_mulsi3_r4000 (operands[0], operands[1], operands[2]));
+    emit_insn (gen_mul<mode>3_r4000 (operands[0], operands[1], operands[2]));
   else
-    emit_insn (gen_mulsi3_internal (operands[0], operands[1], operands[2]));
+    emit_insn
+      (gen_mul<mode>3_internal (operands[0], operands[1], operands[2]));
   DONE;
 })
 
-(define_expand "muldi3"
-  [(set (match_operand:DI 0 "register_operand")
-       (mult:DI (match_operand:DI 1 "register_operand")
-                (match_operand:DI 2 "register_operand")))]
-  "TARGET_64BIT"
-{
-  if (TARGET_FIX_R4000)
-    emit_insn (gen_muldi3_r4000 (operands[0], operands[1], operands[2]));
-  else
-    emit_insn (gen_muldi3_internal (operands[0], operands[1], operands[2]));
-  DONE;
-})
-
-(define_insn "mulsi3_mult3"
+(define_insn "mulsi3_mul3"
   [(set (match_operand:SI 0 "register_operand" "=d,l")
        (mult:SI (match_operand:SI 1 "register_operand" "d,d")
                 (match_operand:SI 2 "register_operand" "d,d")))
   [(set_attr "type" "imul3,imul")
    (set_attr "mode" "SI")])
 
+(define_insn "muldi3_mul3"
+  [(set (match_operand:DI 0 "register_operand" "=d,l")
+       (mult:DI (match_operand:DI 1 "register_operand" "d,d")
+                (match_operand:DI 2 "register_operand" "d,d")))
+   (clobber (match_scratch:DI 3 "=l,X"))]
+  "ISA_HAS_DMUL3"
+{
+  if (which_alternative == 1)
+    return "dmult\t%1,%2";
+  return "dmul\t%0,%1,%2";
+}
+  [(set_attr "type" "imul3,imul")
+   (set_attr "mode" "DI")])
+
 ;; If a register gets allocated to LO, and we spill to memory, the reload
 ;; will include a move from LO to a GPR.  Merge it into the multiplication
 ;; if it can set the GPR directly.
 
 ;; Combiner patterns to optimize shift/truncate combinations.
 
-(define_insn ""
+(define_insn "*ashr_trunc<mode>"
   [(set (match_operand:SUBDI 0 "register_operand" "=d")
         (truncate:SUBDI
          (ashiftrt:DI (match_operand:DI 1 "register_operand" "d")
                       (match_operand:DI 2 "const_arith_operand" ""))))]
-  "TARGET_64BIT && !TARGET_MIPS16 && INTVAL (operands[2]) >= 32"
+  "TARGET_64BIT && !TARGET_MIPS16 && IN_RANGE (INTVAL (operands[2]), 32, 63)"
   "dsra\t%0,%1,%2"
   [(set_attr "type" "shift")
-   (set_attr "mode" "SI")])
+   (set_attr "mode" "<MODE>")])
 
-(define_insn ""
+(define_insn "*lshr32_trunc<mode>"
   [(set (match_operand:SUBDI 0 "register_operand" "=d")
         (truncate:SUBDI
          (lshiftrt:DI (match_operand:DI 1 "register_operand" "d")
   "TARGET_64BIT && !TARGET_MIPS16"
   "dsra\t%0,%1,32"
   [(set_attr "type" "shift")
-   (set_attr "mode" "SI")])
+   (set_attr "mode" "<MODE>")])
 
+;; Logical shift by 32 or more results in proper SI values so
+;; truncation is removed by the middle end.
+(define_insn "*<optab>_trunc<mode>_exts"
+  [(set (match_operand:SUBDI 0 "register_operand" "=d")
+        (truncate:SUBDI
+        (any_shiftrt:DI (match_operand:DI 1 "register_operand" "d")
+                        (match_operand:DI 2 "const_arith_operand" ""))))]
+  "ISA_HAS_EXTS && TARGET_64BIT && UINTVAL (operands[2]) < 32"
+  "exts\t%0,%1,%2,31"
+  [(set_attr "type" "arith")
+   (set_attr "mode" "<MODE>")])
 
 ;; Combiner patterns for truncate/sign_extend combinations.  The SI versions
 ;; use the shift/truncate patterns above.
 
 (define_expand "extv"
   [(set (match_operand 0 "register_operand")
-       (sign_extract (match_operand:QI 1 "memory_operand")
-                     (match_operand 2 "immediate_operand")
-                     (match_operand 3 "immediate_operand")))]
+       (sign_extract (match_operand 1 "nonimmediate_operand")
+                     (match_operand 2 "const_int_operand")
+                     (match_operand 3 "const_int_operand")))]
   "!TARGET_MIPS16"
 {
   if (mips_expand_ext_as_unaligned_load (operands[0], operands[1],
                                         INTVAL (operands[2]),
                                         INTVAL (operands[3])))
     DONE;
+  else if (register_operand (operands[1], GET_MODE (operands[0]))
+          && ISA_HAS_EXTS && UINTVAL (operands[2]) <= 32)
+    {
+      if (GET_MODE (operands[0]) == DImode)
+       emit_insn (gen_extvdi (operands[0], operands[1], operands[2],
+                              operands[3]));
+      else
+       emit_insn (gen_extvsi (operands[0], operands[1], operands[2],
+                              operands[3]));
+      DONE;
+    }
   else
     FAIL;
 })
 
+(define_insn "extv<mode>"
+  [(set (match_operand:GPR 0 "register_operand" "=d")
+        (sign_extract:GPR (match_operand:GPR 1 "register_operand" "d")
+                         (match_operand 2 "const_int_operand" "")
+                         (match_operand 3 "const_int_operand" "")))]
+  "ISA_HAS_EXTS && UINTVAL (operands[2]) <= 32"
+  "exts\t%0,%1,%3,%m2"
+  [(set_attr "type"     "arith")
+   (set_attr "mode"     "<MODE>")])
+
+
 (define_expand "extzv"
   [(set (match_operand 0 "register_operand")
        (zero_extract (match_operand 1 "nonimmediate_operand")
-                     (match_operand 2 "immediate_operand")
-                     (match_operand 3 "immediate_operand")))]
+                     (match_operand 2 "const_int_operand")
+                     (match_operand 3 "const_int_operand")))]
   "!TARGET_MIPS16"
 {
   if (mips_expand_ext_as_unaligned_load (operands[0], operands[1],
 (define_insn "extzv<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=d")
        (zero_extract:GPR (match_operand:GPR 1 "register_operand" "d")
-                         (match_operand:SI 2 "immediate_operand" "I")
-                         (match_operand:SI 3 "immediate_operand" "I")))]
+                         (match_operand 2 "const_int_operand" "")
+                         (match_operand 3 "const_int_operand" "")))]
   "mips_use_ins_ext_p (operands[1], INTVAL (operands[2]),
                       INTVAL (operands[3]))"
   "<d>ext\t%0,%1,%3,%2"
   [(set_attr "type"    "arith")
    (set_attr "mode"    "<MODE>")])
 
+(define_insn "*extzv_trunc<mode>_exts"
+  [(set (match_operand:GPR 0 "register_operand" "=d")
+        (truncate:GPR
+        (zero_extract:DI (match_operand:DI 1 "register_operand" "d")
+                         (match_operand 2 "const_int_operand" "")
+                         (match_operand 3 "const_int_operand" ""))))]
+  "ISA_HAS_EXTS && TARGET_64BIT && IN_RANGE (INTVAL (operands[2]), 32, 63)"
+  "exts\t%0,%1,%3,31"
+  [(set_attr "type"     "arith")
+   (set_attr "mode"     "<MODE>")])
+
 
 (define_expand "insv"
   [(set (zero_extract (match_operand 0 "nonimmediate_operand")
   [(set_attr "type"    "arith")
    (set_attr "mode"    "<MODE>")])
 
+;; Combiner pattern for cins (clear and insert bit field).  We can
+;; implement mask-and-shift-left operation with this.  Note that if
+;; the upper bit of the mask is set in an SImode operation, the mask
+;; itself will be sign-extended.  mask_low_and_shift_len will
+;; therefore be greater than our threshold of 32.
+
+(define_insn "*cins<mode>"
+  [(set (match_operand:GPR 0 "register_operand" "=d")
+       (and:GPR
+        (ashift:GPR (match_operand:GPR 1 "register_operand" "d")
+                    (match_operand:GPR 2 "const_int_operand" ""))
+        (match_operand:GPR 3 "const_int_operand" "")))]
+  "ISA_HAS_CINS
+   && mask_low_and_shift_p (<MODE>mode, operands[3], operands[2], 32)"
+{
+  operands[3] =
+    GEN_INT (mask_low_and_shift_len (<MODE>mode, operands[3], operands[2]));
+  return "cins\t%0,%1,%2,%m3";
+}
+  [(set_attr "type"     "shift")
+   (set_attr "mode"     "<MODE>")])
+
 ;; Unaligned word moves generated by the bit field patterns.
 ;;
 ;; As far as the rtl is concerned, both the left-part and right-part
 }
   [(set_attr "length" "20")])
 
-;; Atomic memory operations.
-
-(define_insn "memory_barrier"
-  [(set (mem:BLK (scratch))
-        (unspec:BLK [(const_int 0)] UNSPEC_MEMORY_BARRIER))]
-  "GENERATE_SYNC"
-  "%|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 "reg_or_0_operand" "dJ,dJ")
-                             (match_operand:GPR 3 "arith_operand" "I,d")]
-        UNSPEC_COMPARE_AND_SWAP))]
-  "GENERATE_LL_SC"
-{
-  if (which_alternative == 0)
-    return MIPS_COMPARE_AND_SWAP ("<d>", "li");
-  else
-    return MIPS_COMPARE_AND_SWAP ("<d>", "move");
-}
-  [(set_attr "length" "32")])
-
-(define_expand "sync_compare_and_swap<mode>"
-  [(match_operand:SHORT 0 "register_operand")
-   (match_operand:SHORT 1 "memory_operand")
-   (match_operand:SHORT 2 "general_operand")
-   (match_operand:SHORT 3 "general_operand")]
-  "GENERATE_LL_SC"
-{
-  union mips_gen_fn_ptrs generator;
-  generator.fn_6 = gen_compare_and_swap_12;
-  mips_expand_atomic_qihi (generator,
-                          operands[0], operands[1], operands[2], operands[3]);
-  DONE;
-})
-
-;; Helper insn for mips_expand_atomic_qihi.
-(define_insn "compare_and_swap_12"
-  [(set (match_operand:SI 0 "register_operand" "=&d,&d")
-       (match_operand:SI 1 "memory_operand" "+R,R"))
-   (set (match_dup 1)
-       (unspec_volatile:SI [(match_operand:SI 2 "register_operand" "d,d")
-                            (match_operand:SI 3 "register_operand" "d,d")
-                            (match_operand:SI 4 "reg_or_0_operand" "dJ,dJ")
-                            (match_operand:SI 5 "reg_or_0_operand" "d,J")]
-                           UNSPEC_COMPARE_AND_SWAP_12))]
-  "GENERATE_LL_SC"
-{
-  if (which_alternative == 0)
-    return MIPS_COMPARE_AND_SWAP_12 (MIPS_COMPARE_AND_SWAP_12_NONZERO_OP);
-  else
-    return MIPS_COMPARE_AND_SWAP_12 (MIPS_COMPARE_AND_SWAP_12_ZERO_OP);
-}
-  [(set_attr "length" "40,36")])
-
-(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))]
-  "GENERATE_LL_SC"
-{
-  if (which_alternative == 0)
-    return MIPS_SYNC_OP ("<d>", "<d>addiu");   
-  else
-    return MIPS_SYNC_OP ("<d>", "<d>addu");    
-}
-  [(set_attr "length" "28")])
-
-(define_expand "sync_<optab><mode>"
-  [(set (match_operand:SHORT 0 "memory_operand")
-       (unspec_volatile:SHORT
-         [(atomic_hiqi_op:SHORT (match_dup 0)
-                                (match_operand:SHORT 1 "general_operand"))]
-         UNSPEC_SYNC_OLD_OP))]
-  "GENERATE_LL_SC"
-{
-  union mips_gen_fn_ptrs generator;
-  generator.fn_4 = gen_sync_<optab>_12;
-  mips_expand_atomic_qihi (generator,
-                          NULL, operands[0], operands[1], NULL);
-  DONE;
-})
-
-;; Helper insn for sync_<optab><mode>
-(define_insn "sync_<optab>_12"
-  [(set (match_operand:SI 0 "memory_operand" "+R")
-       (unspec_volatile:SI
-          [(match_operand:SI 1 "register_operand" "d")
-          (match_operand:SI 2 "register_operand" "d")
-          (atomic_hiqi_op:SI (match_dup 0)
-                             (match_operand:SI 3 "register_operand" "dJ"))]
-         UNSPEC_SYNC_OLD_OP_12))
-   (clobber (match_scratch:SI 4 "=&d"))]
-  "GENERATE_LL_SC"
-{
-    return MIPS_SYNC_OP_12 ("<insn>", MIPS_SYNC_OP_12_NOT_NOP);        
-}
-  [(set_attr "length" "40")])
-
-(define_expand "sync_old_<optab><mode>"
-  [(parallel [
-     (set (match_operand:SHORT 0 "register_operand")
-         (match_operand:SHORT 1 "memory_operand"))
-     (set (match_dup 1)
-         (unspec_volatile:SHORT [(atomic_hiqi_op:SHORT
-                                   (match_dup 1)
-                                   (match_operand:SHORT 2 "general_operand"))]
-           UNSPEC_SYNC_OLD_OP))])]
-  "GENERATE_LL_SC"
-{
-  union mips_gen_fn_ptrs generator;
-  generator.fn_5 = gen_sync_old_<optab>_12;
-  mips_expand_atomic_qihi (generator,
-                          operands[0], operands[1], operands[2], NULL);
-  DONE;
-})
-
-;; Helper insn for sync_old_<optab><mode>
-(define_insn "sync_old_<optab>_12"
-  [(set (match_operand:SI 0 "register_operand" "=&d")
-       (match_operand:SI 1 "memory_operand" "+R"))
-   (set (match_dup 1)
-       (unspec_volatile:SI
-          [(match_operand:SI 2 "register_operand" "d")
-          (match_operand:SI 3 "register_operand" "d")
-          (atomic_hiqi_op:SI (match_dup 0)
-                             (match_operand:SI 4 "register_operand" "dJ"))]
-         UNSPEC_SYNC_OLD_OP_12))
-   (clobber (match_scratch:SI 5 "=&d"))]
-  "GENERATE_LL_SC"
-{
-    return MIPS_SYNC_OLD_OP_12 ("<insn>", MIPS_SYNC_OLD_OP_12_NOT_NOP,
-                               MIPS_SYNC_OLD_OP_12_NOT_NOP_REG);       
-}
-  [(set_attr "length" "40")])
-
-(define_expand "sync_new_<optab><mode>"
-  [(parallel [
-     (set (match_operand:SHORT 0 "register_operand")
-         (unspec_volatile:SHORT [(atomic_hiqi_op:SHORT
-                                   (match_operand:SHORT 1 "memory_operand")
-                                   (match_operand:SHORT 2 "general_operand"))]
-           UNSPEC_SYNC_NEW_OP))
-     (set (match_dup 1)
-         (unspec_volatile:SHORT [(match_dup 1) (match_dup 2)]
-           UNSPEC_SYNC_NEW_OP))])]
-  "GENERATE_LL_SC"
-{
-  union mips_gen_fn_ptrs generator;
-  generator.fn_5 = gen_sync_new_<optab>_12;
-  mips_expand_atomic_qihi (generator,
-                          operands[0], operands[1], operands[2], NULL);
-  DONE;
-})
-
-;; Helper insn for sync_new_<optab><mode>
-(define_insn "sync_new_<optab>_12"
-  [(set (match_operand:SI 0 "register_operand" "=&d")
-       (unspec_volatile:SI
-          [(match_operand:SI 1 "memory_operand" "+R")
-          (match_operand:SI 2 "register_operand" "d")
-          (match_operand:SI 3 "register_operand" "d")
-          (atomic_hiqi_op:SI (match_dup 0)
-                             (match_operand:SI 4 "register_operand" "dJ"))]
-         UNSPEC_SYNC_NEW_OP_12))
-   (set (match_dup 1)
-       (unspec_volatile:SI
-         [(match_dup 1)
-          (match_dup 2)
-          (match_dup 3)
-          (match_dup 4)] UNSPEC_SYNC_NEW_OP_12))]
-  "GENERATE_LL_SC"
-{
-    return MIPS_SYNC_NEW_OP_12 ("<insn>", MIPS_SYNC_NEW_OP_12_NOT_NOP);
-}
-  [(set_attr "length" "40")])
-
-(define_expand "sync_nand<mode>"
-  [(set (match_operand:SHORT 0 "memory_operand")
-       (unspec_volatile:SHORT
-         [(match_dup 0)
-          (match_operand:SHORT 1 "general_operand")]
-         UNSPEC_SYNC_OLD_OP))]
-  "GENERATE_LL_SC"
-{
-  union mips_gen_fn_ptrs generator;
-  generator.fn_4 = gen_sync_nand_12;
-  mips_expand_atomic_qihi (generator,
-                          NULL, operands[0], operands[1], NULL);
-  DONE;
-})
-
-;; Helper insn for sync_nand<mode>
-(define_insn "sync_nand_12"
-  [(set (match_operand:SI 0 "memory_operand" "+R")
-       (unspec_volatile:SI
-          [(match_operand:SI 1 "register_operand" "d")
-          (match_operand:SI 2 "register_operand" "d")
-          (match_dup 0)
-          (match_operand:SI 3 "register_operand" "dJ")]
-         UNSPEC_SYNC_OLD_OP_12))
-   (clobber (match_scratch:SI 4 "=&d"))]
-  "GENERATE_LL_SC"
-{
-    return MIPS_SYNC_OP_12 ("and", MIPS_SYNC_OP_12_NOT_NOT);   
-}
-  [(set_attr "length" "44")])
-
-(define_expand "sync_old_nand<mode>"
-  [(parallel [
-     (set (match_operand:SHORT 0 "register_operand")
-         (match_operand:SHORT 1 "memory_operand"))
-     (set (match_dup 1)
-         (unspec_volatile:SHORT [(match_dup 1)
-                                 (match_operand:SHORT 2 "general_operand")]
-           UNSPEC_SYNC_OLD_OP))])]
-  "GENERATE_LL_SC"
-{
-  union mips_gen_fn_ptrs generator;
-  generator.fn_5 = gen_sync_old_nand_12;
-  mips_expand_atomic_qihi (generator,
-                          operands[0], operands[1], operands[2], NULL);
-  DONE;
-})
-
-;; Helper insn for sync_old_nand<mode>
-(define_insn "sync_old_nand_12"
-  [(set (match_operand:SI 0 "register_operand" "=&d")
-       (match_operand:SI 1 "memory_operand" "+R"))
-   (set (match_dup 1)
-       (unspec_volatile:SI
-          [(match_operand:SI 2 "register_operand" "d")
-          (match_operand:SI 3 "register_operand" "d")
-          (match_operand:SI 4 "register_operand" "dJ")]
-         UNSPEC_SYNC_OLD_OP_12))
-   (clobber (match_scratch:SI 5 "=&d"))]
-  "GENERATE_LL_SC"
-{
-    return MIPS_SYNC_OLD_OP_12 ("and", MIPS_SYNC_OLD_OP_12_NOT_NOT,
-                               MIPS_SYNC_OLD_OP_12_NOT_NOT_REG);       
-}
-  [(set_attr "length" "44")])
-
-(define_expand "sync_new_nand<mode>"
-  [(parallel [
-     (set (match_operand:SHORT 0 "register_operand")
-         (unspec_volatile:SHORT [(match_operand:SHORT 1 "memory_operand")
-                                 (match_operand:SHORT 2 "general_operand")]
-           UNSPEC_SYNC_NEW_OP))
-     (set (match_dup 1)
-         (unspec_volatile:SHORT [(match_dup 1) (match_dup 2)]
-           UNSPEC_SYNC_NEW_OP))])]
-  "GENERATE_LL_SC"
-{
-  union mips_gen_fn_ptrs generator;
-  generator.fn_5 = gen_sync_new_nand_12;
-  mips_expand_atomic_qihi (generator,
-                          operands[0], operands[1], operands[2], NULL);
-  DONE;
-})
-
-;; Helper insn for sync_new_nand<mode>
-(define_insn "sync_new_nand_12"
-  [(set (match_operand:SI 0 "register_operand" "=&d")
-       (unspec_volatile:SI
-          [(match_operand:SI 1 "memory_operand" "+R")
-          (match_operand:SI 2 "register_operand" "d")
-          (match_operand:SI 3 "register_operand" "d")
-          (match_operand:SI 4 "register_operand" "dJ")]
-         UNSPEC_SYNC_NEW_OP_12))
-   (set (match_dup 1)
-       (unspec_volatile:SI
-         [(match_dup 1)
-          (match_dup 2)
-          (match_dup 3)
-          (match_dup 4)] UNSPEC_SYNC_NEW_OP_12))]
-  "GENERATE_LL_SC"
-{
-    return MIPS_SYNC_NEW_OP_12 ("and", MIPS_SYNC_NEW_OP_12_NOT_NOT);
-}
-  [(set_attr "length" "40")])
-
-(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))]
-  "GENERATE_LL_SC"
-{
-  return MIPS_SYNC_OP ("<d>", "<d>subu");      
-}
-  [(set_attr "length" "28")])
-
-(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))]
-  "GENERATE_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" "28")])
-
-(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))]
-  "GENERATE_LL_SC"
-{
-  return MIPS_SYNC_OLD_OP ("<d>", "<d>subu");  
-}
-  [(set_attr "length" "28")])
-
-(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))]
-  "GENERATE_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" "28")])
-
-(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))]
-  "GENERATE_LL_SC"
-{
-  return MIPS_SYNC_NEW_OP ("<d>", "<d>subu");  
-}
-  [(set_attr "length" "28")])
-
-(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))]
-  "GENERATE_LL_SC"
-{
-  if (which_alternative == 0)
-    return MIPS_SYNC_OP ("<d>", "<immediate_insn>");   
-  else
-    return MIPS_SYNC_OP ("<d>", "<insn>");     
-}
-  [(set_attr "length" "28")])
-
-(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))]
-  "GENERATE_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" "28")])
-
-(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))]
-  "GENERATE_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" "28")])
-
-(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))]
-  "GENERATE_LL_SC"
-{
-  if (which_alternative == 0)
-    return MIPS_SYNC_NAND ("<d>", "andi");     
-  else
-    return MIPS_SYNC_NAND ("<d>", "and");      
-}
-  [(set_attr "length" "32")])
-
-(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))]
-  "GENERATE_LL_SC"
-{
-  if (which_alternative == 0)
-    return MIPS_SYNC_OLD_NAND ("<d>", "andi"); 
-  else
-    return MIPS_SYNC_OLD_NAND ("<d>", "and");  
-}
-  [(set_attr "length" "32")])
-
-(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))]
-  "GENERATE_LL_SC"
-{
-  if (which_alternative == 0)
-    return MIPS_SYNC_NEW_NAND ("<d>", "andi"); 
-  else
-    return MIPS_SYNC_NEW_NAND ("<d>", "and");  
-}
-  [(set_attr "length" "32")])
-
-(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))]
-  "GENERATE_LL_SC"
-{
-  if (which_alternative == 0)
-    return MIPS_SYNC_EXCHANGE ("<d>", "li");
-  else
-    return MIPS_SYNC_EXCHANGE ("<d>", "move");
-}
-  [(set_attr "length" "24")])
-
-(define_expand "sync_lock_test_and_set<mode>"
-  [(match_operand:SHORT 0 "register_operand")
-   (match_operand:SHORT 1 "memory_operand")
-   (match_operand:SHORT 2 "general_operand")]
-  "GENERATE_LL_SC"
-{
-  union mips_gen_fn_ptrs generator;
-  generator.fn_5 = gen_test_and_set_12;
-  mips_expand_atomic_qihi (generator,
-                          operands[0], operands[1], operands[2], NULL);
-  DONE;
-})
-
-(define_insn "test_and_set_12"
-  [(set (match_operand:SI 0 "register_operand" "=&d,&d")
-       (match_operand:SI 1 "memory_operand" "+R,R"))
-   (set (match_dup 1)
-       (unspec_volatile:SI [(match_operand:SI 2 "register_operand" "d,d")
-                            (match_operand:SI 3 "register_operand" "d,d")
-                            (match_operand:SI 4 "arith_operand" "d,J")]
-         UNSPEC_SYNC_EXCHANGE_12))]
-  "GENERATE_LL_SC"
-{
-  if (which_alternative == 0)
-    return MIPS_SYNC_EXCHANGE_12 (MIPS_SYNC_EXCHANGE_12_NONZERO_OP);
-  else
-    return MIPS_SYNC_EXCHANGE_12 (MIPS_SYNC_EXCHANGE_12_ZERO_OP);
-}
-  [(set_attr "length" "28,24")])
 \f
 ;; Block moves, see mips.c for more details.
 ;; Argument 0 is the destination
        (if_then_else (match_operand 0)
                      (label_ref (match_operand 1))
                      (pc)))])
+
+;; Branch if bit is set/clear.
+
+(define_insn "*branch_bit<bbv><mode>"
+  [(set (pc)
+       (if_then_else
+        (equality_op (zero_extract:GPR
+                      (match_operand:GPR 1 "register_operand" "d")
+                      (const_int 1)
+                      (match_operand 2 "const_int_operand" ""))
+                     (const_int 0))
+        (label_ref (match_operand 0 ""))
+        (pc)))]
+  "ISA_HAS_BBIT && UINTVAL (operands[2]) < GET_MODE_BITSIZE (<MODE>mode)"
+{
+  return
+    mips_output_conditional_branch (insn, operands,
+                                   MIPS_BRANCH ("bbit<bbv>", "%1,%2,%0"),
+                                   MIPS_BRANCH ("bbit<bbinv>", "%1,%2,%0"));
+}
+  [(set_attr "type"         "branch")
+   (set_attr "mode"         "none")
+   (set_attr "branch_likely" "no")])
+
+(define_insn "*branch_bit<bbv><mode>_inverted"
+  [(set (pc)
+       (if_then_else
+        (equality_op (zero_extract:GPR
+                      (match_operand:GPR 1 "register_operand" "d")
+                      (const_int 1)
+                      (match_operand 2 "const_int_operand" ""))
+                     (const_int 0))
+        (pc)
+        (label_ref (match_operand 0 ""))))]
+  "ISA_HAS_BBIT && UINTVAL (operands[2]) < GET_MODE_BITSIZE (<MODE>mode)"
+{
+  return
+    mips_output_conditional_branch (insn, operands,
+                                   MIPS_BRANCH ("bbit<bbinv>", "%1,%2,%0"),
+                                   MIPS_BRANCH ("bbit<bbv>", "%1,%2,%0"));
+}
+  [(set_attr "type"         "branch")
+   (set_attr "mode"         "none")
+   (set_attr "branch_likely" "no")])
 \f
 ;;
 ;;  ....................
   ""
   { if (mips_expand_scc (EQ, operands[0])) DONE; else FAIL; })
 
-(define_insn "*seq_<GPR:mode><GPR2:mode>"
+(define_insn "*seq_zero_<GPR:mode><GPR2:mode>"
   [(set (match_operand:GPR2 0 "register_operand" "=d")
        (eq:GPR2 (match_operand:GPR 1 "register_operand" "d")
                 (const_int 0)))]
-  "!TARGET_MIPS16"
+  "!TARGET_MIPS16 && !ISA_HAS_SEQ_SNE"
   "sltu\t%0,%1,1"
   [(set_attr "type" "slt")
    (set_attr "mode" "<GPR:MODE>")])
 
-(define_insn "*seq_<GPR:mode><GPR2:mode>_mips16"
+(define_insn "*seq_zero_<GPR:mode><GPR2:mode>_mips16"
   [(set (match_operand:GPR2 0 "register_operand" "=t")
        (eq:GPR2 (match_operand:GPR 1 "register_operand" "d")
                 (const_int 0)))]
-  "TARGET_MIPS16"
+  "TARGET_MIPS16 && !ISA_HAS_SEQ_SNE"
   "sltu\t%1,1"
   [(set_attr "type" "slt")
    (set_attr "mode" "<GPR:MODE>")])
 
+;; Generate sltiu unless using seq results in better code.
+(define_insn "*seq_<GPR:mode><GPR2:mode>_seq"
+  [(set (match_operand:GPR2 0 "register_operand" "=d,d,d")
+       (eq:GPR2 (match_operand:GPR 1 "register_operand" "%d,d,d")
+                (match_operand:GPR 2 "reg_imm10_operand" "d,J,YB")))]
+  "ISA_HAS_SEQ_SNE"
+  "@
+   seq\t%0,%1,%2
+   sltiu\t%0,%1,1
+   seqi\t%0,%1,%2"
+  [(set_attr "type" "slt")
+   (set_attr "mode" "<GPR:MODE>")])
+
 ;; "sne" uses sltu instructions in which the first operand is $0.
 ;; This isn't possible in mips16 code.
 
   "!TARGET_MIPS16"
   { if (mips_expand_scc (NE, operands[0])) DONE; else FAIL; })
 
-(define_insn "*sne_<GPR:mode><GPR2:mode>"
+(define_insn "*sne_zero_<GPR:mode><GPR2:mode>"
   [(set (match_operand:GPR2 0 "register_operand" "=d")
        (ne:GPR2 (match_operand:GPR 1 "register_operand" "d")
                 (const_int 0)))]
-  "!TARGET_MIPS16"
+  "!TARGET_MIPS16 && !ISA_HAS_SEQ_SNE"
   "sltu\t%0,%.,%1"
   [(set_attr "type" "slt")
    (set_attr "mode" "<GPR:MODE>")])
 
+;; Generate sltu unless using sne results in better code.
+(define_insn "*sne_<GPR:mode><GPR2:mode>_sne"
+  [(set (match_operand:GPR2 0 "register_operand" "=d,d,d")
+       (ne:GPR2 (match_operand:GPR 1 "register_operand" "%d,d,d")
+                (match_operand:GPR 2 "reg_imm10_operand" "d,J,YB")))]
+  "ISA_HAS_SEQ_SNE"
+  "@
+   sne\t%0,%1,%2
+   sltu\t%0,%.,%1
+   snei\t%0,%1,%2"
+  [(set_attr "type" "slt")
+   (set_attr "mode" "<GPR:MODE>")])
+
 (define_expand "sgt<u>"
   [(set (match_operand:SI 0 "register_operand")
        (any_gt:SI (match_dup 1)
    (set_attr "can_delay" "no")
    (set_attr "mode" "<MODE>")])
 \f
+;; Synchronization instructions.
+
+(include "sync.md")
+
 ; The MIPS Paired-Single Floating Point and MIPS-3D Instructions.
 
 (include "mips-ps-3d.md")