re PR middle-end/65958 (-fstack-check breaks alloca on architectures using generic...
authorEric Botcazou <ebotcazou@adacore.com>
Fri, 4 Dec 2015 11:57:15 +0000 (11:57 +0000)
committerEric Botcazou <ebotcazou@gcc.gnu.org>
Fri, 4 Dec 2015 11:57:15 +0000 (11:57 +0000)
PR middle-end/65958
* gimplify.c (struct gimplify_ctx): Turn boolean fields into 1-bit
fields, add keep_stack and reorder them.
(gimplify_bind_expr): Save gimplify_ctxp->keep_stack on entry then
set it to false.  Do not insert a stack save/restore pair if it has
been set to true by the gimplification of the statements.
Restore it to the saved value on exit if it is still false.
(gimplify_vla_decl): Do not set gimplify_ctxp->save_stack here.
(gimplify_call_expr) <BUILT_IN_ALLOCA[_WITH_ALIGN]>: New case.  Set
either save_stack or keep_stack depending on CALL_ALLOCA_FOR_VAR_P.
* doc/extend.texi (Variable Length): Document new behavior.
* doc/generic.texi (Blocks): Document new handling of VLAs.

From-SVN: r231260

gcc/ChangeLog
gcc/doc/extend.texi
gcc/doc/generic.texi
gcc/gimplify.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/vla-24.c [new file with mode: 0644]

index c05a96b5e73d35a8ebc92d85c8fc9789edaee4a7..cfc56586f2c800dd84924e35517cf4d910c4d0c3 100644 (file)
@@ -1,3 +1,18 @@
+2015-12-04  Eric Botcazou  <ebotcazou@adacore.com>
+
+       PR middle-end/65958
+       * gimplify.c (struct gimplify_ctx): Turn boolean fields into 1-bit
+       fields, add keep_stack and reorder them.
+       (gimplify_bind_expr): Save gimplify_ctxp->keep_stack on entry then
+       set it to false.  Do not insert a stack save/restore pair if it has
+       been set to true by the gimplification of the statements.
+       Restore it to the saved value on exit if it is still false.
+       (gimplify_vla_decl): Do not set gimplify_ctxp->save_stack here.
+       (gimplify_call_expr) <BUILT_IN_ALLOCA[_WITH_ALIGN]>: New case.  Set
+       either save_stack or keep_stack depending on CALL_ALLOCA_FOR_VAR_P.
+       * doc/extend.texi (Variable Length): Document new behavior.
+       * doc/generic.texi (Blocks): Document new handling of VLAs.
+
 2015-12-04  Eric Botcazou  <ebotcazou@adacore.com>
             Tristan Gingold  <gingold@adacore.com>
 
index 63fce0f9cf4a8fa53a2da4c00180f5065464c337..6a5e2b86f780e3d9de8dc64cffae13c41a792125 100644 (file)
@@ -1658,9 +1658,7 @@ variable-length arrays are more elegant.
 There are other differences between these two methods.  Space allocated
 with @code{alloca} exists until the containing @emph{function} returns.
 The space for a variable-length array is deallocated as soon as the array
-name's scope ends.  (If you use both variable-length arrays and
-@code{alloca} in the same function, deallocation of a variable-length array
-also deallocates anything more recently allocated with @code{alloca}.)
+name's scope ends, unless you also use @code{alloca} in this scope.
 
 You can also use variable-length arrays as arguments to functions:
 
index bbafad9f931e68cc1afe389532fb68c8366384a7..f6b43977c368256929f61e74859acd562fd6c571 100644 (file)
@@ -1950,11 +1950,15 @@ this initialization replaces the @code{DECL_STMT}.  These variables
 will never require cleanups.  The scope of these variables is just the
 body
 
-Variable-length arrays (VLAs) complicate this process, as their
-size often refers to variables initialized earlier in the block.
-To handle this, we currently split the block at that point, and
-move the VLA into a new, inner @code{BIND_EXPR}.  This strategy
-may change in the future.
+Variable-length arrays (VLAs) complicate this process, as their size
+often refers to variables initialized earlier in the block and their
+initialization involves an explicit stack allocation.  To handle this,
+we add an indirection and replace them with a pointer to stack space
+allocated by means of @code{alloca}.  In most cases, we also arrange
+for this space to be reclaimed when the enclosing @code{BIND_EXPR} is
+exited, the exception to this being when there is an explicit call to
+@code{alloca} in the source code, in which case the stack is left
+depressed on exit of the @code{BIND_EXPR}.
 
 A C++ program will usually contain more @code{BIND_EXPR}s than
 there are syntactic blocks in the source code, since several C++
index 7146a01a5afe0656f1fca3beb5c9a4129a1641ac..80c6bf2b90f5668f3f9bfe5547819f67886d79e8 100644 (file)
@@ -155,10 +155,11 @@ struct gimplify_ctx
   hash_table<gimplify_hasher> *temp_htab;
 
   int conditions;
