PR16867: Fix a long standing DCE bug

Diego Novillo dnovillo@redhat.com
Thu Aug 12 07:25:00 GMT 2004


This patch fixes PR 16867 by teaching the middle-end the difference
between global variables, variables that need to reside in memory and
call-clobbered variables.

In particular, DCE was removing stores to global memory because it was
checking the symbols for each virtual definitions, not the actual object
being stored.  For instance,

foo (int *p, int i)
{
   int x;
   p = (i > 5) ? &x : p;
   # x = V_MAY_DEF <x>
   *p = 3;
   return 2;
}

DCE used to check each virtual definition in *p = 3, but in this case
'x' is a local variable, so it would not be marked as inherently
necessary.  And since there is no other uses of 'x' nor '*p' in foo(),
DCE would remove the store.

The reason we used to get away with it is because DCE would ask if the
variable needed to live in memory.  Since 'x' is addressable, the test
would succeed and the store preserved.

However, that is the wrong test to make.  The fact that a symbol needs
to live in memory is irrelevant.  A local addressable whose address does
not escape, also needs to live in memory.  But that doesn't mean that
stores to it are inherently necessary.  Only stores to global memory are
inherently necessary.

Most of the changes in the patch deal with this distinction.  There is
now a new predicate, is_global_var, which returns true if the symbol is
TREE_STATIC or DECL_EXTERNAL (rth suggests that only TREE_STATIC should
be needed but more cleanup is necessary for that).

The patch also removes NEEDS_TO_LIVE_IN_MEMORY_INTERNAL.  Now that we
deal with globals and memory variables properly, we don't need that
hackery.

Finally, I tripped over something odd in the Java front end.  There are
some internal functions generated by the front end that have no
TREE_SIDE_EFFECTS set and yet they are not marked with ECF_PURE nor
ECF_CONST.  This causes the operand scanner to consider these functions
as call-clobbering, which is wrong.

For now, I've told it not to mark call-clobbering functions that have no
TREE_SIDE_EFFECTS, but I will change it soon to abort if this happens
and fix the affected front ends.

Bootstrapped and tested x86, x86-64, alpha, ia64 and ppc.  The new test
case in libjava could use a bit of checking by a java person.  I copied
it from other files in libjava.lang and it passes.  Is the test OK?

This patch may also help in other situations where DCE was mysteriously
throwing stores away.  At the same time, it should make DCE a bit more
aggressive, as it will now throw away stores to variables that reside in
local memory.


Diego.


	PR tree-optimization/16867
	* tree.c (is_global_var): New function.
	(needs_to_live_in_memory): Check for TREE_ADDRESSABLE.
	Call is_global_var.
	* tree.h (DECL_NEEDS_TO_LIVE_IN_MEMORY_INTERNAL): Remove.
	Update all users.
	(is_global_var): Declare.
	* tree-dfa.c (dump_variable): Display global and addressable
	attributes.
	(add_referenced_var): Clarify documentation when marking
	variables call-clobbered.
	* tree-flow-inline.h (is_call_clobbered): Call is_global_var
	instead of needs_to_live_in_memory.
	(mark_call_clobbered): If the variable is a tag, mark it
	DECL_EXTERNAL.
	* tree-gimple.c (is_gimple_reg): Don't check for
	TREE_ADDRESSABLE.
	(is_gimple_non_addressable): Likewise.
	* tree-ssa-alias.c (get_nmt_for): Always check whether the tag
	needs to be marked call-clobbered.
	(setup_pointers_and_addressables): Call is_global_var instead
	of needs_to_live_in_memory.
	* tree-ssa-dce.c (need_to_preserve_store): Remove.
	Update all users with is_global_var.
	(mark_stmt_if_obviously_necessary): Fix processing of aliased
	stores.  Don't check the virtual definitions.  Rather, check
	whether the store is going into global memory.
	(find_obviously_necessary_stmts): Get the symbol from the PHI
	result.
	* tree-ssa-operands.c (get_call_expr_operands): Do not add
	clobbering may-defs if the call does not have side effects.
	

