+2018-03-21 Jakub Jelinek <jakub@redhat.com>
+
+ PR tree-optimization/84982
+ * gimple-ssa-store-merging.c (invert_op): Handle boolean inversion
+ by flipping the least significant bit rather than all bits from
+ bitpos to bitpos + bitsize - 1.
+
2018-03-21 Nathan Sidwell <nathan@acm.org>
* doc/extend.texi (Deprecated Features): Remove mention of
unsigned int i;
store_immediate_info *info;
unsigned int cnt = 0;
+ bool any_paddings = false;
FOR_EACH_VEC_ELT (split_store->orig_stores, i, info)
{
bool bit_not_p = idx < 2 ? info->ops[idx].bit_not_p : info->bit_not_p;
if (bit_not_p)
- ++cnt;
+ {
+ ++cnt;
+ tree lhs = gimple_assign_lhs (info->stmt);
+ if (INTEGRAL_TYPE_P (TREE_TYPE (lhs))
+ && TYPE_PRECISION (TREE_TYPE (lhs)) < info->bitsize)
+ any_paddings = true;
+ }
}
mask = NULL_TREE;
if (cnt == 0)
return NOP_EXPR;
- if (cnt == split_store->orig_stores.length ())
+ if (cnt == split_store->orig_stores.length () && !any_paddings)
return BIT_NOT_EXPR;
unsigned HOST_WIDE_INT try_bitpos = split_store->bytepos * BITS_PER_UNIT;
clear regions with !bit_not_p, so that gaps in between stores aren't
set in the mask. */
unsigned HOST_WIDE_INT bitsize = info->bitsize;
+ unsigned HOST_WIDE_INT prec = bitsize;
unsigned int pos_in_buffer = 0;
+ if (any_paddings)
+ {
+ tree lhs = gimple_assign_lhs (info->stmt);
+ if (INTEGRAL_TYPE_P (TREE_TYPE (lhs))
+ && TYPE_PRECISION (TREE_TYPE (lhs)) < bitsize)
+ prec = TYPE_PRECISION (TREE_TYPE (lhs));
+ }
if (info->bitpos < try_bitpos)
{
gcc_assert (info->bitpos + bitsize > try_bitpos);
- bitsize -= (try_bitpos - info->bitpos);
+ if (!BYTES_BIG_ENDIAN)
+ {
+ if (prec <= try_bitpos - info->bitpos)
+ continue;
+ prec -= try_bitpos - info->bitpos;
+ }
+ bitsize -= try_bitpos - info->bitpos;
+ if (BYTES_BIG_ENDIAN && prec > bitsize)
+ prec = bitsize;
}
else
pos_in_buffer = info->bitpos - try_bitpos;
+ if (prec < bitsize)
+ {
+ /* If this is a bool inversion, invert just the least significant
+ prec bits rather than all bits of it. */
+ if (BYTES_BIG_ENDIAN)
+ {
+ pos_in_buffer += bitsize - prec;
+ if (pos_in_buffer >= split_store->size)
+ continue;
+ }
+ bitsize = prec;
+ }
if (pos_in_buffer + bitsize > split_store->size)
bitsize = split_store->size - pos_in_buffer;
unsigned char *p = buf + (pos_in_buffer / BITS_PER_UNIT);
--- /dev/null
+/* PR tree-optimization/84982 */
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+#ifndef __cplusplus
+#define bool _Bool
+#define true 1
+#define false 0
+#endif
+
+struct S { bool a, b, c, d; };
+
+__attribute__((noipa)) void
+bar (bool *x)
+{
+ if (x[0] || !x[1] || !x[2] || x[3])
+ __builtin_abort ();
+}
+
+__attribute__((noipa)) void
+foo (struct S *x)
+{
+ bool a[4];
+ a[0] = !x->a;
+ a[1] = !x->b;
+ a[2] = x->c;
+ a[3] = !x->d;
+ bar (a);
+}
+
+int
+main ()
+{
+ struct S s;
+ s.a = true; s.b = false; s.c = true; s.d = true;
+ foo (&s);
+ return 0;
+}