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 >
