Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(revision 170734)
+++ gcc/doc/invoke.texi	(working copy)
@@ -741,7 +741,7 @@
 -mno-am33 -mam33 -mam33-2 -mam34 @gol
 -mtune=@var{cpu-type} @gol
 -mreturn-pointer-on-d0 @gol
--mno-crt0  -mrelax -mliw}
+-mno-crt0  -mrelax -mliw -msetlb}
 
 @emph{PDP-11 Options}
 @gccoptlist{-mfpu  -msoft-float  -mac0  -mno-ac0  -m40  -m45  -m10 @gol
@@ -15075,6 +15075,18 @@
 instructions.  This option defines the preprocessor macro
 @samp{__NO_LIW__}.
 
+@item -msetlb
+@opindex msetlb
+Allow the compiler to generate the @emph{SETLB} and @emph{Lcc}
+instructions if the target is the @samp{AM33} or later.  This is the
+default.  This option defines the preprocessor macro @samp{__SETLB__}.
+
+@item -mnosetlb
+@opindex mnosetlb
+Do not allow the compiler to generate @emph{SETLB} or @emph{Lcc}
+instructions.  This option defines the preprocessor macro
+@samp{__NO_SETLB__}.
+
 @end table
 
 @node PDP-11 Options
Index: gcc/config/mn10300/mn10300.c
===================================================================
--- gcc/config/mn10300/mn10300.c	(revision 170734)
+++ gcc/config/mn10300/mn10300.c	(working copy)
@@ -44,7 +44,9 @@
 #include "target.h"
 #include "target-def.h"
 #include "df.h"
+#include "cfgloop.h"
 
+
 /* This is used in the am33_2.0-linux-gnu port, in which global symbol
    names are not prefixed by underscores, to tell whether to prefix a
    label with a plus sign or not, so that the assembler can tell
@@ -3134,11 +3136,193 @@
     }
 }
 
+#define DUMP(reason, insn)			\
+  do						\
+    {						\
+      if (dump_file)				\
+	{					\
+	  fprintf (dump_file, reason "\n");	\
+	  if (insn != NULL_RTX)			\
+	    print_rtl_single (dump_file, insn);	\
+	  fprintf(dump_file, "\n");		\
+	}					\
+    }						\
+  while (0)
+
+/* Replace the BRANCH insn with a Lcc insn that goes to LABEL.
+   Insert a SETLB insn after LABEL.  */
+
 static void
+mn10300_insert_setlb_lcc (rtx label, rtx branch)
+{
+  rtx lcc, comparison, cmp_reg;
+
+  DUMP ("Inserting SETLB insn after:", label);
+  emit_insn_after (gen_setlb (), label);
+
+  comparison = XEXP (SET_SRC (PATTERN (branch)), 0);
+  cmp_reg = XEXP (comparison, 0);
+  gcc_assert (REG_P (cmp_reg));
+
+  /* If the comparison has not already been split out of the branch
+     then do so now.  */
+  if (REGNO (cmp_reg) != CC_REG)
+    {
+      rtx cmp;
+
+      cmp = emit_insn_before (gen_cmpsi (cmp_reg, XEXP (comparison, 1)), branch);
+
+      DUMP ("Extracted comparison from branch:", cmp);
+    }
+
+  if (GET_MODE (cmp_reg) == CC_FLOATmode)
+    lcc = gen_FLcc (comparison, label);
+  else
+    lcc = gen_Lcc (comparison, label);    
+
+  lcc = emit_jump_insn_before (lcc, branch);
+  mark_jump_label (XVECEXP (PATTERN (lcc), 0, 0), lcc, 0);
+  DUMP ("Replacing branch insn...", branch);
+  DUMP ("... with Lcc insn:", lcc);  
+  delete_insn (branch);
+}
+
+static bool
+mn10300_block_contains_call (struct basic_block_def * block)
+{
+  rtx insn;
+
+  for (insn = block->il.rtl->head_;
+       insn != NULL_RTX;
+       insn = NEXT_INSN (insn))
+    {
+      if (CALL_P (insn))
+	return true;
+
+      if (insn == block->il.rtl->end_)
+	break;
+    }
+
+  return false;
+}
+
+static bool
+mn10300_loop_contains_call_insn (loop_p loop)
+{
+  basic_block * bbs;
+  bool result = false;
+  unsigned int i;
+
+  bbs = get_loop_body (loop);
+
+  for (i = 0; i < loop->num_nodes; i++)
+    if (mn10300_block_contains_call (bbs[i]))
+      {
+	result = true;
+	break;
+      }
+
+  free (bbs);
+  return result;
+}
+
+static void
+mn10300_scan_for_setlb_lcc (void)
+{
+  struct loops loops;
+
+  DUMP ("Looking for loops that can use the SETLB insn", NULL_RTX);
+
+  df_analyze ();
+  if (flow_loops_find (& loops) > 0)
+    {
+      unsigned int i;
+      loop_p loop;
+
+      FOR_EACH_VEC_ELT (loop_p, loops.larray, i, loop)
+	{
+	  const char * reason = NULL;
+
+	  /* Check to see if we can modify this loop.  If we cannot
+	     then set 'reason' to describe why it could not be done.  */
+	  if (loop == loops.tree_root)
+	    ; /* Fake loop - ignore.  */
+	  else if (get_loop_level (loop) > 0)
+	    reason = "it contains other loops";
+	  else if (loop->latch == NULL)
+	    reason = "it contains multiple latches";
+	  else if (loop->header != loop->latch)
+	    reason = "it is not a simple do-while loop";
+	  else if (mn10300_loop_contains_call_insn (loop))
+	    reason = "it contains CALL insns";
+	  else
+	    {
+	      rtx branch = loop->header->il.rtl->end_;
+
+	      gcc_assert (JUMP_P (branch));
+	      if (single_set (branch) == NULL_RTX
+		  || GET_CODE (SET_SRC (single_set (branch))) != IF_THEN_ELSE)
+		{
+		  /* We do not support tablejumps and the like.  */
+		  reason = "it is not a simple loop";
+		}
+	      else
+		{
+		  rtx label;
+
+		  if (dump_file)
+		    flow_loop_dump (loop, dump_file, NULL, 0);
+
+		  label = loop->latch->il.rtl->head_;
+		  /* If necessary, extract the label from the branch insn.  */
+		  if (! LABEL_P (label))
+		    {
+		      rtx ref = XEXP (SET_SRC (PATTERN (branch)), 1);
+
+		      gcc_assert (GET_CODE (ref) == LABEL_REF);
+
+		      for (label = get_insns ();
+			   label != NULL_RTX;
+			   label = next_nonnote_nondebug_insn (label))
+			if (INSN_UID (label) == INSN_UID (XEXP (ref, 0)))
+			  break;
+
+		      gcc_assert (label != NULL_RTX);
+		      gcc_assert (LABEL_P (label));
+		    }
+
+		  mn10300_insert_setlb_lcc (label, branch);
+		}
+	    }
+
+	  if (dump_file && reason != NULL)
+	    fprintf (dump_file, "Loop starting with insn %d is not suitable because %s\n",
+		     INSN_UID (loop->header->il.rtl->head_),
+		     reason);
+	}
+
+      /* FIXME: Calling flow_loops_free() appears to be the correct thing to do,
+	 but it results in a seg-fault when building regex.c in the target libiberty
+	 library.  I have no idea why; so I have disabled the call for now.  */
+      /* flow_loops_free (& loops); */
+    }
+  else
+    DUMP ("No loops found", NULL_RTX);
+
+  df_finish_pass (false);  
+
+  DUMP ("SETLB scan complete", NULL_RTX);
+}
+
+static void
 mn10300_reorg (void)
 {
-  if (TARGET_AM33)
+  /* These are optimizations, so only run them if optimizing.  */
+  if (TARGET_AM33 && (optimize > 0 || optimize_size))
     {
+      if (TARGET_ALLOW_SETLB)
+	mn10300_scan_for_setlb_lcc ();
+
       if (TARGET_ALLOW_LIW)
 	mn10300_bundle_liw ();
     }
@@ -3176,7 +3360,7 @@
 #define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA mn10300_asm_output_addr_const_extra
 
 #undef  TARGET_DEFAULT_TARGET_FLAGS
-#define TARGET_DEFAULT_TARGET_FLAGS MASK_MULT_BUG | MASK_PTR_A0D0 | MASK_ALLOW_LIW
+#define TARGET_DEFAULT_TARGET_FLAGS MASK_MULT_BUG | MASK_PTR_A0D0 | MASK_ALLOW_LIW | MASK_ALLOW_SETLB
 #undef  TARGET_HANDLE_OPTION
 #define TARGET_HANDLE_OPTION mn10300_handle_option
 #undef  TARGET_OPTION_OVERRIDE
Index: gcc/config/mn10300/mn10300.opt
===================================================================
--- gcc/config/mn10300/mn10300.opt	(revision 170734)
+++ gcc/config/mn10300/mn10300.opt	(working copy)
@@ -54,3 +54,7 @@
 mliw
 Target Report Mask(ALLOW_LIW)
 Allow gcc to generate LIW instructions
+
+msetlb
+Target Report Mask(ALLOW_SETLB)
+Allow gcc to generate the SETLB and Lcc instructions
Index: gcc/config/mn10300/mn10300.h
===================================================================
--- gcc/config/mn10300/mn10300.h	(revision 170734)
+++ gcc/config/mn10300/mn10300.h	(working copy)
@@ -54,6 +55,8 @@
       builtin_define (TARGET_ALLOW_LIW ?	\
 		      "__LIW__" : "__NO_LIW__");\
 						\
+      builtin_define (TARGET_ALLOW_SETLB  ?	\
+		      "__SETLB__" : "__NO_SETLB__");\
     }						\
   while (0)
 
Index: gcc/config/mn10300/mn10300.md
===================================================================
--- gcc/config/mn10300/mn10300.md	(revision 170734)
+++ gcc/config/mn10300/mn10300.md	(working copy)
@@ -42,6 +42,8 @@
 
   ;; This is used to encode LIW patterns.
   (UNSPEC_LIW		8)
+  ;; This is for the low overhead loop instructions.
+  (UNSPEC_SETLB         9)
 ])
 
 (include "predicates.md")
