By tracking bits we can track more complex bit permutations. For this
the old "uint64_t n" was replaced by a uint8_t array that tracks each
bit separatedly. Any transformations or merges are adjusted as needed
to reflect this change. Other than this, the patch should be mostly a
no-op.
gcc/ChangeLog:
* gimple-ssa-store-merging.cc (MAX_SYM_BITS): New macro.
(struct symbolic_number): Grow "n" to track bits.
(BITS_PER_MARKER): Delete unused.
(MARKER_MASK): Likewise.
(MARKER_BYTE_UNKNOWN): Likewise.
(HEAD_MARKER): Likewise.
(CMPNOP): Likewise.
(CMPXCHG): Likewise.
(MARKER_BIT_UNKNOWN): New macro, replaces MARKER_BYTE_UNKNOWN.
(sym_shift_right): New function.
(sym_is_range_zero): New function.
(do_shift_rotate): Adjust to rotate bits instead of bytes.
(init_symbolic_number): Adjust to track bits instead of bytes.
(perform_symbolic_merge): Likewise.
(find_bswap_or_nop_1): Likewise.
(find_bswap_or_nop_2): Likewise.
(find_bswap_or_nop_finalize): Likewise.
(is_bswap_or_nop_p): Likewise.
(find_bswap_or_nop): Likewise.
(imm_store_chain_info::try_coalesce_bswap): Likewise.
(pass_store_merging::process_store): Likewise.
Signed-off-by: David Guillen Fandos <[email protected]>
---
gcc/gimple-ssa-store-merging.cc | 414 +++++++++++++++-----------------
1 file changed, 196 insertions(+), 218 deletions(-)
diff --git a/gcc/gimple-ssa-store-merging.cc b/gcc/gimple-ssa-store-merging.cc
index 39ef59ab9a6..9de8e4be1cf 100644
--- a/gcc/gimple-ssa-store-merging.cc
+++ b/gcc/gimple-ssa-store-merging.cc
@@ -193,14 +193,13 @@ struct bswap_stat
int found_64bit;
} nop_stats, bswap_stats;
-/* A symbolic number structure is used to detect byte permutation and selection
- patterns of a source. To achieve that, its field N contains an artificial
- number consisting of BITS_PER_MARKER sized markers tracking where does each
- byte come from in the source:
+/* A symbolic number structure is used to detect bit permutation and selection
+ patterns of a source. To achieve that, its array N contains a series of
+ markers representing a bit and where it comes from in the source.
- 0 - target byte has the value 0
- FF - target byte has an unknown value (eg. due to sign extension)
- 1..size - marker value is the byte index in the source (0 for lsb).
+ 0 - target bit has the value 0
+ FF - target bit has an unknown value
+ 1..size - marker value is the bit index in the source (1 for lsb).
To detect permutations on memory sources (arrays and structures), a symbolic
number is also associated:
@@ -222,8 +221,10 @@ struct bswap_stat
Note 3: SRC points to the SSA_NAME in case of non-memory source. */
+#define MAX_SYM_BITS 64
+
struct symbolic_number {
- uint64_t n;
+ uint8_t n[MAX_SYM_BITS];
tree type;
tree base_addr;
tree offset;
@@ -235,23 +236,26 @@ struct symbolic_number {
int n_ops;
};
-#define BITS_PER_MARKER 8
-#define MARKER_MASK ((1 << BITS_PER_MARKER) - 1)
-#define MARKER_BYTE_UNKNOWN MARKER_MASK
-#define HEAD_MARKER(n, size) \
- ((n) & ((uint64_t) MARKER_MASK << (((size) - 1) * BITS_PER_MARKER)))
+#define MARKER_BIT_UNKNOWN 0xFF
-/* The number which the find_bswap_or_nop_1 result should match in
- order to have a nop. The number is masked according to the size of
- the symbolic number before using it. */
-#define CMPNOP (sizeof (int64_t) < 8 ? 0 : \
- (uint64_t)0x08070605 << 32 | 0x04030201)
+/* Perform a right shift on a symbolic_number by amount bits.
+ Fill any new bits with the provided fill value. */
-/* The number which the find_bswap_or_nop_1 result should match in
- order to have a byte swap. The number is masked according to the
- size of the symbolic number before using it. */
-#define CMPXCHG (sizeof (int64_t) < 8 ? 0 : \
- (uint64_t)0x01020304 << 32 | 0x05060708)
+static void
+sym_shift_right (uint8_t *n, unsigned int amount, uint8_t fillvalue)
+{
+ for (unsigned int i = 0; i < MAX_SYM_BITS; i++)
+ n[i] = i + amount < MAX_SYM_BITS ? n[amount + i] : fillvalue;
+}
+
+static bool
+sym_is_range_zero (const uint8_t *n, unsigned int start, unsigned int count)
+{
+ for (unsigned int i = 0; i < count; i++)
+ if (n[start + i])
+ return false;
+ return true;
+}
/* Perform a SHIFT or ROTATE operation by COUNT bits on symbolic
number N. Return false if the requested operation is not permitted
@@ -262,46 +266,44 @@ do_shift_rotate (enum tree_code code,
struct symbolic_number *n,
int count)
{
- int i, size = TYPE_PRECISION (n->type) / BITS_PER_UNIT;
- uint64_t head_marker;
+ int i, size = TYPE_PRECISION (n->type);
+ uint8_t newv[MAX_SYM_BITS];
- if (count < 0
- || count >= TYPE_PRECISION (n->type)
+ if (size > MAX_SYM_BITS
+ || count < 0
+ || count >= size
|| count % BITS_PER_UNIT != 0)
return false;
- count = (count / BITS_PER_UNIT) * BITS_PER_MARKER;
-
- /* Zero out the extra bits of N in order to avoid them being shifted
- into the significant bits. */
- if (size < 64 / BITS_PER_MARKER)
- n->n &= ((uint64_t) 1 << (size * BITS_PER_MARKER)) - 1;
switch (code)
{
case LSHIFT_EXPR:
- n->n <<= count;
+ for (i = 0; i < size; i++)
+ newv[i] = i < count ? 0 : n->n[i - count];
break;
case RSHIFT_EXPR:
- head_marker = HEAD_MARKER (n->n, size);
- n->n >>= count;
/* Arithmetic shift of signed type: result is dependent on the value. */
- if (!TYPE_UNSIGNED (n->type) && head_marker)
- for (i = 0; i < count / BITS_PER_MARKER; i++)
- n->n |= (uint64_t) MARKER_BYTE_UNKNOWN
- << ((size - 1 - i) * BITS_PER_MARKER);
+ {
+ uint8_t fillv = (TYPE_UNSIGNED (n->type) || n->n[size - 1] == 0)
+ ? 0 : MARKER_BIT_UNKNOWN;
+ for (i = 0; i < size; i++)
+ newv[i] = (i + count < size) ? n->n[i + count] : fillv;
+ }
break;
case LROTATE_EXPR:
- n->n = (n->n << count) | (n->n >> ((size * BITS_PER_MARKER) - count));
+ for (i = 0; i < size; i++)
+ newv[i] = n->n[(i + size - count) % size];
break;
case RROTATE_EXPR:
- n->n = (n->n >> count) | (n->n << ((size * BITS_PER_MARKER) - count));
+ for (i = 0; i < size; i++)
+ newv[i] = n->n[(i + count) % size];
break;
default:
return false;
}
/* Zero unused bits for size. */
- if (size < 64 / BITS_PER_MARKER)
- n->n &= ((uint64_t) 1 << (size * BITS_PER_MARKER)) - 1;
+ for (i = 0; i < MAX_SYM_BITS; i++)
+ n->n[i] = (i < size) ? newv[i] : 0;
return true;
}
@@ -339,22 +341,19 @@ init_symbolic_number (struct symbolic_number *n, tree src)
n->base_addr = n->offset = n->alias_set = n->vuse = NULL_TREE;
n->src = src;
- /* Set up the symbolic number N by setting each byte to a value between 1 and
- the byte size of rhs1. The highest order byte is set to n->size and the
+ /* Set up the symbolic number N by setting each bit to a value between 1 and
+ the bit size of rhs1. The highest order bit is set to n->size and the
lowest order byte to 1. */
n->type = TREE_TYPE (src);
size = TYPE_PRECISION (n->type);
if (size % BITS_PER_UNIT != 0)
return false;
- size /= BITS_PER_UNIT;
- if (size > 64 / BITS_PER_MARKER)
+ if (size > MAX_SYM_BITS)
return false;
- n->range = size;
- n->n = CMPNOP;
+ n->range = size / BITS_PER_UNIT;
n->n_ops = 1;
-
- if (size < 64 / BITS_PER_MARKER)
- n->n &= ((uint64_t) 1 << (size * BITS_PER_MARKER)) - 1;
+ for (int i = 0; i < MAX_SYM_BITS; i++)
+ n->n[i] = (i < size) ? i + 1 : 0;
return true;
}
@@ -444,7 +443,6 @@ perform_symbolic_merge (gimple *source_stmt1, struct
symbolic_number *n1,
struct symbolic_number *n, enum tree_code code)
{
int i, size;
- uint64_t mask;
gimple *source_stmt;
struct symbolic_number *n_start;
@@ -461,7 +459,7 @@ perform_symbolic_merge (gimple *source_stmt1, struct
symbolic_number *n1,
the same base (array, structure, ...). */
if (rhs1 != rhs2)
{
- uint64_t inc;
+ unsigned int inc;
HOST_WIDE_INT start1, start2, start_sub, end_sub, end1, end2, end;
struct symbolic_number *toinc_n_ptr, *n_end;
basic_block bb1, bb2;
@@ -522,20 +520,16 @@ perform_symbolic_merge (gimple *source_stmt1, struct
symbolic_number *n1,
/* Check that the range of memory covered can be represented by
a symbolic number. */
- if (n->range > 64 / BITS_PER_MARKER)
+ if (n->range > MAX_SYM_BITS / BITS_PER_UNIT)
return NULL;
/* Reinterpret byte marks in symbolic number holding the value of
bigger weight according to target endianness. */
- inc = BYTES_BIG_ENDIAN ? end_sub : start_sub;
- size = TYPE_PRECISION (n1->type) / BITS_PER_UNIT;
- for (i = 0; i < size; i++, inc <<= BITS_PER_MARKER)
- {
- unsigned marker
- = (toinc_n_ptr->n >> (i * BITS_PER_MARKER)) & MARKER_MASK;
- if (marker && marker != MARKER_BYTE_UNKNOWN)
- toinc_n_ptr->n += inc;
- }
+ inc = (BYTES_BIG_ENDIAN ? end_sub : start_sub) * BITS_PER_UNIT;
+ size = TYPE_PRECISION (n1->type);
+ for (i = 0; i < size; i++)
+ if (toinc_n_ptr->n[i] && toinc_n_ptr->n[i] != MARKER_BIT_UNKNOWN)
+ toinc_n_ptr->n[i] += inc;
}
else
{
@@ -555,42 +549,23 @@ perform_symbolic_merge (gimple *source_stmt1, struct
symbolic_number *n1,
n->src = n_start->src;
n->bytepos = n_start->bytepos;
n->type = n_start->type;
- size = TYPE_PRECISION (n->type) / BITS_PER_UNIT;
- uint64_t res_n = n1->n | n2->n;
- for (i = 0, mask = MARKER_MASK; i < size; i++, mask <<= BITS_PER_MARKER)
+ for (i = 0; i < MAX_SYM_BITS; i++)
{
- uint64_t masked1, masked2;
-
- masked1 = n1->n & mask;
- masked2 = n2->n & mask;
- /* If at least one byte is 0, all of 0 | x == 0 ^ x == 0 + x == x. */
- if (masked1 && masked2)
- {
- /* + can carry into upper bits, just punt. */
- if (code == PLUS_EXPR)
- return NULL;
- /* x | x is still x. */
- if (code == BIT_IOR_EXPR && masked1 == masked2)
- continue;
- if (code == BIT_XOR_EXPR)
- {
- /* x ^ x is 0, but MARKER_BYTE_UNKNOWN stands for
- unknown values and unknown ^ unknown is unknown. */
- if (masked1 == masked2
- && masked1 != ((uint64_t) MARKER_BYTE_UNKNOWN
- << i * BITS_PER_MARKER))
- {
- res_n &= ~mask;
- continue;
- }
- }
- /* Otherwise set the byte to unknown, it might still be
- later masked off. */
- res_n |= mask;
- }
+ if (n1->n[i] == 0)
+ n->n[i] = n2->n[i]; /* 0 op n2 = n2. */
+ else if (n2->n[i] == 0)
+ n->n[i] = n1->n[i]; /* n1 op 0 = n1. */
+ else if (code == BIT_IOR_EXPR && n1->n[i] == n2->n[i])
+ n->n[i] = n1->n[i]; /* x | x = x (also unk | unk = unk). */
+ else if (code == BIT_XOR_EXPR && n1->n[i] == n2->n[i])
+ /* x ^ x = 0 (but unk ^ unk = unk). */
+ n->n[i] = (n1->n[i] == MARKER_BIT_UNKNOWN) ? MARKER_BIT_UNKNOWN : 0;
+ else if (code == PLUS_EXPR)
+ return NULL; /* + can carry into upper bits, just punt. */
+ else
+ n->n[i] = MARKER_BIT_UNKNOWN;
}
- n->n = res_n;
n->n_ops = n1->n_ops + n2->n_ops;
return source_stmt;
@@ -643,10 +618,8 @@ find_bswap_or_nop_1 (gimple *stmt, struct symbolic_number
*n, int limit)
return NULL;
/* Mask. */
- uint64_t mask = 0;
- for (unsigned i = 0; i < bitsize / BITS_PER_UNIT; i++)
- mask |= (uint64_t) MARKER_MASK << (i * BITS_PER_MARKER);
- n->n &= mask;
+ for (unsigned i = bitsize; i < MAX_SYM_BITS; i++)
+ n->n[i] = 0;
/* Convert. */
n->type = TREE_TYPE (rhs1);
@@ -703,18 +676,18 @@ find_bswap_or_nop_1 (gimple *stmt, struct symbolic_number
*n, int limit)
{
case BIT_AND_EXPR:
{
- int i, size = TYPE_PRECISION (n->type) / BITS_PER_UNIT;
- uint64_t val = int_cst_value (rhs2), mask = 0;
+ int i, size = TYPE_PRECISION (n->type);
+ uint64_t val = int_cst_value (rhs2);
uint64_t tmp = (1 << BITS_PER_UNIT) - 1;
/* Only constants masking full bytes are allowed. */
- for (i = 0; i < size; i++, tmp <<= BITS_PER_UNIT)
+ for (i = 0; i < size; i += BITS_PER_UNIT, tmp <<= BITS_PER_UNIT)
if ((val & tmp) != 0 && (val & tmp) != tmp)
return NULL;
- else if (val & tmp)
- mask |= (uint64_t) MARKER_MASK << (i * BITS_PER_MARKER);
- n->n &= mask;
+ for (i = 0; i < size; i++)
+ if (((val >> i) & 1) == 0)
+ n->n[i] = 0; /* Clear the bit to zero if mask is zero. */
}
break;
case LSHIFT_EXPR:
@@ -733,27 +706,23 @@ find_bswap_or_nop_1 (gimple *stmt, struct symbolic_number
*n, int limit)
type_size = TYPE_PRECISION (type);
if (type_size % BITS_PER_UNIT != 0)
return NULL;
- type_size /= BITS_PER_UNIT;
- if (type_size > 64 / BITS_PER_MARKER)
+ if (type_size > MAX_SYM_BITS)
return NULL;
/* Sign extension: result is dependent on the value. */
- old_type_size = TYPE_PRECISION (n->type) / BITS_PER_UNIT;
- if (!TYPE_UNSIGNED (n->type) && type_size > old_type_size
- && HEAD_MARKER (n->n, old_type_size))
- for (i = 0; i < type_size - old_type_size; i++)
- n->n |= (uint64_t) MARKER_BYTE_UNKNOWN
- << ((type_size - 1 - i) * BITS_PER_MARKER);
-
- if (type_size < 64 / BITS_PER_MARKER)
- {
- /* If STMT casts to a smaller type mask out the bits not
- belonging to the target type. */
- n->n &= ((uint64_t) 1 << (type_size * BITS_PER_MARKER)) - 1;
- }
+ old_type_size = TYPE_PRECISION (n->type);
+ if (type_size > old_type_size)
+ for (i = old_type_size; i < type_size; i++)
+ n->n[i] = (TYPE_UNSIGNED (n->type)
+ || n->n[old_type_size - 1] == 0)
+ ? 0 : MARKER_BIT_UNKNOWN;
+ else
+ for (i = type_size; i < old_type_size; i++)
+ n->n[i] = 0;
+
n->type = type;
if (!n->base_addr)
- n->range = type_size;
+ n->range = type_size / BITS_PER_UNIT;
}
break;
default:
@@ -853,38 +822,42 @@ find_bswap_or_nop_2 (gimple *stmt, struct symbolic_number
*n, int limit)
return NULL;
if (n1.vuse != n2.vuse)
return NULL;
- auto nn2 = n2.n;
- n2.n = 0;
+ uint8_t nn2[MAX_SYM_BITS];
+ memcpy (nn2, n2.n, MAX_SYM_BITS);
+ memset (n2.n, 0, MAX_SYM_BITS);
/* We need to take into account number of elements of each vector,
which perform_symbolic_merge doesn't know. So, handle it as
two separate BIT_IOR_EXPR merges, each time with one operand
- with changed mastk to all 0s, and then merge here. */
+ with changed mask to all 0s, and then merge here. */
gimple *source_stmt
= perform_symbolic_merge (source_stmt1, &n1, source_stmt2, &n2, n,
BIT_IOR_EXPR);
if (!source_stmt)
return NULL;
- n2.n = nn2;
- auto nn1 = n->n;
- n1.n = 0;
+ memcpy (n2.n, nn2, MAX_SYM_BITS);
+ uint8_t nn1[MAX_SYM_BITS];
+ memcpy (nn1, n->n, MAX_SYM_BITS);
+ memset (n1.n, 0, MAX_SYM_BITS);
gimple *source_stmt3
= perform_symbolic_merge (source_stmt1, &n1, source_stmt2, &n2, n,
BIT_IOR_EXPR);
gcc_assert (source_stmt == source_stmt3);
- nn2 = n->n;
+ memcpy (nn2, n->n, MAX_SYM_BITS);
tree lhs = gimple_assign_lhs (stmt);
int eltsize
= TYPE_PRECISION (TREE_TYPE (TREE_TYPE (lhs))) / BITS_PER_UNIT;
int nelts = TYPE_VECTOR_SUBPARTS (TREE_TYPE (lhs)).to_constant ();
int size = eltsize * nelts;
int hsize = size / 2;
- n->n = 0;
+ memset (n->n, 0, MAX_SYM_BITS);
if (!BYTES_BIG_ENDIAN)
for (int i = 0; i < size; i++)
- n->n |= ((((i < hsize ? nn1 : nn2)
- >> (((i % hsize) / eltsize * 2 * eltsize
- + (i % eltsize))) * BITS_PER_MARKER) & MARKER_MASK)
- << (i * BITS_PER_MARKER));
+ {
+ const uint8_t *src = i < hsize ? nn1 : nn2;
+ int j = (i % hsize) / eltsize * 2 * eltsize + (i % eltsize);
+ memcpy (&n->n[i * BITS_PER_UNIT], &src[j * BITS_PER_UNIT],
+ BITS_PER_UNIT);
+ }
else
gcc_unreachable ();
return source_stmt;
@@ -957,22 +930,29 @@ find_bswap_or_nop_2 (gimple *stmt, struct symbolic_number
*n, int limit)
*CMPXCHG, *CMPNOP and adjust *N. */
void
-find_bswap_or_nop_finalize (struct symbolic_number *n, uint64_t *cmpxchg,
- uint64_t *cmpnop, bool *cast64_to_32)
+find_bswap_or_nop_finalize (struct symbolic_number *n, uint8_t *cmpxchg,
+ uint8_t *cmpnop, bool *cast64_to_32)
{
- unsigned rsize;
- uint64_t tmpn, mask;
+ unsigned i, rsize;
/* The number which the find_bswap_or_nop_1 result should match in order
to have a full byte swap. The number is shifted to the right
according to the size of the symbolic number before using it. */
- *cmpxchg = CMPXCHG;
- *cmpnop = CMPNOP;
+ for (i = 0; i < MAX_SYM_BITS; i++)
+ cmpxchg[i] = ((MAX_SYM_BITS / BITS_PER_UNIT - i / BITS_PER_UNIT - 1)
+ * BITS_PER_UNIT + i % BITS_PER_UNIT + 1);
+
+ for (i = 0; i < MAX_SYM_BITS; i++)
+ cmpnop[i] = i + 1;
*cast64_to_32 = false;
/* Find real size of result (highest non-zero byte). */
if (n->base_addr)
- for (tmpn = n->n, rsize = 0; tmpn; tmpn >>= BITS_PER_MARKER, rsize++);
+ {
+ for (i = 0, rsize = 0; i < MAX_SYM_BITS / BITS_PER_UNIT; i++)
+ if (!sym_is_range_zero (n->n, i * BITS_PER_UNIT, BITS_PER_UNIT))
+ rsize = i + 1;
+ }
else
rsize = n->range;
@@ -980,7 +960,6 @@ find_bswap_or_nop_finalize (struct symbolic_number *n,
uint64_t *cmpxchg,
expression. */
if (n->range < (int) sizeof (int64_t))
{
- mask = ((uint64_t) 1 << (n->range * BITS_PER_MARKER)) - 1;
if (n->base_addr == NULL
&& n->range == 4
&& int_size_in_bytes (TREE_TYPE (n->src)) == 8)
@@ -990,19 +969,22 @@ find_bswap_or_nop_finalize (struct symbolic_number *n,
uint64_t *cmpxchg,
It is not worth it for (unsigned short) __builtin_bswap64 (src)
or (unsigned short) __builtin_bswap32 (src). */
*cast64_to_32 = true;
- for (tmpn = n->n; tmpn; tmpn >>= BITS_PER_MARKER)
- if ((tmpn & MARKER_MASK)
- && ((tmpn & MARKER_MASK) <= 4 || (tmpn & MARKER_MASK) > 8))
- {
- *cast64_to_32 = false;
- break;
- }
+ for (i = 0; i < MAX_SYM_BITS; i++)
+ if (n->n[i]
+ && (n->n[i] <= MAX_SYM_BITS / 2 || n->n[i] > MAX_SYM_BITS))
+ {
+ *cast64_to_32 = false;
+ break;
+ }
}
if (*cast64_to_32)
- *cmpxchg &= mask;
+ for (i = n->range * BITS_PER_UNIT; i < MAX_SYM_BITS; i++)
+ cmpxchg[i] = 0;
else
- *cmpxchg >>= (64 / BITS_PER_MARKER - n->range) * BITS_PER_MARKER;
- *cmpnop &= mask;
+ sym_shift_right (cmpxchg, MAX_SYM_BITS - n->range * BITS_PER_UNIT, 0);
+
+ for (i = n->range * BITS_PER_UNIT; i < MAX_SYM_BITS; i++)
+ cmpnop[i] = 0;
}
/* Zero out the bits corresponding to unused bytes in the result of the
@@ -1011,21 +993,15 @@ find_bswap_or_nop_finalize (struct symbolic_number *n,
uint64_t *cmpxchg,
{
if (BYTES_BIG_ENDIAN)
{
- mask = ((uint64_t) 1 << (rsize * BITS_PER_MARKER)) - 1;
- *cmpxchg &= mask;
- if (n->range - rsize == sizeof (int64_t))
- *cmpnop = 0;
- else
- *cmpnop >>= (n->range - rsize) * BITS_PER_MARKER;
+ sym_shift_right (cmpnop, (n->range - rsize) * BITS_PER_UNIT, 0);
+ for (i = rsize * BITS_PER_UNIT; i < MAX_SYM_BITS; i++)
+ cmpxchg[i] = 0;
}
else
{
- mask = ((uint64_t) 1 << (rsize * BITS_PER_MARKER)) - 1;
- if (n->range - rsize == sizeof (int64_t))
- *cmpxchg = 0;
- else
- *cmpxchg >>= (n->range - rsize) * BITS_PER_MARKER;
- *cmpnop &= mask;
+ sym_shift_right (cmpxchg, (n->range - rsize) * BITS_PER_UNIT, 0);
+ for (i = rsize * BITS_PER_UNIT; i < MAX_SYM_BITS; i++)
+ cmpnop[i] = 0;
}
n->range = rsize;
}
@@ -1038,22 +1014,23 @@ find_bswap_or_nop_finalize (struct symbolic_number *n,
uint64_t *cmpxchg,
/* Helper function for find_bswap_or_nop,
Return true if N is a swap or nop with MASK. */
static bool
-is_bswap_or_nop_p (uint64_t n, uint64_t cmpxchg,
- uint64_t cmpnop, uint64_t* mask,
+is_bswap_or_nop_p (const uint8_t *n, const uint8_t *cmpxchg,
+ const uint8_t *cmpnop, uint64_t* mask,
bool* bswap)
{
+ const uint64_t byte_mask = ((uint64_t) 1 << BITS_PER_UNIT) - 1;
*mask = ~(uint64_t) 0;
- if (n == cmpnop)
+ if (memcmp (n, cmpnop, MAX_SYM_BITS) == 0)
*bswap = false;
- else if (n == cmpxchg)
+ else if (memcmp (n, cmpxchg, MAX_SYM_BITS) == 0)
*bswap = true;
else
{
int set = 0;
- for (uint64_t msk = MARKER_MASK; msk; msk <<= BITS_PER_MARKER)
- if ((n & msk) == 0)
- *mask &= ~msk;
- else if ((n & msk) == (cmpxchg & msk))
+ for (unsigned int i = 0; i < MAX_SYM_BITS; i += BITS_PER_UNIT)
+ if (sym_is_range_zero (n, i, BITS_PER_UNIT))
+ *mask &= ~(byte_mask << i);
+ else if (memcmp (&n[i], &cmpxchg[i], BITS_PER_UNIT) == 0)
set++;
else
return false;
@@ -1093,15 +1070,16 @@ find_bswap_or_nop (gimple *stmt, struct symbolic_number
*n, bool *bswap,
if (!ins_stmt)
return NULL;
- uint64_t cmpxchg, cmpnop;
+ uint8_t cmpxchg[MAX_SYM_BITS], cmpnop[MAX_SYM_BITS];
uint64_t orig_range = n->range * BITS_PER_UNIT;
- find_bswap_or_nop_finalize (n, &cmpxchg, &cmpnop, cast64_to_32);
+ find_bswap_or_nop_finalize (n, cmpxchg, cmpnop, cast64_to_32);
/* A complete byte swap should make the symbolic number to start with
the largest digit in the highest order byte. Unchanged symbolic
number indicates a read with same endianness as target architecture. */
*l_rotate = 0;
- uint64_t tmp_n = n->n;
+ uint8_t tmp_n[MAX_SYM_BITS];
+ memcpy (tmp_n, n->n, MAX_SYM_BITS);
if (!is_bswap_or_nop_p (tmp_n, cmpxchg, cmpnop, mask, bswap))
{
/* Try bswap + lrotate. */
@@ -1114,38 +1092,38 @@ find_bswap_or_nop (gimple *stmt, struct symbolic_number
*n, bool *bswap,
&& ((orig_range == 32
&& optab_handler (rotl_optab, SImode) != CODE_FOR_nothing)
|| (orig_range == 64
- && optab_handler (rotl_optab, DImode) != CODE_FOR_nothing))
- && (tmp_n & MARKER_MASK) < orig_range / BITS_PER_UNIT)
+ && optab_handler (rotl_optab, DImode) != CODE_FOR_nothing)))
{
- uint64_t range = (orig_range / BITS_PER_UNIT) * BITS_PER_MARKER;
- uint64_t count = (tmp_n & MARKER_MASK) * BITS_PER_MARKER;
- /* .i.e. handle 0x203040506070800 when lower byte is zero. */
- if (!count)
+ unsigned int count = 0;
+ uint8_t tmp2_n[MAX_SYM_BITS];
+
+ /* Inspecting the lowest bit value, determine the rotation amount.
+ Handles some bits/bytes being zero (i.e. 0x203040506070800). */
+ for (unsigned int i = 0; i < orig_range; i++)
{
- for (uint64_t i = 1; i != range / BITS_PER_MARKER; i++)
- {
- count = (tmp_n >> i * BITS_PER_MARKER) & MARKER_MASK;
- if (count)
- {
- /* Count should be meaningful not 0xff. */
- if (count <= range / BITS_PER_MARKER)
- {
- count = (count + i) * BITS_PER_MARKER % range;
- if (!count)
- return NULL;
- break;
- }
- else
- return NULL;
- }
- }
+ unsigned int v, j;
+ if (tmp_n[i] == 0)
+ continue;
+ if (tmp_n[i] - 1u >= orig_range)
+ return NULL;
+
+ v = tmp_n[i] - 1;
+ j = (orig_range / BITS_PER_UNIT - 1 - v / BITS_PER_UNIT)
+ * BITS_PER_UNIT + v % BITS_PER_UNIT;
+ count = (i + orig_range - j) % orig_range;
+ break;
}
- tmp_n = tmp_n >> count | tmp_n << (range - count);
- if (orig_range == 32)
- tmp_n &= (1ULL << 32) - 1;
- if (!is_bswap_or_nop_p (tmp_n, cmpxchg, cmpnop, mask, bswap))
+
+ if (!count || count % BITS_PER_UNIT != 0)
+ return NULL;
+
+ memcpy (tmp2_n, tmp_n, MAX_SYM_BITS);
+ for (unsigned int i = 0; i < orig_range; i++)
+ tmp2_n[i] = tmp_n[(i + count) % orig_range];
+
+ if (!is_bswap_or_nop_p (tmp2_n, cmpxchg, cmpnop, mask, bswap))
return NULL;
- *l_rotate = count / BITS_PER_MARKER * BITS_PER_UNIT;
+ *l_rotate = count;
gcc_assert (*bswap);
}
else
@@ -1153,7 +1131,9 @@ find_bswap_or_nop (gimple *stmt, struct symbolic_number
*n, bool *bswap,
}
/* Useless bit manipulation performed by code. */
- if (!n->base_addr && n->n == cmpnop && n->n_ops == 1)
+ if (!n->base_addr
+ && n->n_ops == 1
+ && memcmp (n->n, cmpnop, MAX_SYM_BITS) == 0)
return NULL;
return ins_stmt;
@@ -3089,14 +3069,16 @@ imm_store_chain_info::try_coalesce_bswap
(merged_store_group *merged_store,
}
}
- uint64_t cmpxchg, cmpnop;
+ uint8_t cmpxchg[MAX_SYM_BITS], cmpnop[MAX_SYM_BITS];
bool cast64_to_32;
- find_bswap_or_nop_finalize (&n, &cmpxchg, &cmpnop, &cast64_to_32);
+ find_bswap_or_nop_finalize (&n, cmpxchg, cmpnop, &cast64_to_32);
/* A complete byte swap should make the symbolic number to start with
the largest digit in the highest order byte. Unchanged symbolic
number indicates a read with same endianness as target architecture. */
- if (n.n != cmpnop && n.n != cmpxchg)
+ bool is_nop = memcmp (n.n, cmpnop, MAX_SYM_BITS) == 0;
+ bool is_xchg = memcmp (n.n, cmpxchg, MAX_SYM_BITS) == 0;
+ if (!is_nop && !is_xchg)
return false;
/* For now. */
@@ -3112,7 +3094,7 @@ imm_store_chain_info::try_coalesce_bswap
(merged_store_group *merged_store,
/* Don't handle memory copy this way if normal non-bswap processing
would handle it too. */
- if (n.n == cmpnop && (unsigned) n.n_ops == last - first + 1)
+ if (is_nop && (unsigned) n.n_ops == last - first + 1)
{
unsigned int i;
for (i = first; i <= last; ++i)
@@ -3122,7 +3104,7 @@ imm_store_chain_info::try_coalesce_bswap
(merged_store_group *merged_store,
return false;
}
- if (n.n == cmpxchg)
+ if (is_xchg)
switch (try_size)
{
case 16:
@@ -3168,7 +3150,7 @@ imm_store_chain_info::try_coalesce_bswap
(merged_store_group *merged_store,
infof->ins_stmt = ins_stmt;
for (unsigned int i = first; i <= last; ++i)
{
- m_store_info[i]->rhs_code = n.n == cmpxchg ? LROTATE_EXPR : NOP_EXPR;
+ m_store_info[i]->rhs_code = is_xchg ? LROTATE_EXPR : NOP_EXPR;
m_store_info[i]->ops[0].base_addr = NULL_TREE;
m_store_info[i]->ops[1].base_addr = NULL_TREE;
if (i != first)
@@ -5374,12 +5356,8 @@ pass_store_merging::process_store (gimple *stmt)
ins_stmt = find_bswap_or_nop_1 (def_stmt, &n, 12);
if (ins_stmt)
{
- uint64_t nn = n.n;
- for (unsigned HOST_WIDE_INT i = 0;
- i < const_bitsize;
- i += BITS_PER_UNIT, nn >>= BITS_PER_MARKER)
- if ((nn & MARKER_MASK) == 0
- || (nn & MARKER_MASK) == MARKER_BYTE_UNKNOWN)
+ for (unsigned int i = 0; i < const_bitsize; i++)
+ if (n.n[i] == 0 || n.n[i] == MARKER_BIT_UNKNOWN)
{
ins_stmt = NULL;
break;
--
2.55.0