OSDN Git Service

2007-09-02 David Daney <ddaney@avtrex.com>
authordaney <daney@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 3 Sep 2007 05:34:30 +0000 (05:34 +0000)
committerdaney <daney@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 3 Sep 2007 05:34:30 +0000 (05:34 +0000)
* config/mips/mips.md (UNSPEC_COMPARE_AND_SWAP, UNSPEC_SYNC_OLD_OP,
UNSPEC_SYNC_NEW_OP, UNSPEC_SYNC_EXCHANGE): New define_constants.
(optab, insn): Add more attributes.
(fetchop_bit): New code macro.
(immediate_insn): New code macro attribute.
(sync): Change condition to ISA_HAS_SYNC.
(rdhwr): Change predicate for operand 0 to register_operand.
(memory_barrier): New expand.
(sync_compare_and_swap<mode>, sync_add<mode>, sync_sub<mode>,
sync_old_add<mode>, sync_old_sub<mode>, sync_new_add<mode>,
sync_new_sub<mode>, sync_<optab><mode>, sync_old_<optab><mode>,
sync_new_<optab><mode>, sync_nand<mode>, sync_old_nand<mode>,
sync_new_nand<mode>, sync_lock_test_and_set<mode>): New insns.
* config/mips/mips.h (ISA_HAS_SYNC, ISA_HAS_LL_SC): New ISA predicates.
(MIPS_COMPARE_AND_SWAP, MIPS_SYNC_OP, MIPS_SYNC_OLD_OP,
MIPS_SYNC_NEW_OP, MIPS_SYNC_NAND, MIPS_SYNC_OLD_NAND,
MIPS_SYNC_NEW_NAND, MIPS_SYNC_EXCHANGE): New Macros.

2007-09-02  David Daney  <ddaney@avtrex.com>
* gcc.target/mips/gcc-have-sync-compare-and-swap-1.c: New test.
* gcc.target/mips/gcc-have-sync-compare-and-swap-2.c: Ditto.
* gcc.target/mips/atomic-memory-1.c: Ditto.
* testsuite/gcc.target/mips/atomic-memory-2.c: Ditto.

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

gcc/ChangeLog
gcc/config/mips/mips.h
gcc/config/mips/mips.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/mips/atomic-memory-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/atomic-memory-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/gcc-have-sync-compare-and-swap-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/gcc-have-sync-compare-and-swap-2.c [new file with mode: 0644]

index df1be60..6b10f52 100644 (file)
@@ -1,3 +1,23 @@
+2007-09-02  David Daney  <ddaney@avtrex.com>
+
+       * config/mips/mips.md (UNSPEC_COMPARE_AND_SWAP, UNSPEC_SYNC_OLD_OP,
+       UNSPEC_SYNC_NEW_OP, UNSPEC_SYNC_EXCHANGE): New define_constants.
+       (optab, insn): Add more attributes.
+       (fetchop_bit): New code macro.
+       (immediate_insn): New code macro attribute.
+       (sync): Change condition to ISA_HAS_SYNC.
+       (rdhwr): Change predicate for operand 0 to register_operand.
+       (memory_barrier): New expand.
+       (sync_compare_and_swap<mode>, sync_add<mode>, sync_sub<mode>,
+       sync_old_add<mode>, sync_old_sub<mode>, sync_new_add<mode>,
+       sync_new_sub<mode>, sync_<optab><mode>, sync_old_<optab><mode>,
+       sync_new_<optab><mode>, sync_nand<mode>, sync_old_nand<mode>,
+       sync_new_nand<mode>, sync_lock_test_and_set<mode>): New insns.
+       * config/mips/mips.h (ISA_HAS_SYNC, ISA_HAS_LL_SC): New ISA predicates.
+       (MIPS_COMPARE_AND_SWAP, MIPS_SYNC_OP, MIPS_SYNC_OLD_OP,
+       MIPS_SYNC_NEW_OP, MIPS_SYNC_NAND, MIPS_SYNC_OLD_NAND,
+       MIPS_SYNC_NEW_NAND, MIPS_SYNC_EXCHANGE): New Macros.
+       
 2007-09-03  Jesper Nilsson  <jesper.nilsson@axis.com>
            Hans-Peter Nilsson  <hp@axis.com>
 
