[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