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]

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


This patch is a top to bottom cleanup of the way that pure and constant functions are detected and processed. The patch undoes the quick and dirty stage 3 patch for pr33826 and also cleans up a mess made in commits r55767 and r57576 to fix pr7335.

I wanted to do this patch now for trunk because this is the way I want the information about pure and const functions represented in order to serialize it for lto. I plan (assuming this patch is approved) to then merge this back into the lto branch before serializing this information.

pr33826 dealt with pure and constant functions that might infinite loop. Mark, wearing his language committee hat, has decreed that such functions cannot be pure or const because it is not legal to change an infinite looping into a terminating program. I do not disagree with this interpretation but it is more conservative than the compiler needs.

In fact, it is only necessary not to dead code eliminate potientially looping pure or const function, it is perfectly fine to perform commoning and code motion on such functions. So what I have done is added another bit to represent the fact that we cannot prove that a pure or constant function can terminate.

The reason for the size of this patch is that at the three levels of the compiler where we utilize this information, we used 3 completely different representations. While the bits are still stored in different places at different levels, there are now consistently three bits, with similar sets of names.

I had wanted to use an enumeration to represent this information, but this turned out be at least hard if not impossible: first, the front ends play magical and strange games with TREE_READONLY, it is sometimes copied into and out of different types of trees that functions. Second, there are not three contiguous bits available for calls at the rtl level.

So what we have at each level is one bit to say if the function is pure, one bit to say if the function is const, and one bit that is only set if one of the first two bits are set to say that the function may possibly loop.

At the tree level these are TREE_READONLY (i could not touch this), DECL_PURE_P (was DECL_IS_PURE and CONST_OR_PURE_CALL_P.

At the ECF level these are ECF_CONST and ECF_PURE (did not change) and ECF_LOOPING_CONST_OR_PURE.

At the rtl level these are: RTL_CONST_CALL_P, RTL_PURE_CALL_P and RTL_LOOPING_PURE_OR_CONST_CALL. The old representation had i bit in the call_insn for
CONST_OR_PURE_CALL_P and a magical note in the insn that was searched for to see if the pure or const call was really only pure. These notes are no longer generated and the back rtl level passes now just look at the bits.


The issues with respect to r55767 and r57576 to fix pr7335 are obscure. svn blame shows the following for calls.c starting at about line:3489. Note that the code that davem added is both dead and was added after amylaar's commit. There are email messages that knew about this but nothing seems to have happened. I removed amylaar's code (except the lib_call_block part). It seems to still work on the platforms that i tested. pr7335 seems to have been motivated by not keeping the info in flow.c up to date, and this is no longer a problem with the rtl level code so i am pretty sure i did the right thing.

55676 amylaar flags &= ~(ECF_CONST | ECF_PURE | ECF_LIBCALL_BLOCK);
55676 amylaar
57576 davem /* If this was a CONST function, it is now PURE since
57576 davem it now reads memory. */
57576 davem if (flags & ECF_CONST)
57576 davem {
57576 davem flags &= ~ECF_CONST;
57576 davem flags |= ECF_PURE;
57576 davem }
57576 davem


There are two more parts of the patch that have not been addressed:

1) I currently only set the looping bit for recursive functions and not for functions that may contain loops. I did not see the reason to add a lot of code that had to be rewritten when the tuples get merged. I will follow up on this later.

2) While i fixed the rtl level optimizations to use the more precise information, I do not know the tree level that well. I did make sure that TREE_SIDE_EFFECTS is not set if the LOOPING flags are set. But one bit is really not enough information because there are a lot of different kinds of possible side effects and some can be effected by certain optimizations and some some cannot. Any optimization that just looks at that bit for functions, should perhaps be taught to look a little deeper.

The patch is large but mostly boiler plate. In particular, because i could not make the enum, all of the front end changes are mechanical. However this patch will still need a gwm to approve it because this touches code at every level.

kenny

2008-04-09 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-09  Kenneth Zadeck <zadeck@naturalbridge.com>

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


2008-04-09 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-09 Kenneth Zadeck <zadeck@naturalbridge.com>

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

Tested on ppc{32,64}, x86{32,64} and ia-64.

Ok to commit?

Kenny









Index: see.c
===================================================================
--- see.c	(revision 133902)
+++ 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 133902)
+++ 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 133902)
+++ 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 133902)
+++ 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 133902)
+++ tree.h	(working copy)
@@ -793,7 +793,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__,  	\
@@ -1286,13 +1286,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)
@@ -3258,7 +3256,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,
@@ -3356,7 +3363,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;
 
