On Tue, Jan 14, 2025 at 6:05 AM Alexandre Oliva <ol...@adacore.com> wrote: > > > Arrange for decode_field_reference to use local variables throughout, > to modify the out parms only when we're about to return non-NULL, and > to drop the unused case of NULL pand_mask, that had a latent failure > to detect signbit masking. > > Regstrapped on x86_64-linux-gnu along with the PR118456 patch. > Ok to install?
OK. Thanks, Richard. > > for gcc/ChangeLog > > * gimple-fold.cc (decode_field_reference): Rebustify to set > out parms only when returning non-NULL. > (fold_truth_andor_for_ifcombine): Bail if > decode_field_reference returns NULL. Add complementary assert > on r_const's not being set when l_const isn't. > --- > gcc/gimple-fold.cc | 155 > +++++++++++++++++++++++++++------------------------- > 1 file changed, 80 insertions(+), 75 deletions(-) > > diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc > index 5b1fbe6db1df3..3c971a29ef045 100644 > --- a/gcc/gimple-fold.cc > +++ b/gcc/gimple-fold.cc > @@ -7510,18 +7510,17 @@ gimple_binop_def_p (enum tree_code code, tree t, tree > op[2]) > *PREVERSEP is set to the storage order of the field. > > *PAND_MASK is set to the mask found in a BIT_AND_EXPR, if any. If > - PAND_MASK *is NULL, BIT_AND_EXPR is not recognized. If *PAND_MASK > - is initially set to a mask with nonzero precision, that mask is > + *PAND_MASK is initially set to a mask with nonzero precision, that mask is > combined with the found mask, or adjusted in precision to match. > > *PSIGNBIT is set to TRUE if, before clipping to *PBITSIZE, the mask > encompassed bits that corresponded to extensions of the sign bit. > > - *XOR_P is to be FALSE if EXP might be a XOR used in a compare, in which > - case, if XOR_CMP_OP is a zero constant, it will be overridden with *PEXP, > - *XOR_P will be set to TRUE, *XOR_PAND_MASK will be copied from *PAND_MASK, > - and the left-hand operand of the XOR will be decoded. If *XOR_P is TRUE, > - XOR_CMP_OP and XOR_PAND_MASK are supposed to be NULL, and then the > + *PXORP is to be FALSE if EXP might be a XOR used in a compare, in which > + case, if PXOR_CMP_OP is a zero constant, it will be overridden with *PEXP, > + *PXORP will be set to TRUE, *PXOR_AND_MASK will be copied from *PAND_MASK, > + and the left-hand operand of the XOR will be decoded. If *PXORP is TRUE, > + PXOR_CMP_OP and PXOR_AND_MASK are supposed to be NULL, and then the > right-hand operand of the XOR will be decoded. > > *LOAD is set to the load stmt of the innermost reference, if any, > @@ -7538,8 +7537,8 @@ decode_field_reference (tree *pexp, HOST_WIDE_INT > *pbitsize, > HOST_WIDE_INT *pbitpos, > bool *punsignedp, bool *preversep, bool *pvolatilep, > wide_int *pand_mask, bool *psignbit, > - bool *xor_p, tree *xor_cmp_op, wide_int > *xor_pand_mask, > - gimple **load, location_t loc[4]) > + bool *pxorp, tree *pxor_cmp_op, wide_int > *pxor_and_mask, > + gimple **pload, location_t loc[4]) > { > tree exp = *pexp; > tree outer_type = 0; > @@ -7549,9 +7548,11 @@ decode_field_reference (tree *pexp, HOST_WIDE_INT > *pbitsize, > tree res_ops[2]; > machine_mode mode; > bool convert_before_shift = false; > - > - *load = NULL; > - *psignbit = false; > + bool signbit = false; > + bool xorp = false; > + tree xor_cmp_op; > + wide_int xor_and_mask; > + gimple *load = NULL; > > /* All the optimizations using this function assume integer fields. > There are problems with FP fields since the type_for_size call > @@ -7576,7 +7577,7 @@ decode_field_reference (tree *pexp, HOST_WIDE_INT > *pbitsize, > > /* Recognize and save a masking operation. Combine it with an > incoming mask. */ > - if (pand_mask && gimple_binop_def_p (BIT_AND_EXPR, exp, res_ops) > + if (gimple_binop_def_p (BIT_AND_EXPR, exp, res_ops) > && TREE_CODE (res_ops[1]) == INTEGER_CST) > { > loc[1] = gimple_location (SSA_NAME_DEF_STMT (exp)); > @@ -7596,29 +7597,29 @@ decode_field_reference (tree *pexp, HOST_WIDE_INT > *pbitsize, > and_mask &= wide_int::from (*pand_mask, prec_op, UNSIGNED); > } > } > - else if (pand_mask) > + else > and_mask = *pand_mask; > > /* Turn (a ^ b) [!]= 0 into a [!]= b. */ > - if (xor_p && gimple_binop_def_p (BIT_XOR_EXPR, exp, res_ops)) > + if (pxorp && gimple_binop_def_p (BIT_XOR_EXPR, exp, res_ops)) > { > /* No location recorded for this one, it's entirely subsumed by the > compare. */ > - if (*xor_p) > + if (*pxorp) > { > exp = res_ops[1]; > - gcc_checking_assert (!xor_cmp_op && !xor_pand_mask); > + gcc_checking_assert (!pxor_cmp_op && !pxor_and_mask); > } > - else if (!xor_cmp_op) > + else if (!pxor_cmp_op) > /* Not much we can do when xor appears in the right-hand compare > operand. */ > return NULL_TREE; > - else if (integer_zerop (*xor_cmp_op)) > + else if (integer_zerop (*pxor_cmp_op)) > { > - *xor_p = true; > + xorp = true; > exp = res_ops[0]; > - *xor_cmp_op = *pexp; > - *xor_pand_mask = *pand_mask; > + xor_cmp_op = *pexp; > + xor_and_mask = *pand_mask; > } > } > > @@ -7646,12 +7647,12 @@ decode_field_reference (tree *pexp, HOST_WIDE_INT > *pbitsize, > /* Yet another chance to drop conversions. This one is allowed to > match a converting load, subsuming the load identification block > below. */ > - if (!outer_type && gimple_convert_def_p (exp, res_ops, load)) > + if (!outer_type && gimple_convert_def_p (exp, res_ops, &load)) > { > outer_type = TREE_TYPE (exp); > loc[0] = gimple_location (SSA_NAME_DEF_STMT (exp)); > - if (*load) > - loc[3] = gimple_location (*load); > + if (load) > + loc[3] = gimple_location (load); > exp = res_ops[0]; > /* This looks backwards, but we're going back the def chain, so if we > find the conversion here, after finding a shift, that's because the > @@ -7662,14 +7663,13 @@ decode_field_reference (tree *pexp, HOST_WIDE_INT > *pbitsize, > } > > /* Identify the load, if there is one. */ > - if (!(*load) && TREE_CODE (exp) == SSA_NAME > - && !SSA_NAME_IS_DEFAULT_DEF (exp)) > + if (!load && TREE_CODE (exp) == SSA_NAME && !SSA_NAME_IS_DEFAULT_DEF (exp)) > { > gimple *def = SSA_NAME_DEF_STMT (exp); > if (gimple_assign_load_p (def)) > { > loc[3] = gimple_location (def); > - *load = def; > + load = def; > exp = gimple_assign_rhs1 (def); > } > } > @@ -7694,20 +7694,14 @@ decode_field_reference (tree *pexp, HOST_WIDE_INT > *pbitsize, > && !type_has_mode_precision_p (TREE_TYPE (inner)))) > return NULL_TREE; > > - *pbitsize = bs; > - *pbitpos = bp; > - *punsignedp = unsignedp; > - *preversep = reversep; > - *pvolatilep = volatilep; > - > /* Adjust shifts... */ > if (convert_before_shift > - && outer_type && *pbitsize > TYPE_PRECISION (outer_type)) > + && outer_type && bs > TYPE_PRECISION (outer_type)) > { > - HOST_WIDE_INT excess = *pbitsize - TYPE_PRECISION (outer_type); > - if (*preversep ? !BYTES_BIG_ENDIAN : BYTES_BIG_ENDIAN) > - *pbitpos += excess; > - *pbitsize -= excess; > + HOST_WIDE_INT excess = bs - TYPE_PRECISION (outer_type); > + if (reversep ? !BYTES_BIG_ENDIAN : BYTES_BIG_ENDIAN) > + bp += excess; > + bs -= excess; > } > > if (shiftrt) > @@ -7720,49 +7714,57 @@ decode_field_reference (tree *pexp, HOST_WIDE_INT > *pbitsize, > shift after a change of signedness would make the extension > non-uniform, and we can't deal with that (yet ???). See > gcc.dg/field-merge-22.c for a test that would go wrong. */ > - if (*pbitsize <= shiftrt > + if (bs <= shiftrt > || (convert_before_shift > && outer_type && unsignedp != TYPE_UNSIGNED (outer_type))) > return NULL_TREE; > - if (!*preversep ? !BYTES_BIG_ENDIAN : BYTES_BIG_ENDIAN) > - *pbitpos += shiftrt; > - *pbitsize -= shiftrt; > + if (!reversep ? !BYTES_BIG_ENDIAN : BYTES_BIG_ENDIAN) > + bp += shiftrt; > + bs -= shiftrt; > } > > /* ... and bit position. */ > if (!convert_before_shift > - && outer_type && *pbitsize > TYPE_PRECISION (outer_type)) > + && outer_type && bs > TYPE_PRECISION (outer_type)) > { > - HOST_WIDE_INT excess = *pbitsize - TYPE_PRECISION (outer_type); > - if (*preversep ? !BYTES_BIG_ENDIAN : BYTES_BIG_ENDIAN) > - *pbitpos += excess; > - *pbitsize -= excess; > + HOST_WIDE_INT excess = bs - TYPE_PRECISION (outer_type); > + if (reversep ? !BYTES_BIG_ENDIAN : BYTES_BIG_ENDIAN) > + bp += excess; > + bs -= excess; > } > > - *pexp = exp; > - > /* If the number of bits in the reference is the same as the bitsize of > the outer type, then the outer type gives the signedness. Otherwise > (in case of a small bitfield) the signedness is unchanged. */ > - if (outer_type && *pbitsize == TYPE_PRECISION (outer_type)) > - *punsignedp = TYPE_UNSIGNED (outer_type); > + if (outer_type && bs == TYPE_PRECISION (outer_type)) > + unsignedp = TYPE_UNSIGNED (outer_type); > > - if (pand_mask) > + /* Make the mask the expected width. */ > + if (and_mask.get_precision () != 0) > { > - /* Make the mask the expected width. */ > - if (and_mask.get_precision () != 0) > - { > - /* If the AND_MASK encompasses bits that would be extensions of > - the sign bit, set *PSIGNBIT. */ > - if (!unsignedp > - && and_mask.get_precision () > *pbitsize > - && (and_mask > - & wi::mask (*pbitsize, true, and_mask.get_precision ())) != > 0) > - *psignbit = true; > - and_mask = wide_int::from (and_mask, *pbitsize, UNSIGNED); > - } > + /* If the AND_MASK encompasses bits that would be extensions of > + the sign bit, set SIGNBIT. */ > + if (!unsignedp > + && and_mask.get_precision () > bs > + && (and_mask & wi::mask (bs, true, and_mask.get_precision ())) != 0) > + signbit = true; > + and_mask = wide_int::from (and_mask, bs, UNSIGNED); > + } > > - *pand_mask = and_mask; > + *pexp = exp; > + *pload = load; > + *pbitsize = bs; > + *pbitpos = bp; > + *punsignedp = unsignedp; > + *preversep = reversep; > + *pvolatilep = volatilep; > + *psignbit = signbit; > + *pand_mask = and_mask; > + if (xorp) > + { > + *pxorp = xorp; > + *pxor_cmp_op = xor_cmp_op; > + *pxor_and_mask = xor_and_mask; > } > > return inner; > @@ -8168,19 +8170,27 @@ fold_truth_andor_for_ifcombine (enum tree_code code, > tree truth_type, > &ll_and_mask, &ll_signbit, > &l_xor, &lr_arg, &lr_and_mask, > &ll_load, ll_loc); > + if (!ll_inner) > + return 0; > lr_inner = decode_field_reference (&lr_arg, &lr_bitsize, &lr_bitpos, > &lr_unsignedp, &lr_reversep, &volatilep, > &lr_and_mask, &lr_signbit, &l_xor, 0, 0, > &lr_load, lr_loc); > + if (!lr_inner) > + return 0; > rl_inner = decode_field_reference (&rl_arg, &rl_bitsize, &rl_bitpos, > &rl_unsignedp, &rl_reversep, &volatilep, > &rl_and_mask, &rl_signbit, > &r_xor, &rr_arg, &rr_and_mask, > &rl_load, rl_loc); > + if (!rl_inner) > + return 0; > rr_inner = decode_field_reference (&rr_arg, &rr_bitsize, &rr_bitpos, > &rr_unsignedp, &rr_reversep, &volatilep, > &rr_and_mask, &rr_signbit, &r_xor, 0, 0, > &rr_load, rr_loc); > + if (!rr_inner) > + return 0; > > /* It must be true that the inner operation on the lhs of each > comparison must be the same if we are to be able to do anything. > @@ -8188,16 +8198,13 @@ fold_truth_andor_for_ifcombine (enum tree_code code, > tree truth_type, > the rhs's. If one is a load and the other isn't, we have to be > conservative and avoid the optimization, otherwise we could get > SRAed fields wrong. */ > - if (volatilep > - || ll_reversep != rl_reversep > - || ll_inner == 0 || rl_inner == 0) > + if (volatilep || ll_reversep != rl_reversep) > return 0; > > if (! operand_equal_p (ll_inner, rl_inner, 0)) > { > /* Try swapping the operands. */ > if (ll_reversep != rr_reversep > - || !rr_inner > || !operand_equal_p (ll_inner, rr_inner, 0)) > return 0; > > @@ -8266,7 +8273,6 @@ fold_truth_andor_for_ifcombine (enum tree_code code, > tree truth_type, > lr_reversep = ll_reversep; > } > else if (lr_reversep != rr_reversep > - || lr_inner == 0 || rr_inner == 0 > || ! operand_equal_p (lr_inner, rr_inner, 0) > || ((lr_load && rr_load) > ? gimple_vuse (lr_load) != gimple_vuse (rr_load) > @@ -8520,6 +8526,9 @@ fold_truth_andor_for_ifcombine (enum tree_code code, > tree truth_type, > else > rl_mask = wi::shifted_mask (xrl_bitpos, rl_bitsize, false, lnprec); > > + /* When we set l_const, we also set r_const. */ > + gcc_checking_assert (!l_const.get_precision () == !r_const.get_precision > ()); > + > /* Adjust right-hand constants in both original comparisons to match width > and bit position. */ > if (l_const.get_precision ()) > @@ -8550,10 +8559,6 @@ fold_truth_andor_for_ifcombine (enum tree_code code, > tree truth_type, > return constant_boolean_node (wanted_code == NE_EXPR, truth_type); > } > > - /* When we set l_const, we also set r_const, so we need not test it > - again. */ > - gcc_checking_assert (r_const.get_precision ()); > - > /* Before clipping upper bits of the right-hand operand of the compare, > check that they're sign or zero extensions, depending on how the > left-hand operand would be extended. */ > > > -- > Alexandre Oliva, happy hacker https://FSFLA.org/blogs/lxo/ > Free Software Activist GNU Toolchain Engineer > More tolerance and less prejudice are key for inclusion and diversity > Excluding neuro-others for not behaving ""normal"" is *not* inclusive