* 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.
From-SVN: r172516
+2011-04-15 Michael Matz <matz@suse.de>
+
+ * 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.
+
2011-04-15 Martin Jambor <mjambor@suse.cz>
* ipa-prop.c (ipa_analyze_virtual_call_uses): Remove handling
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));
+ target = expand_builtin_alloca (exp, CALL_ALLOCA_FOR_VAR_P (exp));
if (target)
return target;
break;
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);
+ 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));
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;
+ 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);
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));
+ 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));
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
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. */
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;
+ CALL_ALLOCA_FOR_VAR_P (t) = 1;
t = fold_convert (ptr_type, t);
t = build2 (MODIFY_EXPR, TREE_TYPE (addr), addr, t);
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. */
+ 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
all decls
CALL_FROM_THUNK_P and
- ALLOCA_FOR_VAR_P in
+ CALL_ALLOCA_FOR_VAR_P in
CALL_EXPR
side_effects_flag:
/* 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)
+#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