This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: RFC: [PATCH] MIPS: Implement built-in atomic memory operations.


Richard Sandiford wrote:
David Daney <ddaney@avtrex.com> writes:
I split the fetch_ops into two groups (arithmetic and bitwise). This was to make it possible to have patterns that matched immediate operands as they are treated differently in the two cases (sign extended vs. zero extended).

FWIW, that difference could be handled by code attributes. I think the real problem is the need for "<d>" in arithmetic ops and not logical ops.


Right. My stated reason was what go me thinking about splitting them up, but in the end, as you note, the <d> business is what necessitates it. It may be possible to invent some complicated code macro to handle it, but this seems clean enough.


+(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))
+ (clobber (match_scratch:GPR 4 "=d,d"))]

Operand 4 needs to be earlyclobber too, to handle the case where the loop iterates. But why not use $at instead?


Done.


FWIW, we could handle "IKL" (with an appropriate predicate)
without any change to the template.


Perhaps as a follow on. I am not sure how often these built-ins would be used there the "L" constraint would match.


+{
+ output_asm_insn(".set\tpush\n"
+ "\t.set\tnoreorder\n"
+ "\t.set\tnomacro\n"
+ "\tsync\n"
+ "1:\tll<d>\t%0,%1\n"
+ "\tbne\t%0,%2,2f", operands);
+
+ if (which_alternative == 0)
+ output_asm_insn("li\t%4,%3", operands);
+ else
+ output_asm_insn("move\t%4,%3", operands);
+
+ return "sc<d>\t%4,%1\n"
+ "\tbeq\t%4,$0,1b\n"
+ "\tnop\n"
+ "2:\n"
+ "\t.set\tpop";
+}
+ [(set_attr "length" "28")])

Please use %(%<...%>%) to wrap the set noreorder/set nomacro stuff. Make that %(%<%[...%]%>%) if we're using $at (nice and readable, eh?) Also use $@ instead of $at and $. instead of $0.


Oh good. I didn't know about those.



I think it would be (slightly) cleaner to have:

