PATCH for SAVE_EXPRs/variable-sized arrays

Mark Mitchell mark@codesourcery.com
Fri Nov 12 08:57:00 GMT 1999


Jason reported an interesting bug whereby function-at-a-time mode and
SAVE_EXPRs were not playing nice together.  What was happenning was
this:

  o A SAVE_EXPR was created to represent the bound in a variable-sized
    array.

  o The elements of the array had destructors, so a cleanup was
    generated for the array.

  o The cleanup is evaluated both on ordinary exit from the block and
    in the exception-handler for the block.

  o When being used in the exception-handler, the cleanup is passed
    through `unsave_expr_now' which, blows away the saved values in 
    any SAVE_EXPRs, resulting in the recalculation of the array
    bound.

This didn't happen in statement-at-a-time mode due to a kludge in
array_type_nelts which would forcibly return an RTL_EXPR, instead of
the SAVE_EXPR, for the array bounds.

The whole SAVE_EXPR/UNSAVE_EXPR bit is not a particularly nice
abstraction.  Now that we run in function-at-a-time mode we should
come up with some better ways of implementing this stuff.

However, the bug can be fixed, by simply marking these array-bounds as
the sorts of things that should not be recalculated in handlers.

--
Mark Mitchell                   mark@codesourcery.com
CodeSourcery, LLC               http://www.codesourcery.com

Fri Nov 12 08:54:22 1999  Mark Mitchell  <mark@codesourcery.com>

	* tree.h (SAVE_EXPR_PERSISTENT_P): New macro.
	* tree.c (array_type_nelts): Don't handle SAVE_EXPRs specially.
	(unsave_expr_now): Don't unsave SAVE_EXPR_PERSISTENT_P
	expressions.
	* stor-layout.c (variable_size): Set SAVE_EXPR_PERSISTENT_P on
	variable-sized array bounds.
	

Index: stor-layout.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/stor-layout.c,v
retrieving revision 1.35
diff -c -p -r1.35 stor-layout.c
*** stor-layout.c	1999/10/30 00:18:23	1.35
--- stor-layout.c	1999/11/12 16:48:28
*************** variable_size (size)
*** 97,102 ****
--- 97,113 ----
  
    size = save_expr (size);
  
+   /* If an array with a variable number of elements is declared, and
+      the elements require destruction, we will emit a cleanup for the
+      array.  That cleanup is run both on normal exit from the block
+      and in the exception-handler for the block.  Normally, when code
+      is used in both ordinary code and in an exception handler it is
+      `unsaved', i.e., all SAVE_EXPRs are recalculated.  However, we do
+      not wish to do that here; the array-size is the same in both
+      places.  */
+   if (TREE_CODE (size) == SAVE_EXPR)
+     SAVE_EXPR_PERSISTENT_P (size) = 1;
+ 
    if (global_bindings_p ())
      {
        if (TREE_CONSTANT (size))
Index: tree.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/tree.c,v
retrieving revision 1.103
diff -c -p -r1.103 tree.c
*** tree.c	1999/11/10 17:57:21	1.103
--- tree.c	1999/11/12 16:48:31
*************** int_size_in_bytes (type)
*** 2236,2246 ****
  }
  
  /* Return, as a tree node, the number of elements for TYPE (which is an
!    ARRAY_TYPE) minus one. This counts only elements of the top array.
  
-    Don't let any SAVE_EXPRs escape; if we are called as part of a cleanup
-    action, they would get unsaved.  */
- 
  tree
  array_type_nelts (type)
       tree type;
--- 2236,2243 ----
  }
  
  /* Return, as a tree node, the number of elements for TYPE (which is an
!    ARRAY_TYPE) minus one. This counts only elements of the top array.  */
  
  tree
  array_type_nelts (type)
       tree type;
*************** array_type_nelts (type)
*** 2256,2281 ****
    min = TYPE_MIN_VALUE (index_type);
    max = TYPE_MAX_VALUE (index_type);
  
-   if (! TREE_CONSTANT (min))
-     {
-       STRIP_NOPS (min);
-       if (TREE_CODE (min) == SAVE_EXPR && SAVE_EXPR_RTL (min))
- 	min = build (RTL_EXPR, TREE_TYPE (TYPE_MIN_VALUE (index_type)), 0,
- 		     SAVE_EXPR_RTL (min));
-       else
- 	min = TYPE_MIN_VALUE (index_type);
-     }
- 
-   if (! TREE_CONSTANT (max))
-     {
-       STRIP_NOPS (max);
-       if (TREE_CODE (max) == SAVE_EXPR && SAVE_EXPR_RTL (max))
- 	max = build (RTL_EXPR, TREE_TYPE (TYPE_MAX_VALUE (index_type)), 0,
- 		     SAVE_EXPR_RTL (max));
-       else
- 	max = TYPE_MAX_VALUE (index_type);
-     }
- 
    return (integer_zerop (min)
  	  ? max
  	  : fold (build (MINUS_EXPR, TREE_TYPE (max), max, min)));
--- 2253,2258 ----
*************** unsave_expr_now (expr)
*** 2465,2471 ****
    switch (code)
      {
      case SAVE_EXPR:
!       SAVE_EXPR_RTL (expr) = 0;
        break;
  
      case TARGET_EXPR:
--- 2442,2449 ----
    switch (code)
      {
      case SAVE_EXPR:
!       if (!SAVE_EXPR_PERSISTENT_P (expr))
! 	SAVE_EXPR_RTL (expr) = 0;
        break;
  
      case TARGET_EXPR:
Index: tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/tree.h,v
retrieving revision 1.102
diff -c -p -r1.102 tree.h
*** tree.h	1999/11/10 17:57:21	1.102
--- tree.h	1999/11/12 16:48:32
*************** struct tree_vec
*** 717,722 ****
--- 717,727 ----
  #define SAVE_EXPR_CONTEXT(NODE) TREE_OPERAND(NODE, 1)
  #define SAVE_EXPR_RTL(NODE) (*(struct rtx_def **) &EXPR_CHECK (NODE)->exp.operands[2])
  #define SAVE_EXPR_NOPLACEHOLDER(NODE) TREE_UNSIGNED (NODE)
+ /* Nonzero if the SAVE_EXPRs value should be kept, even if it occurs
+    both in normal code and in a handler.  (Normally, in a handler, all
+    SAVE_EXPRs are unsaved, meaning that there values are
+    recalculated.)  */
+ #define SAVE_EXPR_PERSISTENT_P(NODE) TREE_ASM_WRITTEN (NODE)
  
  /* In a RTL_EXPR node.  */
  #define RTL_EXPR_SEQUENCE(NODE) (*(struct rtx_def **) &EXPR_CHECK (NODE)->exp.operands[0])

  


More information about the Gcc-patches mailing list