On Thu, 1 Oct 2026, Richard Biener wrote:

> On Thu, 1 Oct 2026, Richard Biener wrote:
> 
> > On Thu, 1 Oct 2026, Jakub Jelinek wrote:
> > 
> > > Hi!
> > > 
> > > The following testcase is miscompiled for 2 reasons.
> > > 
> > > One missed optimization is that fold_stmt_1 doesn't seem to attempt to
> > > use fold_const_call for internal functions into whose argument a constant
> > > is propagated.  For normal builtins, I think fold_stmt_1 -> 
> > > gimple_fold_call
> > > -> gimple_fold_builtin -> fold_call_stmt -> fold_builtin_n ->
> > > fold_builtin_{1,2,3} -> fold_const_call optimizes it, but for internal
> > > fns we just have selected set of optimizations we do on them but
> > > fold_const_call isn't among those.  That would be certainly nice to get
> > > fixed, but this patch doesn't do that.
> > 
> > Indeed, but the following should already do it:
> > 
> >   /* Dispatch to pattern-based folding.  */
> >   if (!inplace
> >       || is_gimple_assign (stmt)
> >       || gimple_code (stmt) == GIMPLE_COND) 
> >     {
> >       gimple_seq seq = NULL;
> >       gimple_match_op res_op;
> >       if (gimple_simplify (stmt, &res_op, inplace ? NULL : &seq,
> >                            valueize, valueize)
> >           && replace_stmt_with_simplification (gsi, &res_op, &seq, 
> > inplace,
> >                                                dce_worklist))
> >         changed = true;
> > 
> > via
> > 
> > /* Helper that matches and simplifies the toplevel result from 
> >    a gimple_simplify run (where we don't want to build 
> >    a stmt in case it's used in in-place folding).  Replaces
> >    RES_OP with a simplified and/or canonicalized result and
> >    returns whether any change was made.  */
> >    
> > static bool
> > gimple_resimplify1 (gimple_seq *seq, gimple_match_op *res_op,
> >                     tree (*valueize)(tree))
> > {     
> >   if (constant_for_folding (res_op->ops[0]))
> >     { 
> >       tree tem = NULL_TREE;
> >       if (res_op->code.is_tree_code ())
> >         {
> >           auto code = tree_code (res_op->code);
> >           if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))
> >               && TREE_CODE_LENGTH (code) == 1)
> >             tem = const_unop (code, res_op->type, res_op->ops[0]);
> >         }
> >       else
> >         tem = fold_const_call (combined_fn (res_op->code), res_op->type,
> >                                res_op->ops[0]); 
> 
> And the reason it doesn't work is that fold_const_call only
> handles it via fold_const_call_1 which does
> 
>   if (integer_cst_p (arg))
>     {
>       if (SCALAR_INT_MODE_P (mode))
>         {
>           wide_int result;
>           if (fold_const_call_ss (&result, fn, wi::to_wide (arg),
>                                   TYPE_PRECISION (type), TREE_TYPE (arg)))
>             return wide_int_to_tree (type, result);
> 
> and the bit int constant fails the SCALAR_INT_MODE_P check
> (but fold_const_call_ss wouldn't handle bitreverse).  So it seems
> there's no constant folding of bitreverse implemented anywhere
> or if it is, it's in the wrong place?

Ah, it's there.  So

diff --git a/gcc/fold-const-call.cc b/gcc/fold-const-call.cc
index 94841e8fb65..2a8316bf406 100644
--- a/gcc/fold-const-call.cc
+++ b/gcc/fold-const-call.cc
@@ -1311,7 +1311,7 @@ fold_const_call_1 (combined_fn fn, tree type, tree 
arg)
 
   if (integer_cst_p (arg))
     {
-      if (SCALAR_INT_MODE_P (mode))
+      if (INTEGRAL_TYPE_P (type))
        {
          wide_int result;
          if (fold_const_call_ss (&result, fn, wi::to_wide (arg),

works, I wonder why we had the mode check there ...  I'm testing this.

Richard.

> > 
> > > The other problem is forgotten flag.  Because of the above missed
> > > optimization we end up with .BITREVERSE (1) call before bitintlower, where
> > > that 1 is unsigned _BitInt(129).  If there is a partial limb (like in
> > > this case 1 bit), we emit handling of the result partial limb in straight
> > > line code (but that actually reads some bits from the least significant 
> > > limb
> > > of the function argument), and then have a loop to handle the remaining
> > > limbs.  We use there handle_operand with an index which is not constant
> > > in the loop (obviously) and using this read any limbs in the argument in
> > > reverse order, including the partial limb.
> > > Now, handle_operand has an optimization, for most of the lowerings we have
> > > a guarantee that the partial limb is accessed only in straight line code 
> > > with
> > > a constant index and e.g. for constants reading the partial limb in that
> > > case simply folds into the constant value of that partial limb.  So, we
> > > optimize and emit into .rodata only fewer limbs (all but the partial one)
> > > unless it is one of the even more optimized ones (where we treat 0, all 
> > > ones
> > > or values fitting into fewer limbs by always using a constant or by
> > > extending at runtime).  The exception to this has been the LSHIFT_EXPR
> > > lowering and we have the m_var_msb flag to tell we need all the bits
> > > including the partial limb.  Given the way .BSWAP/.BITREVERSE expansion
> > > works, we need that flag for those too.
> > > 
> > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
> > 
> > OK.
> > 
> > > 2026-10-01  Jakub Jelinek  <[email protected]>
> > > 
> > >   PR middle-end/127669
> > >   * gimple-lower-bitint.cc (bitint_large_huge::lower_bswap_bitreverse):
> > >   Set m_var_msb to true.
> > > 
> > >   * gcc.dg/torture/bitint-110.c: New test.
> > > 
> > > --- a/gcc/gimple-lower-bitint.cc  2026-09-18 11:03:21.676039449 +0200
> > > +++ b/gcc/gimple-lower-bitint.cc  2026-09-30 14:29:15.870162767 +0200
> > > @@ -6172,6 +6172,9 @@ bitint_large_huge::lower_bswap_bitrevers
> > >    unsigned prec = TYPE_PRECISION (type);
> > >    tree p = build_int_cst (sizetype,
> > >                     prec / limb_prec - (prec % limb_prec == 0));
> > > +  /* For .BSWAP/.BITREVERSE, we can use handle_operand with 
> > > non-INTEGER_CST
> > > +     idx even to access the most significant partial limb.  */
> > > +  m_var_msb = true;
> > >    /* For IFN .BSWAP or .BITREVERSE and
> > >       FN corresponding __builtin_bswapN or __builtin_bitreverseN where N
> > >       is limb_prec, lower
> > > --- a/gcc/testsuite/gcc.dg/torture/bitint-110.c   2026-09-30 
> > > 14:29:49.463717815 +0200
> > > +++ b/gcc/testsuite/gcc.dg/torture/bitint-110.c   2026-09-30 
> > > 14:31:29.115397910 +0200
> > > @@ -0,0 +1,30 @@
> > > +/* PR middle-end/127669 */
> > > +/* { dg-do run { target bitint } } */
> > > +
> > > +#if __BITINT_MAXWIDTH__ >= 129
> > > +typedef unsigned _BitInt(129) T;
> > > +
> > > +[[gnu::noipa]] static T
> > > +foo (T v)
> > > +{
> > > +  return v;
> > > +}
> > > +
> > > +static T
> > > +bar ()
> > > +{
> > > +  return 1;
> > > +}
> > > +#endif
> > > +
> > > +int
> > > +main ()
> > > +{
> > > +#if __BITINT_MAXWIDTH__ >= 129
> > > +  T x = __builtin_bitreverseg ((T) 1);
> > > +  T y = __builtin_bitreverseg (bar ());
> > > +  T z = __builtin_bitreverseg (foo (1));
> > > +  if (x != y || x != z)
> > > +    __builtin_abort ();
> > > +#endif
> > > +}
> > > 
> > >   Jakub
> > > 
> > > 
> > 
> > 
> 
> 

-- 
Richard Biener <[email protected]>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Stefan Gaiser, Jochen Jaser, Abhinav Puri; (HRB 36809, AG Nuernberg)

Reply via email to