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.  */
  

Reply via email to