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]

Re: [trunk] patch to clean up handling of pure and constant functions.


Mark Mitchell wrote:
Kenneth Zadeck wrote:

But with the common we can be that aggressive. Given that the calls have to do the same thing based on their inputs, you can remove the second call if you have two calls in a row that have the same inputs.

Exactly so. In particular, if one such call is dominated by another, we can use the value returned by the dominating for the dominated call. By the time we re-use the value returned, we are sure that the call would terminate because it already terminated once before. :-)


This is an updated patch that addresses this concern. There are only two changes (not to mention a small bit of patch rot): I made the code in cselib.c and loop-invariant.c conservative with respect to this issue.

There were no changes at the tree level because it appears that most of the tree level is driven off TREE_SIDE_EFFECTS flag and this was already being set conservatively. It may be possible that there are places that i have missed. These are more likely to show up after the tuple merge when i let looping functions be pure or const. Then there will be a lot of functions that will fit this criteria and the code will be stressed a lot harder. At this point i am getting the right answers on the test cases that test this.

kenny

2008-04-23 Kenneth Zadeck <zadeck@naturalbridge.com>

  PATCH rtl/7335
  PATCH rtl/33826
  * see.c (see_copy_insn): Copy new pure const attributes for new
  call.
  * c-decl.c (merge_decls): Ditto.
  * postreload.c (record_opr_changes): Change CONST_OR_PURE_CALL_P
  to RTL_CONST_CALL_P and RTL_PURE_CALL_P.
  * tree.c (define_local_buitin): Rename DECL_IS_PURE to
  DECL_PURE_P.  Initialized DECL_LOOPING_CONST_PURE.
  (process_call_operands): Set tree_side_effects properly.
  * tree.h (TREE_READONLY_DECL_P): Removed.
  (DECL_IS_PURE): Renamed to DECL_PURE_P.
  (DECL_LOOPING_OR_CONST_P): New macro.
  (struct tree_function_decl): Added looping_const_or_pure_p.
  (ECF_*) Renumbered.
  (ECF_LOOPING_OR_CONST_P): New macro,
  * rtlanal.c (pure_const_p): Removed.
  * builtins.c (expand_builtin): Rename DECL_IS_PURE to DECL_PURE_P.
  * reorg.c (delete_prior_computation) Changed CONST_OR_PURE_CALL_P
  to RTL_CONST_CALL_P and RTL_PURE_CALL_P.
  * ipa-pure-const.c (pure_const_state_e): Added looping field.
  (check_decl, check_tree, check_call, scan_function): Initialize
  looping.
  (analyze_function): Rename DECL_IS_PURE to DECL_PURE_P.
  (static_execute): Set looping true for recursive functions.
  Undo setting state to IPA_NEITHER for recursive functions.
  * ifcvt.c (noce_can_store_speculate_p): Changed
  CONST_OR_PURE_CALL_P and pure_call_p to RTL_CONST_CALL_P.
  * dse.c (scan_insn): Ditto.
  * local_alloc (validate_equiv_mem, memref_used_between_p): Ditto.
  * gcse.c (oprs_not_seen_p) Changed CONST_OR_PURE_CALL_P to
  RTL_CONST_CALL_P and RTL_CONST_CALL_P.
  (store_killed_in_insn): Changed CONST_OR_PURE_CALL_P and
  pure_call_p to RTL_CONST_CALL_P.
  * gimplify.c (gimplify_call_expr): Clear side effects for
  non-looping pure and constant calls.
  * calls.c (emit_call_1): Set rtl flags from ecf flags.
  (flags_from_decl_or_type): Set ecf flags from decl flags.
  (initialize_argument_information): Turn off
  ECF_LOOPING_CONST_OR_PURE when turning off ECF_CONST.
  Change const to pure if callee_copies is true rather than just
  turning off const.
  (expand_call): Turn off ECF_LOOPING_PURE_CONST_CALL and remove old
  way of marking pure calls.
  (emit_library_call_value_1): Turn off ECF_LOOPING_PURE_CONST_CALL.
  Remove hack that was supposed to fix pr7335 and remove old
  way of marking pure calls.
  * emit-rtl.c (emit_copy_of_insn_after): Copy RTL_CONST_CALL_P,
  RTL_PURE_CALL_P, RTL_LOOPING_CONST_OR_PURE_CALL_P.
  * cselib.c (cselib_process_insn): Changed CONST_OR_PURE_CALL_P to
  RTL_CONST_CALL_P and RTL_CONST_CALL_P.
  * tree-ssa-pre.c (can_value_number_call): Fixed spacing.
  * loop-invariant.c (find_exits, find_invariant_bb): Changed
  CONST_OR_PURE_CALL_P to RTL_CONST_CALL_P and RTL_CONST_CALL_P.
  * sched-deps.c (schedule_analyze): Ditto.
  * rtl.h (struct rtx_def): Use call field, unchanging field, and
  return_val field of calls to represent pure and const function
  info.
  (CONST_OR_PURE_CALL_P): Deleted macro.
  (RTL_CONST_CALL_P, RTL_PURE_CALL_P,
  RTL_LOOPING_CONST_OR_PURE_CALL_P): New macros.
  * tree-inline.c (copy_body_r): Changed TREE_READONLY_DECL_P to
  TREE_READONLY.
  * tree-optimize.c (execute_fixup_cfg): Added test for
  ECF_LOOPING_CONST_OR_PURE.
  * c-common.c (handle_pure_attribute): Changed DECL_IS_PURE to
  DECL_PURE_P.
  * tree-cfg.c (update_call_expr_flags): Do not clear tree side
  effects for looping pure or const calls.
  * config/alpha/alpha.c (alpha_legitimize_address,
  alpha_emit_xfloating_libcall): Changed CONST_OR_PURE_CALL_P to
  RTL_CONST_CALL_P.
  * config/s390/s390.c (s390_emit_tls_call_insn): Ditto.
  * config/rs6000/rs6000.c (rs6000_legitimize_tls_address): Ditto.
  * config/mips/mips.c (mips_call_tls_get_addr): Ditto.
  * cfgrtl.c (need_fake_edge_p): Changed CONST_OR_PURE_CALL_P to
  RTL_CONST_CALL_P and RTL_CONST_CALL_P.
  * dce.c (deletable_insn_p): Allow non looping, non sibling, pure
  and const calls to be deleted.
  2008-04-09  Kenneth Zadeck <zadeck@naturalbridge.com>


java: 2008-04-23 Kenneth Zadeck <zadeck@naturalbridge.com>


* decl.c (java_init_decl_processing): Change DECL_IS_PURE to DECL_PURE_P. cp:

2008-04-23 Kenneth Zadeck <zadeck@naturalbridge.com>

  decl.c (duplicate_decls): Merge in DECL_PURE_P, TREE_READONLY,
  DECL_LOOPING_CONST_OR_PURE_P attributes.
  * rtti.c (build_dynamic_cast_1): Rename DECL_IS_PURE to
  DECL_PURE_P.


2008-04-23 Kenneth Zadeck <zadeck@naturalbridge.com>


  * trans-decl.c (gfc_get_extern_function_decl, build_function_decl):
  Rename DECL_IS_PURE to DECL_PURE_P.

Index: see.c
===================================================================
--- see.c	(revision 134565)
+++ see.c	(working copy)
@@ -2430,7 +2430,10 @@ see_copy_insn (rtx insn)
 	CALL_INSN_FUNCTION_USAGE (ret)
 	  = copy_rtx (CALL_INSN_FUNCTION_USAGE (insn));
       SIBLING_CALL_P (ret) = SIBLING_CALL_P (insn);
