From a9c9d3fa23bf97cd72cfffd9fff018734145e056 Mon Sep 17 00:00:00 2001
From: Geoffrey Keating <geoffk@gcc.gnu.org>
Date: Wed, 1 Jun 2005 00:45:24 +0000
Subject: [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.

From-SVN: r100418
---
 gcc/ChangeLog                 |  8 +++
 gcc/config/rs6000/rs6000.c    | 21 ++++++--
 gcc/config/rs6000/rs6000.md   | 17 ++++++
 gcc/testsuite/ChangeLog       |  9 ++++
 gcc/testsuite/gcc.dg/sync-2.c | 99 +++++++++++++++++++++++++++++++++++
 5 files changed, 151 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/sync-2.c

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 7b6f3ff390c4..ec8ed235f8e7 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,11 @@
+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.
+
 2005-05-30  Daniel Berlin  <dberlin@dberlin.org>
 
 	* c-objc-common.c (c_tree_printer): Check flag before hashtable.
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 265a9ef402fe..9f8bbd78ca83 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -11409,13 +11409,15 @@ rs6000_emit_sync (enum rtx_code code, enum machine_mode mode,
       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, enum machine_mode mode,
 	  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, enum machine_mode mode,
 	  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, enum machine_mode mode,
 	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);
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 02847df7c2ff..53e4884b4b24 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -14868,6 +14868,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"
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 7e75d3088f02..5b5fce64d409 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+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.
+
 2005-05-31  Zdenek Dvorak  <dvorakz@suse.cz>
 
 	PR tree-optimization/21817
@@ -83,6 +89,9 @@
 
 2005-05-29  Geoffrey Keating  <geoffk@apple.com>
 
+	PR c++/17413
+	* g++.dg/template/local5.C: New.
+
 	PR target/21761
 	* gcc.c-torture/compile/pr21761.c: New.
 
diff --git a/gcc/testsuite/gcc.dg/sync-2.c b/gcc/testsuite/gcc.dg/sync-2.c
new file mode 100644
index 000000000000..41f8ac1c0a53
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/sync-2.c
@@ -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;
+}
-- 
GitLab