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]

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
============================================================


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