patch-2.4.0-test8 linux/arch/arm/lib/memzero.S

Next file: linux/arch/arm/lib/strchr.S
Previous file: linux/arch/arm/lib/memset.S
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0-test7/linux/arch/arm/lib/memzero.S linux/arch/arm/lib/memzero.S
@@ -1,80 +1,76 @@
 /*
  * linux/arch/arm/lib/memzero.S
  *
- * Copyright (C) 1995-1999 Russell King
+ * Copyright (C) 1995-2000 Russell King
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-#include "constants.h"
-
-		.text
 
+	.text
+	.align	5
+	.word	0
 /*
- * Prototype: void memzero(void *d, size_t n)
+ * Align the pointer in r0.  r3 contains the number of bytes that we are
+ * mis-aligned by, and r1 is the number of bytes.  If r1 < 4, then we
+ * don't bother; we use byte stores instead.
+ */
+1:	subs	r1, r1, #4		@ 1 do we have enough
+	blt	5f			@ 1 bytes to align with?
+	cmp	r3, #2			@ 1
+	strltb	r2, [r0], #1		@ 1
+	strleb	r2, [r0], #1		@ 1
+	strb	r2, [r0], #1		@ 1
+	add	r1, r1, r3		@ 1 (r1 = r1 - (4 - r3))
+/*
+ * The pointer is now aligned and the length is adjusted.  Try doing the
+ * memzero again.
  */
-1:		@ 4 <= r1
-		cmp	ip, #2				@	1
-		strltb	r2, [r0], #1			@	1
-		strleb	r2, [r0], #1			@	1
-		strb	r2, [r0], #1			@	1
-		rsb	ip, ip, #4			@	1
-		sub	r1, r1, ip			@	1
-		cmp	r1, #3				@	1
-		bgt	2f				@	1	@ +8
-		b	4f				@	1	@ +9
-
-		.align	5
 
 ENTRY(__memzero)
-		mov	r2, #0				@	1
-		cmp	r1, #4				@	1
-		blt	4f				@	1	@ = 3
-
-		@ r1 >= 4
-
-		ands	ip, r0, #3			@	1
-		bne	1b				@	1	@ = 5
-
-2:		@ r1 >= 4 && (r0 & 3) = 0				@ = 5 or 11
-
-		str	lr, [sp, #-4]!			@	1
-		mov	r3, #0				@	1
-		mov	ip, #0				@	1
-		mov	lr, #0				@	1
-
-		@ 4 <= r1 <= 32						@ = 9 or 15
-
-3:		subs	r1, r1, #32			@	1
-		stmgeia	r0!, {r2, r3, ip, lr}		@	4
-		stmgeia	r0!, {r2, r3, ip, lr}		@	4
-		bgt	3b				@	1
-		LOADREGS(eqfd, sp!, {pc})		@	1/2
-
-		@ -28 <= r1 <= -1
-
-		cmp	r1, #-16			@	1
-		stmgeia	r0!, {r2, r3, ip, lr}		@	4
-		ldr	lr, [sp], #4			@	1
-		addlts	r1, r1, #16			@	1
-		RETINSTR(moveq,pc,lr)			@	1
-
-		@ -12 <= r1 <= -1
-
-		cmp	r1, #-8				@	1
-		stmgeia	r0!, {r2, r3}			@	2
-		addlts	r1, r1, #8			@	1
-		RETINSTR(moveq,pc,lr)			@	1
-
-		@ -4 <= r1 <= -1
-
-		cmp	r1, #-4				@	1
-		strge	r2, [r0], #4			@	1
-		adds	r1, r1, #4			@	1
-		RETINSTR(moveq,pc,lr)			@	1
-
-4:		@ 1 <= r1 <= 3
-		cmp	r1, #2				@	1
-		strgtb	r2, [r0], #1			@	1
-		strgeb	r2, [r0], #1			@	1
-		strb	r2, [r0], #1			@	1
-		RETINSTR(mov,pc,lr)			@	1
+	mov	r2, #0			@ 1
+	ands	r3, r0, #3		@ 1 unaligned?
+	bne	1b			@ 1
+/*
+ * r3 = 0, and we know that the pointer in r0 is aligned to a word boundary.
+ */
+	cmp	r1, #16			@ 1 we can skip this chunk if we
+	blt	4f			@ 1 have < 16 bytes
+/*
+ * We need an extra register for this loop - save the return address and
+ * use the LR
+ */
+	str	lr, [sp, #-4]!		@ 1
+	mov	ip, r2			@ 1
+	mov	lr, r2			@ 1
+
+3:	subs	r1, r1, #64		@ 1 write 32 bytes out per loop
+	stmgeia	r0!, {r2, r3, ip, lr}	@ 4
+	stmgeia	r0!, {r2, r3, ip, lr}	@ 4
+	stmgeia	r0!, {r2, r3, ip, lr}	@ 4
+	stmgeia	r0!, {r2, r3, ip, lr}	@ 4
+	bgt	3b			@ 1
+	LOADREGS(eqfd, sp!, {pc})	@ 1/2 quick exit
+/*
+ * No need to correct the count; we're only testing bits from now on
+ */
+	tst	r1, #32			@ 1
+	stmneia	r0!, {r2, r3, ip, lr}	@ 4
+	stmneia	r0!, {r2, r3, ip, lr}	@ 4
+	tst	r1, #16			@ 1 16 bytes or more?
+	stmneia	r0!, {r2, r3, ip, lr}	@ 4
+	ldr	lr, [sp], #4		@ 1
+
+4:	tst	r1, #8			@ 1 8 bytes or more?
+	stmneia	r0!, {r2, r3}		@ 2
+	tst	r1, #4			@ 1 4 bytes or more?
+	strne	r2, [r0], #4		@ 1
+/*
+ * When we get here, we've got less than 4 bytes to zero.  We
+ * may have an unaligned pointer as well.
+ */
+5:	tst	r1, #2			@ 1 2 bytes or more?
+	strneb	r2, [r0], #1		@ 1
+	strneb	r2, [r0], #1		@ 1
+	tst	r1, #1			@ 1 a byte left over
+	strneb	r2, [r0], #1		@ 1
+	RETINSTR(mov,pc,lr)		@ 1

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)