[PATCH 15/20] alpha: load all 8 quads before storing in the ev6 memcpy unrolled loop
Matt Turner
mattst88@gmail.com
Wed Aug 12 01:19:52 GMT 2026
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
More information about the Libc-alpha
mailing list