/* 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"				\
  OP "\t%@,%3\n"				\
  "\tsd" SUFFIX "%@,%1\n"			\
  "\tbeq\t%@,%.,1b\n"				\
  "\tnop\n"					\
  "2:%]%>%)\n"
....
  if (which_alternative == 0)
    return MIPS_COMPARE_AND_SWAP ("<d>", "li");
  else
    return MIPS_COMPARE_AND_SWAP ("<d>", "move");

The win isn't that big here, but it's bigger if we do the same thing
for the (repeated) sync_old* and sync_new* patterns; more below.


OK. I went with that pretty much verbatim.


+(define_code_macro FETCHOP_ARITH [plus minus])

These are usually lowercase for MIPS. Please put at the top of the file, with the others.


Changed.


+(define_code_attr fetchop_arith_name [(plus "add") (minus "sub")])

Add this to the "optab" attribute



Done


+(define_code_attr fetchop_arith_op [(plus "addu") (minus "subu")])

...and this to the "insn" attribute.



Done.


+(define_code_attr fetchop_arith_imm_op [(plus "addiu") (minus "subiu")])

We shouldn't pretend there's a "subiu" insn. I suppose this is where the idea of using code macros falls down ;( We could get around it by adding code attributes for the predicate and constraint (as Alpha does) but perhaps it is better to keep them separate.


Right. I probably would have discovered that if I tried to assemble it. I handle this case now with the new 'immediate_negative' code macro attribute.


+(define_insn "sync_old_<fetchop_arith_name><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_ARITH:GPR (match_operand:GPR 2 "arith_operand" "I,d")
+ (match_dup 2))]
+ UNSPEC_SYNC_OLD_OP))
+ (clobber (match_scratch:GPR 3 "=d,d"))]
+ "ISA_HAS_LL_SC"

Same $at comment here. Also, the first operand to the fetchop ought to be 1 rather than 2. (Not that it makes any difference to the generated code; it's just a little confusing as-is.)

Again, I think it would be good to add a MIPS_SYNC_OLD macro,
along the lines of MIPS_COMPARE_AND_SWAP above.


Fixed.


+(define_code_attr fetchop_bit_imm_op [(ior "ori") (xor "xori") (and "andi")])

Let's make this "imm_insn", to match "insn".



Uh, I used 'immediate_insn'. If you thing the shorter spelling would be better I will change it.


+(define_insn "sync_new_<fetchop_arith_name><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_ARITH:GPR (match_operand:GPR 2 "arith_operand" "I,d")
+ (match_dup 2))]
+ UNSPEC_SYNC_NEW_OP))
+ (clobber (match_scratch:GPR 3 "=d,d"))]
+ "ISA_HAS_LL_SC"

Again, this pattern is a little confusing. Operand 0 is set to the result of the operation, not the original memory reference.


OK, but who is really to say which part of a parallel happens first? I tried rewriting it as you suggest and it seems to work, but it makes all the cases look so different that I thought it was easier to work on if they were all the same.


Same $at comment, and it might be better to have a MIPS_SYNC_NEW macro.

+(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))
+ (clobber (match_scratch:GPR 3 "=d,d"))]
+ "ISA_HAS_LL_SC"
+{
+ output_asm_insn(".set\tpush\n"
+ "\t.set\tnoreorder\n"
+ "\t.set\tnomacro\n"
+ "\tsync\n"
+ "1:\tll<d>\t%0,%1\n"
+ "\tnor\t%0,$0,%0", operands);
+
+ if (which_alternative == 0)
+ output_asm_insn("andi\t%3,%0,%2", operands);
+ else
+ output_asm_insn("and\t%3,%0,%2", operands);
+
+ return "move\t%0,%3\n"
+ "\tsc<d>\t%3,%1\n"
+ "\tbeq\t%3,$0,1b\n"
+ "\tnop\n"
+ "\t.set\tpop";
+}

Why not avoid the move and use the same delay-slot repeat that you used
in the other sync_new* patterns?

Good point. Fixed now.


+(define_insn "sync_lock_test_and_set<mode>"
+ [(set (match_operand:GPR 0 "register_operand" "=&d")
+ (match_operand:GPR 1 "memory_operand" "+R"))
+ (set (match_dup 1)
+ (unspec_volatile:GPR [(match_operand:GPR 2 "register_operand" "d")]
+ UNSPEC_SYNC_EXCHANGE))
+ (clobber (match_scratch:GPR 3 "=d"))]
+ "ISA_HAS_LL_SC"
+{
+ return ".set\tpush\n"
+ "\t.set\tnoreorder\n"
+ "\t.set\tnomacro\n"
+ "1:\tll<d>\t%0,%1\n"
+ "\tmove\t%3,%2"
+ "\tsc<d>\t%3,%1\n"
+ "\tbeq\t%3,$0,1b\n"
+ "\tnop\n"
+ "\tsync\n"
+ "\t.set\tpop";
+}

No need for a C block. Just make this a plain asm template.

I used the macro like all the other cases because with a constant operand, we can generate smaller code but need two alternatives.



Here is the new patch. I added a new constraint 'Z' which matches constants where we can change the sign and still have sign-extend and fit in 16 bits. This allows subtraction of a constant to be written as addition of the negative value of the constant. Other than that it is mostly just addressing the issues raised by Richard.


I added some tests, and actually am testing this version.

So far tested on mips64-linux n32 ABI only. If OKed, I will also test on o32 and n64 and libjava using these builtins instead of the hand coded assembly routines.

Comments? OK to commit?

David Daney

gcc/
2007-08-17  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_arith, fetchop_bit): New code macros.
   (immediate_constraint, immediate_negative, immediate_insn): New
   code macro attributes.
   (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_<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.
   * config/mips/constraints.md (Z): New mips constraint.
   * doc/md.texi: Document it.

gcc/testsuite/ 2007-08-17 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.



Index: doc/md.texi
===================================================================
--- doc/md.texi	(revision 127356)
+++ doc/md.texi	(working copy)
@@ -2540,6 +2540,9 @@ Floating-point zero.
 
 @item R
 An address that can be used in a non-macro load or store.
+
+@item Z
+A constant in the range -32767 to 32767 (inclusive).
 @end table
 
 @item Motorola 680x0---@file{config/m68k/m68k.h}
Index: testsuite/gcc.target/mips/gcc-have-sync-compare-and-swap-1.c
===================================================================
--- testsuite/gcc.target/mips/gcc-have-sync-compare-and-swap-1.c	(revision 0)
+++ testsuite/gcc.target/mips/gcc-have-sync-compare-and-swap-1.c	(revision 0)
@@ -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
Index: testsuite/gcc.target/mips/atomic-memory-1.c
===================================================================
--- testsuite/gcc.target/mips/atomic-memory-1.c	(revision 0)
+++ testsuite/gcc.target/mips/atomic-memory-1.c	(revision 0)
@@ -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, 100000))
+    abort();
+  __sync_sub_and_fetch (&v, 0x8000);
+  __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);
+}
Index: testsuite/gcc.target/mips/gcc-have-sync-compare-and-swap-2.c
===================================================================
--- testsuite/gcc.target/mips/gcc-have-sync-compare-and-swap-2.c	(revision 0)
+++ testsuite/gcc.target/mips/gcc-have-sync-compare-and-swap-2.c	(revision 0)
@@ -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
Index: config/mips/constraints.md
===================================================================
--- config/mips/constraints.md	(revision 127356)
+++ config/mips/constraints.md	(working copy)
@@ -135,6 +135,11 @@ (define_constraint "P"
   (and (match_code "const_int")
        (match_test "ival > 0 && ival < 0x10000")))
 
+(define_constraint "Z"
+  "A constant in the range -32767 to 32767 (inclusive)."
+  (and (match_code "const_int")
+       (match_test "ival > -0x8000 && ival < 0x8000")))
+
 ;; Floating-point constraints
 
 (define_constraint "G"
Index: config/mips/mips.md
===================================================================
--- config/mips/mips.md	(revision 127356)
+++ config/mips/mips.md	(working copy)
@@ -53,7 +53,11 @@ (define_constants
    (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)
@@ -576,12 +580,22 @@ (define_code_attr su [(sign_extend "s") 
 ;; <optab> expands to the name of the optab for a particular code.
 (define_code_attr optab [(ashift "ashl")
 			 (ashiftrt "ashr")
-			 (lshiftrt "lshr")])
+			 (lshiftrt "lshr")
+			 (plus "add")
+			 (minus "sub")
+			 (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")
+			(plus "addu")
+			(minus "subu")
+			(ior "or")
+			(xor "xor")
+			(and "and")])
 
 ;; <fcond> is the c.cond.fmt condition associated with a particular code.
 (define_code_attr fcond [(unordered "un")
@@ -597,6 +611,25 @@ (define_code_attr swapped_fcond [(ge "le
 				 (gt "lt")
 				 (unge "ule")
 				 (ungt "ult")])
+
+;; Atomic fetch arithmetical operations.
+(define_code_macro fetchop_arith [plus minus])
+
+;; Atomic fetch bitwise operations.
+(define_code_macro fetchop_bit [ior xor and])
+
+;; <immediate_constraint> expands to the constraint to be used
+;; for immediate arithmetical operations.
+(define_code_attr immediate_constraint [(plus "I") (minus "Z")])
+
+;; <immediate_negative> expands to 1 for minus because subtraction may be
+;; implemented as addition of the negative immediate value.
+(define_code_attr immediate_negative [(plus "0") (minus "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")])
+
 
 ;; .........................
 ;;
@@ -4251,7 +4284,7 @@ (define_expand "clear_cache"
 
 (define_insn "sync"
   [(unspec_volatile [(const_int 0)] UNSPEC_SYNC)]
-  "ISA_HAS_SYNCI"
+  "ISA_HAS_SYNC"
   "sync")
 
 (define_insn "synci"
@@ -4261,7 +4294,7 @@ (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"
@@ -4283,6 +4316,209 @@ (define_insn "clear_hazard"
          "\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_<optab><mode>"
+  [(set (match_operand:GPR 0 "memory_operand" "+R,R")
+	(unspec_volatile:GPR
+          [(fetchop_arith:GPR (match_operand:GPR 1 "arith_operand"
+						   "<immediate_constraint>,d")
+			      (match_dup 0))]
+	 UNSPEC_SYNC_OLD_OP))]
+  "ISA_HAS_LL_SC"
+{
+  if (which_alternative == 0)
+    {
+      if (<immediate_negative>)
+	{
+	  gcc_assert(GET_CODE (operands[1]) == CONST_INT);
+	  operands[1] = GEN_INT (-INTVAL (operands[1]));
+	}
+      return MIPS_SYNC_OP ("<d>", "<d>addiu");	
+    }
+  else
+    return MIPS_SYNC_OP ("<d>", "<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_arith:GPR (match_operand:GPR 2 "arith_operand"
+						   "<immediate_constraint>,d")
+			      (match_dup 1))]
+	 UNSPEC_SYNC_OLD_OP))]
+  "ISA_HAS_LL_SC"
+{
+  if (which_alternative == 0)
+    {
+      if (<immediate_negative>)
+	{
+	  gcc_assert(GET_CODE (operands[2]) == CONST_INT);
+	  operands[2] = GEN_INT (-INTVAL (operands[2]));
+	}
+      return MIPS_SYNC_OLD_OP ("<d>", "<d>addiu");	
+    }
+  else
+    return MIPS_SYNC_OLD_OP ("<d>", "<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_arith:GPR (match_operand:GPR 2 "arith_operand"
+						   "<immediate_constraint>,d")
+			      (match_dup 1))]
+	 UNSPEC_SYNC_NEW_OP))]
+  "ISA_HAS_LL_SC"
+{
+  if (which_alternative == 0)
+    {
+      if (<immediate_negative>)
+	{
+	  gcc_assert(GET_CODE (operands[2]) == CONST_INT);
+	  operands[2] = GEN_INT (-INTVAL (operands[2]));
+	}
+      return MIPS_SYNC_NEW_OP ("<d>", "<d>addiu");	
+    }
+  else
+    return MIPS_SYNC_NEW_OP ("<d>", "<d><insn>");	
+}
+  [(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")])
 
 ;; Block moves, see mips.c for more details.
 ;; Argument 0 is the destination
Index: config/mips/mips.h
===================================================================
--- config/mips/mips.h	(revision 127356)
+++ config/mips/mips.h	(working copy)
@@ -876,6 +876,11 @@ extern enum mips_code_readable_setting m
 /* 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.  */
+#define ISA_HAS_LL_SC (mips_isa >= 2 && !TARGET_MIPS16)
 
 /* Add -G xx support.  */
 
@@ -2815,3 +2820,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 Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]