Hi Richard, On Thu, 2025-08-07 at 13:56 +0200, Richard Biener wrote: > The following handles value-numbering of a BIT_FIELD_REF of > a register that's defined by a load by looking up a subset > load similar to how we handle bit-and masked loads. This > allows the testcase to be simplified by two FRE passes, > the first one will create the BIT_FIELD_REF. > > Bootstrapped and tested on x86_64-unknown-linux-gnu, pushed. > > PR tree-optimization/121405 > * tree-ssa-sccvn.cc (visit_nary_op): Handle BIT_FIELD_REF > with reference def by looking up a combination of both. > > * gcc.dg/tree-ssa/ssa-fre-107.c: New testcase. > * gcc.target/i386/pr90579.c: Adjust.
Looks like that broke building of libgo: https://builder.sourceware.org/buildbot/#/builders/312/builds/1759 during GIMPLE pass: fre ../../../../gcc/libgo/go/crypto/elliptic/elliptic.go: In function ‘crypto/elliptic.CurveParams.ScalarMult’: ../../../../gcc/libgo/go/crypto/elliptic/elliptic.go:295:1: internal compiler error: in nonoverlapping_refs_since_match_p, at tree-ssa-alias.cc:1684 295 | func (curve *CurveParams) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) { | ^ 0x3034bfb internal_error(char const*, ...) ../../gcc/gcc/diagnostic-global-context.cc:534 0x101ab65 fancy_abort(char const*, int, char const*) ../../gcc/gcc/diagnostics/context.cc:1640 0x9ba3bc nonoverlapping_refs_since_match_p ../../gcc/gcc/tree-ssa-alias.cc:1684 0x195d17c decl_refs_may_alias_p ../../gcc/gcc/tree-ssa-alias.cc:2073 0x195d17c refs_may_alias_p_2 ../../gcc/gcc/tree-ssa-alias.cc:2467 0x195d17c refs_may_alias_p_1(ao_ref*, ao_ref*, bool) ../../gcc/gcc/tree-ssa-alias.cc:2576 0x19600e3 stmt_may_clobber_ref_p_1(gimple*, ao_ref*, bool) ../../gcc/gcc/tree-ssa-alias.cc:3299 0x1960673 walk_non_aliased_vuses(ao_ref*, tree_node*, bool, void* (*)(ao_ref*, tree_node*, void*), void* (*)(ao_ref*, tree_node*, void*, translate_flags*), tree_node* (*)(tree_node*), unsigned int&, void*) ../../gcc/gcc/tree-ssa-alias.cc:3966 0x1a798a2 vn_reference_lookup(tree_node*, tree_node*, vn_lookup_kind, vn_reference_s**, bool, tree_node**, tree_node*, bool) ../../gcc/gcc/tree-ssa-sccvn.cc:4198 0x1a7d07e visit_nary_op ../../gcc/gcc/tree-ssa-sccvn.cc:5649 0x1a7e820 process_bb ../../gcc/gcc/tree-ssa-sccvn.cc:8331 0x1a80e64 do_rpo_vn_1 ../../gcc/gcc/tree-ssa-sccvn.cc:8917 0x1a81e5b execute ../../gcc/gcc/tree-ssa-sccvn.cc:9078 Please submit a full bug report, with preprocessed source (by using -freport-bug). Please include the complete backtrace with any bug report. See <https://gcc.gnu.org/bugs/> for instructions. > --- > gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-107.c | 29 +++++++++++++++++++++ > gcc/testsuite/gcc.target/i386/pr90579.c | 7 ++--- > gcc/tree-ssa-sccvn.cc | 22 ++++++++++++++++ > 3 files changed, 53 insertions(+), 5 deletions(-) > create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-107.c > > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-107.c > b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-107.c > new file mode 100644 > index 00000000000..f80baf3ca8d > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-107.c > @@ -0,0 +1,29 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O -fdump-tree-optimized" } */ > + > +struct vec_char_16 > +{ > + unsigned char raw[2]; > +}; > + > +static inline struct vec_char_16 > +Dup128VecFromValues(unsigned char t0, unsigned char t1) > +{ > + struct vec_char_16 result; > + result.raw[0] = t0; > + result.raw[1] = t1; > + return result; > +} > + > +int f(unsigned char t0, unsigned char t1) > +{ > + struct vec_char_16 a = Dup128VecFromValues(t0, t1); > + struct vec_char_16 b; > + __builtin_memcpy(&b, &a, sizeof(a)); > + return b.raw[0] + b.raw[1]; > +} > + > +/* Ideally we'd optimize this at FRE1 time but we only replace > + the loads from b.raw[] with BIT_FIELD_REFs which get optimized > + only later in the next FRE. */ > +/* { dg-final { scan-tree-dump-not "MEM" "optimized" } } */ > diff --git a/gcc/testsuite/gcc.target/i386/pr90579.c > b/gcc/testsuite/gcc.target/i386/pr90579.c > index ab48a44063c..bd2fd3378e1 100644 > --- a/gcc/testsuite/gcc.target/i386/pr90579.c > +++ b/gcc/testsuite/gcc.target/i386/pr90579.c > @@ -16,8 +16,5 @@ loop (int k, double x) > return t; > } > > -/* Verify we end up with scalar loads from r for the final sum. */ > -/* { dg-final { scan-assembler "vaddsd\tr\\\+40" } } */ > -/* { dg-final { scan-assembler "vaddsd\tr\\\+32" } } */ > -/* { dg-final { scan-assembler "vaddsd\tr\\\+24" } } */ > -/* { dg-final { scan-assembler "vaddsd\tr\\\+16" } } */ > +/* Verify we end up with no loads from r. */ > +/* { dg-final { scan-assembler-not "v\[ma\]\[^\t \]+\tr" } } */ > diff --git a/gcc/tree-ssa-sccvn.cc b/gcc/tree-ssa-sccvn.cc > index 00315d154e4..1c113f848eb 100644 > --- a/gcc/tree-ssa-sccvn.cc > +++ b/gcc/tree-ssa-sccvn.cc > @@ -5633,6 +5633,28 @@ visit_nary_op (tree lhs, gassign *stmt) > } > } > break; > + case BIT_FIELD_REF: > + if (TREE_CODE (TREE_OPERAND (rhs1, 0)) == SSA_NAME) > + { > + tree op0 = TREE_OPERAND (rhs1, 0); > + gassign *ass = dyn_cast <gassign *> (SSA_NAME_DEF_STMT (op0)); > + if (ass > + && !gimple_has_volatile_ops (ass) > + && vn_get_stmt_kind (ass) == VN_REFERENCE) > + { > + tree last_vuse = gimple_vuse (ass); > + tree op = build3 (BIT_FIELD_REF, TREE_TYPE (rhs1), > + gimple_assign_rhs1 (ass), > + TREE_OPERAND (rhs1, 1), TREE_OPERAND (rhs1, 2)); > + tree result = vn_reference_lookup (op, gimple_vuse (ass), > + default_vn_walk_kind, > + NULL, true, &last_vuse); > + if (result > + && useless_type_conversion_p (type, TREE_TYPE (result))) > + return set_ssa_val_to (lhs, result); > + } > + } > + break; > case TRUNC_DIV_EXPR: > if (TYPE_UNSIGNED (type)) > break;