This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

patch to tree-profiling branch to analyze for const and pure functionsand readonly and non addressable static storage.


This patch has been approved by Jan. This patch has been tested on I686 and Darwin. There is additional one regression failure caused by a test that requires the detection of pure functions at -O1. This patch only preforms that analysis at -O2 or higher. The test will be fixed in a later patch.

This patch also contains fixes that were developed by Jan. This is why the patch has two changelog entries.

2004-12-02 Kenneth Zadeck <Kenneth.Zadeck@NaturalBridge.com>

Removal of const and pure detection from rtl level: * alias.c (nonlocal_mentioned_p_1,nonlocal_mentioned_p,
nonlocal_referenced_p_1,nonlocal_referenced_p,nonlocal_set_p_1,
nonlocal_set_p,mark_constant_function): removed
* calls.c (flags_from_decl_or_type):removed cgraph_rtl_info refs
* passes.c (rest_of_handle_cfg) remove calls to mark_constant_function
* cgraph.h (const_function, pure_function) flags removed from
cgraph_rtl_info


Addition of const and pure function detection to ipa static as well as
detection of readonly static variables are removal of addressable bit
from static varaiables.:
* ipa_static_vars_anal.c (bool has_proper_scope_for_analysis,
check_operand,check_tree,look_for_address_of,check_rhs_var,
check_lhs_var,get_asm_expr_operands,process_call_for_static_vars,
scan_for_static_refs,get_static_name_by_uid,propagate_bits,ipa_init
analyze_variable,analyze_function,static_execute) added functionality.
* tree-cfg.c (need_fake_edge_p): added comment that needs work.
* ipa_static_vars_anal.c (add_static_var): added debugging.
* tree-inline.c (inline_forbidden_p): added debugging.


   Move calls_read_all and calls_write_all from cgraph_node structure to
   ipa_static_info structure.
   * cgraph.c (dump_cgraph_node) removed refs vars.

   Fixed spelling error in *_OVERWRITTABLE
   * cgraph.h
   * cgraph.c (cgraph_master_clone,cgraph_function_body_availability,
   cgraph_variable_initializer_availability)

   Fixed indention and nesting problem in source:
   cgraphunit.c (record_call_1)


2004-12-02 Jan Hubicka <jh@suse.cz> committed by Kenneth Zadeck
Fixes to make variable and functions appear at proper time in ipa analysis.
*cgraph.c (enqueue_needed_varpool_node): renamed to
cgraph_varpool_enqueue_needed_node (cgraph_varpool_reset_queue): new function.
(cgraph_varpool_mark_needed_node, decide_is_variable_needed) add calls.
(cgraph_varpool_finalize_decl) renamed function call
* cgraphunit.c (cgraph_optimize) disabled recovery of useless nodes.
* ipa.c (cgraph_remove_unreachable_nodes) disabled detection.



? makefile.promote
? save-tree-promote-statics.c
? static2.diff
Index: alias.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/alias.c,v
retrieving revision 1.176.2.21.2.12
diff -c -3 -p -r1.176.2.21.2.12 alias.c
*** alias.c	17 Oct 2004 18:29:51 -0000	1.176.2.21.2.12
--- alias.c	3 Dec 2004 03:20:12 -0000
*************** static rtx adjust_offset_for_component_r
*** 115,126 ****
  static int nonoverlapping_memrefs_p (rtx, rtx);
  static int write_dependence_p (rtx, rtx, int);
  
- static int nonlocal_mentioned_p_1 (rtx *, void *);
- static int nonlocal_mentioned_p (rtx);
- static int nonlocal_referenced_p_1 (rtx *, void *);
- static int nonlocal_referenced_p (rtx);
- static int nonlocal_set_p_1 (rtx *, void *);
- static int nonlocal_set_p (rtx);
  static void memory_modified_1 (rtx, rtx, void *);
  
  /* Set up all info needed to perform alias analysis on memory references.  */
--- 115,120 ----
*************** output_dependence (rtx mem, rtx x)
*** 2309,2661 ****
    return write_dependence_p (mem, x, /*writep=*/1);
  }
  
- /* A subroutine of nonlocal_mentioned_p, returns 1 if *LOC mentions
-    something which is not local to the function and is not constant.  */
- 
- static int
- nonlocal_mentioned_p_1 (rtx *loc, void *data ATTRIBUTE_UNUSED)
- {
-   rtx x = *loc;
-   rtx base;
-   int regno;
- 
-   if (! x)
-     return 0;
- 
-   switch (GET_CODE (x))
-     {
-     case SUBREG:
-       if (REG_P (SUBREG_REG (x)))
- 	{
- 	  /* Global registers are not local.  */
- 	  if (REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER
- 	      && global_regs[subreg_regno (x)])
- 	    return 1;
- 	  return 0;
- 	}
-       break;
- 
-     case REG:
-       regno = REGNO (x);
-       /* Global registers are not local.  */
-       if (regno < FIRST_PSEUDO_REGISTER && global_regs[regno])
- 	return 1;
-       return 0;
- 
-     case SCRATCH:
-     case PC:
-     case CC0:
-     case CONST_INT:
-     case CONST_DOUBLE:
-     case CONST_VECTOR:
-     case CONST:
-     case LABEL_REF:
-       return 0;
- 
-     case SYMBOL_REF:
-       /* Constants in the function's constants pool are constant.  */
-       if (CONSTANT_POOL_ADDRESS_P (x))
- 	return 0;
-       return 1;
- 
-     case CALL:
-       /* Non-constant calls and recursion are not local.  */
-       return 1;
- 
-     case MEM:
-       /* Be overly conservative and consider any volatile memory
- 	 reference as not local.  */
-       if (MEM_VOLATILE_P (x))
- 	return 1;
-       base = find_base_term (XEXP (x, 0));
-       if (base)
- 	{
- 	  /* A Pmode ADDRESS could be a reference via the structure value
- 	     address or static chain.  Such memory references are nonlocal.
- 
- 	     Thus, we have to examine the contents of the ADDRESS to find
- 	     out if this is a local reference or not.  */
- 	  if (GET_CODE (base) == ADDRESS
- 	      && GET_MODE (base) == Pmode
- 	      && (XEXP (base, 0) == stack_pointer_rtx
- 		  || XEXP (base, 0) == arg_pointer_rtx
- #if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
- 		  || XEXP (base, 0) == hard_frame_pointer_rtx
- #endif
- 		  || XEXP (base, 0) == frame_pointer_rtx))
- 	    return 0;
- 	  /* Constants in the function's constant pool are constant.  */
- 	  if (GET_CODE (base) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (base))
- 	    return 0;
- 	}
-       return 1;
- 
-     case UNSPEC_VOLATILE:
-     case ASM_INPUT:
-       return 1;
- 
-     case ASM_OPERANDS:
-       if (MEM_VOLATILE_P (x))
- 	return 1;
- 
-     /* Fall through.  */
- 
-     default:
-       break;
-     }
- 
-   return 0;
- }
- 
- /* Returns nonzero if X might mention something which is not
-    local to the function and is not constant.  */
- 
- static int
- nonlocal_mentioned_p (rtx x)
- {
-   if (INSN_P (x))
-     {
-       if (CALL_P (x))
- 	{
- 	  if (! CONST_OR_PURE_CALL_P (x))
- 	    return 1;
- 	  x = CALL_INSN_FUNCTION_USAGE (x);
- 	  if (x == 0)
- 	    return 0;
- 	}
-       else
- 	x = PATTERN (x);
-     }
- 
-   return for_each_rtx (&x, nonlocal_mentioned_p_1, NULL);
- }
- 
- /* A subroutine of nonlocal_referenced_p, returns 1 if *LOC references
-    something which is not local to the function and is not constant.  */
- 
- static int
- nonlocal_referenced_p_1 (rtx *loc, void *data ATTRIBUTE_UNUSED)
- {
-   rtx x = *loc;
- 
-   if (! x)
-     return 0;
- 
-   switch (GET_CODE (x))
-     {
-     case MEM:
-     case REG:
-     case SYMBOL_REF:
-     case SUBREG:
-       return nonlocal_mentioned_p (x);
- 
-     case CALL:
-       /* Non-constant calls and recursion are not local.  */
-       return 1;
- 
-     case SET:
-       if (nonlocal_mentioned_p (SET_SRC (x)))
- 	return 1;
- 
-       if (MEM_P (SET_DEST (x)))
- 	return nonlocal_mentioned_p (XEXP (SET_DEST (x), 0));
- 
-       /* If the destination is anything other than a CC0, PC,
- 	 MEM, REG, or a SUBREG of a REG that occupies all of
- 	 the REG, then X references nonlocal memory if it is
- 	 mentioned in the destination.  */
-       if (GET_CODE (SET_DEST (x)) != CC0
- 	  && GET_CODE (SET_DEST (x)) != PC
- 	  && !REG_P (SET_DEST (x))
- 	  && ! (GET_CODE (SET_DEST (x)) == SUBREG
- 		&& REG_P (SUBREG_REG (SET_DEST (x)))
- 		&& (((GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_DEST (x))))
- 		      + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)
- 		    == ((GET_MODE_SIZE (GET_MODE (SET_DEST (x)))
- 			 + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD))))
- 	return nonlocal_mentioned_p (SET_DEST (x));
-       return 0;
- 
-     case CLOBBER:
-       if (MEM_P (XEXP (x, 0)))
- 	return nonlocal_mentioned_p (XEXP (XEXP (x, 0), 0));
-       return 0;
- 
-     case USE:
-       return nonlocal_mentioned_p (XEXP (x, 0));
- 
-     case ASM_INPUT:
-     case UNSPEC_VOLATILE:
-       return 1;
- 
-     case ASM_OPERANDS:
-       if (MEM_VOLATILE_P (x))
- 	return 1;
- 
-     /* Fall through.  */
- 
-     default:
-       break;
-     }
- 
-   return 0;
- }
- 
- /* Returns nonzero if X might reference something which is not
-    local to the function and is not constant.  */
- 
- static int
- nonlocal_referenced_p (rtx x)
- {
-   if (INSN_P (x))
-     {
-       if (CALL_P (x))
- 	{
- 	  if (! CONST_OR_PURE_CALL_P (x))
- 	    return 1;
- 	  x = CALL_INSN_FUNCTION_USAGE (x);
- 	  if (x == 0)
- 	    return 0;
- 	}
-       else
- 	x = PATTERN (x);
-     }
- 
-   return for_each_rtx (&x, nonlocal_referenced_p_1, NULL);
- }
- 
- /* A subroutine of nonlocal_set_p, returns 1 if *LOC sets
-    something which is not local to the function and is not constant.  */
- 
- static int
- nonlocal_set_p_1 (rtx *loc, void *data ATTRIBUTE_UNUSED)
- {
-   rtx x = *loc;
- 
-   if (! x)
-     return 0;
- 
-   switch (GET_CODE (x))
-     {
-     case CALL:
-       /* Non-constant calls and recursion are not local.  */
-       return 1;
- 
-     case PRE_INC:
-     case PRE_DEC:
-     case POST_INC:
-     case POST_DEC:
-     case PRE_MODIFY:
-     case POST_MODIFY:
-       return nonlocal_mentioned_p (XEXP (x, 0));
- 
-     case SET:
-       if (nonlocal_mentioned_p (SET_DEST (x)))
- 	return 1;
-       return nonlocal_set_p (SET_SRC (x));
- 
-     case CLOBBER:
-       return nonlocal_mentioned_p (XEXP (x, 0));
- 
-     case USE:
-       return 0;
- 
-     case ASM_INPUT:
-     case UNSPEC_VOLATILE:
-       return 1;
- 
-     case ASM_OPERANDS:
-       if (MEM_VOLATILE_P (x))
- 	return 1;
- 
-     /* Fall through.  */
- 
-     default:
-       break;
-     }
- 
-   return 0;
- }
- 
- /* Returns nonzero if X might set something which is not
-    local to the function and is not constant.  */
- 
- static int
- nonlocal_set_p (rtx x)
- {
-   if (INSN_P (x))
-     {
-       if (CALL_P (x))
- 	{
- 	  if (! CONST_OR_PURE_CALL_P (x))
- 	    return 1;
- 	  x = CALL_INSN_FUNCTION_USAGE (x);
- 	  if (x == 0)
- 	    return 0;
- 	}
-       else
- 	x = PATTERN (x);
-     }
- 
-   return for_each_rtx (&x, nonlocal_set_p_1, NULL);
- }
- 
- /* Mark the function if it is pure or constant.  */
- 
- void
- mark_constant_function (void)
- {
-   rtx insn;
-   int nonlocal_memory_referenced;
- 
-   if (TREE_READONLY (current_function_decl)
-       || DECL_IS_PURE (current_function_decl)
-       || TREE_THIS_VOLATILE (current_function_decl)
-       || current_function_has_nonlocal_goto
-       || !targetm.binds_local_p (current_function_decl))
-     return;
- 
-   /* A loop might not return which counts as a side effect.  */
-   if (mark_dfs_back_edges ())
-     return;
- 
-   nonlocal_memory_referenced = 0;
- 
-   init_alias_analysis ();
- 
-   /* Determine if this is a constant or pure function.  */
- 
-   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
-     {
-       if (! INSN_P (insn))
- 	continue;
- 
-       if (nonlocal_set_p (insn) || global_reg_mentioned_p (insn)
- 	  || volatile_refs_p (PATTERN (insn)))
- 	break;
- 
-       if (! nonlocal_memory_referenced)
- 	nonlocal_memory_referenced = nonlocal_referenced_p (insn);
-     }
- 
-   end_alias_analysis ();
- 
-   /* Mark the function.  */
- 
-   if (insn)
-     ;
-   else if (nonlocal_memory_referenced)
-     {
-       cgraph_rtl_info (current_function_decl)->pure_function = 1;
-       DECL_IS_PURE (current_function_decl) = 1;
-     }
-   else
-     {
-       cgraph_rtl_info (current_function_decl)->const_function = 1;
-       TREE_READONLY (current_function_decl) = 1;
-     }
- }
- 
  
  void
  init_alias_once (void)
