This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
short/char atomic operations testcase, bugfixes
- From: gkeating at apple dot com (Geoffrey Keating)
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 31 May 2005 17:42:12 -0700 (PDT)
- Subject: short/char atomic operations testcase, bugfixes
On my todo list for a while: "write execution tests for < SImode
atomic operations and fix bugs".
I suppose I should explain the way the andc operations work. Suppose
you're doing
__sync_nand (some_char_array + 2, 4);
What GCC wants to emit is
operand = 0xFFFF04FF;
mask = 0x0000FF00;
and then it atomically does:
*(unsigned *)some_char_array =
(*(unsigned *)some_char_array ^ mask) & operand;
the ^ gets you the 'c' part of the 'andc', and the '& operand' does
the rest. For an 'and' (no 'c'), you do the same thing but without
the '^' operation.
Bootstrapped & tested on powerpc-darwin8.
--
- Geoffrey Keating <geoffk@apple.com>
===File ~/patches/rs6000-atomicshort-1.patch================
Index: ChangeLog
2005-05-31 Geoffrey Keating <geoffk@geoffk.org>
* config/rs6000/rs6000.md (sync_boolcshort_internal): New.
* config/rs6000/rs6000.c (rs6000_emit_sync): Shift count must
be complemented for big-endian. Mask for AND must be rotated,
not shifted. Handle short operands with NOT on the memory
operation.
Index: testsuite/ChangeLog
2005-05-31 Geoffrey Keating <geoffk@geoffk.org>
* lib/target-supports.exp
(check_effective_target_sync_char_short): New.
* gcc.dg/sync-2.c: New.
Index: config/rs6000/rs6000.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.827
diff -u -p -r1.827 rs6000.c
--- config/rs6000/rs6000.c 26 May 2005 18:15:07 -0000 1.827
+++ config/rs6000/rs6000.c 31 May 2005 21:30:32 -0000
@@ -11409,13 +11409,15 @@ rs6000_emit_sync (enum rtx_code code, en
else
{
rtx addrSI, aligned_addr;
+ int shift_mask = mode == QImode ? 0x18 : 0x10;
addrSI = force_reg (SImode, gen_lowpart_common (SImode,
XEXP (used_m, 0)));
shift = gen_reg_rtx (SImode);
emit_insn (gen_rlwinm (shift, addrSI, GEN_INT (3),
- GEN_INT (0x18)));
+ GEN_INT (shift_mask)));
+ emit_insn (gen_xorsi3 (shift, shift, GEN_INT (shift_mask)));
aligned_addr = expand_binop (Pmode, and_optab,
XEXP (used_m, 0),
@@ -11453,7 +11455,7 @@ rs6000_emit_sync (enum rtx_code code, en
newop = expand_binop (SImode, ior_optab,
oldop, GEN_INT (~imask), NULL_RTX,
1, OPTAB_LIB_WIDEN);
- emit_insn (gen_ashlsi3 (newop, newop, shift));
+ emit_insn (gen_rotlsi3 (newop, newop, shift));
break;
case PLUS:
@@ -11482,6 +11484,19 @@ rs6000_emit_sync (enum rtx_code code, en
gcc_unreachable ();
}
+ if (GET_CODE (m) == NOT)
+ {
+ rtx mask, xorm;
+
+ mask = gen_reg_rtx (SImode);
+ emit_move_insn (mask, GEN_INT (imask));
+ emit_insn (gen_ashlsi3 (mask, mask, shift));
+
+ xorm = gen_rtx_XOR (SImode, used_m, mask);
+ /* Depending on the value of 'op', the XOR or the operation might
+ be able to be simplified away. */
+ newop = simplify_gen_binary (code, SImode, xorm, newop);
+ }
op = newop;
used_mode = SImode;
before = gen_reg_rtx (used_mode);
@@ -11499,7 +11514,7 @@ rs6000_emit_sync (enum rtx_code code, en
after = gen_reg_rtx (used_mode);
}
- if (code == PLUS && used_mode != mode)
+ if ((code == PLUS || GET_CODE (m) == NOT) && used_mode != mode)
the_op = op; /* Computed above. */
else if (GET_CODE (op) == NOT && GET_CODE (m) != NOT)
the_op = gen_rtx_fmt_ee (code, used_mode, op, m);
Index: config/rs6000/rs6000.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.md,v
retrieving revision 1.370
diff -u -p -r1.370 rs6000.md
--- config/rs6000/rs6000.md 30 May 2005 06:09:46 -0000 1.370
+++ config/rs6000/rs6000.md 31 May 2005 21:30:33 -0000
@@ -14776,6 +14776,23 @@
"<larx> %3,%y0\n\t%q4 %2,%1,%3\n\t<stcx> %2,%y0\n\tbne- $-12"
[(set_attr "length" "16")])
+; This pattern could also take immediate values of operand 1,
+; since the non-NOT version of the operator is used; but this is not
+; very useful, since in practise operand 1 is a full 32-bit value.
+; Likewise, operand 5 is in practise either <= 2^16 or it is a register.
+(define_insn "*sync_boolcshort_internal"
+ [(set (match_operand:SI 2 "gpc_reg_operand" "=&r")
+ (match_operator:SI 4 "boolean_operator"
+ [(xor:SI (match_operand:SI 0 "memory_operand" "+Z")
+ (match_operand:SI 5 "logical_operand" "rK"))
+ (match_operand:SI 1 "gpc_reg_operand" "r")]))
+ (set (match_operand:SI 3 "gpc_reg_operand" "=&b") (match_dup 0))
+ (set (match_dup 0) (unspec:SI [(match_dup 4)] UNSPEC_SYNC_OP))
+ (clobber (match_scratch:CC 6 "=&x"))]
+ "TARGET_POWERPC"
+ "lwarx %3,%y0\n\txor%I2 %2,%3,%5\n\t%q4 %2,%2,%1\n\tstwcx. %2,%y0\n\tbne- $-16"
+ [(set_attr "length" "20")])
+
(define_insn "*sync_boolc<mode>_internal2"
[(set (match_operand:GPR 2 "gpc_reg_operand" "=&r")
(match_operator:GPR 4 "boolean_operator"
Index: testsuite/gcc.dg/sync-2.c
===================================================================
RCS file: testsuite/gcc.dg/sync-2.c
diff -N testsuite/gcc.dg/sync-2.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ testsuite/gcc.dg/sync-2.c 31 May 2005 21:30:45 -0000
@@ -0,0 +1,99 @@
+/* { dg-do run } */
+/* { dg-require-effective-target sync_char_short } */
+
+/* Test functionality of the intrinsics for 'short' and 'char'. */
+
+extern void abort (void);
+extern void *memcpy (void *, const void *, __SIZE_TYPE__);
+
+static char AI[18];
+static char init_qi[18] = { 3,5,7,9,0,0,0,0,-1,0,0,0,0,0,-1,0,0,0 };
+static char test_qi[18] = { 3,5,7,9,1,4,22,-12,7,8,9,7,1,-12,7,8,9,7 };
+
+static void
+do_qi (void)
+{
+ if (__sync_fetch_and_add(AI+4, 1) != 0)
+ abort ();
+ if (__sync_fetch_and_add(AI+5, 4) != 0)
+ abort ();
+ if (__sync_fetch_and_add(AI+6, 22) != 0)
+ abort ();
+ if (__sync_fetch_and_sub(AI+7, 12) != 0)
+ abort ();
+ if (__sync_fetch_and_and(AI+8, 7) != -1)
+ abort ();
+ if (__sync_fetch_and_or(AI+9, 8) != 0)
+ abort ();
+ if (__sync_fetch_and_xor(AI+10, 9) != 0)
+ abort ();
+ if (__sync_fetch_and_nand(AI+11, 7) != 0)
+ abort ();
+
+ if (__sync_add_and_fetch(AI+12, 1) != 1)
+ abort ();
+ if (__sync_sub_and_fetch(AI+13, 12) != -12)
+ abort ();
+ if (__sync_and_and_fetch(AI+14, 7) != 7)
+ abort ();
+ if (__sync_or_and_fetch(AI+15, 8) != 8)
+ abort ();
+ if (__sync_xor_and_fetch(AI+16, 9) != 9)
+ abort ();
+ if (__sync_nand_and_fetch(AI+17, 7) != 7)
+ abort ();
+}
+
+static short AL[18];
+static short init_hi[18] = { 3,5,7,9,0,0,0,0,-1,0,0,0,0,0,-1,0,0,0 };
+static short test_hi[18] = { 3,5,7,9,1,4,22,-12,7,8,9,7,1,-12,7,8,9,7 };
+
+static void
+do_hi (void)
+{
+ if (__sync_fetch_and_add(AL+4, 1) != 0)
+ abort ();
+ if (__sync_fetch_and_add(AL+5, 4) != 0)
+ abort ();
+ if (__sync_fetch_and_add(AL+6, 22) != 0)
+ abort ();
+ if (__sync_fetch_and_sub(AL+7, 12) != 0)
+ abort ();
+ if (__sync_fetch_and_and(AL+8, 7) != -1)
+ abort ();
+ if (__sync_fetch_and_or(AL+9, 8) != 0)
+ abort ();
+ if (__sync_fetch_and_xor(AL+10, 9) != 0)
+ abort ();
+ if (__sync_fetch_and_nand(AL+11, 7) != 0)
+ abort ();
+
+ if (__sync_add_and_fetch(AL+12, 1) != 1)
+ abort ();
+ if (__sync_sub_and_fetch(AL+13, 12) != -12)
+ abort ();
+ if (__sync_and_and_fetch(AL+14, 7) != 7)
+ abort ();
+ if (__sync_or_and_fetch(AL+15, 8) != 8)
+ abort ();
+ if (__sync_xor_and_fetch(AL+16, 9) != 9)
+ abort ();
+ if (__sync_nand_and_fetch(AL+17, 7) != 7)
+ abort ();
+}
+
+int main()
+{
+ memcpy(AI, init_qi, sizeof(init_qi));
+ memcpy(AL, init_hi, sizeof(init_hi));
+
+ do_qi ();
+ do_hi ();
+
+ if (memcmp (AI, test_qi, sizeof(test_qi)))
+ abort ();
+ if (memcmp (AL, test_hi, sizeof(test_hi)))
+ abort ();
+
+ return 0;
+}
Index: testsuite/lib/target-supports.exp
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/lib/target-supports.exp,v
retrieving revision 1.58
diff -u -p -r1.58 target-supports.exp
--- testsuite/lib/target-supports.exp 17 May 2005 04:33:42 -0000 1.58
+++ testsuite/lib/target-supports.exp 31 May 2005 21:30:49 -0000
@@ -990,6 +990,29 @@ proc check_effective_target_sync_int_lon
return $et_sync_int_long_saved
}
+# Return 1 if the target supports atomic operations on "char" and "short".
+
+proc check_effective_target_sync_char_short { } {
+ global et_sync_char_short_saved
+
+ if [info exists et_sync_char_short_saved] {
+ verbose "check_effective_target_sync_char_short: using cached result" 2
+ } else {
+ set et_sync_char_short_saved 0
+# This is intentionally powerpc but not rs6000, rs6000 doesn't have the
+# load-reserved/store-conditional instructions.
+ if { [istarget ia64-*-*]
+ || [istarget i?86-*-*]
+ || [istarget x86_64-*-*]
+ || [istarget powerpc*-*-*] } {
+ set et_sync_char_short_saved 1
+ }
+ }
+
+ verbose "check_effective_target_sync_char_short: returning $et_sync_char_short_saved" 2
+ return $et_sync_char_short_saved
+}
+
# Return 1 if the target matches the effective target 'arg', 0 otherwise.
# This can be used with any check_* proc that takes no argument and
# returns only 1 or 0. It could be used with check_* procs that take
============================================================