summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog10
-rw-r--r--gcc/builtins.c13
-rw-r--r--gcc/optabs.c11
-rw-r--r--gcc/testsuite/gcc.dg/atomic-noinline-aux.c15
-rw-r--r--gcc/testsuite/gcc.dg/atomic-noinline.c7
5 files changed, 51 insertions, 5 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 86515365d21..fa7cbeb1bb5 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,13 @@
+2011-11-10 Andrew MacLeod <amacleod@redhat.com>
+
+ PR rtl-optimization/51040
+ * optabs.c (expand_atomic_fetch_op): Patchup code for NAND should be AND
+ followed by NOT.
+ * builtins.c (expand_builtin_atomic_fetch_op): Patchup code for NAND
+ should be AND followed by NOT.
+ * testsuite/gcc.dg/atomic-noinline[-aux].c: Test no-inline NAND and
+ patchup code.
+
2011-11-10 Jakub Jelinek <jakub@redhat.com>
* vec.h (VEC_BASE): If base is at offset 0 in the structure,
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 516292783bc..d949dbb632f 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -5460,8 +5460,17 @@ expand_builtin_atomic_fetch_op (enum machine_mode mode, tree exp, rtx target,
/* Then issue the arithmetic correction to return the right result. */
if (!ignore)
- ret = expand_simple_binop (mode, code, ret, val, NULL_RTX, true,
- OPTAB_LIB_WIDEN);
+ {
+ if (code == NOT)
+ {
+ ret = expand_simple_binop (mode, AND, ret, val, NULL_RTX, true,
+ OPTAB_LIB_WIDEN);
+ ret = expand_simple_unop (mode, NOT, ret, target, true);
+ }
+ else
+ ret = expand_simple_binop (mode, code, ret, val, target, true,
+ OPTAB_LIB_WIDEN);
+ }
return ret;
}
diff --git a/gcc/optabs.c b/gcc/optabs.c
index b2388ec5c74..c87f5cd84ad 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -7875,8 +7875,15 @@ expand_atomic_fetch_op (rtx target, rtx mem, rtx val, enum rtx_code code,
Fetch_before == after REVERSE_OP val. */
if (!after)
code = optab.reverse_code;
- result = expand_simple_binop (mode, code, result, val, target, true,
- OPTAB_LIB_WIDEN);
+ if (code == NOT)
+ {
+ result = expand_simple_binop (mode, AND, result, val, NULL_RTX,
+ true, OPTAB_LIB_WIDEN);
+ result = expand_simple_unop (mode, NOT, result, target, true);
+ }
+ else
+ result = expand_simple_binop (mode, code, result, val, target,
+ true, OPTAB_LIB_WIDEN);
return result;
}
}
diff --git a/gcc/testsuite/gcc.dg/atomic-noinline-aux.c b/gcc/testsuite/gcc.dg/atomic-noinline-aux.c
index b92fcfcd60f..b05460e469b 100644
--- a/gcc/testsuite/gcc.dg/atomic-noinline-aux.c
+++ b/gcc/testsuite/gcc.dg/atomic-noinline-aux.c
@@ -40,11 +40,24 @@ char __atomic_fetch_add_1 (char *p, char v, int i)
*p = 1;
}
-short __atomic_fetch_add_2 (short *p, short v, short i)
+short __atomic_fetch_add_2 (short *p, short v, int i)
{
*p = 1;
}
+/* Really perform a NAND. PR51040 showed incorrect calculation of a
+ non-inlined fetch_nand. */
+unsigned char
+__atomic_fetch_nand_1 (unsigned char *p, unsigned char v, int i)
+{
+ unsigned char ret;
+
+ ret = *p;
+ *p = ~(*p & v);
+
+ return ret;
+}
+
int __atomic_is_lock_free (int i, void *p)
{
return 10;
diff --git a/gcc/testsuite/gcc.dg/atomic-noinline.c b/gcc/testsuite/gcc.dg/atomic-noinline.c
index 06a93e0058e..eb0866e549e 100644
--- a/gcc/testsuite/gcc.dg/atomic-noinline.c
+++ b/gcc/testsuite/gcc.dg/atomic-noinline.c
@@ -49,6 +49,13 @@ main ()
if (__atomic_is_lock_free (4, 0) != 10)
abort ();
+ /* PR 51040 was caused by arithmetic code not patching up nand_fetch properly
+ when used an an external function. Look for proper return value here. */
+ ac = 0x3C;
+ bc = __atomic_nand_fetch (&ac, 0x0f, __ATOMIC_RELAXED);
+ if (bc != ac)
+ abort ();
+
return 0;
}
OpenPOWER on IntegriCloud