libjava/testsuite

	PR tree-optimization/16867
	* testsuite/libjava.lang/PR16867.java: New test.

Index: gcc/tree-dfa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-dfa.c,v
retrieving revision 2.22
diff -d -c -p -r2.22 tree-dfa.c
*** gcc/tree-dfa.c	27 Jul 2004 00:20:00 -0000	2.22
--- gcc/tree-dfa.c	12 Aug 2004 05:46:03 -0000
*************** dump_variable (FILE *file, tree var)
*** 562,569 ****
    if (ann->is_alias_tag)
      fprintf (file, ", is an alias tag");
  
!   if (needs_to_live_in_memory (var))
!     fprintf (file, ", is %s", TREE_STATIC (var) ? "static" :
"global");
  
    if (is_call_clobbered (var))
      fprintf (file, ", call clobbered");
--- 562,572 ----
    if (ann->is_alias_tag)
      fprintf (file, ", is an alias tag");
  
!   if (TREE_ADDRESSABLE (var))
!     fprintf (file, ", is addressable");
!   
!   if (is_global_var (var))
!     fprintf (file, ", is global");
  
    if (is_call_clobbered (var))
      fprintf (file, ", call clobbered");
*************** add_referenced_var (tree var, struct wal
*** 900,906 ****
        v_ann->uid = num_referenced_vars;
        VARRAY_PUSH_TREE (referenced_vars, var);
  
!       /* Global and static variables are call-clobbered, always.  */
        if (needs_to_live_in_memory (var))
  	mark_call_clobbered (var);
  
--- 903,911 ----
        v_ann->uid = num_referenced_vars;
        VARRAY_PUSH_TREE (referenced_vars, var);
  
!       /* Initially assume that all memory variables are
! 	 call-clobbered.  This will be refined later by the alias
! 	 analyzer.  */
        if (needs_to_live_in_memory (var))
  	mark_call_clobbered (var);
  
Index: gcc/tree-flow-inline.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-flow-inline.h,v
retrieving revision 2.18
diff -d -c -p -r2.18 tree-flow-inline.h
*** gcc/tree-flow-inline.h	23 Jul 2004 22:37:23 -0000	2.18
--- gcc/tree-flow-inline.h	12 Aug 2004 05:46:03 -0000
*************** loop_containing_stmt (tree stmt)
*** 639,645 ****
  static inline bool
  is_call_clobbered (tree var)
  {
!   return needs_to_live_in_memory (var)
  	 || bitmap_bit_p (call_clobbered_vars, var_ann (var)->uid);
  }
  
--- 639,645 ----
  static inline bool
  is_call_clobbered (tree var)
  {
!   return is_global_var (var)
  	 || bitmap_bit_p (call_clobbered_vars, var_ann (var)->uid);
  }
  
*************** static inline void
*** 648,655 ****
  mark_call_clobbered (tree var)
  {
    var_ann_t ann = var_ann (var);
!   /* Call-clobbered variables need to live in memory.  */
!   DECL_NEEDS_TO_LIVE_IN_MEMORY_INTERNAL (var) = 1;
    bitmap_set_bit (call_clobbered_vars, ann->uid);
  }
  
--- 648,659 ----
  mark_call_clobbered (tree var)
  {
    var_ann_t ann = var_ann (var);
!   /* If VAR is a memory tag, then we need to consider it a global
!      variable.  This is because the pointer that VAR represents has
!      been found to point to either an arbitrary location or to a known
!      location in global memory.  */
!   if (ann->mem_tag_kind != NOT_A_TAG)
!     DECL_EXTERNAL (var) = 1;
    bitmap_set_bit (call_clobbered_vars, ann->uid);
  }
  
*************** static inline void
*** 658,664 ****
  mark_non_addressable (tree var)
  {
    bitmap_clear_bit (call_clobbered_vars, var_ann (var)->uid);
-   DECL_NEEDS_TO_LIVE_IN_MEMORY_INTERNAL (var) = 0;
    TREE_ADDRESSABLE (var) = 0;
  }
  
--- 662,667 ----
Index: gcc/tree-gimple.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-gimple.c,v
retrieving revision 2.20
diff -d -c -p -r2.20 tree-gimple.c
*** gcc/tree-gimple.c	30 Jul 2004 22:55:24 -0000	2.20
--- gcc/tree-gimple.c	12 Aug 2004 05:46:03 -0000
*************** is_gimple_reg (tree t)
*** 441,447 ****
  	  /* A volatile decl is not acceptable because we can't reuse it as
  	     needed.  We need to copy it into a temp first.  */
  	  && ! TREE_THIS_VOLATILE (t)
- 	  && ! TREE_ADDRESSABLE (t)
  	  && ! needs_to_live_in_memory (t));
  }
  