@@ -3364,8 +3370,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.) */
@@ -4985,31 +4994,37 @@ 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)
 /* Nonzero if this is a call to a function that returns with the stack
    pointer depressed.  */
-#define ECF_SP_DEPRESSED	256
+#define ECF_SP_DEPRESSED	  (1 << 9)
 /* Create libcall block around the call.  */
-#define ECF_LIBCALL_BLOCK	512
+#define ECF_LIBCALL_BLOCK	  (1 << 10)
 /* Function does not read or write memory (but may have side effects, so
    it does not necessarily fit ECF_CONST).  */
-#define ECF_NOVOPS		1024
+#define ECF_NOVOPS		  (1 << 11)
 
 extern int flags_from_decl_or_type (const_tree);
 extern int call_expr_flags (const_tree);
Index: rtlanal.c
===================================================================
--- rtlanal.c	(revision 133902)
+++ 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 133902)
+++ 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 133902)
+++ reorg.c	(working copy)
@@ -3152,10 +3152,10 @@ delete_prior_computation (rtx note, rtx 
     {
       rtx pat = PATTERN (our_prev);
 
-      /* If we reach a CALL which is not calling a const function
-	 or the callee pops the arguments, then give up.  */
+      /* If we reach a CALL which is not calling a const or pure
+	 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) || RTL_PURE_CALL_P (our_prev))
 	      || GET_CODE (pat) != SET || GET_CODE (SET_SRC (pat)) != CALL))
 	break;
 
Index: cp/decl.c
===================================================================
--- cp/decl.c	(revision 133902)
+++ 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 133902)
+++ 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 133902)
+++ 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 133902)
+++ 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 133902)
+++ 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 133902)
+++ dse.c	(working copy)
@@ -1958,7 +1958,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 133902)
+++ 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 133902)
+++ fortran/trans-decl.c	(working copy)
@@ -1199,7 +1199,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
@@ -1326,7 +1326,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 133902)
+++ 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 133902)
+++ 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);
 }
 
@@ -5988,7 +5988,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 133902)
+++ 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 133902)
+++ 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.  */
@@ -581,9 +580,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;
@@ -591,9 +594,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))
@@ -607,7 +607,7 @@ flags_from_decl_or_type (const_tree exp)
   if (TREE_CODE (type) == FUNCTION_TYPE && TYPE_RETURNS_STACK_DEPRESSED (type))
     {
       flags |= ECF_SP_DEPRESSED;
-      flags &= ~(ECF_PURE | ECF_CONST);
+      flags &= ~(ECF_PURE | ECF_CONST | ECF_LOOPING_CONST_OR_PURE);
     }
 
   return flags;
@@ -1047,7 +1047,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
 	    {
@@ -1082,10 +1084,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));
@@ -2031,10 +2042,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))
     {
@@ -2070,7 +2083,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
       {
@@ -2864,13 +2878,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);
 
@@ -3391,7 +3398,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
@@ -3494,10 +3502,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;
@@ -3923,14 +3930,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 133902)
+++ emit-rtl.c	(working copy)
@@ -5445,7 +5445,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 133902)
+++ cselib.c	(working copy)
@@ -1693,7 +1693,7 @@ 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))
+      if (!(RTL_CONST_CALL_P (insn) || RTL_PURE_CALL_P (insn)))
 	cselib_invalidate_mem (callmem);
     }
 
Index: tree-ssa-pre.c
===================================================================
--- tree-ssa-pre.c	(revision 133902)
+++ 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 133902)
+++ loop-invariant.c	(working copy)
@@ -563,7 +563,7 @@ find_exits (struct loop *loop, basic_blo
 	  FOR_BB_INSNS (body[i], insn)
 	    {
 	      if (CALL_P (insn)
-		  && !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 +904,7 @@ find_invariants_bb (basic_block bb, bool
 
       if (always_reached
 	  && CALL_P (insn)
-	  && !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 133902)
+++ 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 133902)
+++ 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)						\
@@ -1732,7 +1746,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 133902)
+++ 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 133902)
+++ 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 133902)
+++ c-common.c	(working copy)
@@ -5946,7 +5946,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 133902)
+++ 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 133902)
+++ 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 133902)
+++ 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 133902)
+++ config/i386/i386.c	(working copy)
@@ -7808,7 +7808,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)
@@ -7839,7 +7839,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 133902)
+++ 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 133902)
+++ 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 133902)
+++ 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 133902)
+++ 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]