diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index cb72d95662752823eac4ad71db7198540066c4ec..9df927a19b231603f188fd8a8c0b915abeb1e9c1 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -110,6 +110,12 @@ Tue Aug 24 09:32:07 1999  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
 
 Tue Aug 24 12:35:20 1999  Bernd Schmidt  <bernds@cygnus.co.uk>
 
+	* gcse.c (find_avail_set): Follow chains of register-register copies.
+	Use oprs_not_set_p to guarantee that the returned value can be
+	substituted.
+	(cprop_insn): Don't verify the return value of find_avail_set with
+	oprs_not_set_p.
+
 	* gcse.c (cprop_jump): New function, broken out of cprop_insn.
 	(cprop_cc0_jump): New function.
 	(cprop_insn): Break out new function cprop_jump and use it.
diff --git a/gcc/gcse.c b/gcc/gcse.c
index 36b376b68670a639ad9764143723c78f055a951e..f5fe9b9cd6f572b05a13b7946bdb4ade71f177c0 100644
--- a/gcc/gcse.c
+++ b/gcc/gcse.c
@@ -3656,16 +3656,65 @@ find_avail_set (regno, insn)
      int regno;
      rtx insn;
 {
-  struct expr *set = lookup_set (regno, NULL_RTX);
+  /* SET1 contains the last set found that can be returned to the caller for
+     use in a substitution.  */
+  struct expr *set1 = 0;
+ 
+  /* Loops are not possible here.  To get a loop we would need two sets
+     available at the start of the block containing INSN.  ie we would
+     need two sets like this available at the start of the block:
+
+       (set (reg X) (reg Y))
+       (set (reg Y) (reg X))
+
+     This can not happen since the set of (reg Y) would have killed the
+     set of (reg X) making it unavailable at the start of this block.  */
+  while (1)
+     {
+      rtx src;
+      struct expr *set = lookup_set (regno, NULL_RTX);
+
+      /* Find a set that is available at the start of the block
+	 which contains INSN.  */
+      while (set)
+	{
+	  if (TEST_BIT (cprop_avin[BLOCK_NUM (insn)], set->bitmap_index))
+	    break;
+	  set = next_set (regno, set);
+	}
 
-  while (set)
-    {
-      if (TEST_BIT (cprop_avin[BLOCK_NUM (insn)], set->bitmap_index))
+      /* If no available set was found we've reached the end of the
+	 (possibly empty) copy chain.  */
+      if (set == 0)
+ 	break;
+
+      if (GET_CODE (set->expr) != SET)
+	abort ();
+
+      src = SET_SRC (set->expr);
+
+      /* We know the set is available.
+	 Now check that SRC is ANTLOC (i.e. none of the source operands
+	 have changed since the start of the block).  
+
+         If the source operand changed, we may still use it for the next
+         iteration of this loop, but we may not use it for substitutions.  */
+      if (CONSTANT_P (src) || oprs_not_set_p (src, insn))
+	set1 = set;
+
+      /* If the source of the set is anything except a register, then
+	 we have reached the end of the copy chain.  */
+      if (GET_CODE (src) != REG)
 	break;
-      set = next_set (regno, set);
-    }
 
-  return set;
+      /* Follow the copy chain, ie start another iteration of the loop
+	 and see if we have an available copy into SRC.  */
+      regno = REGNO (src);
+     }
+
+  /* SET1 holds the last set that was available and anticipatable at
+     INSN.  */
+  return set1;
 }
 
 /* Subroutine of cprop_insn that tries to propagate constants into
@@ -3875,27 +3924,21 @@ cprop_insn (insn, alter_jumps)
 	       && REGNO (src) >= FIRST_PSEUDO_REGISTER
 	       && REGNO (src) != regno)
 	{
-	  /* We know the set is available.
-	     Now check that SET_SRC is ANTLOC (i.e. none of the source operands
-	     have changed since the start of the block).  */
-	  if (oprs_not_set_p (src, insn))
+	  if (try_replace_reg (reg_used->reg_rtx, src, insn))
 	    {
-	      if (try_replace_reg (reg_used->reg_rtx, src, insn))
+	      changed = 1;
+	      copy_prop_count++;
+	      if (gcse_file != NULL)
 		{
-		  changed = 1;
-		  copy_prop_count++;
-		  if (gcse_file != NULL)
-		    {
-		      fprintf (gcse_file, "COPY-PROP: Replacing reg %d in insn %d with reg %d\n",
-			       regno, INSN_UID (insn), REGNO (src));
-		    }
-
-		  /* The original insn setting reg_used may or may not now be
-		     deletable.  We leave the deletion to flow.  */
-		  /* FIXME: If it turns out that the insn isn't deletable,
-		     then we may have unnecessarily extended register lifetimes
-		     and made things worse.  */
+		  fprintf (gcse_file, "COPY-PROP: Replacing reg %d in insn %d with reg %d\n",
+			   regno, INSN_UID (insn), REGNO (src));
 		}
+
+	      /* The original insn setting reg_used may or may not now be
+		 deletable.  We leave the deletion to flow.  */
+	      /* FIXME: If it turns out that the insn isn't deletable,
+		 then we may have unnecessarily extended register lifetimes
+		 and made things worse.  */
 	    }
 	}
     }