--- 441,446 ----
*************** is_gimple_non_addressable (tree t)
*** 481,489 ****
    if (TREE_CODE (t) == SSA_NAME)
      t = SSA_NAME_VAR (t);
  
!   return (is_gimple_variable (t)
! 	  && ! TREE_ADDRESSABLE (t)
! 	  && ! needs_to_live_in_memory (t));
  }
  
  /* Return true if T is a GIMPLE rvalue, i.e. an identifier or a
constant.  */
--- 480,486 ----
    if (TREE_CODE (t) == SSA_NAME)
      t = SSA_NAME_VAR (t);
  
!   return (is_gimple_variable (t) && ! needs_to_live_in_memory (t));
  }
  
  /* Return true if T is a GIMPLE rvalue, i.e. an identifier or a
constant.  */
Index: gcc/tree-ssa-alias.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-alias.c,v
retrieving revision 2.22
diff -d -c -p -r2.22 tree-ssa-alias.c
*** gcc/tree-ssa-alias.c	30 Jul 2004 19:40:30 -0000	2.22
--- gcc/tree-ssa-alias.c	12 Aug 2004 05:46:03 -0000
*************** init_alias_info (void)
*** 390,396 ****
        EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i,
  	{
  	  tree var = referenced_var (i);
- 	  DECL_NEEDS_TO_LIVE_IN_MEMORY_INTERNAL (var) = 0;
  
  	  /* Variables that are intrinsically call-clobbered (globals,
  	     local statics, etc) will not be marked by the aliasing
--- 390,395 ----
*************** setup_pointers_and_addressables (struct 
*** 1329,1335 ****
  	{
  	  if (!bitmap_bit_p (ai->addresses_needed, v_ann->uid)
  	      && v_ann->mem_tag_kind == NOT_A_TAG
! 	      && !needs_to_live_in_memory (var))
  	    {
  	      /* The address of VAR is not needed, remove the
  		 addressable bit, so that it can be optimized as a
--- 1328,1334 ----
  	{
  	  if (!bitmap_bit_p (ai->addresses_needed, v_ann->uid)
  	      && v_ann->mem_tag_kind == NOT_A_TAG
! 	      && !is_global_var (var))
  	    {
  	      /* The address of VAR is not needed, remove the
  		 addressable bit, so that it can be optimized as a
*************** setup_pointers_and_addressables (struct 
*** 1391,1397 ****
  	      /* If pointer VAR is a global variable or a PARM_DECL,
  		 then its memory tag should be considered a global
  		 variable.  */
! 	      if (TREE_CODE (var) == PARM_DECL || needs_to_live_in_memory
(var))
  		mark_call_clobbered (tag);
  
  	      /* All the dereferences of pointer VAR count as
--- 1390,1396 ----
  	      /* If pointer VAR is a global variable or a PARM_DECL,
  		 then its memory tag should be considered a global
  		 variable.  */
! 	      if (TREE_CODE (var) == PARM_DECL || is_global_var (var))
  		mark_call_clobbered (tag);
  
  	      /* All the dereferences of pointer VAR count as
*************** get_nmt_for (tree ptr)
*** 2105,2122 ****
    tree tag = pi->name_mem_tag;
  
    if (tag == NULL_TREE)
!     {
!       tag = create_memory_tag (TREE_TYPE (TREE_TYPE (ptr)), false);
  
!       /* If PTR is a PARM_DECL, its memory tag should be considered a
! 	 global variable.  */
!       if (TREE_CODE (SSA_NAME_VAR (ptr)) == PARM_DECL)
! 	mark_call_clobbered (tag);
  
!       /* Similarly, if PTR points to malloc, then TAG is a global.  */
!       if (pi->pt_malloc)
! 	mark_call_clobbered (tag);
!     }
  
    return tag;
  }
