diff options
Diffstat (limited to 'sysdeps/alpha/memcpy.S')
-rw-r--r-- | sysdeps/alpha/memcpy.S | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/sysdeps/alpha/memcpy.S b/sysdeps/alpha/memcpy.S new file mode 100644 index 0000000..4ee9c11 --- /dev/null +++ b/sysdeps/alpha/memcpy.S @@ -0,0 +1,276 @@ +/* Copyright (C) 1996 Free Software Foundation, Inc. + Contributed by Richard Henderson (rth@tamu.edu) + + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, write to the Free Software Foundation, Inc., 675 Mass Ave, + Cambridge, MA 02139, USA. */ + + +/* This is the child of the C-with-inline-assembly memcpy posted by + Martin Ostermann (ost@comnets.rwth-aachen.de). + + This is generally scheduled for the EV5, but whenever necessary and + possible, the autoswap slotting feature of the EV5 is used so that the + code lays out nicely for the EV4 as well. */ + +#include <alpha/regdef.h> + + .set noreorder + + .text + + .ent copy_fwd_aligned +copy_fwd_aligned: + .frame sp, 0, ra, 0 + .prologue 0 + + /* Aligned forward copy main loop. On entry to this basic block: + t0 == source word waiting to be stored + t2 == loop counter + a0 == destination pointer + a1 == source pointer + a2 mod 8 == byte count in final word */ + .align 4 +$fa_loop: + and t2, 7, t1 # e0 : + beq t1, 1f # .. e1 : + +0: stq_u t0, 0(a0) # e0 : + subq t1, 1, t1 # .. e1 : + ldq_u t0, 8(a1) # e0 : copy up to seven words + addq a0, 8, a0 # .. e1 : + addq a1, 8, a1 # e0 : + bne t1, 0b # .. e1 : + +1: bic t2, 7, t2 # e0 : + beq t2, $fa_tail # .. e1 : + +2: stq_u t0, 0(a0) # e0 : + addq a0, 64, a0 # .. e1 : + ldq_u t3, 8(a1) # e0 : copy eight words as fast as we can + ldq_u t4, 16(a1) # .. e1 : + ldq_u t5, 24(a1) # e0 : + ldq_u t6, 32(a1) # .. e1 : + ldq_u t7, 40(a1) # e0 : + ldq_u t8, 48(a1) # .. e1 : + ldq_u t9, 56(a1) # e0 : + ldq_u t0, 64(a1) # .. e1 : + stq_u t3, -56(a0) # e0 : + subq t2, 8, t2 # .. e1 : + stq_u t4, -48(a0) # e0 : + addq a1, 64, a1 # .. e1 : + stq_u t5, -40(a0) # e0 : + stq_u t6, -32(a0) # e0 : + stq_u t7, -24(a0) # e0 : + stq_u t8, -16(a0) # e0 : + stq_u t9, -8(a0) # e0 : + bne t2, 2b # .. e1 : + + /* Take care of a partial word tail. */ +$fa_tail: + and a2, 7, t3 # e0 : + bne t3, 1f # .. e1 (zdb) + + /* Aligned copy, aligned tail, final store. */ + stq_u t0, 0(a0) + ret + +1: ldq_u t1, 0(a0) # e1 : + mskql t0, a2, t0 # .. e1 : + mskqh t1, a2, t1 # e0 (stall) + bis t0, t1, t0 # e1 : + stq_u t0, 0(a0) # e0 : + ret # .. e1 : + + /* This is the actual entry point to this function. */ + .align 3 +$fwd_aligned: + ldq_u t0, 0(a1) # e0 : + and a0, 7, t3 # .. e1 : + addq a2, t3, a2 # e0 : + subq a2, 1, t2 # e1 : + sra t2, 3, t2 # e0 : + beq t3, $fa_loop # .. e1 : + + ldq_u t1, 0(a0) # e0 : + beq t2, $fa_small # .. e1 : + mskqh t0, a0, t0 # e0 : + mskql t1, a0, t3 # e0 : + bis t0, t3, t0 # e0 : + br $fa_loop # .. e1 : + + /* The move affects exactly one destination word. */ +$fa_small: + mskqh t0, a0, t0 # e0 : + and a2, 7, t4 # .. e1 : + mskql t1, a0, t3 # e0 : + bne t4, 1f # .. e1 : + + or t0, t3, t0 # e0 : + unop # : + stq_u t0, 0(a0) # e0 : + ret # .. e1 : + +1: mskql t0, a2, t0 # e0 : + mskqh t1, a2, t1 # e0 : + or t0, t3, t0 # e0 : + or t0, t1, t0 # e1 : + stq_u t0, 0(a0) # e0 : + ret # .. e1 : + + .end copy_fwd_aligned + + .ent memcpy + .globl memcpy + .align 3 +memcpy: + .frame sp, 0, ra, 0 +#ifdef PROF + ldgp gp, 0(ra) + lda AT, _mcount + jsr AT, (AT), _mcount + .prologue 1 +#else + .prologue 0 +#endif + + mov a0, v0 + beq a2, $zero_length + + /* Are source and destination co-aligned? */ + xor a0, a1, t0 + unop + and t0, 7, t0 + beq t0, $fwd_aligned + br $fwd_unaligned + + .end memcpy + + .ent copy_fwd_unaligned +copy_fwd_unaligned: + .frame sp, 0, ra, 0 + .prologue 0 + + /* Unaligned forward copy main loop. On entry to this basic block: + t0 == source low word, unshifted + t2 == loop counter + t7 == last source byte + 1 + a0 == destination pointer + a1 == source pointer + a2 mod 8 == byte count in final word */ + .align 4 +$fu_loop: + beq t2, $fu_tail # e1 : + blbc t2, 0f # e1 : + + ldq_u t1, 8(a1) # e1 : copy one unaligned word + extql t0, a1, t3 # .. e0 : + addq a1, 8, a1 # e0 : + addq a0, 8, a0 # .. e1 : + extqh t1, a1, t4 # e0 : + subq t2, 1, t2 # .. e1 : + mov t1, t0 # e0 : + or t3, t4, t3 # .. e1 : + stq_u t3, -8(a0) # e0 : + beq t2, $fu_tail # .. e1 : + +0: ldq_u t1, 8(a1) # e1 : copy two unaligned words + extql t0, a1, t3 # .. e0 : + ldq_u t0, 16(a1) # e0 : + subq t2, 2, t2 # .. e1 : + extqh t1, a1, t4 # e0 : + addq a0, 16, a0 # .. e1 : + extql t1, a1, t5 # e0 : + or t3, t4, t3 # .. e1 : + extqh t0, a1, t6 # e0 : + addq a1, 16, a1 # .. e1 : + stq_u t3, -16(a0) # e0 : + or t5, t6, t5 # .. e1 : + stq_u t5, -8(a0) # e0 : + bne t2, 0b # .. e1 : + + /* Take care of a partial words tail. */ +$fu_tail: + ldq_u t4, -1(t7) # e1 : + extql t0, a1, t3 # .. e0 : + extqh t4, a1, t4 # e0 (stall) + and a2, 7, t5 # .. e1 : + or t3, t4, t3 # e0 : + beq t5, 1f # .. e1 : + + ldq_u t1, 0(a0) # e1 : + mskql t3, a2, t3 # .. e0 : + mskqh t1, a2, t1 # e0 (stall) + or t1, t3, t3 # e1 : + +1: stq_u t3, 0(a0) # e0 : + ret # .. e1 : + + /* The entry point to the unaligned forward copy. */ + .align 3 +$fwd_unaligned: + ldq_u t0, 0(a1) # e0 : load initial bits of src + addq a1, a2, t7 # .. e1 : record last byte + 1 of src + and a0, 7, t3 # e0 : find dst misalignment + addq a2, t3, a2 # e1 : find number of words affected + subq a2, 1, t2 # e0 : + cmple a2, 8, t4 # .. e1 : are we dealing with a small block? + subq a1, t3, a1 # e0 : + bne t4, $fu_small # .. e1 : + srl t2, 3, t2 # e0 : + beq t3, $fu_loop # .. e1 : + + /* Take care of an unaligned dst head. */ + ldq_u t5, 0(a0) # e0 : + ldq_u t1, 8(a1) # .. e1 : + extql t0, a1, t3 # e0 : + addq a0, 8, a0 # .. e1 : + extqh t1, a1, t4 # e0 : + addq a1, 8, a1 # .. e1 : + mskql t5, a0, t5 # e0 : + or t3, t4, t3 # .. e1 : + mskqh t3, a0, t3 # e0 : + subq t2, 1, t2 # .. e1 : + or t3, t5, t3 # e0 : + mov t1, t0 # .. e1 : + stq_u t3, -8(a0) # e0 : + br $fu_loop # .. e1 : + + /* The move affects exactly one destination word. */ + .align 3 +$fu_small: + ldq_u t2, 0(a0) # e1 : + extql t0, a1, t3 # .. e0 : + ldq_u t1, -1(t7) # e0 : + and a2, 7, t8 # .. e1 : + mskqh t2, a2, t6 # e0 : + mskql t2, a0, t5 # e0 : + extqh t1, a1, t4 # e0 : + cmovne t8, t6, t8 # .. e1 : + or t3, t4, t3 # e0 : + or t5, t8, t5 # .. e1 : + mskqh t3, a0, t3 # e0 : + and a2, 7, t8 # .. e1 : + mskql t3, a2, t6 # e0 : + cmovne t8, t6, t8 # e1 : + or t3, t5, t3 # e0 : + unop # : + stq_u t3, 0(a0) # e0 : + +$zero_length: + ret # .. e1 : + + .end copy_fwd_unaligned |