-      CONST_OR_PURE_CALL_P (ret) = CONST_OR_PURE_CALL_P (insn);
+      RTL_CONST_CALL_P (ret) = RTL_CONST_CALL_P (insn);
+      RTL_PURE_CALL_P (ret) = RTL_PURE_CALL_P (insn);
+      RTL_LOOPING_CONST_OR_PURE_CALL_P (ret) 
+	= RTL_LOOPING_CONST_OR_PURE_CALL_P (insn);
     }
   else
     gcc_unreachable ();
Index: java/decl.c
===================================================================
--- java/decl.c	(revision 134565)
+++ java/decl.c	(working copy)
@@ -906,7 +906,7 @@ java_init_decl_processing (void)
     = add_builtin_function ("_Jv_ResolvePoolEntry",
 			    build_function_type (ptr_type_node, t),
 			    0,NOT_BUILT_IN, NULL, NULL_TREE);
-  DECL_IS_PURE (soft_resolvepoolentry_node) = 1;
+  DECL_PURE_P (soft_resolvepoolentry_node) = 1;
   throw_node = add_builtin_function ("_Jv_Throw",
 				     build_function_type (void_type_node, t),
 				     0, NOT_BUILT_IN, NULL, NULL_TREE);
@@ -1000,7 +1000,7 @@ java_init_decl_processing (void)
     = add_builtin_function ("_Jv_IsInstanceOf",
 			    build_function_type (boolean_type_node, t),
 			    0, NOT_BUILT_IN, NULL, NULL_TREE);
-  DECL_IS_PURE (soft_instanceof_node) = 1;
+  DECL_PURE_P (soft_instanceof_node) = 1;
   t = tree_cons (NULL_TREE, object_ptr_type_node,
 		 tree_cons (NULL_TREE, object_ptr_type_node, endlink));
   soft_checkarraystore_node
@@ -1014,7 +1014,7 @@ java_init_decl_processing (void)
     = add_builtin_function ("_Jv_LookupInterfaceMethodIdx",
 			    build_function_type (ptr_type_node, t),
 			    0, NOT_BUILT_IN, NULL, NULL_TREE);
-  DECL_IS_PURE (soft_lookupinterfacemethod_node) = 1;
+  DECL_PURE_P (soft_lookupinterfacemethod_node) = 1;
   t = tree_cons (NULL_TREE, ptr_type_node,
 		 tree_cons (NULL_TREE, ptr_type_node,
 			    tree_cons (NULL_TREE, ptr_type_node, endlink)));
Index: postreload-gcse.c
===================================================================
--- postreload-gcse.c	(revision 134565)
+++ postreload-gcse.c	(working copy)
@@ -758,7 +758,7 @@ record_opr_changes (rtx insn)
 	      }
 	  }
 
-      if (! CONST_OR_PURE_CALL_P (insn))
+      if (! (RTL_CONST_CALL_P (insn) || RTL_PURE_CALL_P (insn)))
 	record_last_mem_set_info (insn);
     }
 }
Index: tree.c
===================================================================
--- tree.c	(revision 134565)
+++ tree.c	(working copy)
@@ -7294,7 +7294,9 @@ local_define_builtin (const char *name, 
   if (ecf_flags & ECF_CONST)
     TREE_READONLY (decl) = 1;
   if (ecf_flags & ECF_PURE)
-    DECL_IS_PURE (decl) = 1;
+    DECL_PURE_P (decl) = 1;
+  if (ecf_flags & ECF_LOOPING_CONST_OR_PURE)
+    DECL_LOOPING_CONST_OR_PURE_P (decl) = 1;
   if (ecf_flags & ECF_NORETURN)
     TREE_THIS_VOLATILE (decl) = 1;
   if (ecf_flags & ECF_NOTHROW)
@@ -7687,7 +7689,7 @@ process_call_operands (tree t)
       /* Calls have side-effects, except those to const or
 	 pure functions.  */
       i = call_expr_flags (t);
-      if (!(i & (ECF_CONST | ECF_PURE)))
+      if ((i & ECF_LOOPING_CONST_OR_PURE) || !(i & (ECF_CONST | ECF_PURE)))
 	side_effects = 1;
     }
   TREE_SIDE_EFFECTS (t) = side_effects;
Index: tree.h
===================================================================
--- tree.h	(revision 134565)
+++ tree.h	(working copy)
@@ -794,7 +794,7 @@ enum tree_node_structure_enum {
     &__t->phi.a[__i]; }))
 
 #define OMP_CLAUSE_ELT_CHECK(T, I) __extension__			\
