From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2140) id 5584D38708DE; Thu, 24 Sep 2020 19:16:57 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 5584D38708DE Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Alexandre Oliva To: gcc-cvs@gcc.gnu.org Subject: [gcc(refs/users/aoliva/heads/testme)] unify split logic, reorder neighbors if needed X-Act-Checkin: gcc X-Git-Author: Alexandre Oliva X-Git-Refname: refs/users/aoliva/heads/testme X-Git-Oldrev: 74332e0ce188a9671229ac58ca612dcac46ef799 X-Git-Newrev: 6e7427d55b312da45624b7163dbc4c0403e342ca Message-Id: <20200924191657.5584D38708DE@sourceware.org> Date: Thu, 24 Sep 2020 19:16:57 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 24 Sep 2020 19:16:57 -0000 https://gcc.gnu.org/g:6e7427d55b312da45624b7163dbc4c0403e342ca commit 6e7427d55b312da45624b7163dbc4c0403e342ca Author: Alexandre Oliva 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, + "% 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, + "% 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, "% of unmatched not-equal tests is always 1"); - return constant_boolean_node (true, truth_type); - } - else - { - warning (0, "% 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;