index c3797e5..a44460b 100644 (file)
@@ -881,6 +881,13 @@ extern enum mips_code_readable_setting mips_code_readable;
 /* ISA includes synci, jr.hb and jalr.hb.  */
 #define ISA_HAS_SYNCI (ISA_MIPS32R2 && !TARGET_MIPS16)
 
+/* ISA includes sync.  */
+#define ISA_HAS_SYNC ((mips_isa >= 2 || TARGET_MIPS3900) && !TARGET_MIPS16)
+
+/* ISA includes ll and sc.  Note that this implies ISA_HAS_SYNC
+   because the expanders use both ISA_HAS_SYNC and ISA_HAS_LL_SC
+   instructions.  */
+#define ISA_HAS_LL_SC (mips_isa >= 2 && !TARGET_MIPS16)
 \f
 /* Add -G xx support.  */
 
@@ -2871,3 +2878,140 @@ while (0)
 #ifndef HAVE_AS_TLS
 #define HAVE_AS_TLS 0
 #endif
+
+/* Return an asm string that atomically:
+
+     - Compares memory reference %1 to register %2 and, if they are
+       equal, changes %1 to %3.
+
+     - Sets register %0 to the old value of memory reference %1.
+
+   SUFFIX is the suffix that should be added to "ll" and "sc" instructions
+   and OP is the instruction that should be used to load %3 into a
+   register.  */
+#define MIPS_COMPARE_AND_SWAP(SUFFIX, OP)      \
+  "%(%<%[sync\n"                               \
+  "1:\tll" SUFFIX "\t%0,%1\n"                  \
+  "\tbne\t%0,%2,2f\n"                          \
+  "\t" OP "\t%@,%3\n"                          \
+  "\tsc" SUFFIX "\t%@,%1\n"                    \
+  "\tbeq\t%@,%.,1b\n"                          \
+  "\tnop\n"                                    \
+  "2:%]%>%)"
+
+/* Return an asm string that atomically:
+
+     - Sets memory reference %0 to %0 INSN %1.
+
+   SUFFIX is the suffix that should be added to "ll" and "sc"
+   instructions.  */
+#define MIPS_SYNC_OP(SUFFIX, INSN)             \
+  "%(%<%[sync\n"                               \
+  "1:\tll" SUFFIX "\t%@,%0\n"                  \
+  "\t" INSN "\t%@,%@,%1\n"                     \
+  "\tsc" SUFFIX "\t%@,%0\n"                    \
+  "\tbeq\t%@,%.,1b\n"                          \
+  "\tnop%]%>%)"
+
+/* Return an asm string that atomically:
+
+     - Sets memory reference %1 to %1 INSN %2.
+
+     - Sets register %0 to the old value of memory reference %1.
+
+   SUFFIX is the suffix that should be added to "ll" and "sc"
+   instructions.  */
+#define MIPS_SYNC_OLD_OP(SUFFIX, INSN)         \
+  "%(%<%[sync\n"                               \
+  "1:\tll" SUFFIX "\t%0,%1\n"                  \
+  "\t" INSN "\t%@,%0,%2\n"                     \
+  "\tsc" SUFFIX "\t%@,%1\n"                    \
+  "\tbeq\t%@,%.,1b\n"                          \
+  "\tnop%]%>%)"
+
+/* Return an asm string that atomically:
+
+     - Sets memory reference %1 to %1 INSN %2.
+
+     - Sets register %0 to the new value of memory reference %1.
+
+   SUFFIX is the suffix that should be added to "ll" and "sc"
+   instructions.  */
+#define MIPS_SYNC_NEW_OP(SUFFIX, INSN)         \
+  "%(%<%[sync\n"                               \
+  "1:\tll" SUFFIX "\t%0,%1\n"                  \
+  "\t" INSN "\t%@,%0,%2\n"                     \
+  "\tsc" SUFFIX "\t%@,%1\n"                    \
+  "\tbeq\t%@,%.,1b\n"                          \
+  "\t" INSN "\t%0,%0,%2%]%>%)"
+
+/* Return an asm string that atomically:
+
+     - Sets memory reference %0 to ~%0 AND %1.
+
+   SUFFIX is the suffix that should be added to "ll" and "sc"
+   instructions.  INSN is the and instruction needed to and a register
+   with %2.  */
+#define MIPS_SYNC_NAND(SUFFIX, INSN)           \
+  "%(%<%[sync\n"                               \
+  "1:\tll" SUFFIX "\t%@,%0\n"                  \
+  "\tnor\t%@,%@,%.\n"                          \
+  "\t" INSN "\t%@,%@,%1\n"                     \
+  "\tsc" SUFFIX "\t%@,%0\n"                    \
+  "\tbeq\t%@,%.,1b\n"                          \
+  "\tnop%]%>%)"
+
+/* Return an asm string that atomically:
+
+     - Sets memory reference %1 to ~%1 AND %2.
+
+     - Sets register %0 to the old value of memory reference %1.
+
+   SUFFIX is the suffix that should be added to "ll" and "sc"
+   instructions.  INSN is the and instruction needed to and a register
+   with %2.  */
+#define MIPS_SYNC_OLD_NAND(SUFFIX, INSN)       \
+  "%(%<%[sync\n"                               \
+  "1:\tll" SUFFIX "\t%0,%1\n"                  \
+  "\tnor\t%@,%0,%.\n"                          \
+  "\t" INSN "\t%@,%@,%2\n"                     \
+  "\tsc" SUFFIX "\t%@,%1\n"                    \
+  "\tbeq\t%@,%.,1b\n"                          \
+  "\tnop%]%>%)"
+
+/* Return an asm string that atomically:
+
+     - Sets memory reference %1 to ~%1 AND %2.
+
+     - Sets register %0 to the new value of memory reference %1.
+
+   SUFFIX is the suffix that should be added to "ll" and "sc"
+   instructions.  INSN is the and instruction needed to and a register
+   with %2.  */
+#define MIPS_SYNC_NEW_NAND(SUFFIX, INSN)       \
+  "%(%<%[sync\n"                               \
+  "1:\tll" SUFFIX "\t%0,%1\n"                  \
+  "\tnor\t%0,%0,%.\n"                          \
+  "\t" INSN "\t%@,%0,%2\n"                     \
+  "\tsc" SUFFIX "\t%@,%1\n"                    \
+  "\tbeq\t%@,%.,1b\n"                          \
+  "\t" INSN "\t%0,%0,%2%]%>%)"
+
+/* Return an asm string that atomically:
+
+     - Sets memory reference %1 to %2.
+
+     - Sets register %0 to the old value of memory reference %1.
+
+   SUFFIX is the suffix that should be added to "ll" and "sc"
+   instructions.  OP is the and instruction that should be used to
+   load %2 into a register.  */
+#define MIPS_SYNC_EXCHANGE(SUFFIX, OP)         \
+  "%(%<%[\n"                                   \
+  "1:\tll" SUFFIX "\t%0,%1\n"                  \
+  "\t" OP "\t%@,%2\n"                          \
+  "\tsc" SUFFIX "\t%@,%1\n"                    \
+  "\tbeq\t%@,%.,1b\n"                          \
+  "\tnop\n"                                    \
+  "\tsync%]%>%)"
+
index 44c3c9c..368da18 100644 (file)
    (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)
 ;; <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_macro 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
 ;; .........................
 ;;
 
 (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
index eb93d33..620c7a7 100644 (file)
@@ -1,3 +1,10 @@
+2007-09-02  David Daney  <ddaney@avtrex.com>
+
+       * gcc.target/mips/gcc-have-sync-compare-and-swap-1.c: New test.
+       * gcc.target/mips/gcc-have-sync-compare-and-swap-2.c: Ditto.
+       * gcc.target/mips/atomic-memory-1.c: Ditto.
+       * testsuite/gcc.target/mips/atomic-memory-2.c: Ditto.
+
 2007-09-03  Jesper Nilsson  <jesper.nilsson@axis.com>
 
        * gcc.target/cris/builtin_clz_v0.c: New testcase.
diff --git a/gcc/testsuite/gcc.target/mips/atomic-memory-1.c b/gcc/testsuite/gcc.target/mips/atomic-memory-1.c
new file mode 100644 (file)
index 0000000..1664daa
--- /dev/null
@@ -0,0 +1,41 @@
+/* { dg-do run } */
+extern void abort (void);
+extern void exit (int);
+
+int main ()
+{
+#ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
+  unsigned v = 0;
+  __sync_synchronize ();
+
+  if (!__sync_bool_compare_and_swap (&v, 0, 30000))
+    abort();
+  if (30000 != __sync_val_compare_and_swap (&v, 30000, 100001))
+    abort();
+  __sync_sub_and_fetch (&v, 0x8001);
+  __sync_sub_and_fetch (&v, 0x7fff);
+  if (v != 34465)
+    abort();
+  if (__sync_nand_and_fetch (&v, 0xff) != 94)
+    abort();
+  if (__sync_fetch_and_add (&v, 6) != 94)
+    abort();
+  if (v != 100)
+    abort();
+  if (__sync_or_and_fetch (&v, 0xf001) != 0xf065)
+    abort();
+  if (__sync_and_and_fetch (&v, 0x1000) != 0x1000)
+    abort();
+  if (__sync_xor_and_fetch (&v, 0xa51040) != 0xa50040)
+    abort();
+  __sync_and_and_fetch (&v, 7);
+  if (__sync_lock_test_and_set(&v, 1) != 0)
+    abort();
+  if (v != 1)
+    abort();
+  __sync_lock_release (&v);
+  if (v != 0)
+    abort();
+#endif
+  exit(0);
+}
diff --git a/gcc/testsuite/gcc.target/mips/atomic-memory-2.c b/gcc/testsuite/gcc.target/mips/atomic-memory-2.c
new file mode 100644 (file)
index 0000000..b0492be
--- /dev/null
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-mips-options "-O2 -mips32 -mabi=32" } */
+/* { dg-final { scan-assembler "addiu" } } */
+/* { dg-final { scan-assembler-not "subu" } } */
+
+unsigned long
+f(unsigned long *p)
+{
+    return __sync_fetch_and_sub (p, 5);
+}
diff --git a/gcc/testsuite/gcc.target/mips/gcc-have-sync-compare-and-swap-1.c b/gcc/testsuite/gcc.target/mips/gcc-have-sync-compare-and-swap-1.c
new file mode 100644 (file)
index 0000000..315aa46
--- /dev/null
@@ -0,0 +1,22 @@
+/* { dg-do preprocess } */
+/* { dg-options "-mips32 -mabi=32" } */
+
+#ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1
+#error nonono
+#endif
+
+#ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2
+#error nonono
+#endif
+
+#ifndef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
+#error nonono
+#endif
+
+#ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8
+#error nonono
+#endif
+
+#ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16
+#error nonono
+#endif
diff --git a/gcc/testsuite/gcc.target/mips/gcc-have-sync-compare-and-swap-2.c b/gcc/testsuite/gcc.target/mips/gcc-have-sync-compare-and-swap-2.c
new file mode 100644 (file)
index 0000000..f07ebe7
--- /dev/null
@@ -0,0 +1,22 @@
+/* { dg-do preprocess { target { mips64*-*-* } } } */
+/* { dg-options "-mips64 -mabi=64" } */
+
+#ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1
+#error nonono
+#endif
+
+#ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2
+#error nonono
+#endif
+
+#ifndef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
+#error nonono
+#endif
+
+#ifndef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8
+#error nonono
+#endif
+
+#ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16
+#error nonono
+#endif