--- 2303,2308 ----
Index: calls.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/calls.c,v
retrieving revision 1.229.2.42.2.12
diff -c -3 -p -r1.229.2.42.2.12 calls.c
*** calls.c	12 Sep 2004 16:38:47 -0000	1.229.2.42.2.12
--- calls.c	3 Dec 2004 03:20:13 -0000
*************** flags_from_decl_or_type (tree exp)
*** 568,584 ****
  
    if (DECL_P (exp))
      {
-       struct cgraph_rtl_info *i = cgraph_rtl_info (exp);
        type = TREE_TYPE (exp);
  
-       if (i)
- 	{
- 	  if (i->pure_function)
- 	    flags |= ECF_PURE | ECF_LIBCALL_BLOCK;
- 	  if (i->const_function)
- 	    flags |= ECF_CONST | ECF_LIBCALL_BLOCK;
- 	}
- 
        /* The function exp may have the `malloc' attribute.  */
        if (DECL_IS_MALLOC (exp))
  	flags |= ECF_MALLOC;
--- 568,575 ----
Index: cgraph.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraph.c,v
retrieving revision 1.4.4.18.2.18
diff -c -3 -p -r1.4.4.18.2.18 cgraph.c
*** cgraph.c	30 Nov 2004 17:43:42 -0000	1.4.4.18.2.18
--- cgraph.c	3 Dec 2004 03:20:13 -0000
*************** dump_cgraph_node (FILE *f, struct cgraph
*** 532,541 ****
      fprintf (f, " externally_visible");
    if (node->local.finalized)
      fprintf (f, " finalized");
-   if (node->local.calls_read_all)
-     fprintf (f, " calls_read_all");
-   if (node->local.calls_write_all)
-     fprintf (f, " calls_write_all");
    if (node->local.disregard_inline_limits)
      fprintf (f, " always_inline");
    else if (node->local.inlinable)
--- 532,537 ----
*************** change_decl_assembler_name (tree decl, t
*** 674,683 ****
    SET_DECL_ASSEMBLER_NAME (decl, name);
  }
  
! /* Helped function for finalization code - add node into lists so it will
     be analyzed and compiled.  */
! static void
! enqueue_needed_varpool_node (struct cgraph_varpool_node *node)
  {
    if (cgraph_varpool_last_needed_node)
      cgraph_varpool_last_needed_node->next_needed = node;
--- 670,679 ----
    SET_DECL_ASSEMBLER_NAME (decl, name);
  }
  
! /* Helper function for finalization code - add node into lists so it will
     be analyzed and compiled.  */
! void
! cgraph_varpool_enqueue_needed_node (struct cgraph_varpool_node *node)
  {
    if (cgraph_varpool_last_needed_node)
      cgraph_varpool_last_needed_node->next_needed = node;
*************** enqueue_needed_varpool_node (struct cgra
*** 690,702 ****
    notice_global_symbol (node->decl);
  }
  
  /* Notify finalize_compilation_unit that given node is reachable
     or needed.  */
  void
  cgraph_varpool_mark_needed_node (struct cgraph_varpool_node *node)
  {
    if (!node->needed && node->finalized)
!     enqueue_needed_varpool_node (node);
    node->needed = 1;
  }
  
--- 686,707 ----
    notice_global_symbol (node->decl);
  }
  
+ /* Reset the queue of needed nodes.  */
+ void
+ cgraph_varpool_reset_queue (void)
+ {
+   cgraph_varpool_last_needed_node = NULL;
+   cgraph_varpool_nodes_queue = NULL;
+   cgraph_varpool_first_unanalyzed_node = NULL;
+ }
+ 
  /* Notify finalize_compilation_unit that given node is reachable
     or needed.  */
  void
  cgraph_varpool_mark_needed_node (struct cgraph_varpool_node *node)
  {
    if (!node->needed && node->finalized)
!     cgraph_varpool_enqueue_needed_node (node);
    node->needed = 1;
  }
  
*************** decide_is_variable_needed (struct cgraph
*** 712,721 ****
    if (lookup_attribute ("used", DECL_ATTRIBUTES (decl)))
      {
        if (TREE_PUBLIC (decl))
!         node->externally_visible = true;
        return true;
      }
! 
    /* ??? If the assembler name is set by hand, it is possible to assemble
       the name later after finalizing the function and the fact is noticed
       in assemble_name then.  This is arguably a bug.  */
--- 717,726 ----
    if (lookup_attribute ("used", DECL_ATTRIBUTES (decl)))
      {
        if (TREE_PUBLIC (decl))
! 	node->externally_visible = true;
        return true;
      }
!   
    /* ??? If the assembler name is set by hand, it is possible to assemble
       the name later after finalizing the function and the fact is noticed
       in assemble_name then.  This is arguably a bug.  */
*************** decide_is_variable_needed (struct cgraph
*** 723,748 ****
        && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
      {
        if (TREE_PUBLIC (decl))
!         node->externally_visible = true;
        return true;
      }
! 
    /* If we decided it was needed before, but at the time we didn't have
       the definition available, then it's still needed.  */
    if (node->needed)
      return true;
! 
    /* Externally visible functions must be output.  The exception is
       COMDAT functions that must be output only when they are needed.  */
    if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))
      return true;
! 
    if (flag_unit_at_a_time)
      return false;
! 
    /* If not doing unit at a time, then we'll only defer this function
       if its marked for inlining.  Otherwise we want to emit it now.  */
! 
    /* We want to emit COMDAT variables only when absolutely necessary.  */
    if (DECL_COMDAT (decl))
      return false;
--- 728,753 ----
        && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
      {
        if (TREE_PUBLIC (decl))
! 	node->externally_visible = true;
        return true;
      }
!   
    /* If we decided it was needed before, but at the time we didn't have
       the definition available, then it's still needed.  */
    if (node->needed)
      return true;
!   
    /* Externally visible functions must be output.  The exception is
       COMDAT functions that must be output only when they are needed.  */
    if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))
      return true;
!   
    if (flag_unit_at_a_time)
      return false;
!   
    /* If not doing unit at a time, then we'll only defer this function
       if its marked for inlining.  Otherwise we want to emit it now.  */
!   
    /* We want to emit COMDAT variables only when absolutely necessary.  */
    if (DECL_COMDAT (decl))
      return false;
*************** void
*** 753,759 ****
  cgraph_varpool_finalize_decl (tree decl)
  {
    struct cgraph_varpool_node *node = cgraph_varpool_node (decl);
!  
    /* The first declaration of a variable that comes through this function
       decides whether it is global (in C, has external linkage)
       or local (in C, has internal linkage).  So do nothing more
--- 758,764 ----
  cgraph_varpool_finalize_decl (tree decl)
  {
    struct cgraph_varpool_node *node = cgraph_varpool_node (decl);
!   
    /* The first declaration of a variable that comes through this function
       decides whether it is global (in C, has external linkage)
       or local (in C, has internal linkage).  So do nothing more
*************** cgraph_varpool_finalize_decl (tree decl)
*** 761,780 ****
    if (node->finalized)
      {
        if (cgraph_global_info_ready || !flag_unit_at_a_time)
! 	cgraph_varpool_assemble_pending_decls ();
        return;
      }
    if (node->needed)
!     enqueue_needed_varpool_node (node);
    node->finalized = true;
! 
    if (decide_is_variable_needed (node, decl))
      cgraph_varpool_mark_needed_node (node);
    if (cgraph_global_info_ready || !flag_unit_at_a_time)
      cgraph_varpool_assemble_pending_decls ();
  }
  
- 
  /* Return true when the DECL can possibly be inlined.  */
  bool
  cgraph_function_possibly_inlined_p (tree decl)
--- 766,784 ----
    if (node->finalized)
      {
        if (cgraph_global_info_ready || !flag_unit_at_a_time)
!  	cgraph_varpool_assemble_pending_decls ();
        return;
      }
    if (node->needed)
!     cgraph_varpool_enqueue_needed_node (node);
    node->finalized = true;
!   
    if (decide_is_variable_needed (node, decl))
      cgraph_varpool_mark_needed_node (node);
    if (cgraph_global_info_ready || !flag_unit_at_a_time)
      cgraph_varpool_assemble_pending_decls ();
  }
  
  /* Return true when the DECL can possibly be inlined.  */
  bool
  cgraph_function_possibly_inlined_p (tree decl)