--- 2104,2119 ----
    tree tag = pi->name_mem_tag;
  
    if (tag == NULL_TREE)
!     tag = create_memory_tag (TREE_TYPE (TREE_TYPE (ptr)), false);
  
!   /* If PTR is a PARM_DECL, its memory tag should be considered a
global
!      variable.  */
!   if (TREE_CODE (SSA_NAME_VAR (ptr)) == PARM_DECL)
!     mark_call_clobbered (tag);
  
!   /* Similarly, if PTR points to malloc, then TAG is a global.  */
!   if (pi->pt_malloc)
!     mark_call_clobbered (tag);
  
    return tag;
  }
Index: gcc/tree-ssa-dce.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-dce.c,v
retrieving revision 2.11
diff -d -c -p -r2.11 tree-ssa-dce.c
*** gcc/tree-ssa-dce.c	28 Jul 2004 05:13:08 -0000	2.11
--- gcc/tree-ssa-dce.c	12 Aug 2004 05:46:03 -0000
*************** static inline basic_block find_pdom (bas
*** 107,113 ****
  static inline void mark_stmt_necessary (tree, bool);
  static inline void mark_operand_necessary (tree);
  
- static bool need_to_preserve_store (tree);
  static void mark_stmt_if_obviously_necessary (tree, bool);
  static void find_obviously_necessary_stmts (struct edge_list *);
  
--- 107,112 ----
*************** mark_operand_necessary (tree op)
*** 267,280 ****
    VARRAY_PUSH_TREE (worklist, stmt);
  }
  
- /* Return true if a store to a variable needs to be preserved.  */
- 
- static inline bool
- need_to_preserve_store (tree ssa_name)
- {
-   return (needs_to_live_in_memory (SSA_NAME_VAR (ssa_name)));
- }
- 
  
  /* Mark STMT as necessary if it is obviously is.  Add it to the
worklist if
     it can make other statements necessary.
--- 266,271 ----
*************** mark_stmt_if_obviously_necessary (tree s
*** 367,376 ****
      }
  
    ann = stmt_ann (stmt);
!   /* If the statement has volatile operands, it needs to be
preserved.  Same
!      for statements that can alter control flow in unpredictable
ways.  */
!   if (ann->has_volatile_ops
!       || is_ctrl_altering_stmt (stmt))
      {
        mark_stmt_necessary (stmt, true);
        return;
--- 358,368 ----
      }
  
    ann = stmt_ann (stmt);
