On Wed, 15 Jan 2025, Jakub Jelinek wrote:

> On Wed, Jan 15, 2025 at 03:16:04PM +0100, Richard Biener wrote:
> > > +      /* If IPA-VRP proves called function always returns a singleton 
> > > range,
> > > +  the return value is replaced by the only value in that range.
> > > +  For tail call purposes, pretend such replacement didn't happen.  */
> > > +      if (ass_var == NULL_TREE
> > > +   && !tail_recursion
> > > +   && TREE_CONSTANT (ret_var))
> > > + if (tree type = gimple_range_type (call))
> > > +   if (tree callee = gimple_call_fndecl (call))
> > > +     if ((INTEGRAL_TYPE_P (type) || SCALAR_FLOAT_TYPE_P (type))
> > > +         && useless_type_conversion_p (TREE_TYPE (TREE_TYPE (callee)),
> > > +                                       type)
> > > +         && useless_type_conversion_p (TREE_TYPE (ret_var), type)
> > > +         && ipa_return_value_range (val, callee)
> > > +         && val.singleton_p (&valr)
> > 
> > I suppose it's good enough to check
> > 
> >  useless_type_conversion_p (TREE_TYPE (ret_var), TREE_TYPE (valr))?
> 
> One of the checks is for the gimple_fntype to actually match the type of
> the gimple_call_fndecl, one could always have some ugly hacks like
> int foo (void);
> ...
>   long (*fn) (void) = (long (*) (void)) foo;
>   fn ();
> etc., copied over from gimple-range-fold.cc, the other is making sure
> it matches also the caller's return type.
> 
> > but the bigger question is whether RTL expansion does the right thing
> > here without changing the IL at this point back to return the LHS
> > and put that back?  IIRC there are some sanity checks upon tail call
> > expansion, but does this all work when the call itself doesn't have
> > its return value used?  Aka some call expansion checks might be
> > elided in this case.
> 
> It does the right thing, it just relies on the tailc pass to do its job
> properly.
> E.g. when we have
>   <bb 2> [local count: 1073741824]:
>   foo (x_2(D));
>   baz (&v);
>   v ={v} {CLOBBER(eos)};
>   bar (x_2(D)); [tail call]
>   return 1;
> when expand_gimple_basic_block handles the bar (x_2(D)); call, it uses
>           if (call_stmt && gimple_call_tail_p (call_stmt))
>             {
>               bool can_fallthru;
>               new_bb = expand_gimple_tailcall (bb, call_stmt, &can_fallthru);
>               if (new_bb)
>                 {
>                   if (can_fallthru)
>                     bb = new_bb;
>                   else
>                     {
>                       currently_expanding_gimple_stmt = NULL;
>                       return new_bb;
>                     }
>                 }
>             }
> As it is actually tail callable during expansion of the bar (x_2(D)); call
> stmt, expand_gimple_tailbb returns non-NULL and sets can_fallthru to false,
> plus emits
> ;; bar (x_2(D)); [tail call]
> 
> (insn 11 10 12 2 (set (reg:SI 5 di)
>         (reg/v:SI 99 [ x ])) "pr118430.c":35:10 -1
>      (nil))
>         
> (call_insn/j 12 11 13 2 (set (reg:SI 0 ax)
>         (call (mem:QI (symbol_ref:DI ("bar") [flags 0x3]  <function_decl 
> 0x7fb39020bd00 bar>) [0 bar S1 A8])
>             (const_int 0 [0]))) "pr118430.c":35:10 -1
>      (expr_list:REG_CALL_DECL (symbol_ref:DI ("bar") [flags 0x3]  
> <function_decl 0x7fb39020bd00 bar>)
>         (expr_list:REG_EH_REGION (const_int 0 [0])
>             (nil)))
>     (expr_list:SI (use (reg:SI 5 di))
>         (nil)))
> 
> (barrier 13 12 0)
> Because it doesn't fallthru, no further statements in the same bb are
> expanded.  Now, if the bb with return happened to be in some other basic
> block from the [tail call], it could be expanded but because the bb with
> tail call ends with a barrier, it doesn't fall thru there and if nothing
> else could reach it, we'd remove the unreachable bb RSN.
> 
> > So I feel a bit nervous marking sth as tail-call that doesn't
> > actually look like one (unless we make it so again).
> 
> Expansion really counts on tailc to verify all the following statements
> are useless.  Even if it is
>   _1 = bar (...); [tail call]
>   return _1;
> it is treated the same, we also don't expand the return _1; there
> separately, after all, nothing initializes the _1 anywhere when expanding
> the tail call (unless tail call fails and we expand it as normal call of
> course).  And as tailc allows, there could be further statements, copying of
> SSA_NAMEs, debug statements, clobber statements, ...

I see.

The patch is OK then.

Thanks,
Richard.

>       Jakub
> 
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)

Reply via email to