diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 5ac385c421e6dba82c570a7771c6b4f7d2e90911..7a793511fd1832811465d5cf74d312304b07a138 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,4 +1,12 @@
-2004-08-10  Caroline Tice  <ctice@apple.com
+2004-08-10  David Edelsohn  <edelsohn@gnu.org>
+
+	* config/rs6000/rs6000-protos.h (expand_block_clear): Declare.
+	* config/rs6000/rs6000.md (clrmemsi): New pattern.
+	* config/rs6000/rs6000.c (expand_block_clear): New function.
+	(expand_block_move): Convert alignment to bits.  Use SImode and
+	HImode for unaligned addresses if not STRICT_ALIGNMENT.
+
+2004-08-10  Caroline Tice  <ctice@apple.com>
 
 	* varasm.c (unlikely_section_label): New global variable.
 	(unlikely_text_section_name): New global variable.
diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
index 5a85078e15887fb0c5204360505d4cf7fc2ab537..2e5afb6cb440e82b532058f0c45f2e4cd9ea4440 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -86,6 +86,7 @@ extern int input_operand (rtx, enum machine_mode);
 extern int small_data_operand (rtx, enum machine_mode);
 extern int s8bit_cint_operand (rtx, enum machine_mode);
 extern bool legitimate_constant_pool_address_p (rtx);
+extern int expand_block_clear (rtx[]);
 extern int expand_block_move (rtx[]);
 extern int load_multiple_operation (rtx, enum machine_mode);
 extern const char * rs6000_output_load_multiple (rtx[]);
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 338ed8250315af323ef8ad980e19c08e80ddecd8..7381a464a12483b8b74c722e5b5c8158b25f6998 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -8253,6 +8253,89 @@ rs6000_init_libfuncs (void)
       set_conv_libfunc (sfloat_optab, TFmode, SImode, "_q_itoq");
     }
 }
+
+
+/* Expand a block clear operation, and return 1 if successful.  Return 0
+   if we should let the compiler generate normal code.
+
+   operands[0] is the destination
+   operands[1] is the length
+   operands[2] is the alignment */
+
+int
+expand_block_clear (rtx operands[])
+{
+  rtx orig_dest = operands[0];
+  rtx bytes_rtx	= operands[1];
+  rtx align_rtx = operands[2];
+  int constp	= (GET_CODE (bytes_rtx) == CONST_INT);
+  int align;
+  int bytes;
+  int offset;
+  int clear_bytes;
+
+  /* If this is not a fixed size move, just call memcpy */
+  if (! constp)
+    return 0;
+
+  /* If this is not a fixed size alignment, abort */
+  if (GET_CODE (align_rtx) != CONST_INT)
+    abort ();
+  align = INTVAL (align_rtx) * BITS_PER_UNIT;
+
+  /* Anything to clear? */
+  bytes = INTVAL (bytes_rtx);
+  if (bytes <= 0)
+    return 1;
+
+  if (bytes > (TARGET_POWERPC64 && align >= 32 ? 64 : 32))
+    return 0;
+
+  if (optimize_size && bytes > 16)
+    return 0;
+
+  for (offset = 0; bytes > 0; offset += clear_bytes, bytes -= clear_bytes)
+    {
+      rtx (*mov) (rtx, rtx);
+      enum machine_mode mode = BLKmode;
+      rtx dest;
+      
+      if (bytes >= 8 && TARGET_POWERPC64
+	       /* 64-bit loads and stores require word-aligned
+		  displacements.  */
+	       && (align >= 64 || (!STRICT_ALIGNMENT && align >= 32)))
+	{
+	  clear_bytes = 8;
+	  mode = DImode;
+	  mov = gen_movdi;
+	}
+      else if (bytes >= 4 && !STRICT_ALIGNMENT)
+	{			/* move 4 bytes */
+	  clear_bytes = 4;
+	  mode = SImode;
+	  mov = gen_movsi;
+	}
+      else if (bytes == 2 && !STRICT_ALIGNMENT)
+	{			/* move 2 bytes */
+	  clear_bytes = 2;
+	  mode = HImode;
+	  mov = gen_movhi;
+	}
+      else /* move 1 byte at a time */
+	{
+	  clear_bytes = 1;
+	  mode = QImode;
+	  mov = gen_movqi;
+	}
+      
+      dest = adjust_address (orig_dest, mode, offset);
+      
+      emit_insn ((*mov) (dest, const0_rtx));
+    }
+
+  return 1;
+}
+
 
 /* Expand a block move operation, and return 1 if successful.  Return 0
    if we should let the compiler generate normal code.
@@ -8286,7 +8369,7 @@ expand_block_move (rtx operands[])
   /* If this is not a fixed size alignment, abort */
   if (GET_CODE (align_rtx) != CONST_INT)
     abort ();
-  align = INTVAL (align_rtx);
+  align = INTVAL (align_rtx) * BITS_PER_UNIT;
 
   /* Anything to move? */
   bytes = INTVAL (bytes_rtx);
@@ -8346,7 +8429,7 @@ expand_block_move (rtx operands[])
       else if (bytes >= 8 && TARGET_POWERPC64
 	       /* 64-bit loads and stores require word-aligned
 		  displacements.  */
-	       && (align >= 8 || (! STRICT_ALIGNMENT && align >= 4)))
+	       && (align >= 64 || (!STRICT_ALIGNMENT && align >= 32)))
 	{
 	  move_bytes = 8;
 	  mode = DImode;
@@ -8357,13 +8440,13 @@ expand_block_move (rtx operands[])
 	  move_bytes = (bytes > 8) ? 8 : bytes;
 	  gen_func.movmemsi = gen_movmemsi_2reg;
 	}
-      else if (bytes >= 4 && (align >= 4 || ! STRICT_ALIGNMENT))
+      else if (bytes >= 4 && !STRICT_ALIGNMENT)
 	{			/* move 4 bytes */
 	  move_bytes = 4;
 	  mode = SImode;
 	  gen_func.mov = gen_movsi;
 	}
-      else if (bytes == 2 && (align >= 2 || ! STRICT_ALIGNMENT))
+      else if (bytes == 2 && !STRICT_ALIGNMENT)
 	{			/* move 2 bytes */
 	  move_bytes = 2;
 	  mode = HImode;
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index dc8ce50b137554e60d9714506cf7e415ca1e76f8..aef44d53e4a8553aed731829b9936ea9cd7b3f49 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -9093,6 +9093,20 @@
   "{stsi|stswi} %2,%1,%O0"
   [(set_attr "type" "store")])
 
+(define_expand "clrmemsi"
+  [(parallel [(set (match_operand:BLK 0 "" "")
+		   (const_int 0))
+	      (use (match_operand:SI 1 "" ""))
+	      (use (match_operand:SI 2 "" ""))])]
+  ""
+  "
+{
+  if (expand_block_clear (operands))
+    DONE;
+  else
+    FAIL;
+}")
+
 ;; String/block move insn.
 ;; Argument 0 is the destination
 ;; Argument 1 is the source