Hi, On Thu, 14 Apr 2011, Michael Matz wrote:
> > Btw, I don't remember why I chose ALLOCA_FOR_VAR_P over > > CALL_ALLOCA_FOR_VAR_P but, given the name of the GIMPLE flag and > > predicate, it's probably time to change it. > > Good idea, I'll rename it before checking in. r172516, for reference also below. I later saw that my patch causes cxg2001 to fail. I've analyzed it enough to be sure that it's only exposed by this patch (due to inlining now happening), in fact it's a problem in IRA that is reproducible with a C++ testcase even without the patch. I've filed PR48633 for this. Ciao, Michael. * tree.h (ALLOCA_FOR_VAR_P): Rename to CALL_ALLOCA_FOR_VAR_P. * builtins.c (expand_builtin): Use CALL_ALLOCA_FOR_VAR_P. * function.c (gimplify_parameters): Ditto. * gimplify.c (gimplify_vla_decl): Ditto. * gimple.h (enum gf_mask): Add GF_CALL_ALLOCA_FOR_VAR. (gimple_call_set_alloca_for_var): New inline function. (gimple_call_alloca_for_var_p): Ditto. * gimple.c (gimple_build_call_from_tree): Remember CALL_ALLOCA_FOR_VAR_P state. * cfgexpand.c (expand_call_stmt): Restore CALL_ALLOCA_FOR_VAR_P state. * tree-inline.c (inline_forbidden_p_stmt): Don't reject alloca calls if they were for VLA objects. Index: tree.h =================================================================== *** tree.h (revision 172431) --- tree.h (working copy) *************** struct GTY(()) tree_common { *** 574,580 **** all decls CALL_FROM_THUNK_P and ! ALLOCA_FOR_VAR_P in CALL_EXPR side_effects_flag: --- 574,580 ---- all decls CALL_FROM_THUNK_P and ! CALL_ALLOCA_FOR_VAR_P in CALL_EXPR side_effects_flag: *************** extern void omp_clause_range_check_faile *** 1388,1394 **** /* In a CALL_EXPR, if the function being called is BUILT_IN_ALLOCA, means that it has been built for the declaration of a variable-sized object. */ ! #define ALLOCA_FOR_VAR_P(NODE) (CALL_EXPR_CHECK (NODE)->base.protected_flag) /* In a type, nonzero means that all objects of the type are guaranteed by the language or front-end to be properly aligned, so we can indicate that a MEM --- 1388,1395 ---- /* In a CALL_EXPR, if the function being called is BUILT_IN_ALLOCA, means that it has been built for the declaration of a variable-sized object. */ ! #define CALL_ALLOCA_FOR_VAR_P(NODE) \ ! (CALL_EXPR_CHECK (NODE)->base.protected_flag) /* In a type, nonzero means that all objects of the type are guaranteed by the language or front-end to be properly aligned, so we can indicate that a MEM Index: builtins.c =================================================================== *** builtins.c (revision 172431) --- builtins.c (working copy) *************** expand_builtin (tree exp, rtx target, rt *** 6025,6031 **** case BUILT_IN_ALLOCA: /* If the allocation stems from the declaration of a variable-sized object, it cannot accumulate. */ ! target = expand_builtin_alloca (exp, ALLOCA_FOR_VAR_P (exp)); if (target) return target; break; --- 6025,6031 ---- case BUILT_IN_ALLOCA: /* If the allocation stems from the declaration of a variable-sized object, it cannot accumulate. */ ! target = expand_builtin_alloca (exp, CALL_ALLOCA_FOR_VAR_P (exp)); if (target) return target; break; Index: function.c =================================================================== *** function.c (revision 172431) --- function.c (working copy) *************** gimplify_parameters (void) *** 3652,3658 **** t = built_in_decls[BUILT_IN_ALLOCA]; t = build_call_expr (t, 1, DECL_SIZE_UNIT (parm)); /* The call has been built for a variable-sized object. */ ! ALLOCA_FOR_VAR_P (t) = 1; t = fold_convert (ptr_type, t); t = build2 (MODIFY_EXPR, TREE_TYPE (addr), addr, t); gimplify_and_add (t, &stmts); --- 3652,3658 ---- t = built_in_decls[BUILT_IN_ALLOCA]; t = build_call_expr (t, 1, DECL_SIZE_UNIT (parm)); /* The call has been built for a variable-sized object. */ ! CALL_ALLOCA_FOR_VAR_P (t) = 1; t = fold_convert (ptr_type, t); t = build2 (MODIFY_EXPR, TREE_TYPE (addr), addr, t); gimplify_and_add (t, &stmts); Index: gimplify.c =================================================================== *** gimplify.c (revision 172431) --- gimplify.c (working copy) *************** gimplify_vla_decl (tree decl, gimple_seq *** 1329,1335 **** t = built_in_decls[BUILT_IN_ALLOCA]; t = build_call_expr (t, 1, DECL_SIZE_UNIT (decl)); /* The call has been built for a variable-sized object. */ ! ALLOCA_FOR_VAR_P (t) = 1; t = fold_convert (ptr_type, t); t = build2 (MODIFY_EXPR, TREE_TYPE (addr), addr, t); --- 1329,1335 ---- t = built_in_decls[BUILT_IN_ALLOCA]; t = build_call_expr (t, 1, DECL_SIZE_UNIT (decl)); /* The call has been built for a variable-sized object. */ ! CALL_ALLOCA_FOR_VAR_P (t) = 1; t = fold_convert (ptr_type, t); t = build2 (MODIFY_EXPR, TREE_TYPE (addr), addr, t); Index: cfgexpand.c =================================================================== *** cfgexpand.c (revision 172431) --- cfgexpand.c (working copy) *************** expand_call_stmt (gimple stmt) *** 1873,1879 **** CALL_EXPR_TAILCALL (exp) = gimple_call_tail_p (stmt); CALL_EXPR_RETURN_SLOT_OPT (exp) = gimple_call_return_slot_opt_p (stmt); ! CALL_FROM_THUNK_P (exp) = gimple_call_from_thunk_p (stmt); CALL_CANNOT_INLINE_P (exp) = gimple_call_cannot_inline_p (stmt); CALL_EXPR_VA_ARG_PACK (exp) = gimple_call_va_arg_pack_p (stmt); SET_EXPR_LOCATION (exp, gimple_location (stmt)); --- 1873,1884 ---- CALL_EXPR_TAILCALL (exp) = gimple_call_tail_p (stmt); CALL_EXPR_RETURN_SLOT_OPT (exp) = gimple_call_return_slot_opt_p (stmt); ! if (decl ! && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL ! && DECL_FUNCTION_CODE (decl) == BUILT_IN_ALLOCA) ! CALL_ALLOCA_FOR_VAR_P (exp) = gimple_call_alloca_for_var_p (stmt); ! else ! CALL_FROM_THUNK_P (exp) = gimple_call_from_thunk_p (stmt); CALL_CANNOT_INLINE_P (exp) = gimple_call_cannot_inline_p (stmt); CALL_EXPR_VA_ARG_PACK (exp) = gimple_call_va_arg_pack_p (stmt); SET_EXPR_LOCATION (exp, gimple_location (stmt)); Index: tree-inline.c =================================================================== *** tree-inline.c (revision 172431) --- tree-inline.c (working copy) *************** inline_forbidden_p_stmt (gimple_stmt_ite *** 2997,3004 **** this may change program's memory overhead drastically when the function using alloca is called in loop. In GCC present in SPEC2000 inlining into schedule_block cause it to require 2GB of ! RAM instead of 256MB. */ if (gimple_alloca_call_p (stmt) && !lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn))) { inline_forbidden_reason --- 2997,3007 ---- this may change program's memory overhead drastically when the function using alloca is called in loop. In GCC present in SPEC2000 inlining into schedule_block cause it to require 2GB of ! RAM instead of 256MB. Don't do so for alloca calls emitted for ! VLA objects as those can't cause unbounded growth (they're always ! wrapped inside stack_save/stack_restore regions. */ if (gimple_alloca_call_p (stmt) + && !gimple_call_alloca_for_var_p (stmt) && !lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn))) { inline_forbidden_reason Index: gimple.c =================================================================== *** gimple.c (revision 172431) --- gimple.c (working copy) *************** gimple_build_call_from_tree (tree t) *** 303,309 **** gimple_call_set_tail (call, CALL_EXPR_TAILCALL (t)); gimple_call_set_cannot_inline (call, CALL_CANNOT_INLINE_P (t)); gimple_call_set_return_slot_opt (call, CALL_EXPR_RETURN_SLOT_OPT (t)); ! gimple_call_set_from_thunk (call, CALL_FROM_THUNK_P (t)); gimple_call_set_va_arg_pack (call, CALL_EXPR_VA_ARG_PACK (t)); gimple_call_set_nothrow (call, TREE_NOTHROW (t)); gimple_set_no_warning (call, TREE_NO_WARNING (t)); --- 303,314 ---- gimple_call_set_tail (call, CALL_EXPR_TAILCALL (t)); gimple_call_set_cannot_inline (call, CALL_CANNOT_INLINE_P (t)); gimple_call_set_return_slot_opt (call, CALL_EXPR_RETURN_SLOT_OPT (t)); ! if (fndecl ! && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL ! && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_ALLOCA) ! gimple_call_set_alloca_for_var (call, CALL_ALLOCA_FOR_VAR_P (t)); ! else ! gimple_call_set_from_thunk (call, CALL_FROM_THUNK_P (t)); gimple_call_set_va_arg_pack (call, CALL_EXPR_VA_ARG_PACK (t)); gimple_call_set_nothrow (call, TREE_NOTHROW (t)); gimple_set_no_warning (call, TREE_NO_WARNING (t)); Index: gimple.h =================================================================== *** gimple.h (revision 172431) --- gimple.h (working copy) *************** enum gf_mask { *** 102,107 **** --- 102,108 ---- GF_CALL_TAILCALL = 1 << 3, GF_CALL_VA_ARG_PACK = 1 << 4, GF_CALL_NOTHROW = 1 << 5, + GF_CALL_ALLOCA_FOR_VAR = 1 << 6, GF_OMP_PARALLEL_COMBINED = 1 << 0, /* True on an GIMPLE_OMP_RETURN statement if the return does not require *************** gimple_call_nothrow_p (gimple s) *** 2329,2334 **** --- 2330,2358 ---- return (gimple_call_flags (s) & ECF_NOTHROW) != 0; } + /* If FOR_VAR is true, GIMPLE_CALL S is a call to builtin_alloca that + is known to be emitted for VLA objects. Those are wrapped by + stack_save/stack_restore calls and hence can't lead to unbounded + stack growth even when they occur in loops. */ + + static inline void + gimple_call_set_alloca_for_var (gimple s, bool for_var) + { + GIMPLE_CHECK (s, GIMPLE_CALL); + if (for_var) + s->gsbase.subcode |= GF_CALL_ALLOCA_FOR_VAR; + else + s->gsbase.subcode &= ~GF_CALL_ALLOCA_FOR_VAR; + } + + /* Return true of S is a call to builtin_alloca emitted for VLA objects. */ + + static inline bool + gimple_call_alloca_for_var_p (gimple s) + { + GIMPLE_CHECK (s, GIMPLE_CALL); + return (s->gsbase.subcode & GF_CALL_ALLOCA_FOR_VAR) != 0; + } /* Copy all the GF_CALL_* flags from ORIG_CALL to DEST_CALL. */