*************** cgraph_master_clone (struct cgraph_node 
*** 855,861 ****
  {
    enum availability avail = cgraph_function_body_availability (n);
     
!   if (avail == AVAIL_NOT_AVAILABLE || avail == AVAIL_OVERWRITTABLE)
      return NULL;
  
    if (!n->master_clone) 
--- 859,865 ----
  {
    enum availability avail = cgraph_function_body_availability (n);
     
!   if (avail == AVAIL_NOT_AVAILABLE || avail == AVAIL_OVERWRITABLE)
      return NULL;
  
    if (!n->master_clone) 
*************** cgraph_function_body_availability (struc
*** 914,920 ****
    else if (!node->local.externally_visible)
      avail = AVAIL_AVAILABLE;
  
!   /* If the function can be overwritten, return OVERWRITTABLE.  Take
       care at least of two notable extensions - the COMDAT functions
       used to share template instantiations in C++ (this is symmetric
       to code cp_cannot_inline_tree_fn and probably shall be shared and
--- 918,924 ----
    else if (!node->local.externally_visible)
      avail = AVAIL_AVAILABLE;
  
!   /* If the function can be overwritten, return OVERWRITABLE.  Take
       care at least of two notable extensions - the COMDAT functions
       used to share template instantiations in C++ (this is symmetric
       to code cp_cannot_inline_tree_fn and probably shall be shared and
*************** cgraph_function_body_availability (struc
*** 932,940 ****
    else if (!(*targetm.binds_local_p) (node->decl)
  	   && !DECL_COMDAT (node->decl) && !DECL_EXTERNAL (node->decl))
      if (DECL_DECLARED_INLINE_P (node->decl))
!       avail = AVAIL_OVERWRITTABLE_BUT_INLINABLE;
      else 
!       avail = AVAIL_OVERWRITTABLE;
    else avail = AVAIL_AVAILABLE;
    node->local.avail = avail;
    return avail;
--- 936,944 ----
    else if (!(*targetm.binds_local_p) (node->decl)
  	   && !DECL_COMDAT (node->decl) && !DECL_EXTERNAL (node->decl))
      if (DECL_DECLARED_INLINE_P (node->decl))
!       avail = AVAIL_OVERWRITABLE_BUT_INLINABLE;
      else 
!       avail = AVAIL_OVERWRITABLE;
    else avail = AVAIL_AVAILABLE;
    node->local.avail = avail;
    return avail;
*************** cgraph_variable_initializer_availability
*** 949,959 ****
      return AVAIL_NOT_AVAILABLE;
    if (!TREE_PUBLIC (node->decl))
      return AVAIL_AVAILABLE;
!   /* If the variable can be overwritted, return OVERWRITTABLE.  Takes
       care of at least two notable extensions - the COMDAT variables
       used to share template instantiations in C++.  */
    if (!(*targetm.binds_local_p) (node->decl) && !DECL_COMDAT (node->decl))
!     return AVAIL_OVERWRITTABLE;
    return AVAIL_AVAILABLE;
  }
  
--- 953,963 ----
      return AVAIL_NOT_AVAILABLE;
    if (!TREE_PUBLIC (node->decl))
      return AVAIL_AVAILABLE;
!   /* If the variable can be overwritted, return OVERWRITABLE.  Takes
       care of at least two notable extensions - the COMDAT variables
       used to share template instantiations in C++.  */
    if (!(*targetm.binds_local_p) (node->decl) && !DECL_COMDAT (node->decl))
!     return AVAIL_OVERWRITABLE;
    return AVAIL_AVAILABLE;
  }
  
Index: cgraph.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraph.h,v
retrieving revision 1.1.4.16.2.18
diff -c -3 -p -r1.1.4.16.2.18 cgraph.h
*** cgraph.h	2 Dec 2004 15:32:17 -0000	1.1.4.16.2.18
--- cgraph.h	3 Dec 2004 03:20:13 -0000
*************** enum availability
*** 35,44 ****
    /* Function body/variable initializer is known but might be replaced
       by a different one from other compilation unit and thus can be
       dealt with only as a hint.  */
!   AVAIL_OVERWRITTABLE,
!   /* Same as AVAIL_OVERWRITTABLE except the front end has said that
       this instance is stable enough to analyze or even inline.  */
!   AVAIL_OVERWRITTABLE_BUT_INLINABLE,
    /* Function body/variable initializer is known and will be used in final
       program.  */
    AVAIL_AVAILABLE,
--- 35,44 ----
    /* Function body/variable initializer is known but might be replaced
       by a different one from other compilation unit and thus can be
       dealt with only as a hint.  */
!   AVAIL_OVERWRITABLE,
!   /* Same as AVAIL_OVERWRITABLE except the front end has said that
       this instance is stable enough to analyze or even inline.  */
!   AVAIL_OVERWRITABLE_BUT_INLINABLE,
    /* Function body/variable initializer is known and will be used in final
       program.  */
    AVAIL_AVAILABLE,
*************** struct cgraph_local_info GTY(())
*** 67,80 ****
    /* Set when function is visible by other units.  */
    bool externally_visible;
  
-   /* Set when this function calls another function external to the
-      compilation unit or if the function has a asm clobber of memory.
-      In general, such calls are modeled as reading and writing all
-      variables (both bits on) but sometime there are attributes on the
-      called function so we can do better.  */
-   bool calls_read_all;
-   bool calls_write_all;
- 
    /* Set once it has been finalized so we consider it to be output.  */
    bool finalized;
  
--- 67,72 ----
*************** struct cgraph_global_info GTY(())
*** 110,117 ****
  struct cgraph_rtl_info GTY(())
  {
     int preferred_incoming_stack_boundary;
-    bool const_function;
-    bool pure_function;
  };
  
  /* The cgraph data structure.
--- 102,107 ----
*************** struct cgraph_varpool_node GTY(())
*** 199,207 ****
    /* Pointer to the next function in cgraph_varpool_nodes_queue.  */
    struct cgraph_varpool_node *next_needed;
  
!   /* Set when function must be output - it is externally visible
!      or it's address is taken.  */
    bool needed;
    /* Set once the variable has been instantiated and its callee
       lists created.  */
    bool analyzed;
--- 189,200 ----
    /* Pointer to the next function in cgraph_varpool_nodes_queue.  */
    struct cgraph_varpool_node *next_needed;
  
!   /* Set when variable is visible - it is externally visible,
!      it is used directly or it's address is taken.  */
    bool needed;
+   /* Needed variables might become dead by optimization.  This flag
+      forces the variable to be output even if it appears dead otherwise.  */
+   bool force_output;
    /* Set once the variable has been instantiated and its callee
       lists created.  */
    bool analyzed;
*************** bool cgraph_is_master_clone (struct cgra
*** 261,266 ****
--- 254,261 ----
  bool cgraph_is_immortal_master_clone (struct cgraph_node *);
  struct cgraph_node *cgraph_master_clone (struct cgraph_node *);
  struct cgraph_node *cgraph_immortal_master_clone (struct cgraph_node *);
+ void cgraph_varpool_enqueue_needed_node (struct cgraph_varpool_node *);
+ void cgraph_varpool_reset_queue (void);
  void cgraph_mark_needed_node (struct cgraph_node *);
  void cgraph_mark_reachable_node (struct cgraph_node *);
  bool cgraph_inline_p (struct cgraph_edge *, const char **);
Index: cgraphunit.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraphunit.c,v
retrieving revision 1.1.4.35.2.32
diff -c -3 -p -r1.1.4.35.2.32 cgraphunit.c
*** cgraphunit.c	2 Dec 2004 15:50:27 -0000	1.1.4.35.2.32
--- cgraphunit.c	3 Dec 2004 03:20:14 -0000
*************** record_call_1 (tree *tp, int *walk_subtr
*** 452,470 ****
          if (flag_ipa_cp && decl == NULL_TREE)
            flag_ipa_cp = 0;
  	break;
  
!       case STATEMENT_LIST:
! 	{
! 	  tree_stmt_iterator tsi;
! 	  /* Track current statement while finding CALL_EXPRs.  */
! 	  for (tsi = tsi_start (*tp); !tsi_end_p (tsi); tsi_next (&tsi))
! 	    {
! 	      walk_tree (tsi_stmt_ptr (tsi), record_call_1, data,
! 			 visited_nodes);
! 	    }
! 	}
! 	break;
        }
  
      default:
        /* Save some cycles by not walking types and declaration as we
--- 452,470 ----
          if (flag_ipa_cp && decl == NULL_TREE)
            flag_ipa_cp = 0;
  	break;
+       }
  
!     case STATEMENT_LIST:
!       {
! 	tree_stmt_iterator tsi;
! 	/* Track current statement while finding CALL_EXPRs.  */
! 	for (tsi = tsi_start (*tp); !tsi_end_p (tsi); tsi_next (&tsi))
! 	  {
! 	    walk_tree (tsi_stmt_ptr (tsi), record_call_1, data,
! 		       visited_nodes);
! 	  }
        }
+       break;
  
      default:
        /* Save some cycles by not walking types and declaration as we
*************** cgraph_varpool_analyze_pending_decls (vo
*** 724,729 ****
--- 724,730 ----
        else
          cgraph_varpool_first_unanalyzed_node->non_ipa = true;
        cgraph_varpool_first_unanalyzed_node = cgraph_varpool_first_unanalyzed_node->next_needed;
+ 
        if (DECL_INITIAL (decl))
  	cgraph_create_edges (NULL, DECL_INITIAL (decl));
        changed = true;
*************** cgraph_finalize_compilation_unit (void)
*** 836,842 ****
        node->next_needed = NULL;
  
        /* ??? It is possible to create extern inline function and later using
! 	 weak alas attribute to kill its body. See
  	 gcc.c-torture/compile/20011119-1.c  */
        if (!DECL_SAVED_TREE (decl))
  	{
--- 837,843 ----
        node->next_needed = NULL;
  
        /* ??? It is possible to create extern inline function and later using
! 	 weak alias attribute to kill its body. See
  	 gcc.c-torture/compile/20011119-1.c  */
        if (!DECL_SAVED_TREE (decl))
  	{
*************** cgraph_expand_function (struct cgraph_no
*** 987,992 ****
--- 988,1000 ----
      }
  }
  
+ /* FIXME this needs to be enhanced.  If we are compiling a single
+    module this returns true if the variable is a module level static,
+    but if we are doing whole program compilation, this could return
+    true if TREE_PUBLIC is true. */
+ /* Return true if the variable T is the right kind of static variable to
+    perform compilation unit scope escape analysis.  */
+ 
  /* Expand all functions that must be output.
  
     Attempt to topologically sort the nodes so function is output when
*************** cgraph_optimize (void)
*** 1129,1134 ****
--- 1137,1144 ----
        cgraph_varpool_assemble_pending_decls ();
        return;
      }
+   cgraph_varpool_analyze_pending_decls ();
+ 
    timevar_push (TV_IPA_OPT);
  
    /* Frontend may output common variables after the unit has been finalized.
*************** cgraph_optimize (void)
*** 1178,1206 ****
        fprintf (cgraph_dump_file, "\nFinal ");
        dump_cgraph (cgraph_dump_file);
      }
! #ifdef ENABLE_CHECKING
!   verify_cgraph ();
!   /* Double check that all inline clones are gone and that all
!      function bodies have been released from memory.  */
!   if (flag_unit_at_a_time
!       && !dump_enabled_p (TDI_tree_all)
!       && !(sorrycount || errorcount))
!     {
!       struct cgraph_node *node;
!       bool error_found = false;
! 
!       for (node = cgraph_nodes; node; node = node->next)
! 	if (node->analyzed
! 	    && (node->global.inlined_to
! 	        || DECL_SAVED_TREE (node->decl)))
! 	  {
! 	    error_found = true;
! 	    dump_cgraph_node (stderr, node);
!  	  }
!       if (error_found)
! 	internal_error ("Nodes with no released memory found.");
!     }
! #endif
  }
  
  /* Generate and emit a static constructor or destructor.  WHICH must be
--- 1188,1216 ----
        fprintf (cgraph_dump_file, "\nFinal ");
        dump_cgraph (cgraph_dump_file);
      }
! /* #ifdef ENABLE_CHECK */
! /*   verify_cgraph (); */
!      /* Double check that all inline clones are gone and that all 
!         function bodies have been released from memory.  */ 
! /*   if (flag_unit_at_a_time */
! /*       && !dump_enabled_p (TDI_tree_all) */
! /*       && !(sorrycount || errorcount)) */
! /*     { */
! /*       struct cgraph_node *node; */
! /*       bool error_found = false; */
! 
! /*       for (node = cgraph_nodes; node; node = node->next) */
! /* 	if (node->analyzed */
! /* 	    && (node->global.inlined_to */
! /* 	        || DECL_SAVED_TREE (node->decl))) */
! /* 	  { */
! /* 	    error_found = true; */
! /* 	    dump_cgraph_node (stderr, node); */
! /*  	  } */
! /*       if (error_found) */
! /* 	internal_error ("Nodes with no released memory found."); */
! /*     } */
! /* #endif */
  }
  
  /* Generate and emit a static constructor or destructor.  WHICH must be
Index: ipa-static-vars-anal.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/ipa-static-vars-anal.c,v
retrieving revision 1.1.2.2
diff -c -3 -p -r1.1.2.2 ipa-static-vars-anal.c
*** ipa-static-vars-anal.c	28 Nov 2004 17:59:35 -0000	1.1.2.2
--- ipa-static-vars-anal.c	3 Dec 2004 03:20:14 -0000
*************** Software Foundation, 59 Temple Place - S
*** 23,42 ****
     the compilation unit are used.  It is to be run after the call
     graph is built and after inlining decisions have been made.
  
!    First each function is analyzed to determine which local static
!    variables are either read or written or have their address taken.
!    Any local static that has its address taken is removed from
!    consideration.  Once the local read and writes are determined, a
!    transitive closure of this information is performed over the call
!    graph to determine the worst case set of side effects of each call.
!    In later parts of the compiler, these local and global sets are
!    examined to make the call clobbering less traumatic, promote some
!    statics to registers, and improve aliasing information.
  
     This must be run after inlining decisions have been made since
     otherwise, the local sets will not contain information that is
!    consistent with post inlined state.  The global sets are less prone
!    to problems since they are by definition transitive.  */
  
  /* The code in this module is called by the ipa pass manager. It
     should be one of the later passes since it's information is used by
--- 23,51 ----
     the compilation unit are used.  It is to be run after the call
     graph is built and after inlining decisions have been made.
  
!    First each function and static variable initialization is analyzed
!    to determine which local static variables are either read, written,
!    or have their address taken.  Any local static that has its address
!    taken is removed from consideration.  Once the local read and
!    writes are determined, a transitive closure of this information is
!    performed over the call graph to determine the worst case set of
!    side effects of each call.  In later parts of the compiler, these
!    local and global sets are examined to make the call clobbering less
!    traumatic, promote some statics to registers, and improve aliasing
!    information.
!    
!    As a direct result of the information gathered here, the
!    TREE_READONLY bits can be set and TREE_ADDRESSABLE can be cleared
!    for all compilation unit level static variables that satisfy those
!    criteria.
! 
!    Lastly, all of this information is used to mark functions as being
!    either const (TREE_READONLY) or pure (DECL_IS_PURE).
  
     This must be run after inlining decisions have been made since
     otherwise, the local sets will not contain information that is
!    consistent with post inlined state.  The global sets are not prone
!    to this problem since they are by definition transitive.  */
  
  /* The code in this module is called by the ipa pass manager. It
     should be one of the later passes since it's information is used by
*************** static GTY((param1_is(int), param2_is(tr
*** 76,81 ****
--- 85,94 ----
     uid.  */
  static bitmap module_statics_escape;
  
+ /* This bitmap is used to knock out the module static variables that
+    are not readonly.  This is indexed by uid.  */
+ static bitmap module_statics_written;
+ 
  /* FIXME -- PROFILE-RESTRUCTURE: change comment from DECL_UID to var-ann. */    
  /* A bit is set for every module static we are considering and is
     indexed by DECL_UID.  This is ored into the local info when asm
*************** static bitmap all_module_statics;
*** 88,93 ****
--- 101,116 ----
     scan_for_static_refs.  */
  static struct pointer_set_t *visited_nodes;
  
+ enum initialization_status_t
+ {
+   UNINITIALIZED,
+   RUNNING,
+   FINISHED
+ };
+ 
+ static enum initialization_status_t initialization_status = UNINITIALIZED;
+   
+ 
  tree memory_identifier_string;
  
  /* Debugging function for postorder and inorder code. NOTE is a string
*************** void add_static_var (tree var) 
*** 487,495 ****
    splay_tree_insert (static_vars_to_consider_by_uid,
  		     DECL_UID (var), (splay_tree_value)var);
    
-   if (dump_file)
-     fprintf (dump_file, "\nConsidering var:%s",
- 	     lang_hooks.decl_printable_name (var, 2));
    /* FIXME -- PROFILE-RESTRUCTURE: Change the call from
       DECL_UID to get the uid from the var_ann field. */    
    bitmap_set_bit (all_module_statics, DECL_UID (var));
--- 510,515 ----
*************** void add_static_var (tree var) 
*** 502,539 ****
  /* Return true if the variable T is the right kind of static variable to
     perform compilation unit scope escape analysis.  */
  
! static inline
! bool has_proper_scope_for_analysis (tree t)
! {
!   bool result = (TREE_STATIC (t)) && !(TREE_PUBLIC (t)) && !(TREE_THIS_VOLATILE (t));
!   if ((result) && !bitmap_bit_p (all_module_statics, DECL_UID (t)))
      add_static_var (t);
!   return result;
  }
  
  /* If T is a VAR_DECL for a static that we are interrested in, add the
     uid to the bitmap.  */
  
  static void
! check_operand (tree t, bitmap bm)
  {
    if (!t) return;
  
    /* FIXME -- PROFILE-RESTRUCTURE: Change the call from DECL_UID to
       get the uid from the var_ann field. */    
!   if ((TREE_CODE (t) == VAR_DECL) && has_proper_scope_for_analysis (t))
!     bitmap_set_bit (bm, DECL_UID (t));
  }
  
  /* Examine tree T for references to static variables. All internal
     references like array references or indirect references are added
!    to the INTERNAL_BM. Direct references are added to BASE_BM.  When
!    this is called from the rhs or recursively, both bitmap operands
!    are for the read bitmap.  When called from the lhs, the BASE_BM is
!    the write bitmap.  */
  
  static void
! check_tree (tree t, bitmap base_bm, bitmap internal_bm)
  {
    if ((TREE_CODE (t) == EXC_PTR_EXPR) || (TREE_CODE (t) == FILTER_EXPR))
      return;
--- 522,613 ----
  /* Return true if the variable T is the right kind of static variable to
     perform compilation unit scope escape analysis.  */
  
! static inline bool 
! has_proper_scope_for_analysis (ipa_local_static_vars_info_t local, 
! 			       tree t, bool checking_write)
! {
!   /* Do not want to do anything with volatile except mark any
!      function that uses one to be not const or pure.  */
!   if (TREE_THIS_VOLATILE (t)) 
!     { 
!       if (local && local->pure_const_not_set_in_source)
! 	local->pure_const_state = IPA_NEITHER;
!       return false;
!     }
! 
!   /* Do not care about a local automatic that is not static.  */
!   if (!TREE_STATIC (t) && !DECL_EXTERNAL (t))
!     return false;
! 
!   /* Since we have dispatched the locals and params, if we are writing, this
!      cannot be a pure or constant function.  */
!   if (checking_write && local && local->pure_const_not_set_in_source) 
!     local->pure_const_state = IPA_NEITHER;
! 
!   if (DECL_EXTERNAL (t) || TREE_PUBLIC (t))
!     {
!       /* If the front end set the variable to be READONLY and
! 	 constant, we can allow this variable in pure or const
! 	 functions but the scope is too large for our analysis to set
! 	 these bits ourselves.  */
!       
!       if (TREE_READONLY (t)
! 	  && DECL_INITIAL (t)
! 	  && is_gimple_min_invariant (DECL_INITIAL (t)))
! 	; /* Read of a constant, do not change the function state.  */
!       else 
! 	/* Just a regular read.  */
! 	if (local 
! 	    && local->pure_const_not_set_in_source
! 	    && local->pure_const_state == IPA_CONST)
! 	  local->pure_const_state = IPA_PURE;
! 
!       return false;
!     }
! 
!   /* This is a variable we care about.  Check if we have seen it
!      before, and if not add it the set of variables we care about.  */
!   if (!bitmap_bit_p (all_module_statics, DECL_UID (t)))
      add_static_var (t);
! 
!   return true;
  }
  
  /* If T is a VAR_DECL for a static that we are interrested in, add the
     uid to the bitmap.  */
  
  static void
! check_operand (ipa_local_static_vars_info_t local, 
! 	       tree t, bool checking_write)
  {
    if (!t) return;
  
    /* FIXME -- PROFILE-RESTRUCTURE: Change the call from DECL_UID to
       get the uid from the var_ann field. */    
!   if ((TREE_CODE (t) == VAR_DECL) 
!       && has_proper_scope_for_analysis (local, t, checking_write)) 
!     {
!       if (checking_write)
! 	{
! 	  if (local)
! 	    bitmap_set_bit (local->statics_written_by_decl_uid, DECL_UID (t));
! 	  /* Mark the write so we can tell which statics are
! 	     readonly.  */
! 	  bitmap_set_bit (module_statics_written, DECL_UID (t));
! 	}
!       else if (local)
! 	bitmap_set_bit (local->statics_read_by_decl_uid, DECL_UID (t));
!     }
!   else return;
  }
  
  /* Examine tree T for references to static variables. All internal
     references like array references or indirect references are added
!    to the READ_BM. Direct references are added to either READ_BM or
!    WRITE_BM depending on the value of CHECKING_WRITE.   */
  
  static void
! check_tree (ipa_local_static_vars_info_t local, tree t, bool checking_write)
  {
    if ((TREE_CODE (t) == EXC_PTR_EXPR) || (TREE_CODE (t) == FILTER_EXPR))
      return;
*************** check_tree (tree t, bitmap base_bm, bitm
*** 543,619 ****
  	 || handled_component_p (t))
      {
        if (TREE_CODE (t) == ARRAY_REF)
! 	check_operand (TREE_OPERAND (t, 1), internal_bm);
        t = TREE_OPERAND (t, 0);
      }
  
    /* The bottom of an indirect reference can only be read, not
!      written.  So just recurse and but what ever we find, check it
!      against the read bitmaps.  */
    if (INDIRECT_REF_P (t))
!     check_tree (TREE_OPERAND (t, 0), internal_bm, internal_bm);
  
    if (SSA_VAR_P (t))
!     check_operand (t, base_bm);
  }
  
  /* Scan tree T to see if there are any addresses taken in within T.  */
  
  static void 
! look_for_address_of (tree t)
  {
    if (TREE_CODE (t) == ADDR_EXPR)
      {
        tree x = get_base_var (t);
!       if ((TREE_CODE (x) == VAR_DECL) && has_proper_scope_for_analysis (x))
  	{
! 	  if (dump_file)
! 	    fprintf (dump_file, "\nadding address:%s",
! 		     lang_hooks.decl_printable_name (x, 2));
  	  
! 	  /* FIXME -- PROFILE-RESTRUCTURE: Change the call from
! 	     DECL_UID to get the uid from the var_ann field. */    
! 	  bitmap_set_bit (module_statics_escape, DECL_UID (x));
  	}
      }
  }
  
  
  /* Check to see if T is a read or address of operation on a static var
!    we are interested in analyzing.  FN is passed in to get access to
     its bit vectors.  */
  
  static void
! check_rhs_var (struct cgraph_node *fn, tree t)
  {
!   look_for_address_of (t);
  
!   if (fn == NULL) 
      return;
  
!   /* FIXME -- PROFILE-RESTRUCTURE: Change the call from DECL_UID to
!      get the uid from the var_ann field. */    
!   check_tree(t,
! 	     fn->static_vars_info->local->statics_read_by_decl_uid,
! 	     fn->static_vars_info->local->statics_read_by_decl_uid);
  }
  
  /* Check to see if T is an assignment to a static var we are
!    interrested in analyzing.  FN is passed in to get access to its bit
     vectors.
  */
  
  static void
! check_lhs_var (struct cgraph_node *fn, tree t)
  {
!   if (fn == NULL) 
      return;
  
!   /* FIXME -- PROFILE-RESTRUCTURE: Change the call from DECL_UID to
!      get the uid from the var_ann field. */    
!   check_tree(t, 
! 	     fn->static_vars_info->local->statics_written_by_decl_uid,
! 	     fn->static_vars_info->local->statics_read_by_decl_uid);
  }
  
  /* This is a scaled down version of get_asm_expr_operands from
--- 617,715 ----
  	 || handled_component_p (t))
      {
        if (TREE_CODE (t) == ARRAY_REF)
! 	check_operand (local, TREE_OPERAND (t, 1), false);
        t = TREE_OPERAND (t, 0);
      }
  
    /* The bottom of an indirect reference can only be read, not
!      written.  So just recurse and whatever we find, check it against
!      the read bitmaps.  */
    if (INDIRECT_REF_P (t))
!     {
!       check_tree (local, TREE_OPERAND (t, 0), false);
!       
!       if (local && local->pure_const_not_set_in_source)
! 	{
! 	  /* Any indirect reference that occurs on the lhs
! 	     disqualifies the function from being pure or const. Any
! 	     indirect reference that occurs on the rhs disqualifies
! 	     the function from being const.  */
! 	  if (checking_write) 
! 	    local->pure_const_state = IPA_NEITHER;
! 	  else 
! 	    if (local->pure_const_state == IPA_CONST)
! 	      local->pure_const_state = IPA_PURE;
! 	}
!     }
  
    if (SSA_VAR_P (t))
!     check_operand (local, t, checking_write);
  }
  
  /* Scan tree T to see if there are any addresses taken in within T.  */
  
  static void 
! look_for_address_of (ipa_local_static_vars_info_t local, tree t)
  {
    if (TREE_CODE (t) == ADDR_EXPR)
      {
        tree x = get_base_var (t);
!       if (TREE_CODE (x) == VAR_DECL) 
  	{
! 	  if (has_proper_scope_for_analysis (local, x, false))
! 	    /* FIXME -- PROFILE-RESTRUCTURE: Change the call from
! 	       DECL_UID to get the uid from the var_ann field. */    
! 	    bitmap_set_bit (module_statics_escape, DECL_UID (x));
  	  
! 	  /* Taking the address of something appears to be reasonable
! 	     in PURE code.  Not allowed in const.  */
! 	  if (local && local->pure_const_not_set_in_source
! 	      && local->pure_const_state == IPA_CONST)
! 	    local->pure_const_state = IPA_PURE;
  	}
      }
  }
  
  
  /* Check to see if T is a read or address of operation on a static var
!    we are interested in analyzing.  LOCAL is passed in to get access to
     its bit vectors.  */
  
  static void
! check_rhs_var (ipa_local_static_vars_info_t local, tree t)
  {
!   look_for_address_of (local, t);
  
!   if (local == NULL) 
      return;
  
!   /* Memcmp and strlen can both trap and they are declared pure.  */
!   if (tree_could_trap_p (t)
!       && local->pure_const_not_set_in_source
!       && local->pure_const_state == IPA_CONST)
!     local->pure_const_state = IPA_PURE;
! 
!   check_tree(local, t, false);
  }
  
  /* Check to see if T is an assignment to a static var we are
!    interrested in analyzing.  LOCAL is passed in to get access to its bit
     vectors.
  */
  
  static void
! check_lhs_var (ipa_local_static_vars_info_t local, tree t)
  {
!   if (local == NULL) 
      return;
  
!   /* Memcmp and strlen can both trap and they are declared pure.  */
!   if (tree_could_trap_p (t)
!       && local->pure_const_not_set_in_source
!       && local->pure_const_state == IPA_CONST)
!     local->pure_const_state = IPA_PURE;
!     
!   check_tree(local, t, true);
  }
  
  /* This is a scaled down version of get_asm_expr_operands from
*************** check_lhs_var (struct cgraph_node *fn, t
*** 624,630 ****
     function being analyzed and STMT is the actual asm statement.  */
  
  static void
! get_asm_expr_operands (struct cgraph_node * fn, tree stmt)
  {
    int noutputs = list_length (ASM_OUTPUTS (stmt));
    const char **oconstraints
--- 720,726 ----
     function being analyzed and STMT is the actual asm statement.  */
  
  static void
! get_asm_expr_operands (ipa_local_static_vars_info_t local, tree stmt)
  {
    int noutputs = list_length (ASM_OUTPUTS (stmt));
    const char **oconstraints
*************** get_asm_expr_operands (struct cgraph_nod
*** 641,650 ****
        parse_output_constraint (&constraint, i, 0, 0,
  			       &allows_mem, &allows_reg, &is_inout);
        
!       /* Memory operands are addressable.  Note that STMT needs the
! 	 address of this operand.  */
!       if (!allows_reg && allows_mem) 
! 	check_lhs_var (fn, TREE_VALUE (link));
      }
  
    for (link = ASM_INPUTS (stmt); link; link = TREE_CHAIN (link))
--- 737,743 ----
        parse_output_constraint (&constraint, i, 0, 0,
  			       &allows_mem, &allows_reg, &is_inout);
        
!       check_lhs_var (local, TREE_VALUE (link));
      }
  
    for (link = ASM_INPUTS (stmt); link; link = TREE_CHAIN (link))
*************** get_asm_expr_operands (struct cgraph_nod
*** 654,671 ****
        parse_input_constraint (&constraint, 0, 0, noutputs, 0,
  			      oconstraints, &allows_mem, &allows_reg);
        
!       /* Memory operands are addressable.  Note that STMT needs the
! 	 address of this operand.  */
!       if (!allows_reg && allows_mem) 
! 	check_rhs_var (fn, TREE_VALUE (link));
      }
    
    for (link = ASM_CLOBBERS (stmt); link; link = TREE_CHAIN (link))
      if (simple_cst_equal(TREE_VALUE (link), memory_identifier_string) == 1) 
        {
  	/* Abandon all hope, ye who enter here. */
! 	fn->local.calls_read_all = true;
! 	fn->local.calls_write_all = true;
        }      
  }
  
--- 747,763 ----
        parse_input_constraint (&constraint, 0, 0, noutputs, 0,
  			      oconstraints, &allows_mem, &allows_reg);
        
!       check_rhs_var (local, TREE_VALUE (link));
      }
    
    for (link = ASM_CLOBBERS (stmt); link; link = TREE_CHAIN (link))
      if (simple_cst_equal(TREE_VALUE (link), memory_identifier_string) == 1) 
        {
  	/* Abandon all hope, ye who enter here. */
! 	local->calls_read_all = true;
! 	local->calls_write_all = true;
! 	if (local->pure_const_not_set_in_source)
! 	  local->pure_const_state = IPA_NEITHER;
        }      
  }
  