-(*({__typeof (T) const __t = (T);						\
+(*({__typeof (T) const __t = (T);					\
     const int __i = (I);						\
     if (TREE_CODE (__t) != OMP_CLAUSE)					\
       tree_check_failed (__t, __FILE__, __LINE__, __FUNCTION__,  	\
@@ -1287,13 +1287,11 @@ extern void omp_clause_range_check_faile
 #define TREE_THIS_NOTRAP(NODE) ((NODE)->base.nothrow_flag)
 
 /* In a VAR_DECL, PARM_DECL or FIELD_DECL, or any kind of ..._REF node,
-   nonzero means it may not be the lhs of an assignment.  */
+   nonzero means it may not be the lhs of an assignment.  
+   Nonzero in a FUNCTION_DECL means this function should be treated
+   as "const" function (can only read its arguments).  */
 #define TREE_READONLY(NODE) (NON_TYPE_CHECK (NODE)->base.readonly_flag)
 
-/* Nonzero if NODE is a _DECL with TREE_READONLY set.  */
-#define TREE_READONLY_DECL_P(NODE)\
-	(DECL_P (NODE) && TREE_READONLY (NODE))
-
 /* Value of expression is constant.  Always on in all ..._CST nodes.  May
    also appear in an expression or decl where the value is constant.  */
 #define TREE_CONSTANT(NODE) (NON_TYPE_CHECK (NODE)->base.constant_flag)
@@ -3254,7 +3252,16 @@ struct tree_decl_non_common GTY(())
 
 /* Nonzero in a FUNCTION_DECL means this function should be treated
    as "pure" function (like const function, but may read global memory).  */
-#define DECL_IS_PURE(NODE) (FUNCTION_DECL_CHECK (NODE)->function_decl.pure_flag)
+#define DECL_PURE_P(NODE) (FUNCTION_DECL_CHECK (NODE)->function_decl.pure_flag)
+
+/* Nonzero only if one of TREE_READONLY or DECL_PURE_P is nonzero AND
+   the const or pure function may not terminate.  When this is nonzero
+   for a const or pure function, it can be dealt with by cse passes
+   but cannot be removed by dce passes since you are not allowed to
+   change an infinite looping program into one that terminates without
+   error.  */
+#define DECL_LOOPING_CONST_OR_PURE_P(NODE) \
+  (FUNCTION_DECL_CHECK (NODE)->function_decl.looping_const_or_pure_flag)
 
 /* Nonzero in a FUNCTION_DECL means this function should be treated
    as "novops" function (function that does not read global memory,
@@ -3352,7 +3359,6 @@ struct tree_function_decl GTY(())
   unsigned returns_twice_flag : 1;
   unsigned malloc_flag : 1;
   unsigned operator_new_flag : 1;
-  unsigned pure_flag : 1;
   unsigned declared_inline_flag : 1;
   unsigned regdecl_flag : 1;
 
@@ -3360,8 +3366,11 @@ struct tree_function_decl GTY(())
   unsigned no_instrument_function_entry_exit : 1;
   unsigned no_limit_stack : 1;
   unsigned disregard_inline_limits : 1;
+  unsigned pure_flag : 1;
+  unsigned looping_const_or_pure_flag : 1;
+
 
-  /* 4 bits left */
+  /* 3 bits left */
 };
 
 /* For a TYPE_DECL, holds the "original" type.  (TREE_TYPE has the copy.) */
@@ -4984,28 +4993,34 @@ extern tree build_duplicate_type (tree);
 
 /* Nonzero if this is a call to a function whose return value depends
    solely on its arguments, has no side effects, and does not read
-   global memory.  */
-#define ECF_CONST		1
+   global memory.  This corresponds to TREE_READONLY for function
+   decls.  */
+#define ECF_CONST		  (1 << 0)
+/* Nonzero if this is a call to "pure" function (like const function,
+   but may read memory.  This corresponds to DECL_PURE_P for function
+   decls.  */
+#define ECF_PURE		  (1 << 1)
+/* Nonzero if this is ECF_CONST or ECF_PURE but cannot be proven to no
+   infinite loop.  This corresponds to DECL_LOOPING_CONST_OR_PURE_P
+   for function decls.*/
+#define ECF_LOOPING_CONST_OR_PURE (1 << 2)
 /* Nonzero if this call will never return.  */
-#define ECF_NORETURN		2
+#define ECF_NORETURN		  (1 << 3)
 /* Nonzero if this is a call to malloc or a related function.  */
-#define ECF_MALLOC		4
+#define ECF_MALLOC		  (1 << 4)
 /* Nonzero if it is plausible that this is a call to alloca.  */
-#define ECF_MAY_BE_ALLOCA	8
+#define ECF_MAY_BE_ALLOCA	  (1 << 5)
 /* Nonzero if this is a call to a function that won't throw an exception.  */
-#define ECF_NOTHROW		16
+#define ECF_NOTHROW		  (1 << 6)
 /* Nonzero if this is a call to setjmp or a related function.  */
-#define ECF_RETURNS_TWICE	32
+#define ECF_RETURNS_TWICE	  (1 << 7)
 /* Nonzero if this call replaces the current stack frame.  */
-#define ECF_SIBCALL		64
-/* Nonzero if this is a call to "pure" function (like const function,
-   but may read memory.  */
-#define ECF_PURE		128
+#define ECF_SIBCALL		  (1 << 8)
 /* Create libcall block around the call.  */
-#define ECF_LIBCALL_BLOCK	256
+#define ECF_LIBCALL_BLOCK	  (1 << 9)
 /* Function does not read or write memory (but may have side effects, so
    it does not necessarily fit ECF_CONST).  */
-#define ECF_NOVOPS		512
+#define ECF_NOVOPS		  (1 << 10)
 
 extern int flags_from_decl_or_type (const_tree);
 extern int call_expr_flags (const_tree);
Index: rtlanal.c
===================================================================
--- rtlanal.c	(revision 134565)
+++ rtlanal.c	(working copy)
@@ -1846,29 +1846,6 @@ find_regno_fusage (const_rtx insn, enum 
   return 0;
 }
 
-/* Return true if INSN is a call to a pure function.  */
-
-int
-pure_call_p (const_rtx insn)
-{
-  const_rtx link;
-
-  if (!CALL_P (insn) || ! CONST_OR_PURE_CALL_P (insn))
-    return 0;
-
-  /* Look for the note that differentiates const and pure functions.  */
-  for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1))
-    {
-      rtx u, m;
-
-      if (GET_CODE (u = XEXP (link, 0)) == USE
-	  && MEM_P (m = XEXP (u, 0)) && GET_MODE (m) == BLKmode
-	  && GET_CODE (XEXP (m, 0)) == SCRATCH)
-	return 1;
-    }
-
-  return 0;
-}
 
 /* Remove register note NOTE from the REG_NOTES of INSN.  */
 
Index: builtins.c
===================================================================
--- builtins.c	(revision 134565)
+++ builtins.c	(working copy)
@@ -6094,7 +6094,7 @@ expand_builtin (tree exp, rtx target, rt
      none of its arguments are volatile, we can avoid expanding the
      built-in call and just evaluate the arguments for side-effects.  */
   if (target == const0_rtx
-      && (DECL_IS_PURE (fndecl) || TREE_READONLY (fndecl)))
+      && (DECL_PURE_P (fndecl) || TREE_READONLY (fndecl)))
     {
       bool volatilep = false;
       tree arg;
Index: reorg.c
===================================================================
--- reorg.c	(revision 134565)
+++ reorg.c	(working copy)
@@ -3155,7 +3155,7 @@ delete_prior_computation (rtx note, rtx 
       /* If we reach a CALL which is not calling a const function
 	 or the callee pops the arguments, then give up.  */
       if (CALL_P (our_prev)
-	  && (! CONST_OR_PURE_CALL_P (our_prev)
+	  && (! RTL_CONST_CALL_P (our_prev)
 	      || GET_CODE (pat) != SET || GET_CODE (SET_SRC (pat)) != CALL))
 	break;
 
Index: cp/decl.c
===================================================================
--- cp/decl.c	(revision 134565)
+++ cp/decl.c	(working copy)
@@ -1802,11 +1802,13 @@ duplicate_decls (tree newdecl, tree oldd
 	    |= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl);
 	  DECL_NO_LIMIT_STACK (newdecl) |= DECL_NO_LIMIT_STACK (olddecl);
 	  TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl);
-	  TREE_READONLY (newdecl) |= TREE_READONLY (olddecl);
 	  TREE_NOTHROW (newdecl) |= TREE_NOTHROW (olddecl);
 	  DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl);
 	  DECL_IS_OPERATOR_NEW (newdecl) |= DECL_IS_OPERATOR_NEW (olddecl);
-	  DECL_IS_PURE (newdecl) |= DECL_IS_PURE (olddecl);
+	  DECL_PURE_P (newdecl) |= DECL_PURE_P (olddecl);
+	  TREE_READONLY (newdecl) |= TREE_READONLY (olddecl);
+	  DECL_LOOPING_CONST_OR_PURE_P (newdecl) 
+	    |= DECL_LOOPING_CONST_OR_PURE_P (olddecl);
 	  /* Keep the old RTL.  */
 	  COPY_DECL_RTL (olddecl, newdecl);
 	}
Index: cp/rtti.c
===================================================================
--- cp/rtti.c	(revision 134565)
+++ cp/rtti.c	(working copy)
@@ -707,7 +707,7 @@ build_dynamic_cast_1 (tree type, tree ex
 		   (NULL_TREE, ptrdiff_type_node, void_list_node))));
 	      tmp = build_function_type (ptr_type_node, tmp);
 	      dcast_fn = build_library_fn_ptr (name, tmp);
-	      DECL_IS_PURE (dcast_fn) = 1;
+	      DECL_PURE_P (dcast_fn) = 1;
 	      pop_abi_namespace ();
 	      dynamic_cast_node = dcast_fn;
 	    }
Index: ipa-pure-const.c
===================================================================
--- ipa-pure-const.c	(revision 134565)
+++ ipa-pure-const.c	(working copy)
@@ -19,7 +19,8 @@ along with GCC; see the file COPYING3.  
 <http://www.gnu.org/licenses/>.  */
 
 /* This file mark functions as being either const (TREE_READONLY) or
-   pure (DECL_IS_PURE).
+   pure (DECL_PURE_P).  It can also set the a variant of these that
+   are allowed to infinite loop (DECL_LOOPING_CONST_PURE_P).
 
    This must be run after inlining decisions have been made since
    otherwise, the local sets will not contain information that is
@@ -69,6 +70,7 @@ enum pure_const_state_e
 struct funct_state_d 
 {
   enum pure_const_state_e pure_const_state;
+  bool looping;
   bool state_set_in_source;
 };
 
@@ -95,6 +97,7 @@ check_decl (funct_state local, 
   if (lookup_attribute ("used", DECL_ATTRIBUTES (t)))
     {
       local->pure_const_state = IPA_NEITHER;
+      local->looping = false;
       return;
     }
 
@@ -103,6 +106,7 @@ check_decl (funct_state local, 
   if (TREE_THIS_VOLATILE (t)) 
     { 
       local->pure_const_state = IPA_NEITHER;
+      local->looping = false;
       return;
     }
 
@@ -116,6 +120,7 @@ check_decl (funct_state local, 
   if (checking_write) 
     {
       local->pure_const_state = IPA_NEITHER;
+      local->looping = false;
       return;
     }
 
@@ -174,6 +179,7 @@ check_tree (funct_state local, tree t, b
   if (TREE_THIS_VOLATILE (t))
     {
       local->pure_const_state = IPA_NEITHER;
+      local->looping = false;
       return;
     }
 
@@ -199,6 +205,7 @@ check_tree (funct_state local, tree t, b
       if (checking_write) 
 	{
 	  local->pure_const_state = IPA_NEITHER;
+	  local->looping = false;
 	  return;
 	}
       else if (local->pure_const_state == IPA_CONST)
@@ -346,7 +353,10 @@ check_call (funct_state local, tree call
       /* When bad things happen to bad functions, they cannot be const
 	 or pure.  */
       if (setjmp_call_p (callee_t))
-	local->pure_const_state = IPA_NEITHER;
+	{
+	  local->pure_const_state = IPA_NEITHER;
+	  local->looping = false;
+	}
 
       if (DECL_BUILT_IN_CLASS (callee_t) == BUILT_IN_NORMAL)
 	switch (DECL_FUNCTION_CODE (callee_t))
@@ -354,6 +364,7 @@ check_call (funct_state local, tree call
 	  case BUILT_IN_LONGJMP:
 	  case BUILT_IN_NONLOCAL_GOTO:
 	    local->pure_const_state = IPA_NEITHER;
+	    local->looping = false;
 	    break;
 	  default:
 	    break;
@@ -480,7 +491,10 @@ scan_function (tree *tp, 
     case LABEL_EXPR:
       if (DECL_NONLOCAL (TREE_OPERAND (t, 0)))
 	/* Target of long jump. */
-	local->pure_const_state = IPA_NEITHER;
+	{
+	  local->pure_const_state = IPA_NEITHER;
+	  local->looping = false;
+	}
       break;
 
     case CALL_EXPR: 
@@ -513,6 +527,10 @@ analyze_function (struct cgraph_node *fn
 
   l->pure_const_state = IPA_CONST;
   l->state_set_in_source = false;
+  if (DECL_LOOPING_CONST_OR_PURE_P (decl))
+    l->looping = true;
+  else
+    l->looping = false;
 
   /* If this function does not return normally or does not bind local,
      do not touch this unless it has been marked as const or pure by the
@@ -529,7 +547,7 @@ analyze_function (struct cgraph_node *fn
       l->pure_const_state = IPA_CONST;
       l->state_set_in_source = true;
     }
-  if (DECL_IS_PURE (decl))
+  if (DECL_PURE_P (decl))
     {
       l->pure_const_state = IPA_PURE;
       l->state_set_in_source = true;
@@ -644,6 +662,7 @@ static_execute (void)
   for (i = 0; i < order_pos; i++ )
     {
       enum pure_const_state_e pure_const_state = IPA_CONST;
+      bool looping = false;
       int count = 0;
       node = order[i];
 
@@ -655,6 +674,9 @@ static_execute (void)
 	  if (pure_const_state < w_l->pure_const_state)
 	    pure_const_state = w_l->pure_const_state;
 
+	  if (w_l->looping)
+	    looping = true;
+
 	  if (pure_const_state == IPA_NEITHER) 
 	    break;
 
@@ -663,24 +685,8 @@ static_execute (void)
 	      struct cgraph_edge *e;
 	      count++;
 
-	      /* FIXME!!!  Because of pr33826, we cannot have either
-		 immediate or transitive recursive functions marked as
-		 pure or const because dce can delete a function that
-		 is in reality an infinite loop.  A better solution
-		 than just outlawing them is to add another bit the
-		 functions to distinguish recursive from non recursive
-		 pure and const function.  This would allow the
-		 recursive ones to be cse'd but not dce'd.  In this
-		 same vein, we could allow functions with loops to
-		 also be cse'd but not dce'd.
-
-		 Unfortunately we are late in stage 3, and the fix
-		 described above is is not appropriate.  */
 	      if (count > 1)
-		{
-		  pure_const_state = IPA_NEITHER;
-		  break;
-		}
+		looping = true;
 		    
 	      for (e = w->callees; e; e = e->next_callee) 
 		{
@@ -688,13 +694,8 @@ static_execute (void)
 		  /* Only look at the master nodes and skip external nodes.  */
 		  y = cgraph_master_clone (y);
 
-		  /* Check for immediate recursive functions.  See the
-		     FIXME above.  */
 		  if (w == y)
-		    {
-		      pure_const_state = IPA_NEITHER;
-		      break;
-		    }
+		    looping = true;
 		  if (y)
 		    {
 		      funct_state y_l = get_function_state (y);
@@ -702,6 +703,8 @@ static_execute (void)
 			pure_const_state = y_l->pure_const_state;
 		      if (pure_const_state == IPA_NEITHER) 
 			break;
+		      if (y_l->looping)
+			looping = true;
 		    }
 		}
 	    }
@@ -724,15 +727,19 @@ static_execute (void)
 		{
 		case IPA_CONST:
 		  TREE_READONLY (w->decl) = 1;
+		  DECL_LOOPING_CONST_OR_PURE_P (w->decl) = looping;
 		  if (dump_file)
-		    fprintf (dump_file, "Function found to be const: %s\n",  
+		    fprintf (dump_file, "Function found to be %sconst: %s\n",  
+			     looping ? "looping " : "",
 			     lang_hooks.decl_printable_name(w->decl, 2)); 
 		  break;
 		  
 		case IPA_PURE:
-		  DECL_IS_PURE (w->decl) = 1;
+		  DECL_PURE_P (w->decl) = 1;
+		  DECL_LOOPING_CONST_OR_PURE_P (w->decl) = looping;
 		  if (dump_file)
-		    fprintf (dump_file, "Function found to be pure: %s\n",  
+		    fprintf (dump_file, "Function found to be %spure: %s\n",  
+			     looping ? "looping " : "",
 			     lang_hooks.decl_printable_name(w->decl, 2)); 
 		  break;
 		  
Index: cse.c
===================================================================
--- cse.c	(revision 134565)
+++ cse.c	(working copy)
@@ -5249,7 +5249,7 @@ cse_insn (rtx insn, rtx libcall_insn)
 
   if (CALL_P (insn))
     {
-      if (! CONST_OR_PURE_CALL_P (insn))
+      if (!(RTL_CONST_CALL_P (insn) || RTL_PURE_CALL_P (insn)))
 	invalidate_memory ();
       invalidate_for_call ();
     }
Index: ifcvt.c
===================================================================
--- ifcvt.c	(revision 134565)
+++ ifcvt.c	(working copy)
@@ -2168,9 +2168,7 @@ noce_can_store_speculate_p (basic_block 
 	     unconditionally before the barrier.  */
 	  if (INSN_P (insn)
 	      && (volatile_insn_p (PATTERN (insn))
-		  || (CALL_P (insn)
-		      && (!CONST_OR_PURE_CALL_P (insn)
-			  || pure_call_p (insn)))))
+		  || (CALL_P (insn) && (!RTL_CONST_CALL_P (insn)))))
 	    return false;
 
 	  if (memory_modified_in_insn_p (mem, insn))
Index: dse.c
===================================================================
--- dse.c	(revision 134565)
+++ dse.c	(working copy)
@@ -1967,7 +1967,7 @@ scan_insn (bb_info_t bb_info, rtx insn)
       /* Const functions cannot do anything bad i.e. read memory,
 	 however, they can read their parameters which may have
 	 been pushed onto the stack.  */
-      if (CONST_OR_PURE_CALL_P (insn) && !pure_call_p (insn))
+      if (RTL_CONST_CALL_P (insn))
 	{
 	  insn_info_t i_ptr = active_local_stores;
 	  insn_info_t last = NULL;
Index: c-decl.c
===================================================================
--- c-decl.c	(revision 134565)
+++ c-decl.c	(working copy)
@@ -1729,10 +1729,10 @@ merge_decls (tree newdecl, tree olddecl,
 	  DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl)
 	    |= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl);
 	  TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl);
-	  TREE_READONLY (newdecl) |= TREE_READONLY (olddecl);
 	  DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl);
 	  DECL_IS_OPERATOR_NEW (newdecl) |= DECL_IS_OPERATOR_NEW (olddecl);
-	  DECL_IS_PURE (newdecl) |= DECL_IS_PURE (olddecl);
+	  TREE_READONLY (newdecl) |= TREE_READONLY (olddecl);
+	  DECL_PURE_P (newdecl) |= DECL_PURE_P (olddecl);
 	  DECL_IS_NOVOPS (newdecl) |= DECL_IS_NOVOPS (olddecl);
 	}
 
Index: fortran/trans-decl.c
===================================================================
--- fortran/trans-decl.c	(revision 134565)
+++ fortran/trans-decl.c	(working copy)
@@ -1196,7 +1196,7 @@ gfc_get_extern_function_decl (gfc_symbol
   if (sym->attr.pure || sym->attr.elemental)
     {
       if (sym->attr.function && !gfc_return_by_reference (sym))
-	DECL_IS_PURE (fndecl) = 1;
+	DECL_PURE_P (fndecl) = 1;
       /* TODO: check if pure SUBROUTINEs don't have INTENT(OUT)
 	 parameters and don't use alternate returns (is this
 	 allowed?). In that case, calls to them are meaningless, and
@@ -1323,7 +1323,7 @@ build_function_decl (gfc_symbol * sym)
 	 including an alternate return. In that case it can also be
 	 marked as PURE. See also in gfc_get_extern_function_decl().  */
       if (attr.function && !gfc_return_by_reference (sym))
-	DECL_IS_PURE (fndecl) = 1;
+	DECL_PURE_P (fndecl) = 1;
       TREE_SIDE_EFFECTS (fndecl) = 0;
     }
 
Index: local-alloc.c
===================================================================
--- local-alloc.c	(revision 134565)
+++ local-alloc.c	(working copy)
@@ -505,7 +505,7 @@ validate_equiv_mem (rtx start, rtx reg, 
 	return 1;
 
       if (CALL_P (insn) && ! MEM_READONLY_P (memref)
-	  && ! CONST_OR_PURE_CALL_P (insn))
+	  && ! (RTL_CONST_CALL_P (insn) || RTL_PURE_CALL_P (insn)))
 	return 0;
 
       note_stores (PATTERN (insn), validate_equiv_mem_from_store, NULL);
@@ -781,9 +781,7 @@ memref_used_between_p (rtx memref, rtx s
 	return 1;
 
       /* Nonconst functions may access memory.  */
-      if (CALL_P (insn)
-	  && (! CONST_OR_PURE_CALL_P (insn)
-	      || pure_call_p (insn)))
+      if (CALL_P (insn) && (! RTL_CONST_CALL_P (insn)))
 	return 1;
     }
 
Index: gcse.c
===================================================================
--- gcse.c	(revision 134565)
+++ gcse.c	(working copy)
@@ -2309,7 +2309,7 @@ oprs_not_set_p (const_rtx x, const_rtx i
 static void
 mark_call (rtx insn)
 {
-  if (! CONST_OR_PURE_CALL_P (insn))
+  if (! (RTL_CONST_CALL_P (insn) || RTL_CONST_CALL_P (insn)))
     record_last_mem_set_info (insn);
 }
 
@@ -5987,7 +5987,7 @@ store_killed_in_insn (const_rtx x, const
     {
       /* A normal or pure call might read from pattern,
 	 but a const call will not.  */
-      if (! CONST_OR_PURE_CALL_P (insn) || pure_call_p (insn))
+      if (RTL_CONST_CALL_P (insn))
 	return true;
 
       /* But even a const call reads its parameters.  Check whether the
Index: gimplify.c
===================================================================
--- gimplify.c	(revision 134565)
+++ gimplify.c	(working copy)
@@ -2265,10 +2265,14 @@ gimplify_call_expr (tree *expr_p, tree *
   /* If the function is "const" or "pure", then clear TREE_SIDE_EFFECTS on its
      decl.  This allows us to eliminate redundant or useless
      calls to "const" functions.  */
-  if (TREE_CODE (*expr_p) == CALL_EXPR
-      && (call_expr_flags (*expr_p) & (ECF_CONST | ECF_PURE)))
-    TREE_SIDE_EFFECTS (*expr_p) = 0;
-
+  if (TREE_CODE (*expr_p) == CALL_EXPR)
+    {
+      int flags = call_expr_flags (*expr_p);
+      if (flags & (ECF_CONST | ECF_PURE)
+	  /* An infinite loop is considered a side effect.  */
+	  && !(flags & (ECF_LOOPING_CONST_OR_PURE)))
+	TREE_SIDE_EFFECTS (*expr_p) = 0;
+    }
   return ret;
 }
 
Index: calls.c
===================================================================
--- calls.c	(revision 134565)
+++ calls.c	(working copy)
@@ -359,21 +359,20 @@ emit_call_1 (rtx funexp, tree fntree, tr
   /* Find the call we just emitted.  */
   call_insn = last_call_insn ();
 
-  /* Mark memory as used for "pure" function call.  */
-  if (ecf_flags & ECF_PURE)
-    call_fusage
-      = gen_rtx_EXPR_LIST
-	(VOIDmode,
-	 gen_rtx_USE (VOIDmode,
-		      gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode))),
-	 call_fusage);
-
   /* Put the register usage information there.  */
   add_function_usage_to (call_insn, call_fusage);
 
   /* If this is a const call, then set the insn's unchanging bit.  */
-  if (ecf_flags & (ECF_CONST | ECF_PURE))
-    CONST_OR_PURE_CALL_P (call_insn) = 1;
+  if (ecf_flags & ECF_CONST)
+    RTL_CONST_CALL_P (call_insn) = 1;
+
+  /* If this is a pure call, then set the insn's unchanging bit.  */
+  if (ecf_flags & ECF_PURE)
+    RTL_PURE_CALL_P (call_insn) = 1;
+
+  /* If this is a const call, then set the insn's unchanging bit.  */
+  if (ecf_flags & ECF_LOOPING_CONST_OR_PURE)
+    RTL_LOOPING_CONST_OR_PURE_CALL_P (call_insn) = 1;
 
   /* If this call can't throw, attach a REG_EH_REGION reg note to that
      effect.  */
@@ -580,9 +579,13 @@ flags_from_decl_or_type (const_tree exp)
       if (DECL_IS_RETURNS_TWICE (exp))
 	flags |= ECF_RETURNS_TWICE;
 
-      /* The function exp may have the `pure' attribute.  */
-      if (DECL_IS_PURE (exp))
+      /* Process the pure and const attributes.  */
+      if (TREE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp))
+	flags |= ECF_CONST;
+      if (DECL_PURE_P (exp))
 	flags |= ECF_PURE;
+      if (DECL_LOOPING_CONST_OR_PURE_P (exp))
+	flags |= ECF_LOOPING_CONST_OR_PURE;
 
       if (DECL_IS_NOVOPS (exp))
 	flags |= ECF_NOVOPS;
@@ -590,9 +593,6 @@ flags_from_decl_or_type (const_tree exp)
       if (TREE_NOTHROW (exp))
 	flags |= ECF_NOTHROW;
 
-      if (TREE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp))
-	flags |= ECF_CONST;
-
       flags = special_function_p (exp, flags);
     }
   else if (TYPE_P (exp) && TYPE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp))