@@ -1375,7 +1377,7 @@
   DONE;
 })
 
-(define_insn "*cmpsi"
+(define_insn "cmpsi"
   [(set (reg CC_REG)
 	(compare (match_operand:SI 0 "register_operand"  "r,r,r")
 		 (match_operand:SI 1 "nonmemory_operand" "r,O,i")))]
@@ -2152,3 +2154,39 @@
   [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
 				       (const_int 13) (const_int 12)))]
 )
+
+;; Note - in theory the doloop patterns could be used here to express
+;; the SETLB and Lcc instructions.  In practice this does not work because
+;; the acceptable forms of the doloop patterns do not include UNSPECs
+;; and without them gcc's basic block reordering code can duplicate the
+;; doloop_end pattern, leading to bogus multiple decrements of the loop
+;; counter. 
+
+(define_insn "setlb"
+  [(unspec [(const_int 0)] UNSPEC_SETLB)]
+  "TARGET_AM33 && TARGET_ALLOW_SETLB"
+  "setlb"
+)
+
+(define_insn "Lcc"
+  [(set (pc)
+	(if_then_else (match_operator 0 "comparison_operator"
+		      [(reg:CC CC_REG) (const_int 0)])
+		      (label_ref (match_operand 1 "" ""))
+		      (pc)))
+   (unspec [(const_int 1)] UNSPEC_SETLB)]
+  "TARGET_AM33 && TARGET_ALLOW_SETLB"
+  "L%b0 # loop back to: %1"
+)
+
+(define_insn "FLcc"
+  [(set (pc)
+	(if_then_else (match_operator 0 "comparison_operator"
+		      [(reg:CC_FLOAT CC_REG) (const_int 0)])
+		      (label_ref (match_operand 1 "" ""))
+		      (pc)))
+   (unspec [(const_int 2)] UNSPEC_SETLB)]
+  "TARGET_AM33_2 && TARGET_ALLOW_SETLB"
+  "FL%b0 # loop back to: %1"
+  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34") (const_int 44) (const_int 11)))]
+)
