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]

[PATCH] Fix IA-64 __sync_*_compare_and_swap_si intrinsic


Hi!

IA-64 cmpxchg4.{acq,rel} instructions do atomically a zero extended
load from memory, compare that to the content of the ar.ccv register
and then store the new value and return old. The comparison is done as a
64-bit register comparison, at least my testing shows that.
So, say mov ar.ccv = -30 is necessarily wrong before cmpxchg4.acq, since
the zero-extended load will never have topmost 32 bits set.
fetch_and_op and op_and_fetch IMHO can stay as is, since they do
emit the memory load (which zero-extends) too and store that into ar.ccv.
I wonder whether removing the mode from cmpxchg_acq_si is ok (a warning
is emitted for it). Should I create two SImode insn patterns instead,
one with SImode and one with DImode ccv?
Ok to commit? 3.3 too?

2003-03-24  Jakub Jelinek  <jakub at redhat dot com>

	* config/ia64/ia64.c (ia64_expand_op_and_fetch): Fix comment.
	(ia64_expand_compare_and_swap): Use always DImode ar.ccv,
	zero extend old to it.
	* config/ia64/ia64.md (cmpxchg_acq_si): Remove mode from ccv
	operand.

	* gcc.dg/ia64-sync-3.c: New test.

--- gcc/config/ia64/ia64.c.jj	2003-03-18 18:55:44.000000000 -0500
+++ gcc/config/ia64/ia64.c	2003-03-24 10:12:13.000000000 -0500
@@ -8047,7 +8047,7 @@ ia64_expand_fetch_and_op (binoptab, mode
      do {
        old = tmp;
        ar.ccv = tmp;
-       ret = tmp + value;
+       ret = tmp <op> value;
        cmpxchgsz.acq tmp = [ptr], ret
      } while (tmp != old)
 */
@@ -8150,8 +8150,15 @@ ia64_expand_compare_and_swap (mode, bool
   else
     tmp = gen_reg_rtx (mode);
 
-  ccv = gen_rtx_REG (mode, AR_CCV_REGNUM);
-  emit_move_insn (ccv, old);
+  ccv = gen_rtx_REG (DImode, AR_CCV_REGNUM);
+  if (mode == DImode)
+    emit_move_insn (ccv, old);
+  else
+    {
+      rtx ccvtmp = gen_reg_rtx (DImode);
+      emit_insn (gen_zero_extendsidi2 (ccvtmp, old));
+      emit_move_insn (ccv, ccvtmp);
+    }
   emit_insn (gen_mf ());
   if (mode == SImode)
     insn = gen_cmpxchg_acq_si (tmp, mem, new, ccv);
--- gcc/config/ia64/ia64.md.jj	2003-03-13 19:23:01.000000000 -0500
+++ gcc/config/ia64/ia64.md	2003-03-24 09:27:03.000000000 -0500
@@ -5424,7 +5424,7 @@
    (set (match_operand:SI 1 "not_postinc_memory_operand" "+S")
         (unspec:SI [(match_dup 1)
                     (match_operand:SI 2 "gr_register_operand" "r")
-		    (match_operand:SI 3 "ar_ccv_reg_operand" "")]
+		    (match_operand 3 "ar_ccv_reg_operand" "")]
 		   UNSPEC_CMPXCHG_ACQ))]
   ""
   "cmpxchg4.acq %0 = %1, %2, %3"
--- gcc/testsuite/gcc.dg/ia64-sync-3.c.jj	2003-03-24 09:54:50.000000000 -0500
+++ gcc/testsuite/gcc.dg/ia64-sync-3.c	2003-03-24 10:02:10.000000000 -0500
@@ -0,0 +1,74 @@
+/* { dg-do run { target ia64-*-* } } */
+/* { dg-options } */
+
+/* Test basic functionality of the intrinsics.  */
+
+#include <ia64intrin.h>
+
+static int AI[4];
+static int init_si[4] = { -30,-30,-50,-50 };
+static int test_si[4] = { -115,-115,25,25 };
+
+static void
+do_si (void)
+{
+  if (__sync_val_compare_and_swap(AI+0, -30, -115) != -30)
+    abort ();
+  if (__sync_val_compare_and_swap(AI+0, -30, -115) != -115)
+    abort ();
+  if (__sync_bool_compare_and_swap(AI+1, -30, -115) != 1)
+    abort ();
+  if (__sync_bool_compare_and_swap(AI+1, -30, -115) != 0)
+    abort ();
+
+  if (__sync_val_compare_and_swap(AI+2, AI[2], 25) != -50)
+    abort ();
+  if (__sync_val_compare_and_swap(AI+2, AI[2], 25) != 25)
+    abort ();
+  if (__sync_bool_compare_and_swap(AI+3, AI[3], 25) != 1)
+    abort ();
+  if (__sync_bool_compare_and_swap(AI+3, AI[3], 25) != 1)
+    abort ();
+}
+
+static long AL[4];
+static long init_di[4] = { -30,-30,-50,-50 };
+static long test_di[4] = { -115,-115,25,25 };
+
+static void
+do_di (void)
+{
+  if (__sync_val_compare_and_swap(AL+0, -30, -115) != -30)
+    abort ();
+  if (__sync_val_compare_and_swap(AL+0, -30, -115) != -115)
+    abort ();
+  if (__sync_bool_compare_and_swap(AL+1, -30, -115) != 1)
+    abort ();
+  if (__sync_bool_compare_and_swap(AL+1, -30, -115) != 0)
+    abort ();
+
+  if (__sync_val_compare_and_swap(AL+2, AL[2], 25) != -50)
+    abort ();
+  if (__sync_val_compare_and_swap(AL+2, AL[2], 25) != 25)
+    abort ();
+  if (__sync_bool_compare_and_swap(AL+3, AL[3], 25) != 1)
+    abort ();
+  if (__sync_bool_compare_and_swap(AL+3, AL[3], 25) != 1)
+    abort ();
+}
+
+int main()
+{
+  memcpy(AI, init_si, sizeof(init_si));
+  memcpy(AL, init_di, sizeof(init_di));
+
+  do_si ();
+  do_di ();
+
+  if (memcmp (AI, test_si, sizeof(test_si)))
+    abort ();
+  if (memcmp (AL, test_di, sizeof(test_di)))
+    abort ();
+
+  return 0;
+}

	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]