[PATCH 15/20] alpha: load all 8 quads before storing in the ev6 memcpy unrolled loop

Matt Turner <[email protected]>
Newsgroups gmane.comp.lib.glibc.alpha
Message-ID <82c81f07e7a2b0c2385f6c8dc5d174cd0edf68fc.1786497497.git.mattst88@gmail.com>
The unrolled loop interleaved load-4/store-4/load-4/store-4 each 64-byte
trip, forcing every store group to wait on the load beside it. Loading
all 8 quads before storing any of them gives the Mbox a full run of
independent loads to hide behind, and the store run after has no load
dependency left to stall on.

Measured on an EV68CB: 19-39% fewer cycles/call hot from 512B upward,
with Mbox replay traps (perf r4) roughly halved at 64KB-256KB, and 1-4%
cold at the same sizes once DRAM latency dominates over scheduling.
Below 512B the two shapes are within measurement noise.
---
 sysdeps/alpha/alphaev6/memcpy.S | 64 ++++++++++++++++++---------------
 1 file changed, 35 insertions(+), 29 deletions(-)

diff --git ./sysdeps/alpha/alphaev6/memcpy.S ./sysdeps/alpha/alphaev6/memcpy.S
index d86c00b9be..fb7bb77d42 100644
--- ./sysdeps/alpha/alphaev6/memcpy.S
+++ ./sysdeps/alpha/alphaev6/memcpy.S
@@ -139,57 +139,61 @@ $do_unroll:
 	subq	$18, 192, $2		# E : room for [$16+128, $16+192)?
 	cmovlt	$2, $16, $7		# E : no -- hint the first block instead
 
+	/*
+	 * Each trip loads all 8 quads before storing any of them, rather than
+	 * interleaving load-4/store-4/load-4/store-4.  The four extra live
+	 * values need four more registers across the trip -- $8/$22/$24/$25
+	 * (t7/t8/t10/t11) join $3-$6, all still caller-saved so this needs no
+	 * prologue.  Interleaving forced a store to wait on the load beside it
+	 * every four quads; loading the whole trip first gives the Mbox a full
+	 * run of independent loads to hide behind before the first store of
+	 * the trip is issued, and the store run after has no load dependency
+	 * left to stall on.  Measured on an EV68CB: 19-39% fewer cycles/call
+	 * hot from 512B upward (Mbox replay traps roughly halved at 64KB-256KB),
+	 * 1-4% cold at the same sizes once DRAM latency dominates.  Below 512B
+	 * the difference is inside measurement noise either way.
+	 */
 $unroll_body:
 	wh64	($7)			# L1 : memory subsystem hint: 64 bytes at
 					# ($7) are about to be over-written
 	ldq	$6, 0($17)		# L0 : bytes 0..7
-	nop				# E :
+	ldq	$4, 8($17)		# L : bytes 8..15
 	nop				# E :
 
-	ldq	$4, 8($17)		# L : bytes 8..15
 	ldq	$5, 16($17)		# L : bytes 16..23
+	ldq	$3, 24($17)		# L : bytes 24..31
 	addq	$7, 64, $7		# E : Update next wh64 address
 	nop				# E :
 
-	ldq	$3, 24($17)		# L : bytes 24..31
+	ldq	$8, 32($17)		# L : bytes 32..39
+	ldq	$22, 40($17)		# L : bytes 40..47
 	addq	$16, 64, $23		# E : fallback wh64 address (see below)
 	nop				# E :
-	nop				# E :
 
-	addq	$17, 32, $17		# E : src += 32 bytes
-	stq	$6, 0($16)		# L : bytes 0..7
-	nop				# E :
-	nop				# E :
-
-	stq	$4, 8($16)		# L : bytes 8..15
-	stq	$5, 16($16)		# L : bytes 16..23
+	ldq	$24, 48($17)		# L : bytes 48..55
+	ldq	$25, 56($17)		# L : bytes 56..63
+	addq	$17, 64, $17		# E : src += 64 bytes
 	lda	$2, -256($18)		# E : room for the +2 line hint next trip?
 					#     it covers [$16+128, $16+192) there,
 					#     so that trip needs 192 and this one
 					#     needs 256 (256 exceeds the subq
 					#     literal field, hence lda)
+
+	stq	$6, 0($16)		# L : bytes 0..7
+	stq	$4, 8($16)		# L : bytes 8..15
+	nop				# E :
 	nop				# E :
 
+	stq	$5, 16($16)		# L : bytes 16..23
 	stq	$3, 24($16)		# L : bytes 24..31
-	addq	$16, 32, $16		# E : dest += 32 bytes
-	nop				# E :
-	nop				# E :
-
-	ldq	$6, 0($17)		# L : bytes 0..7
-	ldq	$4, 8($17)		# L : bytes 8..15
-	nop				# E :
-	nop				# E :
-
-	ldq	$5, 16($17)		# L : bytes 16..23
-	ldq	$3, 24($17)		# L : bytes 24..31
-	addq	$16, 32, $16		# E : dest += 32
 	subq	$18, 64, $18		# E : count -= 64
-
-	addq	$17, 32, $17		# E : src += 32
-	stq	$6, -32($16)		# L : bytes 0..7
-	stq	$4, -24($16)		# L : bytes 8..15
 	cmple	$18, 63, $1		# E : At least one more trip?
 
+	stq	$8, 32($16)		# L : bytes 32..39
+	stq	$22, 40($16)		# L : bytes 40..47
+	nop				# E :
+	nop				# E :
+
 	/*
 	 * $7 is deliberately finalized late, in the group with the loop branch
 	 * rather than alongside the loads above, and the fallback address lives
@@ -203,10 +207,12 @@ $unroll_body:
 	 * Moving it back up, or reusing $1 so that it has to move back up,
 	 * gives up that gain.
 	 */
-	stq	$5, -16($16)		# L : bytes 16..23
-	stq	$3, -8($16)		# L : bytes 24..31
+	stq	$24, 48($16)		# L : bytes 48..55
+	stq	$25, 56($16)		# L : bytes 56..63
+	addq	$16, 64, $16		# E : dest += 64 bytes
 	cmovlt	$2, $23, $7		# E : fallback if < 2 more trips (late; see
 					#     the note above -- do not hoist this)
+
 	beq	$1, $unroll_body
 	br	$31, $tail_quads	# U : 1..15 trailing quads/bytes
 
-- 
2.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.