-  bool save_stack;
-  bool into_ssa;
-  bool allow_rhs_cond_expr;
-  bool in_cleanup_point_expr;
+  unsigned into_ssa : 1;
+  unsigned allow_rhs_cond_expr : 1;
+  unsigned in_cleanup_point_expr : 1;
+  unsigned keep_stack : 1;
+  unsigned save_stack : 1;
 };
 
 struct gimplify_omp_ctx
@@ -1080,6 +1081,7 @@ static enum gimplify_status
 gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p)
 {
   tree bind_expr = *expr_p;
+  bool old_keep_stack = gimplify_ctxp->keep_stack;
   bool old_save_stack = gimplify_ctxp->save_stack;
   tree t;
   gbind *bind_stmt;
@@ -1129,9 +1131,10 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p)
     }
 
   bind_stmt = gimple_build_bind (BIND_EXPR_VARS (bind_expr), NULL,
-                                   BIND_EXPR_BLOCK (bind_expr));
+                                BIND_EXPR_BLOCK (bind_expr));
   gimple_push_bind_expr (bind_stmt);
 
+  gimplify_ctxp->keep_stack = false;
   gimplify_ctxp->save_stack = false;
 
   /* Gimplify the body into the GIMPLE_BIND tuple's body.  */
@@ -1154,7 +1157,10 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p)
 
   cleanup = NULL;
   stack_save = NULL;
-  if (gimplify_ctxp->save_stack)
+
+  /* If the code both contains VLAs and calls alloca, then we cannot reclaim
+     the stack space allocated to the VLAs.  */
+  if (gimplify_ctxp->save_stack && !gimplify_ctxp->keep_stack)
     {
       gcall *stack_restore;
 
@@ -1236,7 +1242,11 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p)
       gimple_bind_set_body (bind_stmt, new_body);
     }
 
+  /* keep_stack propagates all the way up to the outermost BIND_EXPR.  */
+  if (!gimplify_ctxp->keep_stack)
+    gimplify_ctxp->keep_stack = old_keep_stack;
   gimplify_ctxp->save_stack = old_save_stack;
+
   gimple_pop_bind_expr ();
 
   gimplify_seq_add_stmt (pre_p, bind_stmt);
@@ -1393,10 +1403,6 @@ gimplify_vla_decl (tree decl, gimple_seq *seq_p)
   t = build2 (MODIFY_EXPR, TREE_TYPE (addr), addr, t);
 
   gimplify_and_add (t, seq_p);
-
-  /* Indicate that we need to restore the stack level when the
-     enclosing BIND_EXPR is exited.  */
-  gimplify_ctxp->save_stack = true;
 }
 
 /* A helper function to be called via walk_tree.  Mark all labels under *TP
@@ -2377,6 +2383,18 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value)
       && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
     switch (DECL_FUNCTION_CODE (fndecl))
       {
+      case BUILT_IN_ALLOCA:
+      case BUILT_IN_ALLOCA_WITH_ALIGN:
+       /* If the call has been built for a variable-sized object, then we
+          want to restore the stack level when the enclosing BIND_EXPR is
+          exited to reclaim the allocated space; otherwise, we precisely
+          need to do the opposite and preserve the latest stack level.  */
+       if (CALL_ALLOCA_FOR_VAR_P (*expr_p))
+         gimplify_ctxp->save_stack = true;
+       else
+         gimplify_ctxp->keep_stack = true;
+       break;
+
       case BUILT_IN_VA_START:
         {
          builtin_va_start_p = TRUE;
index 20a392ee42e9e1b1ac853803b45ca09b65cd6775..2944394d67a80cc5911ad813e3d454cc943c81b1 100644 (file)
@@ -1,3 +1,7 @@
+2015-12-04  Eric Botcazou  <ebotcazou@adacore.com>
+
+       * gcc.dg/vla-24.c: New test.
+
 2015-12-04  Eric Botcazou  <ebotcazou@adacore.com>
 
        * gcc.target/aarch64/stack-checking.c: New test.
diff --git a/gcc/testsuite/gcc.dg/vla-24.c b/gcc/testsuite/gcc.dg/vla-24.c
new file mode 100644 (file)
index 0000000..5bd5fed
--- /dev/null
@@ -0,0 +1,31 @@
+/* PR middle-end/65958 */
+
+/* { dg-do run } */
+/* { dg-options "-std=gnu99" } */
+
+extern void abort (void);
+
+int foo (int n)
+{
+  char *p, *q;
+
+  if (1)
+    {
+      char i[n];
+      p = __builtin_alloca (8);
+      p[0] = 1;
+    }
+
+  q = __builtin_alloca (64);
+  __builtin_memset (q, 0, 64);
+
+  return !p[0];
+}
+
+int main (void)
+{
+  if (foo (48) != 0)
+    abort ();
+
+  return 0;
+}