@@ -1038,7 +1038,9 @@ initialize_argument_information (int num
 	      args[i].tree_value = build_fold_addr_expr (args[i].tree_value);
 	      type = TREE_TYPE (args[i].tree_value);
 
-	      *ecf_flags &= ~(ECF_CONST | ECF_LIBCALL_BLOCK);
+	      if (*ecf_flags & ECF_CONST)
+		*ecf_flags &= ~(ECF_CONST | ECF_LOOPING_CONST_OR_PURE);
+	      *ecf_flags &= ~ECF_LIBCALL_BLOCK;
 	    }
 	  else
 	    {
@@ -1073,10 +1075,19 @@ initialize_argument_information (int num
 
 	      store_expr (args[i].tree_value, copy, 0, false);
 
-	      if (callee_copies)
-		*ecf_flags &= ~(ECF_CONST | ECF_LIBCALL_BLOCK);
-	      else
-		*ecf_flags &= ~(ECF_CONST | ECF_PURE | ECF_LIBCALL_BLOCK);
+	      *ecf_flags &= ~(ECF_LIBCALL_BLOCK);
+
+	      /* Just change the const function to pure and then let
+		 the next test clear the pure based on
+		 callee_copies.  */
+	      if (*ecf_flags & ECF_CONST)
+		{
+		  *ecf_flags &= ~ECF_CONST;
+		  *ecf_flags |= ECF_PURE;
+		}
+
+	      if (!callee_copies && *ecf_flags & ECF_PURE)
+		*ecf_flags &= ~(ECF_PURE | ECF_LOOPING_CONST_OR_PURE);
 
 	      args[i].tree_value
 		= build_fold_addr_expr (make_tree (type, copy));
@@ -2022,10 +2033,12 @@ expand_call (tree exp, rtx target, int i
   if (AGGREGATE_TYPE_P (TREE_TYPE (exp)))
     warning (OPT_Waggregate_return, "function call has aggregate value");
 
-  /* If the result of a pure or const function call is ignored (or void),
-     and none of its arguments are volatile, we can avoid expanding the
-     call and just evaluate the arguments for side-effects.  */
+  /* If the result of a non looping pure or const function call is
+     ignored (or void), and none of its arguments are volatile, we can
+     avoid expanding the call and just evaluate the arguments for
+     side-effects.  */
   if ((flags & (ECF_CONST | ECF_PURE))
+      && (!(flags & ECF_LOOPING_CONST_OR_PURE))
       && (ignore || target == const0_rtx
 	  || TYPE_MODE (TREE_TYPE (exp)) == VOIDmode))
     {
@@ -2061,7 +2074,8 @@ expand_call (tree exp, rtx target, int i
   if (aggregate_value_p (exp, fndecl))
     {
       /* This call returns a big structure.  */
-      flags &= ~(ECF_CONST | ECF_PURE | ECF_LIBCALL_BLOCK);
+      flags &= ~(ECF_CONST | ECF_PURE | ECF_LOOPING_CONST_OR_PURE 
+		 | ECF_LIBCALL_BLOCK);
 
 #ifdef PCC_STATIC_STRUCT_RETURN
       {
@@ -2854,13 +2868,6 @@ expand_call (tree exp, rtx target, int i
 		    note = gen_rtx_EXPR_LIST (VOIDmode,
 					      args[i].initial_value, note);
 		  note = gen_rtx_EXPR_LIST (VOIDmode, funexp, note);
-
-		  if (flags & ECF_PURE)
-		    note = gen_rtx_EXPR_LIST (VOIDmode,
-			gen_rtx_USE (VOIDmode,
-				     gen_rtx_MEM (BLKmode,
-						  gen_rtx_SCRATCH (VOIDmode))),
-			note);
 		}
 	      emit_libcall_block (insns, temp, valreg, note);
 
@@ -3371,7 +3378,8 @@ emit_library_call_value_1 (int retval, r
 	    mem_value = assign_temp (tfom, 0, 1, 1);
 #endif
 	  /* This call returns a big structure.  */
-	  flags &= ~(ECF_CONST | ECF_PURE | ECF_LIBCALL_BLOCK);
+	  flags &= ~(ECF_CONST | ECF_PURE | ECF_LOOPING_CONST_OR_PURE 
+		     | ECF_LIBCALL_BLOCK);
 	}
     }
   else
@@ -3474,10 +3482,9 @@ emit_library_call_value_1 (int retval, r
 	      end_sequence ();
 	      emit_insn (insns);
 	    }
-	  flags &= ~(ECF_CONST | ECF_PURE | ECF_LIBCALL_BLOCK);
 
-	  /* If this was a CONST function, it is now PURE since
-	     it now reads memory.  */
+	  /* If this was a CONST function, it is now PURE since it now
+	     reads memory.  */
 	  if (flags & ECF_CONST)
 	    {
 	      flags &= ~ECF_CONST;
@@ -3903,14 +3910,6 @@ emit_library_call_value_1 (int retval, r
 
 	  insns = get_insns ();
 	  end_sequence ();
-
-	  if (flags & ECF_PURE)
-	    note = gen_rtx_EXPR_LIST (VOIDmode,
-			gen_rtx_USE (VOIDmode,
-				     gen_rtx_MEM (BLKmode,
-						  gen_rtx_SCRATCH (VOIDmode))),
-			note);
-
 	  emit_libcall_block (insns, temp, valreg, note);
 
 	  valreg = temp;
Index: emit-rtl.c
===================================================================
--- emit-rtl.c	(revision 134565)
+++ emit-rtl.c	(working copy)
@@ -5466,7 +5466,10 @@ emit_copy_of_insn_after (rtx insn, rtx a
 	CALL_INSN_FUNCTION_USAGE (new)
 	  = copy_insn (CALL_INSN_FUNCTION_USAGE (insn));
       SIBLING_CALL_P (new) = SIBLING_CALL_P (insn);
-      CONST_OR_PURE_CALL_P (new) = CONST_OR_PURE_CALL_P (insn);
+      RTL_CONST_CALL_P (new) = RTL_CONST_CALL_P (insn);
+      RTL_PURE_CALL_P (new) = RTL_PURE_CALL_P (insn);
+      RTL_LOOPING_CONST_OR_PURE_CALL_P (new) 
+	= RTL_LOOPING_CONST_OR_PURE_CALL_P (insn);
       break;
 
     default:
Index: cselib.c
===================================================================
--- cselib.c	(revision 134565)
+++ cselib.c	(working copy)
@@ -1693,7 +1693,11 @@ cselib_process_insn (rtx insn)
 		      GET_MODE (REG_VALUES (i)->elt->val_rtx))))
 	  cselib_invalidate_regno (i, reg_raw_mode[i]);
 
-      if (! CONST_OR_PURE_CALL_P (insn))
+      /* Since it is not clear how cselib is going to be used, be
+	 conservative here and treat looping pure or const functions
+	 as if they were regular functions.  */
+      if (RTL_LOOPING_CONST_OR_PURE_CALL_P (insn)
+	  || !(RTL_CONST_CALL_P (insn) || RTL_PURE_CALL_P (insn)))
 	cselib_invalidate_mem (callmem);
     }
 
Index: tree-ssa-pre.c
===================================================================
--- tree-ssa-pre.c	(revision 134565)
+++ tree-ssa-pre.c	(working copy)
@@ -2077,7 +2077,7 @@ can_value_number_call (tree stmt)
 {
   tree call = get_call_expr_in (stmt);
 
-  if (call_expr_flags (call)  & (ECF_PURE | ECF_CONST))
+  if (call_expr_flags (call) & (ECF_PURE | ECF_CONST))
     return true;
   return false;
 }
Index: loop-invariant.c
===================================================================
--- loop-invariant.c	(revision 134565)
+++ loop-invariant.c	(working copy)
@@ -563,7 +563,8 @@ find_exits (struct loop *loop, basic_blo
 	  FOR_BB_INSNS (body[i], insn)
 	    {
 	      if (CALL_P (insn)
-		  && !CONST_OR_PURE_CALL_P (insn))
+		  && (RTL_LOOPING_CONST_OR_PURE_CALL_P (insn)
+		      || !(RTL_CONST_CALL_P (insn) || RTL_PURE_CALL_P (insn))))
 		{
 		  has_call = true;
 		  bitmap_set_bit (may_exit, i);
@@ -904,7 +905,8 @@ find_invariants_bb (basic_block bb, bool
 
       if (always_reached
 	  && CALL_P (insn)
-	  && !CONST_OR_PURE_CALL_P (insn))
+	  && (RTL_LOOPING_CONST_OR_PURE_CALL_P (insn)
+	      || ! (RTL_CONST_CALL_P (insn) || RTL_PURE_CALL_P (insn))))
 	always_reached = false;
     }
 }
Index: sched-deps.c
===================================================================
--- sched-deps.c	(revision 134565)
+++ sched-deps.c	(working copy)
@@ -2304,7 +2304,8 @@ sched_analyze (struct deps *deps, rtx he
 	     all pending reads and writes, and start new dependencies starting
 	     from here.  But only flush writes for constant calls (which may
 	     be passed a pointer to something we haven't written yet).  */
-	  flush_pending_lists (deps, insn, true, !CONST_OR_PURE_CALL_P (insn));
+	  flush_pending_lists (deps, insn, true, 
+			       !(RTL_CONST_CALL_P (insn) || RTL_PURE_CALL_P (insn)));
 
 	  /* Remember the last function call for limiting lifetimes.  */
 	  free_INSN_LIST_list (&deps->last_function_call);
Index: rtl.h
===================================================================
--- rtl.h	(revision 134565)
+++ rtl.h	(working copy)
@@ -253,14 +253,17 @@ struct rtx_def GTY((chain_next ("RTX_NEX
      In a CODE_LABEL, part of the two-bit alternate entry field.  */
   unsigned int jump : 1;
   /* In a CODE_LABEL, part of the two-bit alternate entry field.
-     1 in a MEM if it cannot trap.  */
+     1 in a MEM if it cannot trap.  
+     1 in a CALL_INSN logically equivalent to
+       ECF_LOOPING_CONST_OR_PURE and DECL_LOOPING_CONST_OR_PURE_P. */
   unsigned int call : 1;
   /* 1 in a REG, MEM, or CONCAT if the value is set at most once, anywhere.
      1 in a SUBREG if it references an unsigned object whose mode has been
      from a promoted to a wider mode.
      1 in a SYMBOL_REF if it addresses something in the per-function
      constants pool.
-     1 in a CALL_INSN, NOTE, or EXPR_LIST for a const or pure call.
+     1 in a CALL_INSN logically equivalent to ECF_CONST and TREE_READONLY. 
+     1 in a NOTE, or EXPR_LIST for a const call.
      1 in a JUMP_INSN, CALL_INSN, or INSN of an annulling branch.  */
   unsigned int unchanging : 1;
   /* 1 in a MEM or ASM_OPERANDS expression if the memory reference is volatile.
@@ -303,7 +306,8 @@ struct rtx_def GTY((chain_next ("RTX_NEX
   unsigned frame_related : 1;
   /* 1 in a REG or PARALLEL that is the current function's return value.
      1 in a MEM if it refers to a scalar.
-     1 in a SYMBOL_REF for a weak symbol.  */
+     1 in a SYMBOL_REF for a weak symbol. 
+     1 in a CALL_INSN logically equivalent to ECF_PURE and DECL_PURE_P. */ 
   unsigned return_val : 1;
 
   /* The first element of the operands of this rtx.
@@ -765,10 +769,20 @@ extern void rtl_check_failed_flag (const
   (RTL_FLAG_CHECK6("INSN_DELETED_P", (RTX), INSN, CALL_INSN, JUMP_INSN,	\
 		   CODE_LABEL, BARRIER, NOTE)->volatil)
 
-/* 1 if RTX is a call to a const or pure function.  */
-#define CONST_OR_PURE_CALL_P(RTX)					\
-  (RTL_FLAG_CHECK3("CONST_OR_PURE_CALL_P", (RTX), CALL_INSN, NOTE,	\
-		   EXPR_LIST)->unchanging)
+/* 1 if RTX is a call to a const function.  Built from ECF_CONST and
+   TREE_READONLY.  */
+#define RTL_CONST_CALL_P(RTX)					\
+  (RTL_FLAG_CHECK1("RTL_CONST_CALL_P", (RTX), CALL_INSN)->unchanging)
+
+/* 1 if RTX is a call to a pure function.  Built from ECF_PURE and
+   DECL_PURE_P.  */
+#define RTL_PURE_CALL_P(RTX)					\
+  (RTL_FLAG_CHECK1("RTL_PURE_CALL_P", (RTX), CALL_INSN)->return_val)
+
+/* 1 if RTX is a call to a looping const or pure function.  Built from
+   ECF_LOOPING_CONST_OR_PURE and DECL_LOOPING_CONST_OR_PURE_P.  */
+#define RTL_LOOPING_CONST_OR_PURE_CALL_P(RTX)					\
+  (RTL_FLAG_CHECK1("CONST_OR_PURE_CALL_P", (RTX), CALL_INSN)->call)
 
 /* 1 if RTX is a call_insn for a sibling call.  */
 #define SIBLING_CALL_P(RTX)						\
@@ -1733,7 +1747,6 @@ extern rtx find_reg_equal_equiv_note (co
 extern rtx find_constant_src (const_rtx);
 extern int find_reg_fusage (const_rtx, enum rtx_code, const_rtx);
 extern int find_regno_fusage (const_rtx, enum rtx_code, unsigned int);
-extern int pure_call_p (const_rtx);
 extern void remove_note (rtx, const_rtx);
 extern void remove_reg_equal_equiv_notes (rtx);
 extern int side_effects_p (const_rtx);
Index: tree-inline.c
===================================================================
--- tree-inline.c	(revision 134565)
+++ tree-inline.c	(working copy)
@@ -671,7 +671,7 @@ copy_body_r (tree *tp, int *walk_subtree
 	    {
 	      value = *n;
 	      STRIP_TYPE_NOPS (value);
-	      if (TREE_CONSTANT (value) || TREE_READONLY_DECL_P (value))
+	      if (TREE_CONSTANT (value) || TREE_READONLY (value))
 		{
 		  *tp = build_empty_stmt ();
 		  return copy_body_r (tp, walk_subtrees, data);
Index: tree-optimize.c
===================================================================
--- tree-optimize.c	(revision 134565)
+++ tree-optimize.c	(working copy)
@@ -299,7 +299,8 @@ execute_fixup_cfg (void)
 	    tree call = get_call_expr_in (stmt);
 	    tree decl = call ? get_callee_fndecl (call) : NULL;
 
-	    if (decl && call_expr_flags (call) & (ECF_CONST | ECF_PURE)
+	    if (decl && call_expr_flags (call) & (ECF_CONST | ECF_PURE 
+						  | ECF_LOOPING_CONST_OR_PURE)
 		&& TREE_SIDE_EFFECTS (call))
 	      {
 		if (gimple_in_ssa_p (cfun))
Index: c-common.c
===================================================================
--- c-common.c	(revision 134565)
+++ c-common.c	(working copy)
@@ -6018,7 +6018,7 @@ handle_pure_attribute (tree *node, tree 
 		       int ARG_UNUSED (flags), bool *no_add_attrs)
 {
   if (TREE_CODE (*node) == FUNCTION_DECL)
-    DECL_IS_PURE (*node) = 1;
+    DECL_PURE_P (*node) = 1;
   /* ??? TODO: Support types.  */
   else
     {
Index: tree-cfg.c
===================================================================
--- tree-cfg.c	(revision 134565)
+++ tree-cfg.c	(working copy)
@@ -1791,9 +1791,11 @@ static void
 update_call_expr_flags (tree call)
 {
   tree decl = get_callee_fndecl (call);
+  int flags;
   if (!decl)
     return;
-  if (call_expr_flags (call) & (ECF_CONST | ECF_PURE))
+  flags = call_expr_flags (call);
+  if (flags & (ECF_CONST | ECF_PURE) && !(flags & ECF_LOOPING_CONST_OR_PURE))
     TREE_SIDE_EFFECTS (call) = 0;
   if (TREE_NOTHROW (decl))
     TREE_NOTHROW (call) = 1;
Index: config/alpha/alpha.c
===================================================================
--- config/alpha/alpha.c	(revision 134565)
+++ config/alpha/alpha.c	(working copy)
@@ -986,7 +986,7 @@ alpha_legitimize_address (rtx x, rtx scr
 	  emit_insn (gen_movdi_er_tlsgd (r16, pic_offset_table_rtx, x, seq));
 	  insn = gen_call_value_osf_tlsgd (r0, tga, seq);
 	  insn = emit_call_insn (insn);
-	  CONST_OR_PURE_CALL_P (insn) = 1;
+	  RTL_CONST_CALL_P (insn) = 1;
 	  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r16);
 
           insn = get_insns ();
@@ -1007,7 +1007,7 @@ alpha_legitimize_address (rtx x, rtx scr
 	  emit_insn (gen_movdi_er_tlsldm (r16, pic_offset_table_rtx, seq));
 	  insn = gen_call_value_osf_tlsldm (r0, tga, seq);
 	  insn = emit_call_insn (insn);
-	  CONST_OR_PURE_CALL_P (insn) = 1;
+	  RTL_CONST_CALL_P (insn) = 1;
 	  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r16);
 
           insn = get_insns ();
@@ -3013,7 +3013,7 @@ alpha_emit_xfloating_libcall (rtx func, 
   tmp = emit_call_insn (GEN_CALL_VALUE (reg, tmp, const0_rtx,
 					const0_rtx, const0_rtx));
   CALL_INSN_FUNCTION_USAGE (tmp) = usage;
-  CONST_OR_PURE_CALL_P (tmp) = 1;
+  RTL_CONST_CALL_P (tmp) = 1;
 
   tmp = get_insns ();
   end_sequence ();
Index: config/s390/s390.c
===================================================================
--- config/s390/s390.c	(revision 134565)
+++ config/s390/s390.c	(working copy)
@@ -3178,7 +3178,7 @@ s390_emit_tls_call_insn (rtx result_reg,
 			 gen_rtx_REG (Pmode, RETURN_REGNUM));
 
   use_reg (&CALL_INSN_FUNCTION_USAGE (insn), result_reg);
-  CONST_OR_PURE_CALL_P (insn) = 1;
+  RTL_CONST_CALL_P (insn) = 1;
 }
 
 /* ADDR contains a thread-local SYMBOL_REF.  Generate code to compute
Index: config/i386/i386.c
===================================================================
--- config/i386/i386.c	(revision 134565)
+++ config/i386/i386.c	(working copy)
@@ -7838,7 +7838,7 @@ legitimize_tls_address (rtx x, enum tls_
 	  insns = get_insns ();
 	  end_sequence ();
 
-	  CONST_OR_PURE_CALL_P (insns) = 1;
+	  RTL_CONST_CALL_P (insns) = 1;
 	  emit_libcall_block (insns, dest, rax, x);
 	}
       else if (TARGET_64BIT && TARGET_GNU2_TLS)
@@ -7869,7 +7869,7 @@ legitimize_tls_address (rtx x, enum tls_
 
 	  note = gen_rtx_EXPR_LIST (VOIDmode, const0_rtx, NULL);
 	  note = gen_rtx_EXPR_LIST (VOIDmode, ix86_tls_get_addr (), note);
-	  CONST_OR_PURE_CALL_P (insns) = 1;
+	  RTL_CONST_CALL_P (insns) = 1;
 	  emit_libcall_block (insns, base, rax, note);
 	}
       else if (TARGET_64BIT && TARGET_GNU2_TLS)
Index: config/rs6000/rs6000.c
===================================================================
--- config/rs6000/rs6000.c	(revision 134565)
+++ config/rs6000/rs6000.c	(working copy)
@@ -3886,7 +3886,7 @@ rs6000_legitimize_tls_address (rtx addr,
 	  tga = gen_rtx_MEM (Pmode, rs6000_tls_get_addr ());
 	  insn = gen_call_value (r3, tga, const0_rtx, const0_rtx);
 	  insn = emit_call_insn (insn);
-	  CONST_OR_PURE_CALL_P (insn) = 1;
+	  RTL_CONST_CALL_P (insn) = 1;
 	  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r3);
 	  insn = get_insns ();
 	  end_sequence ();
@@ -3904,7 +3904,7 @@ rs6000_legitimize_tls_address (rtx addr,
 	  tga = gen_rtx_MEM (Pmode, rs6000_tls_get_addr ());
 	  insn = gen_call_value (r3, tga, const0_rtx, const0_rtx);
 	  insn = emit_call_insn (insn);
-	  CONST_OR_PURE_CALL_P (insn) = 1;
+	  RTL_CONST_CALL_P (insn) = 1;
 	  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r3);
 	  insn = get_insns ();
 	  end_sequence ();
Index: config/mips/mips.c
===================================================================
--- config/mips/mips.c	(revision 134565)
+++ config/mips/mips.c	(working copy)
@@ -2358,7 +2358,7 @@ mips_call_tls_get_addr (rtx sym, enum mi
   emit_insn (gen_rtx_SET (Pmode, a0,
 			  gen_rtx_LO_SUM (Pmode, pic_offset_table_rtx, loc)));
   insn = mips_expand_call (v0, mips_tls_symbol, const0_rtx, const0_rtx, false);
-  CONST_OR_PURE_CALL_P (insn) = 1;
+  RTL_CONST_CALL_P (insn) = 1;
   use_reg (&CALL_INSN_FUNCTION_USAGE (insn), a0);
   insn = get_insns ();
 
Index: cfgrtl.c
===================================================================
--- cfgrtl.c	(revision 134565)
+++ cfgrtl.c	(working copy)
@@ -2745,7 +2745,7 @@ need_fake_edge_p (const_rtx insn)
   if ((CALL_P (insn)
        && !SIBLING_CALL_P (insn)
        && !find_reg_note (insn, REG_NORETURN, NULL)
-       && !CONST_OR_PURE_CALL_P (insn)))
+       && !(RTL_CONST_CALL_P (insn) || RTL_PURE_CALL_P (insn))))
     return true;
 
   return ((GET_CODE (PATTERN (insn)) == ASM_OPERANDS
Index: dce.c
===================================================================
--- dce.c	(revision 134565)
+++ dce.c	(working copy)
@@ -99,6 +99,15 @@ deletable_insn_p (rtx insn, bool fast)
   rtx body, x;
   int i;
 
+  /* We can delete dead const or pure calls as long as they do not
+     infinite loop and are not sibling calls.  The problem with
+     sibling calls is that it is hard to see the result.  */
+  if (CALL_P (insn) 
+      && (!SIBLING_CALL_P (insn))
+      && ((RTL_CONST_CALL_P (insn) || RTL_CONST_CALL_P (insn))
+	  && !RTL_LOOPING_CONST_OR_PURE_CALL_P (insn)))
+    return true;
+
   if (!NONJUMP_INSN_P (insn))
     return false;
 

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