On Wed, Sep 24, 2025 at 11:11 AM Andrew Pinski
<[email protected]> wrote:
>
> This moves the va_args functions folding to gimple-fold. Right now this is 
> still
> kept for the last folding but later it can move sometime after stdargs pass 
> is run by
> checking PROP_gimple_lva instead.
> Also for forwprop, if a folding happens for the last folding we need to maybe 
> update the
> variables as non-addressable like what is done in fab. It was originally 
> added in fab for
> __builtin_sincos->__builtin_cexpi folding (PR39643). After the removal of 
> fab, this will
> also be the last pass which updates address taken too.
>
> gcc/ChangeLog:
>
>         * gimple-fold.cc (gimple_fold_builtin_stdarg): New function,
>         moved from tree-ssa-ccp.cc (optimize_stdarg_builtin).
>         (gimple_fold_builtin): Call gimple_fold_builtin_stdarg for
>         va_start, va_copy and va_end.
>         * tree-ssa-ccp.cc (optimize_stdarg_builtin): Remove.
>         (pass_fold_builtins::execute): Remove handling of
>         va_start, va_copy and va_end.
>         * tree-ssa-forwprop.cc (pass_forwprop::execute): Update
>         todos if fold_stmt return true if last forwprop to include
>         TODO_update_address_taken.
>
> Signed-off-by: Andrew Pinski <[email protected]>
> ---
>  gcc/gimple-fold.cc       | 125 ++++++++++++++++++++++++++++++++++++++
>  gcc/tree-ssa-ccp.cc      | 126 ---------------------------------------
>  gcc/tree-ssa-forwprop.cc |   5 ++
>  3 files changed, 130 insertions(+), 126 deletions(-)
>
> diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
> index a12fb5e8eab..2f64de2fb41 100644
> --- a/gcc/gimple-fold.cc
> +++ b/gcc/gimple-fold.cc
> @@ -5252,6 +5252,127 @@ gimple_fold_builtin_assume_aligned 
> (gimple_stmt_iterator *gsi)
>    return true;
>  }
>
> +/* If va_list type is a simple pointer and nothing special is needed,
> +   optimize __builtin_va_start (&ap, 0) into ap = __builtin_next_arg (0),
> +   __builtin_va_end (&ap) out as NOP and __builtin_va_copy into a simple
> +   pointer assignment.  Returns true if a change happened.  */
> +
> +static bool
> +gimple_fold_builtin_stdarg (gimple_stmt_iterator *gsi, gcall *call)
> +{
> +  /* These shouldn't be folded before pass_stdarg.  */
> +  if (!(cfun->curr_properties & PROP_last_full_fold))
> +    return false;
> +
> +  tree callee, lhs, rhs, cfun_va_list;
> +  bool va_list_simple_ptr;
> +  location_t loc = gimple_location (call);
> +  gimple *nstmt0, *nstmt;
> +  tree tlhs, oldvdef, newvdef;
> +
> +  callee = gimple_call_fndecl (call);
> +
> +  cfun_va_list = targetm.fn_abi_va_list (callee);
> +  va_list_simple_ptr = POINTER_TYPE_P (cfun_va_list)
> +                      && (TREE_TYPE (cfun_va_list) == void_type_node
> +                          || TREE_TYPE (cfun_va_list) == char_type_node);
> +
> +  switch (DECL_FUNCTION_CODE (callee))
> +    {
> +    case BUILT_IN_VA_START:
> +      if (!va_list_simple_ptr
> +         || targetm.expand_builtin_va_start != NULL
> +         || !builtin_decl_explicit_p (BUILT_IN_NEXT_ARG))
> +       return false;
> +
> +      if (gimple_call_num_args (call) != 2)
> +       return false;
> +
> +      lhs = gimple_call_arg (call, 0);
> +      if (!POINTER_TYPE_P (TREE_TYPE (lhs))
> +         || TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (lhs)))
> +            != TYPE_MAIN_VARIANT (cfun_va_list))
> +       return false;
> +      /* Create `tlhs = __builtin_next_arg(0);`. */
> +      tlhs = make_ssa_name (cfun_va_list);
> +      nstmt0 = gimple_build_call (builtin_decl_explicit (BUILT_IN_NEXT_ARG), 
> 1, integer_zero_node);
> +      lhs = fold_build2 (MEM_REF, cfun_va_list, lhs, build_zero_cst 
> (TREE_TYPE (lhs)));
> +      gimple_call_set_lhs (nstmt0, tlhs);
> +      gimple_set_location (nstmt0, loc);
> +      gimple_move_vops (nstmt0, call);
> +      gsi_replace (gsi, nstmt0, false);
> +      oldvdef = gimple_vdef (nstmt0);
> +      newvdef = make_ssa_name (gimple_vop (cfun), nstmt0);
> +      gimple_set_vdef (nstmt0, newvdef);
> +
> +      /* Create `*lhs = tlhs;`.  */
> +      nstmt = gimple_build_assign (lhs, tlhs);
> +      gimple_set_location (nstmt, loc);
> +      gimple_set_vuse (nstmt, newvdef);
> +      gimple_set_vdef (nstmt, oldvdef);
> +      SSA_NAME_DEF_STMT (oldvdef) = nstmt;
> +      gsi_insert_after (gsi, nstmt, GSI_NEW_STMT);
> +
> +      if (dump_file && (dump_flags & TDF_DETAILS))
> +       {
> +         fprintf (dump_file, "Simplified\n  ");
> +         print_gimple_stmt (dump_file, call, 0, dump_flags);
> +         fprintf (dump_file, "into\n  ");
> +         print_gimple_stmt (dump_file, nstmt0, 0, dump_flags);
> +         fprintf (dump_file, "  ");
> +         print_gimple_stmt (dump_file, nstmt, 0, dump_flags);
> +       }
> +      return true;
> +
> +    case BUILT_IN_VA_COPY:
> +      if (!va_list_simple_ptr)
> +       return false;
> +
> +      if (gimple_call_num_args (call) != 2)
> +       return false;
> +
> +      lhs = gimple_call_arg (call, 0);
> +      if (!POINTER_TYPE_P (TREE_TYPE (lhs))
> +         || TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (lhs)))
> +            != TYPE_MAIN_VARIANT (cfun_va_list))
> +       return false;
> +      rhs = gimple_call_arg (call, 1);
> +      if (TYPE_MAIN_VARIANT (TREE_TYPE (rhs))
> +         != TYPE_MAIN_VARIANT (cfun_va_list))
> +       return false;
> +
> +      lhs = fold_build2 (MEM_REF, cfun_va_list, lhs, build_zero_cst 
> (TREE_TYPE (lhs)));
> +      nstmt = gimple_build_assign (lhs, rhs);
> +      gimple_set_location (nstmt, loc);
> +      gimple_move_vops (nstmt, call);
> +      gsi_replace (gsi, nstmt, false);
> +
> +      if (dump_file && (dump_flags & TDF_DETAILS))
> +       {
> +         fprintf (dump_file, "Simplified\n  ");
> +         print_gimple_stmt (dump_file, call, 0, dump_flags);
> +         fprintf (dump_file, "into\n  ");
> +         print_gimple_stmt (dump_file, nstmt, 0, dump_flags);
> +       }
> +      return true;
> +
> +    case BUILT_IN_VA_END:
> +      /* No effect, so the statement will be deleted.  */
> +      if (dump_file && (dump_flags & TDF_DETAILS))
> +       {
> +         fprintf (dump_file, "Removed\n  ");
> +         print_gimple_stmt (dump_file, call, 0, dump_flags);
> +       }
> +      unlink_stmt_vdef (call);
> +      release_defs (call);
> +      gsi_replace (gsi, gimple_build_nop (), true);
> +      return true;
> +
> +    default:
> +      gcc_unreachable ();
> +    }
> +}
> +
>  /* Fold the non-target builtin at *GSI and return whether any simplification
>     was made.  */
>
> @@ -5270,6 +5391,10 @@ gimple_fold_builtin (gimple_stmt_iterator *gsi)
>    enum built_in_function fcode = DECL_FUNCTION_CODE (callee);
>    switch (fcode)
>      {
> +    case BUILT_IN_VA_START:
> +    case BUILT_IN_VA_END:
> +    case BUILT_IN_VA_COPY:
> +      return gimple_fold_builtin_stdarg (gsi, stmt);
>      case BUILT_IN_BCMP:
>        return gimple_fold_builtin_bcmp (gsi);
>      case BUILT_IN_BCOPY:
> diff --git a/gcc/tree-ssa-ccp.cc b/gcc/tree-ssa-ccp.cc
> index b69a8b64a61..2d16395ac68 100644
> --- a/gcc/tree-ssa-ccp.cc
> +++ b/gcc/tree-ssa-ccp.cc
> @@ -3085,124 +3085,6 @@ make_pass_ccp (gcc::context *ctxt)
>    return new pass_ccp (ctxt);
>  }
>
> -/* If va_list type is a simple pointer and nothing special is needed,
> -   optimize __builtin_va_start (&ap, 0) into ap = __builtin_next_arg (0),
> -   __builtin_va_end (&ap) out as NOP and __builtin_va_copy into a simple
> -   pointer assignment.  Returns true if a change happened.  */
> -
> -static bool
> -optimize_stdarg_builtin (gimple_stmt_iterator *gsi, gimple *call)
> -{
> -  tree callee, lhs, rhs, cfun_va_list;
> -  bool va_list_simple_ptr;
> -  location_t loc = gimple_location (call);
> -  gimple *nstmt0, *nstmt;
> -  tree tlhs, oldvdef, newvdef;
> -
> -  callee = gimple_call_fndecl (call);
> -
> -  cfun_va_list = targetm.fn_abi_va_list (callee);
> -  va_list_simple_ptr = POINTER_TYPE_P (cfun_va_list)
> -                      && (TREE_TYPE (cfun_va_list) == void_type_node
> -                          || TREE_TYPE (cfun_va_list) == char_type_node);
> -
> -  switch (DECL_FUNCTION_CODE (callee))
> -    {
> -    case BUILT_IN_VA_START:
> -      if (!va_list_simple_ptr
> -         || targetm.expand_builtin_va_start != NULL
> -         || !builtin_decl_explicit_p (BUILT_IN_NEXT_ARG))
> -       return false;
> -
> -      if (gimple_call_num_args (call) != 2)
> -       return false;
> -
> -      lhs = gimple_call_arg (call, 0);
> -      if (!POINTER_TYPE_P (TREE_TYPE (lhs))
> -         || TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (lhs)))
> -            != TYPE_MAIN_VARIANT (cfun_va_list))
> -       return false;
> -      /* Create `tlhs = __builtin_next_arg(0);`. */
> -      tlhs = make_ssa_name (cfun_va_list);
> -      nstmt0 = gimple_build_call (builtin_decl_explicit (BUILT_IN_NEXT_ARG), 
> 1, integer_zero_node);
> -      lhs = fold_build2 (MEM_REF, cfun_va_list, lhs, build_zero_cst 
> (TREE_TYPE (lhs)));
> -      gimple_call_set_lhs (nstmt0, tlhs);
> -      gimple_set_location (nstmt0, loc);
> -      gimple_move_vops (nstmt0, call);
> -      gsi_replace (gsi, nstmt0, false);
> -      oldvdef = gimple_vdef (nstmt0);
> -      newvdef = make_ssa_name (gimple_vop (cfun), nstmt0);
> -      gimple_set_vdef (nstmt0, newvdef);
> -
> -      /* Create `*lhs = tlhs;`.  */
> -      nstmt = gimple_build_assign (lhs, tlhs);
> -      gimple_set_location (nstmt, loc);
> -      gimple_set_vuse (nstmt, newvdef);
> -      gimple_set_vdef (nstmt, oldvdef);
> -      SSA_NAME_DEF_STMT (oldvdef) = nstmt;
> -      gsi_insert_after (gsi, nstmt, GSI_NEW_STMT);
> -
> -      if (dump_file && (dump_flags & TDF_DETAILS))
> -       {
> -         fprintf (dump_file, "Simplified\n  ");
> -         print_gimple_stmt (dump_file, call, 0, dump_flags);
> -         fprintf (dump_file, "into\n  ");
> -         print_gimple_stmt (dump_file, nstmt0, 0, dump_flags);
> -         fprintf (dump_file, "  ");
> -         print_gimple_stmt (dump_file, nstmt, 0, dump_flags);
> -       }
> -      return true;
> -
> -    case BUILT_IN_VA_COPY:
> -      if (!va_list_simple_ptr)
> -       return false;
> -
> -      if (gimple_call_num_args (call) != 2)
> -       return false;
> -
> -      lhs = gimple_call_arg (call, 0);
> -      if (!POINTER_TYPE_P (TREE_TYPE (lhs))
> -         || TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (lhs)))
> -            != TYPE_MAIN_VARIANT (cfun_va_list))
> -       return false;
> -      rhs = gimple_call_arg (call, 1);
> -      if (TYPE_MAIN_VARIANT (TREE_TYPE (rhs))
> -         != TYPE_MAIN_VARIANT (cfun_va_list))
> -       return false;
> -
> -      lhs = fold_build2 (MEM_REF, cfun_va_list, lhs, build_zero_cst 
> (TREE_TYPE (lhs)));
> -      nstmt = gimple_build_assign (lhs, rhs);
> -      gimple_set_location (nstmt, loc);
> -      gimple_move_vops (nstmt, call);
> -      gsi_replace (gsi, nstmt, false);
> -
> -      if (dump_file && (dump_flags & TDF_DETAILS))
> -       {
> -         fprintf (dump_file, "Simplified\n  ");
> -         print_gimple_stmt (dump_file, call, 0, dump_flags);
> -         fprintf (dump_file, "into\n  ");
> -         print_gimple_stmt (dump_file, nstmt, 0, dump_flags);
> -       }
> -      return true;
> -
> -    case BUILT_IN_VA_END:
> -      /* No effect, so the statement will be deleted.  */
> -      if (dump_file && (dump_flags & TDF_DETAILS))
> -       {
> -         fprintf (dump_file, "Removed\n  ");
> -         print_gimple_stmt (dump_file, call, 0, dump_flags);
> -       }
> -      unlink_stmt_vdef (call);
> -      release_defs (call);
> -      gsi_replace (gsi, gimple_build_nop (), true);
> -      return true;
> -
> -    default:
> -      gcc_unreachable ();
> -    }
> -}
> -
> -
>  /* Convert
>     _1 = __atomic_fetch_or_* (ptr_6, 1, _3);
>     _7 = ~_1;
> @@ -4339,14 +4221,6 @@ pass_fold_builtins::execute (function *fun)
>                                                   false);
>                   break;
>
> -               case BUILT_IN_VA_START:
> -               case BUILT_IN_VA_END:
> -               case BUILT_IN_VA_COPY:
> -                 /* These shouldn't be folded before pass_stdarg.  */
> -                 if (optimize_stdarg_builtin (&i, stmt))
> -                   todoflags |= TODO_update_address_taken;
> -                 break;
> -
>                 default:;
>                 }
>
> diff --git a/gcc/tree-ssa-forwprop.cc b/gcc/tree-ssa-forwprop.cc
> index c7ac96a28aa..f72aac21980 100644
> --- a/gcc/tree-ssa-forwprop.cc
> +++ b/gcc/tree-ssa-forwprop.cc
> @@ -5464,6 +5464,11 @@ pass_forwprop::execute (function *fun)
>               if (fold_stmt (&gsi, fwprop_ssa_val, simple_dce_worklist))
>                 {
>                   changed = true;
> +                 /* There is no updating of the address
> +                    taken after the last forwprop so update
> +                    the addresses when a folding happened. */
> +                 if (last_p)
> +                   todoflags |= TODO_update_address_taken;

The patch is OK.  As a followup we might want to consider whether there's
a cheap enough way to see in which cases address-takens are elided.
memcpy() -> assignment transforms come to my mind here, but I
cannot think of anything that wasn't a call before - so maybe it's
enough to add a && was_call (for was_noreturn we already compute
was_call).?

>                   stmt = gsi_stmt (gsi);
>                   /* Cleanup the CFG if we simplified a condition to
>                      true or false.  */
> --
> 2.43.0
>

Reply via email to