This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Fix IA-64 __sync_*_compare_and_swap_si intrinsic
- From: Jakub Jelinek <jakub at redhat dot com>
- To: Richard Henderson <rth at redhat dot com>, Jim Wilson <wilson at tuliptree dot org>, David Mosberger <davidm at hpl dot hp dot com>
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Mon, 24 Mar 2003 16:33:26 +0100
- Subject: [PATCH] Fix IA-64 __sync_*_compare_and_swap_si intrinsic
- Reply-to: Jakub Jelinek <jakub at redhat dot com>
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