! 
!   /* If the statement has volatile operands, it needs to be preserved.
!      Same for statements that can alter control flow in unpredictable
!      ways.  */
!   if (ann->has_volatile_ops || is_ctrl_altering_stmt (stmt))
      {
        mark_stmt_necessary (stmt, true);
        return;
*************** mark_stmt_if_obviously_necessary (tree s
*** 382,414 ****
    for (i = 0; i < NUM_DEFS (defs); i++)
      {
        tree def = DEF_OP (defs, i);
!       if (need_to_preserve_store (def))
  	{
  	  mark_stmt_necessary (stmt, true);
  	  return;
          }
      }
  
    v_may_defs = V_MAY_DEF_OPS (ann);
-   for (i = 0; i < NUM_V_MAY_DEFS (v_may_defs); i++)
-     {
-       tree v_may_def = V_MAY_DEF_RESULT (v_may_defs, i);
-       if (need_to_preserve_store (v_may_def))
- 	{
- 	  mark_stmt_necessary (stmt, true);
- 	  return;
-         }
-     }
-     
    v_must_defs = V_MUST_DEF_OPS (ann);
!   for (i = 0; i < NUM_V_MUST_DEFS (v_must_defs); i++)
      {
!       tree v_must_def = V_MUST_DEF_OP (v_must_defs, i);
!       if (need_to_preserve_store (v_must_def))
  	{
  	  mark_stmt_necessary (stmt, true);
! 	  return;
!         }
      }
  
    return;
--- 374,461 ----
    for (i = 0; i < NUM_DEFS (defs); i++)
      {
        tree def = DEF_OP (defs, i);
!       if (is_global_var (SSA_NAME_VAR (def)))
  	{
  	  mark_stmt_necessary (stmt, true);
  	  return;
          }
      }
  
+   /* Check virtual definitions.  If we get here, the only virtual
+      definitions we should see are those generated by assignment
+      statements.  */
    v_may_defs = V_MAY_DEF_OPS (ann);
    v_must_defs = V_MUST_DEF_OPS (ann);
!   if (NUM_V_MAY_DEFS (v_may_defs) > 0 || NUM_V_MUST_DEFS (v_must_defs)
> 0)
      {
!       tree lhs;
! 
! #if defined ENABLE_CHECKING
!       if (TREE_CODE (stmt) != MODIFY_EXPR)
! 	abort ();
! #endif
! 
!       /* Note that we must not check the individual virtual operands
! 	 here.  In particular, if this is an aliased store, we could
! 	 end up with something like the following (SSA notation
! 	 redacted for brevity):
! 
! 	 	foo (int *p, int i)
! 		{
! 		  int x, y;
! 		  p_1 = (i_2 > 3) ? &x : &y;
! 
! 		  # x_4 = V_MAY_DEF <x_3>
! 		  # y_6 = V_MAY_DEF <y_5>
! 		  *p_1 = 5;
! 
! 		  return 2;
! 		}
! 
! 	 Notice that the store to '*p_1' should be preserved, if we
! 	 were to check the virtual definitions in that store, we would
! 	 not mark it needed.  This is because neither 'x' nor 'y' are
! 	 global variables.
! 
! 	 Therefore, we check the base address of the LHS.  If the
! 	 address is a pointer, we check if its name tag or type tag is
! 	 a global variable.  Otherwise, we check if the base variable
! 	 is a global.  */
!       lhs = TREE_OPERAND (stmt, 0);
!       if (TREE_CODE_CLASS (TREE_CODE (lhs)) == 'r')
! 	lhs = get_base_address (lhs);
! 
!       if (lhs == NULL_TREE)
  	{
+ 	  /* If LHS is NULL, it means that we couldn't get the base
+ 	     address of the reference.  In which case, we should not
+ 	     remove this store. */
  	  mark_stmt_necessary (stmt, true);
! 	}
!       else if (DECL_P (lhs))
! 	{
! 	  /* If the store is to a global symbol, we need to keep it.  */
! 	  if (is_global_var (lhs))
! 	    mark_stmt_necessary (stmt, true);
! 	}
!       else if (TREE_CODE (lhs) == INDIRECT_REF)
! 	{
! 	  tree ptr = TREE_OPERAND (lhs, 0);
! 	  struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
! 	  tree nmt = (pi) ? pi->name_mem_tag : NULL_TREE;
! 	  tree tmt = var_ann (SSA_NAME_VAR (ptr))->type_mem_tag;
! 
! 	  /* If either the name tag or the type tag for PTR is a
! 	     global variable, then the store is necessary.  */
! 	  if ((nmt && is_global_var (nmt))
! 	      || (tmt && is_global_var (tmt)))
! 	    {
! 	      mark_stmt_necessary (stmt, true);
! 	      return;
! 	    }
! 	}
!       else
! 	abort ();
      }
  
    return;
*************** find_obviously_necessary_stmts (struct e
*** 444,450 ****
  	     Thus, we only need to mark PHIs for real variables which
  	     need their result preserved as being inherently necessary.  */
  	  if (is_gimple_reg (PHI_RESULT (phi))
! 	      && need_to_preserve_store (PHI_RESULT (phi)))
  	    mark_stmt_necessary (phi, true);
          }
  
--- 491,497 ----
  	     Thus, we only need to mark PHIs for real variables which
  	     need their result preserved as being inherently necessary.  */
  	  if (is_gimple_reg (PHI_RESULT (phi))
! 	      && is_global_var (SSA_NAME_VAR (PHI_RESULT (phi))))
  	    mark_stmt_necessary (phi, true);
          }
  
Index: gcc/tree-ssa-operands.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-operands.c,v
retrieving revision 2.27
diff -d -c -p -r2.27 tree-ssa-operands.c
*** gcc/tree-ssa-operands.c	29 Jul 2004 17:15:35 -0000	2.27
--- gcc/tree-ssa-operands.c	12 Aug 2004 05:46:03 -0000
*************** get_call_expr_operands (tree stmt, tree 
*** 1248,1255 ****
        /* A 'pure' or a 'const' functions never call clobber anything. 
  	 A 'noreturn' function might, but since we don't return anyway 
  	 there is no point in recording that.  */ 
!       if (!(call_flags
! 	    & (ECF_PURE | ECF_CONST | ECF_NORETURN)))
  	add_call_clobber_ops (stmt, prev_vops);
        else if (!(call_flags & (ECF_CONST | ECF_NORETURN)))
  	add_call_read_ops (stmt, prev_vops);
--- 1248,1255 ----
        /* A 'pure' or a 'const' functions never call clobber anything. 
  	 A 'noreturn' function might, but since we don't return anyway 
  	 there is no point in recording that.  */ 
!       if (TREE_SIDE_EFFECTS (expr)
! 	  && !(call_flags & (ECF_PURE | ECF_CONST | ECF_NORETURN)))
  	add_call_clobber_ops (stmt, prev_vops);
        else if (!(call_flags & (ECF_CONST | ECF_NORETURN)))
  	add_call_read_ops (stmt, prev_vops);
Index: gcc/tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.c,v
retrieving revision 1.408
diff -d -c -p -r1.408 tree.c
*** gcc/tree.c	6 Aug 2004 02:03:19 -0000	1.408
--- gcc/tree.c	12 Aug 2004 05:46:03 -0000
*************** in_array_bounds_p (tree ref)
*** 5624,5638 ****
    return true;
  }
  
  /* Return true if T (assumed to be a DECL) must be assigned a memory
     location.  */
  
  bool
  needs_to_live_in_memory (tree t)
  {
!   return (DECL_NEEDS_TO_LIVE_IN_MEMORY_INTERNAL (t)
! 	  || TREE_STATIC (t)
!           || DECL_EXTERNAL (t)
  	  || (TREE_CODE (t) == RESULT_DECL
  	      && aggregate_value_p (t, current_function_decl)));
  }
--- 5624,5645 ----
    return true;
  }
  
