https://gcc.gnu.org/g:1df85ac92c10919d0da88853d4e9522574c41002
commit 1df85ac92c10919d0da88853d4e9522574c41002 Author: Alexandre Oliva <ol...@gnu.org> Date: Thu Nov 21 22:36:47 2024 -0300 fold_truth_andor: test narrowing conversions Diff: --- gcc/gimple-fold.cc | 4 ++-- gcc/match.pd | 4 ++++ gcc/testsuite/gcc.dg/field-merge-8.c | 25 +++++++++++++++++++++++++ gcc/testsuite/gcc.dg/field-merge-9.c | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 2 deletions(-) diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc index 1abf09470567..73a22ad3be59 100644 --- a/gcc/gimple-fold.cc +++ b/gcc/gimple-fold.cc @@ -7387,7 +7387,7 @@ maybe_fold_comparisons_from_match_pd (tree type, enum tree_code code, return NULL_TREE; } -extern bool gimple_nop_convert (tree, tree *, tree (*)(tree)); +extern bool gimple_any_convert (tree, tree *, tree (*)(tree)); extern bool gimple_bit_and_cst (tree, tree *, tree (*)(tree)); extern bool gimple_bit_xor_cst (tree, tree *, tree (*)(tree)); extern bool gimple_rshift_cst (tree, tree *, tree (*)(tree)); @@ -7403,7 +7403,7 @@ is_cast_p (tree *name) tree type = 0; tree res_ops[1]; - while (gimple_nop_convert (*name, res_ops, follow_all_ssa_edges)) + while (gimple_any_convert (*name, res_ops, follow_all_ssa_edges)) { if (!type) type = TREE_TYPE (*name); diff --git a/gcc/match.pd b/gcc/match.pd index 598624086bd5..9cdb47fafa01 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -202,6 +202,10 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (bit_xor_cst@0 @1 @2)) /* These are used by ifcombine fold_truth_andor. */ +(match (any_convert @0) + (convert @0)) +(match (any_convert @0) + (view_convert @0)) (match (bit_and_cst @0 @1) (bit_and @0 uniform_integer_cst_p@1)) (match (rshift_cst @0 @1) diff --git a/gcc/testsuite/gcc.dg/field-merge-8.c b/gcc/testsuite/gcc.dg/field-merge-8.c new file mode 100644 index 000000000000..ae270e10070e --- /dev/null +++ b/gcc/testsuite/gcc.dg/field-merge-8.c @@ -0,0 +1,25 @@ +/* { dg-do run } */ +/* { dg-options "-O" } */ + +/* Check that conversions are not thrown away. */ + +struct s { + unsigned char a; + unsigned short b; +} __attribute__ ((aligned (4))); + +struct s p = { 42, 0xfe }; +struct s q = { 42, 0xfe | (2 << (__CHAR_BIT__ - 1)) }; + +void f (void) { + if (0 + || p.a != q.a + || (unsigned char)p.b != (unsigned char)q.b + ) + __builtin_abort (); +} + +int main () { + f (); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/field-merge-9.c b/gcc/testsuite/gcc.dg/field-merge-9.c new file mode 100644 index 000000000000..25a8b1fa9b0a --- /dev/null +++ b/gcc/testsuite/gcc.dg/field-merge-9.c @@ -0,0 +1,36 @@ +/* { dg-do run } */ +/* { dg-options "-O" } */ + +/* Check that conversions and selections of similar bit ranges across different + types don't prevent combination. */ + +struct s1 { + unsigned char b[2]; + unsigned char a; +} __attribute__ ((aligned (4))); + +struct s2 { + unsigned short b; + unsigned char a; +} __attribute__ ((aligned (4))); + +static const char le = __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ ? 1 : 0; + +struct s1 p = { { -!le , -le }, 42 }; +struct s2 q = { (le + ? -2 << (__CHAR_BIT__ - 1) + : -1 & ((1 << (__CHAR_BIT__ - 1) << 1) - 1)), 42 }; + +void f (void) { + if (0 + || p.a != q.a + || p.b[!le] != (unsigned char)q.b + || p.b[le] != (char)((q.b >> (__CHAR_BIT__ - 1)) >> 1) + ) + __builtin_abort (); +} + +int main () { + f (); + return 0; +}