On Fri, 3 May 2024, Jakub Jelinek wrote: > Hi! > > The following patch adds save_NNN = __builtin_stack_save (); ... > __builtin_stack_restore (save_NNN); > pair around inline calls which call alloca (alloca calls because of > VLA vars are ignored in that decision). > The patch doesn't change anything on whether we try to inline such calls or > not, it just fixes the behavior when we inline them despite those checks. > The stack save/restore restores the behavior that alloca acquired regions > are freed at the end of the containing call. > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
OK. Thanks, Richard. > 2024-05-03 Jakub Jelinek <ja...@redhat.com> > > PR middle-end/113596 > * tree-inline.cc (expand_call_inline): Emit __builtin_stack_save > and __builtin_stack_restore calls around inlined functions which > call alloca. > > * gcc.dg/pr113596.c: New test. > * gcc.dg/tree-ssa/pr113596.c: New test. > > --- gcc/tree-inline.cc.jj 2024-04-11 11:09:07.274670922 +0200 > +++ gcc/tree-inline.cc 2024-05-02 19:05:06.963750322 +0200 > @@ -4794,6 +4794,7 @@ expand_call_inline (basic_block bb, gimp > use_operand_p use; > gimple *simtenter_stmt = NULL; > vec<tree> *simtvars_save; > + tree save_stack = NULL_TREE; > > /* The gimplifier uses input_location in too many places, such as > internal_get_tmp_var (). */ > @@ -5042,6 +5043,28 @@ expand_call_inline (basic_block bb, gimp > GSI_NEW_STMT); > } > > + /* If function to be inlined calls alloca, wrap the inlined function > + in between save_stack = __builtin_stack_save (); and > + __builtin_stack_restore (save_stack); calls. */ > + if (id->src_cfun->calls_alloca && !gimple_call_noreturn_p (stmt)) > + /* Don't do this for VLA allocations though, just for user alloca > + calls. */ > + for (struct cgraph_edge *e = id->src_node->callees; e; e = > e->next_callee) > + if (gimple_maybe_alloca_call_p (e->call_stmt) > + && !gimple_call_alloca_for_var_p (e->call_stmt)) > + { > + tree fn = builtin_decl_implicit (BUILT_IN_STACK_SAVE); > + gcall *call = gimple_build_call (fn, 0); > + save_stack = make_ssa_name (ptr_type_node); > + gimple_call_set_lhs (call, save_stack); > + gimple_stmt_iterator si = gsi_last_bb (bb); > + gsi_insert_after (&si, call, GSI_NEW_STMT); > + struct cgraph_node *dest = cgraph_node::get_create (fn); > + id->dst_node->create_edge (dest, call, bb->count)->inline_failed > + = CIF_BODY_NOT_AVAILABLE; > + break; > + } > + > if (DECL_INITIAL (fn)) > { > if (gimple_block (stmt)) > @@ -5165,6 +5188,17 @@ expand_call_inline (basic_block bb, gimp > } > } > > + if (save_stack) > + { > + tree fn = builtin_decl_implicit (BUILT_IN_STACK_RESTORE); > + gcall *call = gimple_build_call (fn, 1, save_stack); > + gsi_insert_before (&stmt_gsi, call, GSI_SAME_STMT); > + struct cgraph_node *dest = cgraph_node::get_create (fn); > + id->dst_node->create_edge (dest, call, > + return_block->count)->inline_failed > + = CIF_BODY_NOT_AVAILABLE; > + } > + > /* Reset the escaped solution. */ > if (cfun->gimple_df) > { > --- gcc/testsuite/gcc.dg/pr113596.c.jj 2024-05-02 15:05:25.048642302 > +0200 > +++ gcc/testsuite/gcc.dg/pr113596.c 2024-05-02 15:05:25.048642302 +0200 > @@ -0,0 +1,24 @@ > +/* PR middle-end/113596 */ > +/* { dg-do run } */ > +/* { dg-options "-O2" } */ > + > +__attribute__((noipa)) void > +bar (char *p, int n) > +{ > + p[0] = 1; > + p[n - 1] = 2; > +} > + > +static inline __attribute__((always_inline)) void > +foo (int n) > +{ > + char *p = __builtin_alloca (n); > + bar (p, n); > +} > + > +int > +main () > +{ > + for (int i = 2; i < 8192; ++i) > + foo (i); > +} > --- gcc/testsuite/gcc.dg/tree-ssa/pr113596.c.jj 2024-05-02 > 19:10:29.218455257 +0200 > +++ gcc/testsuite/gcc.dg/tree-ssa/pr113596.c 2024-05-02 19:11:11.211895559 > +0200 > @@ -0,0 +1,37 @@ > +/* PR middle-end/113596 */ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -fdump-tree-einline" } */ > +/* { dg-final { scan-tree-dump-times "__builtin_stack_save \\\(" 3 "einline" > } } */ > +/* { dg-final { scan-tree-dump-times "__builtin_stack_restore \\\(" 3 > "einline" } } */ > + > +void baz (char *p, int n); > +volatile int v; > + > +static inline __attribute__((always_inline)) void > +foo (int n) > +{ > + ++v; > + { > + char *p = __builtin_alloca (n); > + baz (p, n); > + } > + ++v; > +} > + > +static inline __attribute__((always_inline)) void > +bar (int n) > +{ > + ++v; > + { > + char p[n]; > + baz (p, n); > + } > + ++v; > +} > + > +void > +qux (int n) > +{ > + foo (n); > + bar (n); > +} > > 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)