+ /* Return true if T (assumed to be a DECL) is a global variable.  */
+ 
+ bool
+ is_global_var (tree t)
+ {
+   return (TREE_STATIC (t) || DECL_EXTERNAL (t));
+ }
+ 
  /* Return true if T (assumed to be a DECL) must be assigned a memory
     location.  */
  
  bool
  needs_to_live_in_memory (tree t)
  {
!   return (TREE_ADDRESSABLE (t)
! 	  || is_global_var (t)
  	  || (TREE_CODE (t) == RESULT_DECL
  	      && aggregate_value_p (t, current_function_decl)));
  }
Index: gcc/tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.586
diff -d -c -p -r1.586 tree.h
*** gcc/tree.h	11 Aug 2004 04:15:59 -0000	1.586
--- gcc/tree.h	12 Aug 2004 05:46:03 -0000
*************** struct tree_binfo GTY (())
*** 2161,2175 ****
    (! DECL_CONTEXT (EXP)						\
     || TREE_CODE (DECL_CONTEXT (EXP)) == TRANSLATION_UNIT_DECL)
  
- /* Nonzero for a decl that has been marked as needing a memory slot.
-    NOTE: Never use this macro directly.  It will give you incomplete
-    information. Most of the time this bit will only be set after alias
-    analysis in the tree optimizers.  It's always better to call
-    needs_to_live_in_memory instead.  To mark memory variables use
-    mark_call_clobbered.  */
- #define DECL_NEEDS_TO_LIVE_IN_MEMORY_INTERNAL(DECL)		\
-   DECL_CHECK (DECL)->decl.needs_to_live_in_memory
- 
  /* Nonzero for a decl that cgraph has decided should be inlined into
     at least one call site.  It is not meaningful to look at this
     directly; always use cgraph_function_possibly_inlined_p.  */
