public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/users/aoliva/heads/testme)] unify split logic, reorder neighbors if needed
@ 2020-09-24 19:16 Alexandre Oliva
0 siblings, 0 replies; only message in thread
From: Alexandre Oliva @ 2020-09-24 19:16 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:6e7427d55b312da45624b7163dbc4c0403e342ca
commit 6e7427d55b312da45624b7163dbc4c0403e342ca
Author: Alexandre Oliva <oliva@adacore.com>
Date: Thu Sep 24 14:47:17 2020 -0300
unify split logic, reorder neighbors if needed
Diff:
---
gcc/fold-const.c | 451 +++++++++++++++++++++++++------------------------------
1 file changed, 205 insertions(+), 246 deletions(-)
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 87448f9b911..bfbf88c9f15 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -6681,6 +6681,72 @@ fold_truth_andor_1 (location_t loc, enum tree_code code, tree truth_type,
return 0;
}
+ /* This will be bumped to 2 if any of the field pairs crosses an
+ alignment boundary, so the merged compare has to be done in two
+ parts. */
+ int parts = 1;
+ /* Set to true if the second combined compare should come first,
+ e.g., because the second original compare accesses a word that
+ the first one doesn't, and the combined compares access those in
+ cmp[0]. */
+ bool first1 = false;
+ /* Set to true if the first original compare is not the one being
+ split. */
+ bool maybe_separate = false;
+
+ /* The following 2-dimensional arrays use the first index to
+ identify left(0)- vs right(1)-hand compare operands, and the
+ second one to identify merged compare parts. */
+ /* The memory loads or constants to be compared. */
+ tree ld_arg[2][2];
+ /* The first bit of the corresponding inner object that the
+ corresponding LD_ARG covers. */
+ HOST_WIDE_INT bitpos[2][2];
+ /* The bit count starting at BITPOS that the corresponding LD_ARG
+ covers. */
+ HOST_WIDE_INT bitsiz[2][2];
+ /* The number of bits by which LD_ARG has already been shifted
+ right, WRT mask. */
+ HOST_WIDE_INT shifted[2][2];
+ /* The number of bits by which both LD_ARG and MASK need shifting to
+ bring its least-significant bit to bit zero. */
+ HOST_WIDE_INT toshift[2][2];
+ /* An additional mask to be applied to LD_ARG, to remove any bits
+ that may have been loaded for use in another compare, but that
+ don't belong in the corresponding compare. */
+ tree xmask[2][2] = {};
+
+ /* The combined compare or compares. */
+ tree cmp[2];
+
+ /* Consider we're comparing two non-contiguous fields of packed
+ structs, both aligned at 32-bit boundaries:
+
+ ll_arg: an 8-bit field at offset 0
+ lr_arg: a 16-bit field at offset 2
+
+ rl_arg: an 8-bit field at offset 1
+ rr_arg: a 16-bit field at offset 3
+
+ We'll have r_split_load, because rr_arg straddles across an
+ alignment boundary.
+
+ We'll want to have:
+
+ bitpos = { { 0, 0 }, { 0, 32 } }
+ bitsiz = { { 32, 32 }, { 32, 8 } }
+
+ And, for little-endian:
+
+ shifted = { { 0, 0 }, { 0, 32 } }
+ toshift = { { 0, 24 }, { 0, 0 } }
+
+ Or, for big-endian:
+
+ shifted = { { 0, 0 }, { 8, 0 } }
+ toshift = { { 8, 0 }, { 0, 0 } }
+ */
+
/* See if we can find a mode that contains both fields being compared on
the left. If we can't, fail. Otherwise, update all constants and masks
to be relative to a field of that size. */
@@ -6705,6 +6771,11 @@ fold_truth_andor_1 (location_t loc, enum tree_code code, tree truth_type,
return 0;
l_split_load = true;
+ parts = 2;
+ if (ll_bitpos >= boundary)
+ maybe_separate = first1 = true;
+ else if (ll_bitpos + ll_bitsize <= boundary)
+ maybe_separate = true;
}
else
l_split_load = false;
@@ -6804,6 +6875,11 @@ fold_truth_andor_1 (location_t loc, enum tree_code code, tree truth_type,
return 0;
r_split_load = true;
+ parts = 2;
+ if (lr_bitpos >= boundary)
+ maybe_separate = first1 = true;
+ else if (lr_bitpos + lr_bitsize <= boundary)
+ maybe_separate = true;
}
else
r_split_load = false;
@@ -6833,58 +6909,8 @@ fold_truth_andor_1 (location_t loc, enum tree_code code, tree truth_type,
rntype, rr_mask),
size_int (xrr_bitpos));
- ll_mask = const_binop (BIT_IOR_EXPR, ll_mask, rl_mask);
lr_mask = const_binop (BIT_IOR_EXPR, lr_mask, rr_mask);
- int parts = 1;
- tree ld_arg[2][2];
- HOST_WIDE_INT bitpos[2][2];
- HOST_WIDE_INT bitsiz[2][2];
- HOST_WIDE_INT shifted[2][2];
- HOST_WIDE_INT toshift[2][2];
- tree xmask[2][2] = {};
-
- /* Consider we're comparing two non-contiguous fields of packed
- structs, both aligned at 32-bit boundaries:
-
- ll_arg: an 8-bit field at offset 0
- lr_arg: a 16-bit field at offset 2
-
- rl_arg: an 8-bit field at offset 1
- rr_arg: a 16-bit field at offset 3
-
- We'll have r_split_load, because rr_arg straddles across an
- alignment boundary.
-
- We'll want to have:
-
- bitpos = { { 0, 0 }, { 0, 32 } }
- bitsiz = { { 32, 32 }, { 32, 8 } }
-
- And, for little-endian:
-
- shifted = { { 0, 0 }, { 0, 32 } }
- toshift = { { 0, 24 }, { 0, 0 } }
-
- Or, for big-endian:
-
- shifted = { { 0, 0 }, { 8, 0 } }
- toshift = { { 8, 0 }, { 0, 0 } }
- */
-
- toshift[0][0] = MIN (xll_bitpos, xrl_bitpos);
- shifted[0][0] = 0;
-
- if (!l_split_load)
- {
- bitpos[0][0] = lnbitpos;
- bitsiz[0][0] = lnbitsize;
- ld_arg[0][0] = make_bit_field_ref (loc, ll_inner, ll_arg,
- lntype, lnbitsize, lnbitpos,
- ll_unsignedp || rl_unsignedp,
- ll_reversep);
- }
-
toshift[1][0] = MIN (xlr_bitpos, xrr_bitpos);
shifted[1][0] = 0;
@@ -6898,20 +6924,8 @@ fold_truth_andor_1 (location_t loc, enum tree_code code, tree truth_type,
lr_reversep);
}
- if (l_split_load || r_split_load)
+ if (parts > 1)
{
- parts = 2;
-
- if (l_split_load)
- build_split_load (ld_arg[0], bitpos[0], bitsiz[0], toshift[0],
- shifted[0], loc, ll_inner, ll_arg,
- lnmode, lnmode2, lnbitpos, ll_reversep);
- else
- reuse_split_load (ld_arg[0], bitpos[0], bitsiz[0], toshift[0],
- shifted[0], xmask[0],
- rnbitpos + GET_MODE_BITSIZE (rnmode)
- - lr_bitpos + ll_bitpos, ll_reversep);
-
if (r_split_load)
build_split_load (ld_arg[1], bitpos[1], bitsiz[1], toshift[1],
shifted[1], loc, lr_inner, lr_arg,
@@ -6922,215 +6936,160 @@ fold_truth_andor_1 (location_t loc, enum tree_code code, tree truth_type,
lnbitpos + GET_MODE_BITSIZE (lnmode)
- ll_bitpos + lr_bitpos, lr_reversep);
}
-
- tree cmp[2];
-
- for (int i = 0; i < parts; i++)
- {
- tree op[2] = { ld_arg[0][i], ld_arg[1][i] };
- tree mask[2] = { ll_mask, lr_mask };
-
- for (int j = 0; j < 2; j++)
+ }
+ else
+ {
+ /* Handle the case of comparisons with constants. If there is
+ something in common between the masks, those bits of the
+ constants must be the same. If not, the condition is always
+ false. Test for this to avoid generating incorrect code
+ below. */
+ result = const_binop (BIT_AND_EXPR, ll_mask, rl_mask);
+ if (! integer_zerop (result)
+ && simple_cst_equal (const_binop (BIT_AND_EXPR,
+ result, l_const),
+ const_binop (BIT_AND_EXPR,
+ result, r_const)) != 1)
+ {
+ if (wanted_code == NE_EXPR)
{
- /* Mask out the bits belonging to the other part. */
- if (xmask[j][i])
- mask[j] = const_binop (BIT_AND_EXPR, mask[j], xmask[j][i]);
-
- if (shifted[j][i])
- {
- tree shiftsz = bitsize_int (shifted[j][i]);
- mask[j] = const_binop (RSHIFT_EXPR, mask[j], shiftsz);
- }
- mask[j] = fold_convert_loc (loc, TREE_TYPE (op[j]), mask[j]);
+ warning (0,
+ "%<or%> of unmatched not-equal tests"
+ " is always 1");
+ return constant_boolean_node (true, truth_type);
}
-
- HOST_WIDE_INT shift = (toshift[0][i] - toshift[1][i]);
-
- if (shift)
+ else
{
- int j;
- if (shift > 0)
- j = 0;
- else
- {
- j = 1;
- shift = -shift;
- }
-
- tree shiftsz = bitsize_int (shift);
- op[j] = fold_build2_loc (loc, RSHIFT_EXPR, TREE_TYPE (op[j]),
- op[j], shiftsz);
- mask[j] = const_binop (RSHIFT_EXPR, mask[j], shiftsz);
+ warning (0,
+ "%<and%> of mutually exclusive equal-tests"
+ " is always 0");
+ return constant_boolean_node (false, truth_type);
}
+ }
- /* Convert to the smaller type before masking out unwanted
- bits. */
- tree type = TREE_TYPE (op[0]);
- if (type != TREE_TYPE (op[1]))
- {
- int j = (TYPE_PRECISION (type)
- < TYPE_PRECISION (TREE_TYPE (op[1])));
- if (!j)
- type = TREE_TYPE (op[1]);
- op[j] = fold_convert_loc (loc, type, op[j]);
- mask[j] = fold_convert_loc (loc, type, mask[j]);
- }
+ if (lnbitpos < 0)
+ return 0;
- for (int j = 0; j < 2; j++)
- if (! integer_all_onesp (mask[j]))
- op[j] = build2_loc (loc, BIT_AND_EXPR, type,
- op[j], mask[j]);
+ /* The constants are combined so as to line up with the loaded
+ field, so use the same parameters. */
+ ld_arg[1][0] = const_binop (BIT_IOR_EXPR, l_const, r_const);
+ toshift[1][0] = MIN (xll_bitpos, xrl_bitpos);
+ shifted[1][0] = 0;
+ bitpos[1][0] = lnbitpos;
+ bitsiz[1][0] = lnbitsize;
- cmp[i] = build2_loc (loc, wanted_code, truth_type, op[0], op[1]);
- }
+ if (parts > 1)
+ reuse_split_load (ld_arg[1], bitpos[1], bitsiz[1], toshift[1],
+ shifted[1], xmask[1],
+ lnbitpos + GET_MODE_BITSIZE (lnmode),
+ lr_reversep);
- if (parts == 1)
- result = cmp[0];
- else if (!separatep
- || ((!l_split_load
- || (ll_bitpos < bitpos[0][1]
- && ll_bitpos + ll_bitsize > bitpos[0][1]))
- && (!r_split_load
- || (lr_bitpos < bitpos[1][1]
- && lr_bitpos + lr_bitsize > bitpos[1][1]))))
- result = build2_loc (loc, orig_code, truth_type, cmp[0], cmp[1]);
- else if ((l_split_load && ll_bitpos >= bitpos[0][1])
- || (r_split_load && lr_bitpos >= bitpos[1][1]))
- {
- result = cmp[1];
- *separatep = cmp[0];
- }
- else
- {
- result = cmp[0];
- *separatep = cmp[1];
- }
+ lr_mask = build_int_cst_type (TREE_TYPE (ld_arg[1][0]), -1);
- return result;
+ /* If the compiler thinks this is used uninitialized below, it's
+ because it can't realize that parts can only be 2 when
+ comparing wiht constants if l_split_load is also true. This
+ just silences the warning. */
+ rnbitpos = 0;
}
- /* Handle the case of comparisons with constants. If there is something in
- common between the masks, those bits of the constants must be the same.
- If not, the condition is always false. Test for this to avoid generating
- incorrect code below. */
- result = const_binop (BIT_AND_EXPR, ll_mask, rl_mask);
- if (! integer_zerop (result)
- && simple_cst_equal (const_binop (BIT_AND_EXPR, result, l_const),
- const_binop (BIT_AND_EXPR, result, r_const)) != 1)
+ ll_mask = const_binop (BIT_IOR_EXPR, ll_mask, rl_mask);
+ toshift[0][0] = MIN (xll_bitpos, xrl_bitpos);
+ shifted[0][0] = 0;
+
+ if (!l_split_load)
{
- if (wanted_code == NE_EXPR)
- {
- warning (0, "%<or%> of unmatched not-equal tests is always 1");
- return constant_boolean_node (true, truth_type);
- }
- else
- {
- warning (0, "%<and%> of mutually exclusive equal-tests is always 0");
- return constant_boolean_node (false, truth_type);
- }
+ bitpos[0][0] = lnbitpos;
+ bitsiz[0][0] = lnbitsize;
+ ld_arg[0][0] = make_bit_field_ref (loc, ll_inner, ll_arg,
+ lntype, lnbitsize, lnbitpos,
+ ll_unsignedp || rl_unsignedp,
+ ll_reversep);
}
- if (lnbitpos < 0)
- return 0;
+ if (parts > 1)
+ {
+ if (l_split_load)
+ build_split_load (ld_arg[0], bitpos[0], bitsiz[0], toshift[0],
+ shifted[0], loc, ll_inner, ll_arg,
+ lnmode, lnmode2, lnbitpos, ll_reversep);
+ else
+ reuse_split_load (ld_arg[0], bitpos[0], bitsiz[0], toshift[0],
+ shifted[0], xmask[0],
+ rnbitpos + GET_MODE_BITSIZE (rnmode)
+ - lr_bitpos + ll_bitpos, ll_reversep);
+ }
- if (l_split_load)
+ for (int i = 0; i < parts; i++)
{
- HOST_WIDE_INT align = TYPE_ALIGN (TREE_TYPE (ll_inner));
- HOST_WIDE_INT lnlbitsize = GET_MODE_BITSIZE (lnmode);
- HOST_WIDE_INT lnrbitsize = GET_MODE_BITSIZE (lnmode2);
- HOST_WIDE_INT midpoint = lnlbitsize;
- HOST_WIDE_INT lnrbitpos = lnbitpos + midpoint;
- HOST_WIDE_INT lnlbitpos = lnrbitpos - lnlbitsize;
- gcc_checking_assert ((lnrbitpos & (align - 1)) == 0);
- tree lnltype = lang_hooks.types.type_for_size (lnlbitsize, 1);
- tree lnrtype = lang_hooks.types.type_for_size (lnrbitsize, 1);
- tree lll_arg = make_bit_field_ref (loc, ll_inner, ll_arg,
- lnltype, lnlbitsize, lnlbitpos,
- ll_unsignedp || rl_unsignedp,
- ll_reversep);
- tree llr_arg = make_bit_field_ref (loc, ll_inner, ll_arg,
- lnrtype, lnrbitsize, lnrbitpos,
- ll_unsignedp || rl_unsignedp,
- ll_reversep);
+ tree op[2] = { ld_arg[0][i], ld_arg[1][i] };
+ tree mask[2] = { ll_mask, lr_mask };
- HOST_WIDE_INT lnlcbitpos;
- HOST_WIDE_INT lnrcbitpos;
- /* The bit field ref constant folding below already takes care
- of default target endianness. */
- if (!ll_reversep)
+ for (int j = 0; j < 2; j++)
{
- lnlcbitpos = 0;
- lnrcbitpos = lnlbitsize;
+ /* Mask out the bits belonging to the other part. */
+ if (xmask[j][i])
+ mask[j] = const_binop (BIT_AND_EXPR, mask[j], xmask[j][i]);
+
+ if (shifted[j][i])
+ {
+ tree shiftsz = bitsize_int (shifted[j][i]);
+ mask[j] = const_binop (RSHIFT_EXPR, mask[j], shiftsz);
+ }
+ mask[j] = fold_convert_loc (loc, TREE_TYPE (op[j]), mask[j]);
}
- else
+
+ HOST_WIDE_INT shift = (toshift[0][i] - toshift[1][i]);
+
+ if (shift)
{
- lnlcbitpos = lnrbitsize;
- lnrcbitpos = 0;
- }
-
- tree mask = const_binop (BIT_IOR_EXPR, ll_mask, rl_mask);
- tree lll_mask = fold_build3 (BIT_FIELD_REF, lnltype, mask,
- bitsize_int (lnlbitsize),
- bitsize_int (lnlcbitpos));
- if (! integer_all_onesp (lll_mask))
- lll_arg = fold_build2_loc (loc, BIT_AND_EXPR, lnltype,
- lll_arg, lll_mask);
- tree llr_mask = fold_build3 (BIT_FIELD_REF, lnrtype, mask,
- bitsize_int (lnrbitsize),
- bitsize_int (lnrcbitpos));
- if (! integer_all_onesp (llr_mask))
- llr_arg = fold_build2_loc (loc, BIT_AND_EXPR, lnrtype,
- llr_arg, llr_mask);
- tree lnr_const = const_binop (BIT_IOR_EXPR, l_const, r_const);
- tree lll_const = fold_build3 (BIT_FIELD_REF, lnltype, lnr_const,
- bitsize_int (lnlbitsize),
- bitsize_int (lnlcbitpos));
- tree lll_result = fold_build2_loc (loc, wanted_code, truth_type,
- lll_arg, lll_const);
- tree llr_const = fold_build3 (BIT_FIELD_REF, lnrtype, lnr_const,
- bitsize_int (lnrbitsize),
- bitsize_int (lnrcbitpos));
- tree llr_result = fold_build2_loc (loc, wanted_code, truth_type,
- llr_arg, llr_const);
-
- /* If the accesses were adjacent in the compare chain, or if LHS
- already accessed both "words", then we can have both words
- accessed in the RESULT, leaving no remains of *RHS for
- *SEPARATEP. Otherwise, figure out which part of the object
- was already accessed by LHS, and put it in the RESULT,
- returning the bits newly-accessed by RHS in *SEPARATEP. */
- if (!separatep
- || (ll_bitpos < lnrbitpos && ll_bitpos + ll_bitsize > lnrbitpos))
- result = build2_loc (loc, orig_code, truth_type,
- lll_result, llr_result);
- else if (ll_bitpos >= lnrbitpos)
- {
- result = llr_result;
- *separatep = lll_result;
+ int j;
+ if (shift > 0)
+ j = 0;
+ else
+ {
+ j = 1;
+ shift = -shift;
+ }
+
+ tree shiftsz = bitsize_int (shift);
+ op[j] = fold_build2_loc (loc, RSHIFT_EXPR, TREE_TYPE (op[j]),
+ op[j], shiftsz);
+ mask[j] = const_binop (RSHIFT_EXPR, mask[j], shiftsz);
}
- else
+
+ /* Convert to the smaller type before masking out unwanted
+ bits. */
+ tree type = TREE_TYPE (op[0]);
+ if (type != TREE_TYPE (op[1]))
{
- result = lll_result;
- *separatep = llr_result;
+ int j = (TYPE_PRECISION (type)
+ < TYPE_PRECISION (TREE_TYPE (op[1])));
+ if (!j)
+ type = TREE_TYPE (op[1]);
+ op[j] = fold_convert_loc (loc, type, op[j]);
+ mask[j] = fold_convert_loc (loc, type, mask[j]);
}
- }
- else
- {
- /* Construct the expression we will return. First get the component
- reference we will make. Unless the mask is all ones the width of
- that field, perform the mask operation. Then compare with the
- merged constant. */
- result = make_bit_field_ref (loc, ll_inner, ll_arg,
- lntype, lnbitsize, lnbitpos,
- ll_unsignedp || rl_unsignedp, ll_reversep);
+ for (int j = 0; j < 2; j++)
+ if (! integer_all_onesp (mask[j]))
+ op[j] = build2_loc (loc, BIT_AND_EXPR, type,
+ op[j], mask[j]);
+
+ cmp[i] = build2_loc (loc, wanted_code, truth_type, op[0], op[1]);
+ }
- ll_mask = const_binop (BIT_IOR_EXPR, ll_mask, rl_mask);
- if (! integer_all_onesp (ll_mask))
- result = build2_loc (loc, BIT_AND_EXPR, lntype, result, ll_mask);
+ if (first1)
+ std::swap (cmp[0], cmp[1]);
- result = build2_loc (loc, wanted_code, truth_type, result,
- const_binop (BIT_IOR_EXPR, l_const, r_const));
+ if (parts == 1)
+ result = cmp[0];
+ else if (!separatep || !maybe_separate)
+ result = build2_loc (loc, orig_code, truth_type, cmp[0], cmp[1]);
+ else
+ {
+ result = cmp[0];
+ *separatep = cmp[1];
}
return result;
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2020-09-24 19:16 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-24 19:16 [gcc(refs/users/aoliva/heads/testme)] unify split logic, reorder neighbors if needed Alexandre Oliva
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).