diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index d6aa061f637e78a65dc15dd5fb666191be556107..5acda30aa5f64b59a0e1fc3ebbaf4b13405f5679 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,17 @@
+2005-05-25  Adrian Straetling  <straetling@de.ibm.com>
+
+	* loop-doloop.c: Include "target.h". 
+	  (doloop_valid_p): Move tests to function in targhooks.c.
+	* target.h (struct gcc_target): New target hook
+	  "insn_valid_within_doloop".
+	* target-def.h: Define default value for "insn_valid_within_doloop".
+	  (TARGET_INITIALIZER): Insert new target hook into initializer.
+	* targhooks.c (default_insn_valid_within_doloop): New function.
+	* targhooks.h (default_insn_valid_within_doloop): Declare.
+	* hooks.c (hook_bool_rtx_true): New function.
+	* hooks.h (hook_bool_rtx_true): Declare.
+	* doc/tm.texi: Add documentation for new target hook.
+
 2005-05-25  Eric Botcazou  <ebotcazou@libertysurf.fr>
 
 	PR target/21412
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 9e755aaf8af87d65476337adccb7c06bcace1a8b..e541a20d2a9d003125b670193b5a2626166ad7c4 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -9511,6 +9511,17 @@ simplified expression for the call's result.  If @var{ignore} is true
 the value will be ignored.
 @end deftypefn
 
+@deftypefn {Target Hook} bool TARGET_INSN_VALID_WITHIN_DOLOOP (rtx @var{insn})
+
+Take an instruction in @var{insn} and return true if it is valid within a
+low-overhead loop.
+
+Many targets use special registers for low-overhead looping. This function
+should return false for any instruction that clobbers these. 
+By default, the RTL loop optimizer does not use a present doloop pattern for
+loops containing function calls or brach on table instructions.  
+@end deftypefn
+
 @defmac MD_CAN_REDIRECT_BRANCH (@var{branch1}, @var{branch2})
 
 Take a branch insn in @var{branch1} and another in @var{branch2}.
diff --git a/gcc/hooks.c b/gcc/hooks.c
index 6e6e7c70321206121b3bcae63e684a862f7db4c3..30ba6d100dad89fe28688906786d2c5bab01745d 100644
--- a/gcc/hooks.c
+++ b/gcc/hooks.c
@@ -191,6 +191,12 @@ hook_bool_rtx_false (rtx a ATTRIBUTE_UNUSED)
   return false;
 }
 
+bool
+hook_bool_rtx_true (rtx a ATTRIBUTE_UNUSED)
+{
+  return true;
+}
+
 bool
 hook_bool_uintp_uintp_false (unsigned int *a ATTRIBUTE_UNUSED,
 			     unsigned int *b ATTRIBUTE_UNUSED)
diff --git a/gcc/hooks.h b/gcc/hooks.h
index b799a8c0709c8d87b29cd7128409021fb4de5e05..b78f497054998223e6c37e48a0ff9f39dc34a7e8 100644
--- a/gcc/hooks.h
+++ b/gcc/hooks.h
@@ -35,6 +35,7 @@ extern bool hook_bool_tree_hwi_hwi_tree_false (tree, HOST_WIDE_INT, HOST_WIDE_IN
 extern bool hook_bool_tree_hwi_hwi_tree_true (tree, HOST_WIDE_INT, HOST_WIDE_INT,
 				       tree);
 extern bool hook_bool_rtx_false (rtx);
+extern bool hook_bool_rtx_true (rtx);
 extern bool hook_bool_uintp_uintp_false (unsigned int *, unsigned int *);
 extern bool hook_bool_rtx_int_int_intp_false (rtx, int, int, int *);
 extern bool hook_bool_constcharptr_size_t_false (const char *, size_t);
diff --git a/gcc/loop-doloop.c b/gcc/loop-doloop.c
index c6ef37e84d6f5cd3e14fa796a2118c399b267c98..4a2bb8774ee278baadc9c85d2d06e22c110370a5 100644
--- a/gcc/loop-doloop.c
+++ b/gcc/loop-doloop.c
@@ -33,6 +33,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "cfgloop.h"
 #include "output.h"
 #include "params.h"
+#include "target.h"
 
 /* This module is used to modify loops with a determinable number of
    iterations to use special low-overhead looping instructions.
@@ -187,27 +188,14 @@ doloop_valid_p (struct loop *loop, struct niter_desc *desc)
 	   insn != NEXT_INSN (BB_END (bb));
 	   insn = NEXT_INSN (insn))
 	{
-	  /* A called function may clobber any special registers required for
-	     low-overhead looping.  */
-	  if (CALL_P (insn))
-	    {
-	      if (dump_file)
-		fprintf (dump_file, "Doloop: Function call in loop.\n");
+	  /* Different targets have different necessities for low-overhead
+	     looping.  Call the back end for each instruction within the loop
+	     to let it decide whether the insn is valid.  */
+	  if (!targetm.insn_valid_within_doloop (insn))
+	  {
 	      result = false;
 	      goto cleanup;
-	    }
-
-	  /* Some targets (eg, PPC) use the count register for branch on table
-	     instructions.  ??? This should be a target specific check.  */
-	  if (JUMP_P (insn)
-	      && (GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC
-		  || GET_CODE (PATTERN (insn)) == ADDR_VEC))
-	    {
-	      if (dump_file)
-		fprintf (dump_file, "Doloop: Computed branch in the loop.\n");
-	      result = false;
-	      goto cleanup;
-	    }
+	  }
 	}
     }
   result = true;