--- 2161,2166 ----
*************** struct tree_decl GTY(())
*** 2242,2250 ****
    unsigned lang_flag_6 : 1;
    unsigned lang_flag_7 : 1;
  
-   unsigned needs_to_live_in_memory : 1;
    unsigned possibly_inlined : 1;
!   /* 14 unused bits.  */
  
    union tree_decl_u1 {
      /* In a FUNCTION_DECL for which DECL_BUILT_IN holds, this is
--- 2233,2240 ----
    unsigned lang_flag_6 : 1;
    unsigned lang_flag_7 : 1;
  
    unsigned possibly_inlined : 1;
!   /* 15 unused bits.  */
  
    union tree_decl_u1 {
      /* In a FUNCTION_DECL for which DECL_BUILT_IN holds, this is
*************** extern void expand_function_end (void);
*** 3479,3484 ****
--- 3469,3475 ----
  extern void expand_function_start (tree);
  extern void expand_pending_sizes (tree);
  extern void recompute_tree_invarant_for_addr_expr (tree);
+ extern bool is_global_var (tree t);
  extern bool needs_to_live_in_memory (tree);
  extern tree reconstruct_complex_type (tree, tree);
  
Index: libjava/testsuite/libjava.lang/PR16867.java
===================================================================
RCS file: libjava/testsuite/libjava.lang/PR16867.java
diff -N libjava/testsuite/libjava.lang/PR16867.java
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- libjava/testsuite/libjava.lang/PR16867.java	12 Aug 2004 05:46:25
-0000
***************
*** 0 ****
--- 1,17 ----
+ /* The SSA-DCE was removing the initialization of the temporary object
+    in getFoo because it wasn't realizing that the pointer was needed
+    outside of it.  */
+ 
+ public class PR16867
+ {
+   public static Object[] getFoo()
+   {
+     return new Object[] {"OK"};
+   }
+ 
+   public static void main(String[] args)
+   {
+     Object[] a = getFoo();
+     System.out.println(a[0]);
+   }
+ }
Index: libjava/testsuite/libjava.lang/PR16867.out
===================================================================
RCS file: libjava/testsuite/libjava.lang/PR16867.out
diff -N libjava/testsuite/libjava.lang/PR16867.out
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- libjava/testsuite/libjava.lang/PR16867.out	12 Aug 2004 05:46:25
-0000
***************
*** 0 ****
--- 1 ----
+ OK




More information about the Gcc-patches mailing list