*************** get_asm_expr_operands (struct cgraph_nod
*** 677,721 ****
     the tree node for the entire call expression.  */
  
  static void
! process_call_for_static_vars(struct cgraph_node * caller, tree call_expr) 
  {
    int flags = call_expr_flags(call_expr);
    tree operandList = TREE_OPERAND (call_expr, 1);
    tree operand;
    tree callee_t = get_callee_fndecl (call_expr);
  
    for (operand = operandList;
         operand != NULL_TREE;
         operand = TREE_CHAIN (operand))
      {
        tree argument = TREE_VALUE (operand);
!       check_rhs_var (caller, argument);
      }
!   
    /* Const and pure functions have less clobber effects than other
       functions so we process these first.  Otherwise if it is a call
       outside the compilation unit or an indirect call we punt.  This
       leaves local calls which will be processed by following the call
       graph.  */  
  
    if (flags & ECF_CONST) 
      return;
!   else if (flags & ECF_PURE) 
!     caller->local.calls_write_all = true;
!   else 
      {
!       enum availability avail = AVAIL_NOT_AVAILABLE;
!       if (callee_t)
  	{
! 	  struct cgraph_node* callee = cgraph_node(callee_t);
! 	  avail = cgraph_function_body_availability (callee);
  	}
! 
!       /* Indirect call or external call. */
!       if (avail == AVAIL_NOT_AVAILABLE || avail == AVAIL_OVERWRITTABLE) 
  	{
! 	  caller->local.calls_read_all = true;
! 	  caller->local.calls_write_all = true;
  	}
      }
  }
--- 769,870 ----
     the tree node for the entire call expression.  */
  
  static void
! process_call_for_static_vars(ipa_local_static_vars_info_t local, tree call_expr) 
  {
    int flags = call_expr_flags(call_expr);
    tree operandList = TREE_OPERAND (call_expr, 1);
    tree operand;
    tree callee_t = get_callee_fndecl (call_expr);
+   struct cgraph_node* callee;
+   enum availability avail = AVAIL_NOT_AVAILABLE;
  
    for (operand = operandList;
         operand != NULL_TREE;
         operand = TREE_CHAIN (operand))
      {
        tree argument = TREE_VALUE (operand);
!       check_rhs_var (local, argument);
      }
! 
!   /* The const and pure flags are set by a variety of places in the
!      compiler (including here).  If someone has already set the flags
!      for the callee, (such as for some of the builtins) we will use
!      them, otherwise we will compute our own information.  */
! 
    /* Const and pure functions have less clobber effects than other
       functions so we process these first.  Otherwise if it is a call
       outside the compilation unit or an indirect call we punt.  This
       leaves local calls which will be processed by following the call
       graph.  */  
  
+ 
+   if (callee_t)
+     {
+       callee = cgraph_node(callee_t);
+       avail = cgraph_function_body_availability (callee);
+ 
+       /* When bad things happen to bad functions, they cannot be const
+ 	 or pure.  */
+       if (local && local->pure_const_not_set_in_source)
+ 	if (setjmp_call_p (callee_t))
+ 	  local->pure_const_state = IPA_NEITHER;
+ 
+       if (DECL_BUILT_IN_CLASS (callee_t) == BUILT_IN_NORMAL)
+ 	switch (DECL_FUNCTION_CODE (callee_t))
+ 	  {
+ 	  case BUILT_IN_LONGJMP:
+ 	  case BUILT_IN_NONLOCAL_GOTO:
+ 	    local->pure_const_state = IPA_NEITHER;
+ 	    break;
+ 	  default:
+ 	    break;
+ 	  }
+     }
+ 
+   /* If the callee has already been marked as ECF_CONST, we need look
+      no further since it cannot look at any memory except
+      constants. However, if the callee is only ECF_PURE we need to
+      look because if there is also code, we need to mark the variables
+      it is reading from. */
    if (flags & ECF_CONST) 
      return;
! 
!   if (!local) return;
! 
!   /* The callee is either unknown (indirect call) or there is just no
!      scanable code for it (external call) .  We look to see if there
!      are any bits available for the callee (such as by declaration or
!      because it is builtin) and process solely on the basis of those
!      bits. */
! 
!   if (avail == AVAIL_NOT_AVAILABLE || avail == AVAIL_OVERWRITABLE)
      {
!       if (flags & ECF_PURE) 
  	{
! 	  local->calls_read_all = true;
! 	  if (local->pure_const_not_set_in_source
! 	      && local->pure_const_state == IPA_CONST)
! 	    local->pure_const_state = IPA_PURE;
  	}
!       else 
  	{
! 	  local->calls_read_all = true;
! 	  local->calls_write_all = true;
! 	  if (local->pure_const_not_set_in_source)
! 	    local->pure_const_state = IPA_NEITHER;
! 	}
!     }
!   else
!     {
!       /* We have the code and we will scan it for the effects. */
!       if (flags & ECF_PURE) 
! 	{
! 	  /* Since we have the code for the function, we do not need to
! 	     set calls_read_all, we can determine the precise reads
! 	     ourself.  */
! 	  if (local->pure_const_not_set_in_source
! 	      && local->pure_const_state == IPA_CONST)
! 	    local->pure_const_state = IPA_PURE;
  	}
      }
  }
*************** process_call_for_static_vars(struct cgra
*** 734,779 ****
  
  static tree
  scan_for_static_refs (tree *tp, 
! 		      int *walk_subtrees ATTRIBUTE_UNUSED, 
  		      void *data)
  {
    struct cgraph_node *fn = data;
    tree t = *tp;
    
    switch (TREE_CODE (t))  
      {
      case VAR_DECL:
        if (DECL_INITIAL (t))
  	walk_tree (&DECL_INITIAL (t), scan_for_static_refs, fn, visited_nodes);
        break;
  
      case MODIFY_EXPR:
        {
  	/* First look on the lhs and see what variable is stored to */
  	tree rhs = TREE_OPERAND (t, 1);
! 	check_lhs_var (fn, TREE_OPERAND (t, 0));
  	/* Next check the operands on the rhs to see if they are ok. */
  	switch (TREE_CODE_CLASS (TREE_CODE (rhs))) 
  	  {
  	  case tcc_binary:
! 	    check_rhs_var (fn, TREE_OPERAND (rhs, 0));
! 	    check_rhs_var (fn, TREE_OPERAND (rhs, 1));
  	    break;
  	  case tcc_unary:
  	  case tcc_reference:
! 	    check_rhs_var (fn, TREE_OPERAND (rhs, 0));
  	    break;
  	  case tcc_declaration:
! 	    check_rhs_var (fn, rhs);
  	    break;
  	  case tcc_expression:
  	    switch (TREE_CODE (rhs)) 
  	      {
  	      case ADDR_EXPR:
! 		check_rhs_var (fn, rhs);
  		break;
  	      case CALL_EXPR: 
! 		process_call_for_static_vars (fn, rhs);
  		break;
  	      default:
  		break;
--- 883,935 ----
  
  static tree
  scan_for_static_refs (tree *tp, 
! 		      int *walk_subtrees, 
  		      void *data)
  {
    struct cgraph_node *fn = data;
    tree t = *tp;
+   ipa_local_static_vars_info_t local = NULL;
+   if (fn)
+     local = fn->static_vars_info->local;
    
    switch (TREE_CODE (t))  
      {
      case VAR_DECL:
        if (DECL_INITIAL (t))
  	walk_tree (&DECL_INITIAL (t), scan_for_static_refs, fn, visited_nodes);
+       *walk_subtrees = 0;
        break;
  
      case MODIFY_EXPR:
        {
  	/* First look on the lhs and see what variable is stored to */
  	tree rhs = TREE_OPERAND (t, 1);
! 	check_lhs_var (local, TREE_OPERAND (t, 0));
! 
  	/* Next check the operands on the rhs to see if they are ok. */
  	switch (TREE_CODE_CLASS (TREE_CODE (rhs))) 
  	  {
  	  case tcc_binary:
! 	    check_rhs_var (local, TREE_OPERAND (rhs, 0));
! 	    check_rhs_var (local, TREE_OPERAND (rhs, 1));
  	    break;
  	  case tcc_unary:
+ 	    check_rhs_var (local, TREE_OPERAND (rhs, 0));
+ 	    break;
  	  case tcc_reference:
! 	    check_rhs_var (local, rhs);
  	    break;
  	  case tcc_declaration:
! 	    check_rhs_var (local, rhs);
  	    break;
  	  case tcc_expression:
  	    switch (TREE_CODE (rhs)) 
  	      {
  	      case ADDR_EXPR:
! 		check_rhs_var (local, rhs);
  		break;
  	      case CALL_EXPR: 
! 		process_call_for_static_vars (local, rhs);
  		break;
  	      default:
  		break;
*************** scan_for_static_refs (tree *tp, 
*** 782,797 ****
  	  default:
  	    break;
  	  }
        }
        break;
!       
!       
      case CALL_EXPR: 
!       process_call_for_static_vars (fn, t);
        break;
        
      case ASM_EXPR:
!       get_asm_expr_operands (fn, t);
        break;
        
      default:
--- 938,973 ----
  	  default:
  	    break;
  	  }
+ 	*walk_subtrees = 0;
        }
        break;
! 
!     case ADDR_EXPR:
!       /* This case is here to find addresses on rhs of constructors in
! 	 decl_initial of static variables. */
!       check_rhs_var (local, t);
!       *walk_subtrees = 0;
!       break;
! 
!     case LABEL_EXPR:
!       if (DECL_NONLOCAL (TREE_OPERAND (t, 0)))
! 	{
! 	  /* Target of long jump. */
! 	  local->calls_read_all = true;
! 	  local->calls_write_all = true;
! 	  if (local->pure_const_not_set_in_source)
! 	    local->pure_const_state = IPA_NEITHER;
! 	}
!       break;
! 
      case CALL_EXPR: 
!       process_call_for_static_vars (local, t);
!       *walk_subtrees = 0;
        break;
        
      case ASM_EXPR:
!       get_asm_expr_operands (local, t);
!       *walk_subtrees = 0;
        break;
        
      default:
*************** scan_for_static_refs (tree *tp, 
*** 800,812 ****
    return NULL;
  }
  
  /* Lookup the tree node for the static variable that has UID and
     conver the name to a string for debugging.  */
  
  static const char *
  get_static_name_by_uid (int index)
  {
!   splay_tree_node stn = splay_tree_lookup (static_vars_to_consider_by_uid, index);
    if (stn)
      return lang_hooks.decl_printable_name ((tree)(stn->value), 2);
    return NULL;
--- 976,1000 ----
    return NULL;
  }
  
+ /* Lookup the tree node for the static variable that has UID.  */
+ static tree
+ get_static_decl_by_uid (int index)
+ {
+   splay_tree_node stn = 
+     splay_tree_lookup (static_vars_to_consider_by_uid, index);
+   if (stn)
+     return (tree)stn->value;
+   return NULL;
+ }
+ 
  /* Lookup the tree node for the static variable that has UID and
     conver the name to a string for debugging.  */
  
  static const char *
  get_static_name_by_uid (int index)
  {
!   splay_tree_node stn = 
!     splay_tree_lookup (static_vars_to_consider_by_uid, index);
    if (stn)
      return lang_hooks.decl_printable_name ((tree)(stn->value), 2);
    return NULL;
*************** propagate_bits (struct cgraph_node *x)
*** 835,845 ****
  	{
  	  if (y->static_vars_info)
  	    {
! 	      ipa_static_vars_info_t y_info; 
! 	      ipa_global_static_vars_info_t y_global;
! 	      y_info = y->static_vars_info;
! 	      y_global = y_info->global;
  	      
  	      if (x_global->statics_read_by_decl_uid != all_module_statics)
  		{
  		  if (y_global->statics_read_by_decl_uid 
--- 1023,1041 ----
  	{
  	  if (y->static_vars_info)
  	    {
! 	      ipa_static_vars_info_t y_info = y->static_vars_info;
! 	      ipa_global_static_vars_info_t y_global = y_info->global;
  	      
+ 	      if (x_global->pure_const_state < y_global->pure_const_state)
+ 		{
+ 		  if (dump_file)
+ 		  fprintf (dump_file, "$$$$raising level for call: %s(%d) -> %s(%d)\n",  
+ 			   lang_hooks.decl_printable_name(x->decl, 2), 
+ 			   x_global->pure_const_state,
+ 			   lang_hooks.decl_printable_name(y->decl, 2),
+ 			   y_global->pure_const_state); 
+ 		  x_global->pure_const_state = y_global->pure_const_state;
+ 		}
  	      if (x_global->statics_read_by_decl_uid != all_module_statics)
  		{
  		  if (y_global->statics_read_by_decl_uid 
*************** propagate_bits (struct cgraph_node *x)
*** 878,884 ****
  	    }
  	  else 
  	    {
! 
  	    }
  	}
      }
--- 1074,1080 ----
  	    }
  	  else 
  	    {
! 	      abort ();
  	    }
  	}
      }
*************** merge_callee_local_info (struct cgraph_n
*** 923,930 ****
  	      bitmap_a_or_b (x_l->statics_written_by_decl_uid,
  			     x_l->statics_written_by_decl_uid,
  			     y_l->statics_written_by_decl_uid);
! 	      target->local.calls_read_all |= y->local.calls_read_all;
! 	      target->local.calls_write_all |= y->local.calls_write_all;
  	      merge_callee_local_info (target, y);
  	    }
  	  else 
--- 1119,1126 ----
  	      bitmap_a_or_b (x_l->statics_written_by_decl_uid,
  			     x_l->statics_written_by_decl_uid,
  			     y_l->statics_written_by_decl_uid);
! 	      x_l->calls_read_all |= y_l->calls_read_all;
! 	      x_l->calls_write_all |= y_l->calls_write_all;
  	      merge_callee_local_info (target, y);
  	    }
  	  else 
*************** merge_callee_local_info (struct cgraph_n
*** 942,959 ****
    x->aux = NULL;
  }
  
! /* The init routine for analyzing global static variable usage. See
     comments at top for description.  */
  
  static void 
  ipa_init (void) 
  {
    memory_identifier_string = build_string(7, "memory");
  
    static_vars_to_consider_by_uid =
      splay_tree_new_ggc (splay_tree_compare_ints);
  
    module_statics_escape = BITMAP_XMALLOC ();
    all_module_statics = BITMAP_XMALLOC ();
  
    /* There are some shared nodes, in particular the initializers on
--- 1138,1158 ----
    x->aux = NULL;
  }
  
! /* The init routine for analyzing global static variable usage.  See
     comments at top for description.  */
  
  static void 
  ipa_init (void) 
  {
+   initialization_status = RUNNING;
+ 
    memory_identifier_string = build_string(7, "memory");
  
    static_vars_to_consider_by_uid =
      splay_tree_new_ggc (splay_tree_compare_ints);
  
    module_statics_escape = BITMAP_XMALLOC ();
+   module_statics_written = BITMAP_XMALLOC ();
    all_module_statics = BITMAP_XMALLOC ();
  
    /* There are some shared nodes, in particular the initializers on
*************** ipa_init (void) 
*** 965,971 ****
  
  /* Check out the rhs of a static or global initialization VNODE to see
     if any of them contain addressof operations.  Note that some of
!    these variables may not even be referenced in the code in this
     compilation unit but their right hand sides may contain references
     to variables defined within this unit.  */
  
--- 1164,1170 ----
  
  /* Check out the rhs of a static or global initialization VNODE to see
     if any of them contain addressof operations.  Note that some of
!    these variables may  not even be referenced in the code in this
     compilation unit but their right hand sides may contain references
     to variables defined within this unit.  */
  
*************** static void 
*** 973,984 ****
  analyze_variable (struct cgraph_varpool_node *vnode)
  {
    tree global = vnode->decl;
!   if (!memory_identifier_string) ipa_init();
  
    if (TREE_CODE (global) == VAR_DECL)
!     if (DECL_INITIAL (global)) 
!       walk_tree (&DECL_INITIAL (global), scan_for_static_refs, 
! 		 NULL, visited_nodes);
  }
  
  /* This is the main routine for finding the reference patterns for
--- 1172,1201 ----
  analyze_variable (struct cgraph_varpool_node *vnode)
  {
    tree global = vnode->decl;
!   switch (initialization_status) 
!     {
!     case UNINITIALIZED:
!       ipa_init();
!       break;
! 
!     case RUNNING:
!       break;
! 
!     case FINISHED:
! /*       fprintf(stderr,  */
! /* 	      "AV analyze_variable called after execute for variable %s\n" , */
! /* 	      lang_hooks.decl_printable_name (global, 2)); */
!       /*abort ();*/
!       break;
!     }
  
    if (TREE_CODE (global) == VAR_DECL)
!     {
!       if (DECL_INITIAL (global)) 
! 	walk_tree (&DECL_INITIAL (global), scan_for_static_refs, 
! 		   NULL, visited_nodes);
!     } 
!   else abort();
  }
  
  /* This is the main routine for finding the reference patterns for
*************** analyze_function (struct cgraph_node *fn
*** 992,1001 ****
    ipa_local_static_vars_info_t l
      = xcalloc (1, sizeof (struct ipa_local_static_vars_info_d));
    var_ann_t var_ann = get_var_ann (fn->decl);
!   tree step;
!   basic_block this_block;
  
!   if (!memory_identifier_string) ipa_init();
  
    /* Add the info to the tree's annotation.  */
    fn->static_vars_info = info;
--- 1209,1236 ----
    ipa_local_static_vars_info_t l
      = xcalloc (1, sizeof (struct ipa_local_static_vars_info_d));
    var_ann_t var_ann = get_var_ann (fn->decl);
!   tree decl = fn->decl;
! 
!   switch (initialization_status) 
!     {
!     case UNINITIALIZED:
!       ipa_init();
!       break;
  
!     case RUNNING:
!       break;
! 
!     case FINISHED:
!       abort ();
!     }
! 
! /*   fprintf (stderr, "AF called %s(%d)\n", cgraph_node_name (fn), fn->uid); */
! /*  		  fprintf(stderr, "decl=%x\n", */
! /*  			  fn->decl); */
! /* 		  fprintf(stderr, "cfun=%x\n", */
! /* 			  DECL_STRUCT_FUNCTION (fn->decl)); */
! /* 		  fprintf(stderr, "cfg=%x\n", */
! /* 			  DECL_STRUCT_FUNCTION (fn->decl) -> cfg); */
  
    /* Add the info to the tree's annotation.  */
    fn->static_vars_info = info;
*************** analyze_function (struct cgraph_node *fn
*** 1007,1037 ****
    l->statics_read_by_ann_uid = BITMAP_XMALLOC ();
    l->statics_written_by_ann_uid = BITMAP_XMALLOC ();
  
    if (dump_file)
      fprintf (dump_file, "\n local analysis of %s", cgraph_node_name (fn));
    
    /* Walk over any private statics that may take addresses of functions.  */
!   if (TREE_CODE (DECL_INITIAL (fn->decl)) == BLOCK)
      {
!       for (step = BLOCK_VARS (DECL_INITIAL (fn->decl));
  	   step;
  	   step = TREE_CHAIN (step))
  	if (DECL_INITIAL (step))
! 	  walk_tree (&DECL_INITIAL (step), scan_for_static_refs, fn, visited_nodes);
      }
    /* Also look here for private statics.  */
!   if (DECL_STRUCT_FUNCTION (fn->decl))
!     for (step = DECL_STRUCT_FUNCTION (fn->decl)->unexpanded_var_list;
! 	 step;
! 	 step = TREE_CHAIN (step))
!       {
! 	tree decl = TREE_VALUE (step);
! 	if (DECL_INITIAL (decl) && TREE_STATIC (decl))
! 	  walk_tree (&DECL_INITIAL (decl), scan_for_static_refs, fn, visited_nodes);
!       }
!   FOR_EACH_BB (this_block)
      {
!       walk_tree (&this_block->stmt_list, scan_for_static_refs, fn, visited_nodes);
      }
  }
  
--- 1242,1309 ----
    l->statics_read_by_ann_uid = BITMAP_XMALLOC ();
    l->statics_written_by_ann_uid = BITMAP_XMALLOC ();
  
+   l->pure_const_not_set_in_source = true;
+   l->pure_const_state = IPA_CONST;
+ 
+   /* If this is a volatile function, do not touch this unless it has
+      been marked as const or pure by the front end.  */
+   if (TREE_THIS_VOLATILE (decl))
+     l->pure_const_state = IPA_NEITHER;
+ 
+   if (TREE_READONLY (decl))
+     {
+       l->pure_const_state = IPA_CONST;
+       l->pure_const_not_set_in_source = false;
+     }
+   if (DECL_IS_PURE (decl))
+     {
+       l->pure_const_state = IPA_PURE;
+       l->pure_const_not_set_in_source = false;
+     }
+ 
    if (dump_file)
      fprintf (dump_file, "\n local analysis of %s", cgraph_node_name (fn));
    
+   {
+     struct function *this_cfun = DECL_STRUCT_FUNCTION (decl);
+     basic_block this_block;
+ 
+     FOR_EACH_BB_FN (this_block, this_cfun)
+       {
+ 	block_stmt_iterator bsi;
+ 	for (bsi = bsi_start (this_block); !bsi_end_p (bsi); bsi_next (&bsi))
+ 	  walk_tree (bsi_stmt_ptr (bsi), scan_for_static_refs, 
+ 		     fn, visited_nodes);
+       }
+   }
+ 
+   /* FIXME - When Jan gets the local statics promoted to the global
+      variable list, the next two loops go away.  */
    /* Walk over any private statics that may take addresses of functions.  */
!   if (TREE_CODE (DECL_INITIAL (decl)) == BLOCK)
      {
!       tree step;
!       for (step = BLOCK_VARS (DECL_INITIAL (decl));
  	   step;
  	   step = TREE_CHAIN (step))
  	if (DECL_INITIAL (step))
! 	  walk_tree (&DECL_INITIAL (step), scan_for_static_refs, 
! 		     fn, visited_nodes);
      }
+   
    /* Also look here for private statics.  */
!   if (DECL_STRUCT_FUNCTION (decl))
      {
!       tree step;
!       for (step = DECL_STRUCT_FUNCTION (decl)->unexpanded_var_list;
! 	   step;
! 	   step = TREE_CHAIN (step))
! 	{
! 	  tree var = TREE_VALUE (step);
! 	  if (DECL_INITIAL (var) && TREE_STATIC (var))
! 	    walk_tree (&DECL_INITIAL (var), scan_for_static_refs, 
! 		       fn, visited_nodes);
! 	}
      }
  }
  
*************** static_execute (void)
*** 1050,1056 ****
    int order_pos = order_pos = reduced_inorder (order, false);
    int i;
  
!   if (!memory_identifier_string) ipa_init();
    pointer_set_destroy (visited_nodes);
    visited_nodes = NULL;
    if (dump_file) 
--- 1322,1344 ----
    int order_pos = order_pos = reduced_inorder (order, false);
    int i;
  
!   switch (initialization_status) 
!     {
!     case UNINITIALIZED:
!       ipa_init();
!       break;
! 
!     case RUNNING:
!       break;
! 
!     case FINISHED:
!       abort ();
!     }
! 
!   /* This will force an abort if analyze_variable or analyze_function
!      is called after static_execute.  */
!   initialization_status = FINISHED;
! 
    pointer_set_destroy (visited_nodes);
    visited_nodes = NULL;
    if (dump_file) 
*************** static_execute (void)
*** 1061,1075 ****
--- 1349,1405 ----
    {
      int index;
      bitmap_iterator bi;
+     bitmap module_statics_readonly = BITMAP_XMALLOC ();
+     bitmap module_statics_const = BITMAP_XMALLOC ();
+     bitmap bm_temp = BITMAP_XMALLOC ();
  
      EXECUTE_IF_SET_IN_BITMAP (module_statics_escape, 0, index, bi)
        {
  	splay_tree_remove (static_vars_to_consider_by_uid, index);
        }
+ 
      bitmap_operation (all_module_statics, all_module_statics,
  		      module_statics_escape, BITMAP_AND_COMPL);
  
+     bitmap_operation (module_statics_readonly, all_module_statics,
+ 		      module_statics_written, BITMAP_AND_COMPL);
+ 
+     /* If the address is not taken, we can unset the addressable bit
+        on this variable.  */
+     EXECUTE_IF_SET_IN_BITMAP (all_module_statics, 0, index, bi)
+       {
+ 	tree var = get_static_decl_by_uid (index);
+  	TREE_ADDRESSABLE (var) = 0;
+ 	if (dump_file) 
+ 	  fprintf (dump_file, "&&&&NOT TREE ADDRESSABLE VAR %s\n",
+ 		   get_static_name_by_uid (index));
+       }
+ 
+     /* If the variable is never written, we can set the TREE_READONLY
+        flag.  Additionally if it has a DECL_INITIAL that is made up of
+        constants we can treat the entire global as a constant.  */
+ 
+     bitmap_operation (module_statics_readonly, all_module_statics,
+ 		      module_statics_written, BITMAP_AND_COMPL);
+     EXECUTE_IF_SET_IN_BITMAP (module_statics_readonly, 0, index, bi)
+       {
+ 	tree var = get_static_decl_by_uid (index);
+ 	TREE_READONLY (var) = 1;
+ 	if (dump_file)
+ 	  fprintf (dump_file, "&&&&READONLY VAR %s\n", 
+ 		   get_static_name_by_uid (index)); 
+ 	if (DECL_INITIAL (var)
+ 	    && is_gimple_min_invariant (DECL_INITIAL (var)))
+ 	  {
+  	    bitmap_set_bit (module_statics_const, index);
+ 	    if (dump_file)
+ 	      fprintf (dump_file, "&&&&READONLY CONST %s\n",
+ 		       get_static_name_by_uid (index));
+ 	  }
+       }
+ 
      BITMAP_XFREE(module_statics_escape);
+     BITMAP_XFREE(module_statics_written);
  
      if (0) {
        FILE *ok_statics_file = fopen("/home/zadeck/ok_statics", "r");
*************** static_execute (void)
*** 1095,1109 ****
  		   get_static_name_by_uid (index));
  	}
  
-     /* Remove any variables from the local maps that are not in
-        all_module_statics.  This will include all of the variables
-        that were found to escape in the function scanning.  */
      for (i = 0; i < order_pos; i++ )
        {
  	ipa_local_static_vars_info_t l;
  	node = order[i];
  	l = node->static_vars_info->local;
  
  	bitmap_a_and_b (l->statics_read_by_decl_uid, 
  			l->statics_read_by_decl_uid,
  			all_module_statics);
--- 1425,1523 ----
  		   get_static_name_by_uid (index));
  	}
  
      for (i = 0; i < order_pos; i++ )
        {
  	ipa_local_static_vars_info_t l;
  	node = order[i];
  	l = node->static_vars_info->local;
  
+ 	/* First we check the bitmaps to see if there is anything in
+ 	   them that would disqualify the CONST or PURE status. */
+ 	/* WARNING, this case statement has drop throughs.  */
+ 	if (l->pure_const_not_set_in_source)
+ 	  switch (l->pure_const_state)
+ 	    {
+ 	    case IPA_CONST:
+ 	      /* Any bits in the read bitmap that are not in the
+ 		 module_statics_const bitmap disqualify a function from
+ 		 being const.  There is no reason to check the
+ 		 calls_read_all flag since if the bit has been set the
+ 		 function cannot have been marked const.  */
+ 	      bitmap_operation (bm_temp, l->statics_read_by_decl_uid,
+ 				module_statics_const, BITMAP_AND_COMPL);
+ 	      if (bitmap_first_set_bit(bm_temp) != -1)
+ 		l->pure_const_state = IPA_PURE;
+ 	      else 
+ 		{
+ 		  tree old_decl = current_function_decl;
+ 		  /* Const functions cannot have back edges (an
+ 		     indication of possible infinite loop side
+ 		     effect.  */
+ 
+ 		  current_function_decl = node->decl;
+ 		  push_cfun (DECL_STRUCT_FUNCTION (node->decl));
+ /* 		  fprintf(stderr, "decl=%x\n", */
+ /* 			  node->decl); */
+ /* 		  fprintf(stderr, "cfun=%x\n", */
+ /* 			  DECL_STRUCT_FUNCTION (node->decl)); */
+ /* 		  fprintf(stderr, "cfg=%x\n", */
+ /* 			  DECL_STRUCT_FUNCTION (node->decl) -> cfg); */
+ 
+ /* 		  fprintf (stderr, "n_basic_block=%d\n",  */
+ /* 			   n_basic_blocks); */
+ 
+ 		  /* This is an utter HACK FIXEME PLEASE!!!!!!!  The
+ 		     C++ front end, for reasons that are only apparent
+ 		     to it's designers, decides that it was only
+ 		     kidding when it generated some of the functions.
+ 		     As a further joke it then decides, after
+ 		     compilation is underway, to null out the
+ 		     DECL_STRUCT_FUNCTION (node->decl) field of these
+ 		     function so that no one can use them.  What a
+ 		     funny joke!!!!  */
+ 		  
+ 		  if (DECL_STRUCT_FUNCTION (node->decl))
+ 		    {
+ 		      if (mark_dfs_back_edges ())
+ 			l->pure_const_state = IPA_PURE;
+ 		    }
+ 		  else 
+ 		    {
+ /* 		      fprintf (stderr, "jan it is still happening\n"); */
+ 		      l->pure_const_state = IPA_NEITHER;
+ 		    }
+ 
+ 		  current_function_decl = old_decl;
+ 		  pop_cfun ();
+ 		}
+ 	      
+ 	    case IPA_PURE:
+ 	      /* There is no reason to check the calls_write_all flag
+ 		 since if the bit has been set the function cannot have
+ 		 been marked const.  Any bits in the function's write
+ 		 bitmap disqualify pure and const.  */
+ 	      if (bitmap_first_set_bit(l->statics_written_by_decl_uid) != -1)
+ 		l->pure_const_state = IPA_NEITHER;
+ 	      
+ 	    default:
+ 	      break;
+ 	    }
+ 
+ /* 	if (l->pure_const_state == IPA_PURE) */
+ /* 	  { */
+ /* 	    fprintf (stderr, " before %s(%d)=%d\n", cgraph_node_name (node),  */
+ /* 		     node->uid, l->pure_const_state); */
+ /* 	  l->pure_const_state = IPA_NEITHER; */
+ 
+ 
+ /* 	  } */
+ 
+ 	
+ 	/* Any variables that are not in all_module_statics are
+ 	   removed from the local maps.  This will include all of the
+ 	   variables that were found to escape in the function
+ 	   scanning.  */
+ 
  	bitmap_a_and_b (l->statics_read_by_decl_uid, 
  			l->statics_read_by_decl_uid,
  			all_module_statics);
*************** static_execute (void)
*** 1111,1116 ****
--- 1525,1534 ----
  			l->statics_written_by_decl_uid,
  			all_module_statics);
        }
+ 
+     BITMAP_XFREE(module_statics_readonly);
+     BITMAP_XFREE(module_statics_const);
+     BITMAP_XFREE(bm_temp);
    }
  
    if (dump_file)
*************** static_execute (void)
*** 1160,1165 ****
--- 1578,1584 ----
        
        bool read_all;
        bool write_all;
+       enum ipa_static_pure_const_state pure_const_state;
  
        node = order[i];
        node_info = node->static_vars_info;
*************** static_execute (void)
*** 1173,1188 ****
        node_info->global = node_g;
        node_l = node_info->local;
  
!       read_all = node->local.calls_read_all;
!       write_all = node->local.calls_write_all;
  
        /* If any node in a cycle is calls_read_all or calls_write_all
  	 they all are. */
        w = node->next_cycle;
        while (w)
  	{
! 	  read_all |= w->local.calls_read_all;
! 	  write_all |= w->local.calls_write_all;
  	  w = w->next_cycle;
  	}
  
--- 1592,1612 ----
        node_info->global = node_g;
        node_l = node_info->local;
  
!       read_all = node_l->calls_read_all;
!       write_all = node_l->calls_write_all;
!       pure_const_state = node_l->pure_const_state;
  
        /* If any node in a cycle is calls_read_all or calls_write_all
  	 they all are. */
        w = node->next_cycle;
        while (w)
  	{
! 	  ipa_local_static_vars_info_t w_l = w->static_vars_info->local;
! 	  read_all |= w_l->calls_read_all;
! 	  write_all |= w_l->calls_write_all;
! 	  if (node_l->pure_const_state < w_l->pure_const_state)
! 	    pure_const_state = w_l->pure_const_state;
! 
  	  w = w->next_cycle;
  	}
  
*************** static_execute (void)
*** 1205,1210 ****
--- 1629,1638 ----
  		       node_l->statics_written_by_decl_uid);
  	}
  
+       /* Copy the region's pure_const_state which is shared by all
+ 	 nodes in the region.  */
+       node_g->pure_const_state = pure_const_state;
+ 
        w = node->next_cycle;
        while (w)
  	{
*************** static_execute (void)
*** 1229,1237 ****
  	  w = w->next_cycle;
  	}
  
!       propagate_bits (node);
! 
!       w = node->next_cycle;
        while (w)
  	{
  	  propagate_bits (w);
--- 1657,1663 ----
  	  w = w->next_cycle;
  	}
  
!       w = node;
        while (w)
  	{
  	  propagate_bits (w);
*************** static_execute (void)
*** 1340,1347 ****
  			  all_module_statics,
  			  node_g->statics_written_by_decl_uid,
  			  BITMAP_AND_COMPL);
-       w = node;
  
        while (w)
  	{
  	  struct cgraph_node * last = w;
--- 1766,1773 ----
  			  all_module_statics,
  			  node_g->statics_written_by_decl_uid,
  			  BITMAP_AND_COMPL);
  
+       w = node;
        while (w)
  	{
  	  struct cgraph_node * last = w;
*************** static_execute (void)
*** 1349,1354 ****
--- 1775,1801 ----
  	  ipa_local_static_vars_info_t w_l = w_info->local;
  	  w_l->var_anns_valid = false;
  
+ 	  if (w_l->pure_const_not_set_in_source) 
+ 	    switch (node_g->pure_const_state)
+ 	      {
+ 	      case IPA_CONST:
+   		TREE_READONLY (w->decl) = 1;
+ 		if (dump_file)
+ 		  fprintf (dump_file, "$$$$CONST: %s\n",  
+ 			   lang_hooks.decl_printable_name(w->decl, 2)); 
+ 		break;
+ 		
+ 	      case IPA_PURE:
+   		DECL_IS_PURE (w->decl) = 1;
+ 		if (dump_file)
+ 		  fprintf (dump_file, "$$$$PURE: %s\n",  
+ 			   lang_hooks.decl_printable_name(w->decl, 2)); 
+ 		break;
+ 		
+ 	      default:
+ 		break;
+ 	      }
+ 	  
  	  w = w->next_cycle;
  	  last->next_cycle = NULL;
  	}
*************** static_execute (void)
*** 1357,1363 ****
    free (order);
  }
  
- 
  static bool
  gate_static_vars (void)
  {
--- 1804,1809 ----
*************** struct tree_opt_pass pass_ipa_static =
*** 1371,1377 ****
    analyze_function,                     /* IPA function */
    analyze_variable,		        /* IPA variable */
    static_execute,			/* execute */
!   NULL, NULL,				/* IPA modification */
    NULL,					/* sub */
    NULL,					/* next */
    0,					/* static_pass_number */
--- 1817,1824 ----
    analyze_function,                     /* IPA function */
    analyze_variable,		        /* IPA variable */
    static_execute,			/* execute */
!   NULL,                                 /* IPA function */
!   NULL,	                                /* IPA variable */
    NULL,					/* sub */
    NULL,					/* next */
    0,					/* static_pass_number */
*************** struct tree_opt_pass pass_ipa_static =
*** 1384,1388 ****
    0					/* letter */
  };
  
- 
  #include "gt-ipa-static-vars-anal.h"
--- 1831,1834 ----
Index: ipa-static.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/ipa-static.h,v
retrieving revision 1.1.2.1
diff -c -3 -p -r1.1.2.1 ipa-static.h
*** ipa-static.h	8 Nov 2004 19:17:49 -0000	1.1.2.1
--- ipa-static.h	3 Dec 2004 03:20:14 -0000
*************** Software Foundation, 59 Temple Place - S
*** 24,29 ****
--- 24,39 ----
  #include "bitmap.h"
  #include "tree.h"
  
+ /* Lattice values for const and pure functions.  Everything starts out
+    being const, then may drop to pure and then neither depending on
+    what is found.  */
+ enum ipa_static_pure_const_state
+ {
+   IPA_CONST,
+   IPA_PURE,
+   IPA_NEITHER
+ };
+ 
  /* The static variables defined within the compilation unit that are
     loaded or stored directly by function that owns this structure.  */ 
  
*************** struct ipa_local_static_vars_info_d 
*** 34,44 ****
--- 44,68 ----
    bitmap statics_read_by_ann_uid;
    bitmap statics_written_by_ann_uid;
  
+   enum ipa_static_pure_const_state pure_const_state;
+ 
+   /* False if the front end set either TREE_READONLY or DECL_IS_PURE
+      in front end.  If false, do not change the theses flags no matter
+      what we find.  */
+   bool pure_const_not_set_in_source;
+ 
    /* Var_anns_valid is reset at the start of compilation for each
       function because the indexing that the "_var_anns" is based
       on is invalidated between function compilations.  This allows for
       lazy creation of the "_var_ann" variables.  */
    bool var_anns_valid;
+   /* Set when this function calls another function external to the
+      compilation unit or if the function has a asm clobber of memory.
+      In general, such calls are modeled as reading and writing all
+      variables (both bits on) but sometime there are attributes on the
+      called function so we can do better.  */
+   bool calls_read_all;
+   bool calls_write_all;
  };
  
  struct ipa_global_static_vars_info_d
*************** struct ipa_global_static_vars_info_d
*** 52,57 ****
--- 76,83 ----
    bitmap statics_not_read_by_ann_uid;
    bitmap statics_not_written_by_ann_uid;
  
+   enum ipa_static_pure_const_state pure_const_state;
+ 
    /* Var_anns_valid is reset at the start of compilation for each
       function because the indexing that the "_var_anns" is based
       on is invalidated between function compilations.  This allows for
Index: ipa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/ipa.c,v
retrieving revision 1.1.2.2
diff -c -3 -p -r1.1.2.2 ipa.c
*** ipa.c	2 Dec 2004 15:32:17 -0000	1.1.2.2
--- ipa.c	3 Dec 2004 03:20:14 -0000
*************** cgraph_remove_unreachable_nodes (bool be
*** 99,104 ****
--- 99,105 ----
    bool changed = false;
    int insns = 0;
  
+   return false;
  #ifdef ENABLE_CHECKING
    verify_cgraph ();
  #endif
Index: passes.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/passes.c,v
retrieving revision 2.2.4.18
diff -c -3 -p -r2.2.4.18 passes.c
*** passes.c	29 Nov 2004 03:09:10 -0000	2.2.4.18
--- passes.c	3 Dec 2004 03:20:15 -0000
*************** rest_of_handle_cfg (void)
*** 875,902 ****
      cleanup_cfg (CLEANUP_EXPENSIVE
  		 | (flag_thread_jumps ? CLEANUP_THREADING : 0));
  
-   /* It may make more sense to mark constant functions after dead code is
-      eliminated by life_analysis, but we need to do it early, as -fprofile-arcs
-      may insert code making function non-constant, but we still must consider
-      it as constant, otherwise -fbranch-probabilities will not read data back.
- 
-      life_analysis rarely eliminates modification of external memory.
- 
-      FIXME: now with tree based profiling we are in the trap described above
-      again.  It seems to be easiest to disable the optimization for time
-      being before the problem is either solved by moving the transformation
-      to the IPA level (we need the CFG for this) or the very early optimization
-      passes are made to ignore the const/pure flags so code does not change.  */
-   if (optimize
-       && (!flag_tree_based_profiling
- 	  || (!profile_arc_flag && !flag_branch_probabilities)))
-     {
-       /* Alias analysis depends on this information and mark_constant_function
-        depends on alias analysis.  */
-       reg_scan (get_insns (), max_reg_num (), 1);
-       mark_constant_function ();
-     }
- 
    close_dump_file (DFI_cfg, print_rtl_with_bb, get_insns ());
  }
  
--- 875,880 ----
Index: rtl.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/rtl.h,v
retrieving revision 1.362.2.34.2.14
diff -c -3 -p -r1.362.2.34.2.14 rtl.h
*** rtl.h	22 Oct 2004 17:34:55 -0000	1.362.2.34.2.14
--- rtl.h	3 Dec 2004 03:20:16 -0000
*************** extern int canon_true_dependence (rtx, e
*** 2155,2161 ****
  extern int read_dependence (rtx, rtx);
  extern int anti_dependence (rtx, rtx);
  extern int output_dependence (rtx, rtx);
- extern void mark_constant_function (void);
  extern void init_alias_once (void);
  extern void init_alias_analysis (void);
  extern void end_alias_analysis (void);
--- 2155,2160 ----
Index: tree-cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-cfg.c,v
retrieving revision 1.1.4.267.2.30
diff -c -3 -p -r1.1.4.267.2.30 tree-cfg.c
*** tree-cfg.c	28 Nov 2004 17:59:35 -0000	1.1.4.267.2.30
--- tree-cfg.c	3 Dec 2004 03:20:17 -0000
*************** need_fake_edge_p (tree t)
*** 4980,4985 ****
--- 4980,4993 ----
       figured out from the RTL in mark_constant_function, and
       the counter incrementation code from -fprofile-arcs
       leads to different results from -fbranch-probabilities.  */
+ 
+   /* FIXME The previous comment is wrong in many ways.  We now allow
+      PURE functions to have loops so if the fake edge is because of
+      this, PURE would need to be checked.  Also, we do the analysis
+      earlier than we used to as well as there are also functions which
+      were marked in the source. Currently we mark these function in
+      ipa-static-vars-analysis. */
+ 
    call = get_call_expr_in (t);
    if (call
        && !(call_expr_flags (call) & 
Index: tree-inline.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-inline.c,v
retrieving revision 1.26.2.83.2.17
diff -c -3 -p -r1.26.2.83.2.17 tree-inline.c
*** tree-inline.c	2 Dec 2004 11:20:08 -0000	1.26.2.83.2.17
--- tree-inline.c	3 Dec 2004 03:20:18 -0000
*************** inline_forbidden_p (tree fndecl)
*** 1531,1537 ****
  
    /* We should always be called after the CFG is built. */
    if (basic_block_info_for_function (DECL_STRUCT_FUNCTION (fndecl))== (varray_type) 0)
!     abort ();
  
    FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (fndecl))
      for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
--- 1531,1541 ----
  
    /* We should always be called after the CFG is built. */
    if (basic_block_info_for_function (DECL_STRUCT_FUNCTION (fndecl))== (varray_type) 0)
!     {
!       fprintf (stderr, "\nunlowered function:%s",
! 	       lang_hooks.decl_printable_name (fndecl, 2));
!       abort ();
!     }
  
    FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (fndecl))
      for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
Index: varasm.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/varasm.c,v
retrieving revision 1.295.2.44.2.13
diff -c -3 -p -r1.295.2.44.2.13 varasm.c
*** varasm.c	25 Sep 2004 23:18:06 -0000	1.295.2.44.2.13
--- varasm.c	3 Dec 2004 03:20:19 -0000
*************** mark_decl_referenced (tree decl)
*** 1823,1829 ****
    if (TREE_CODE (decl) == FUNCTION_DECL)
      cgraph_mark_needed_node (cgraph_node (decl));
    else if (TREE_CODE (decl) == VAR_DECL)
!     cgraph_varpool_mark_needed_node (cgraph_varpool_node (decl));
    /* else do nothing - we can get various sorts of CST nodes here,
       which do not need to be marked.  */
  }
--- 1823,1835 ----
    if (TREE_CODE (decl) == FUNCTION_DECL)
      cgraph_mark_needed_node (cgraph_node (decl));
    else if (TREE_CODE (decl) == VAR_DECL)
!     {
!       struct cgraph_varpool_node *node = cgraph_varpool_node (decl);
!       cgraph_varpool_mark_needed_node (node);
!       /* C++ frontend use mark_decl_references to force COMDAT variables
!          to be output that might appear dead otherwise.  */
!       node->force_output = true;
!     }
    /* else do nothing - we can get various sorts of CST nodes here,
       which do not need to be marked.  */
  }

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]