diff --git a/gcc/target-def.h b/gcc/target-def.h
index 27e851123f2af91d8ed18b895403c3f32366f107..49e25a168baf4b067cf0d2eb81a09990c789336d 100644
--- a/gcc/target-def.h
+++ b/gcc/target-def.h
@@ -137,6 +137,10 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 #define TARGET_HAVE_NAMED_SECTIONS false
 #endif
 
+#ifndef TARGET_INSN_VALID_WITHIN_DOLOOP
+#define TARGET_INSN_VALID_WITHIN_DOLOOP default_insn_valid_within_doloop
+#endif
+
 #ifndef TARGET_HAVE_TLS
 #define TARGET_HAVE_TLS false
 #endif
@@ -553,6 +557,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
   TARGET_DWARF_CALLING_CONVENTION,              \
   TARGET_DWARF_HANDLE_FRAME_UNSPEC,		\
   TARGET_STDARG_OPTIMIZE_HOOK,			\
+  TARGET_INSN_VALID_WITHIN_DOLOOP,		\
   TARGET_CALLS,					\
   TARGET_CXX,					\
   TARGET_HAVE_NAMED_SECTIONS,			\
diff --git a/gcc/target.h b/gcc/target.h
index f141f04095f4bde8ad777b28c16b6eee33ac2f17..38f09b01e0555463d53e1d40dde748497d69ae6d 100644
--- a/gcc/target.h
+++ b/gcc/target.h
@@ -520,6 +520,9 @@ struct gcc_target
      to be checked for va_list references.  */
   bool (*stdarg_optimize_hook) (struct stdarg_info *ai, tree lhs, tree rhs);
 
+  /* Returns true if target supports the insn within a doloop block.  */
+  bool (*insn_valid_within_doloop) (rtx);
+    
   /* Functions relating to calls - argument passing, returns, etc.  */
   struct calls {
     bool (*promote_function_args) (tree fntype);
diff --git a/gcc/targhooks.c b/gcc/targhooks.c
index 2bf11a431eb0df0c66f67116863fab0f00654da2..1f8b5b76ee7d2bfcd80e4c824dda3621cc3b51ed 100644
--- a/gcc/targhooks.c
+++ b/gcc/targhooks.c
@@ -262,6 +262,36 @@ default_scalar_mode_supported_p (enum machine_mode mode)
     }
 }
 
+/* TRUE if INSN insn is valid within a low-overhead loop.
+  
+   This function checks wheter a given INSN is valid within a low-overhead
+   loop.  A called function may clobber any special registers required for
+   low-overhead looping. Additionally, some targets (eg, PPC) use the count
+   register for branch on table instructions. We reject the doloop pattern in
+   these cases.  */
+
+bool 
+default_insn_valid_within_doloop (rtx insn)
+{
+  if (CALL_P (insn))
+    {
+      if (dump_file)
+	fprintf (dump_file, "Doloop: Function call in loop.\n");
+	return false;
+    }
+  
+  if (JUMP_P (insn)
+      && (GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC
+	  || GET_CODE (PATTERN (insn)) == ADDR_VEC))
+    {
+      if (dump_file)
+	fprintf (dump_file, "Doloop: Computed branch in the loop.\n");
+      return false;
+    }
+  
+  return true;
+}
+
 bool
 hook_bool_CUMULATIVE_ARGS_mode_tree_bool_false (
 	CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
diff --git a/gcc/targhooks.h b/gcc/targhooks.h
index ae6cf53c2a0f602c842444648532e5be8147570c..b4906ae1b3ac5d0d384cbd707cd0d74e59163e4b 100644
--- a/gcc/targhooks.h
+++ b/gcc/targhooks.h
@@ -46,6 +46,8 @@ extern void default_unwind_emit (FILE *, rtx);
 
 extern bool default_scalar_mode_supported_p (enum machine_mode);
 
+extern bool default_insn_valid_within_doloop (rtx);
+
 /* These are here, and not in hooks.[ch], because not all users of
    hooks.h include tm.h, and thus we don't have CUMULATIVE_ARGS.  */