Chris Zankel | 249ac17 | 2005-06-23 22:01:20 -0700 | [diff] [blame] | 1 | /* |
| 2 | * arch/xtensa/lib/memset.S |
| 3 | * |
| 4 | * ANSI C standard library function memset |
| 5 | * (Well, almost. .fixup code might return zero.) |
| 6 | * |
| 7 | * This file is subject to the terms and conditions of the GNU General |
| 8 | * Public License. See the file "COPYING" in the main directory of |
| 9 | * this archive for more details. |
| 10 | * |
| 11 | * Copyright (C) 2002 Tensilica Inc. |
| 12 | */ |
| 13 | |
Chris Zankel | 173d6681 | 2006-12-10 02:18:48 -0800 | [diff] [blame] | 14 | #include <asm/variant/core.h> |
Chris Zankel | 249ac17 | 2005-06-23 22:01:20 -0700 | [diff] [blame] | 15 | |
| 16 | /* |
| 17 | * void *memset(void *dst, int c, size_t length) |
| 18 | * |
| 19 | * The algorithm is as follows: |
| 20 | * Create a word with c in all byte positions |
| 21 | * If the destination is aligned, |
| 22 | * do 16B chucks with a loop, and then finish up with |
| 23 | * 8B, 4B, 2B, and 1B stores conditional on the length. |
| 24 | * If destination is unaligned, align it by conditionally |
| 25 | * setting 1B and 2B and then go to aligned case. |
| 26 | * This code tries to use fall-through branches for the common |
| 27 | * case of an aligned destination (except for the branches to |
| 28 | * the alignment labels). |
| 29 | */ |
| 30 | |
| 31 | /* Load or store instructions that may cause exceptions use the EX macro. */ |
| 32 | |
| 33 | #define EX(insn,reg1,reg2,offset,handler) \ |
| 34 | 9: insn reg1, reg2, offset; \ |
| 35 | .section __ex_table, "a"; \ |
| 36 | .word 9b, handler; \ |
| 37 | .previous |
| 38 | |
| 39 | |
| 40 | .text |
| 41 | .align 4 |
| 42 | .global memset |
| 43 | .type memset,@function |
| 44 | memset: |
| 45 | entry sp, 16 # minimal stack frame |
| 46 | # a2/ dst, a3/ c, a4/ length |
| 47 | extui a3, a3, 0, 8 # mask to just 8 bits |
| 48 | slli a7, a3, 8 # duplicate character in all bytes of word |
| 49 | or a3, a3, a7 # ... |
| 50 | slli a7, a3, 16 # ... |
| 51 | or a3, a3, a7 # ... |
| 52 | mov a5, a2 # copy dst so that a2 is return value |
| 53 | movi a6, 3 # for alignment tests |
| 54 | bany a2, a6, .Ldstunaligned # if dst is unaligned |
| 55 | .L0: # return here from .Ldstunaligned when dst is aligned |
| 56 | srli a7, a4, 4 # number of loop iterations with 16B |
| 57 | # per iteration |
| 58 | bnez a4, .Laligned |
| 59 | retw |
| 60 | |
| 61 | /* |
| 62 | * Destination is word-aligned. |
| 63 | */ |
| 64 | # set 16 bytes per iteration for word-aligned dst |
| 65 | .align 4 # 1 mod 4 alignment for LOOPNEZ |
| 66 | .byte 0 # (0 mod 4 alignment for LBEG) |
| 67 | .Laligned: |
| 68 | #if XCHAL_HAVE_LOOPS |
| 69 | loopnez a7, .Loop1done |
| 70 | #else /* !XCHAL_HAVE_LOOPS */ |
| 71 | beqz a7, .Loop1done |
| 72 | slli a6, a7, 4 |
| 73 | add a6, a6, a5 # a6 = end of last 16B chunk |
| 74 | #endif /* !XCHAL_HAVE_LOOPS */ |
| 75 | .Loop1: |
| 76 | EX(s32i, a3, a5, 0, memset_fixup) |
| 77 | EX(s32i, a3, a5, 4, memset_fixup) |
| 78 | EX(s32i, a3, a5, 8, memset_fixup) |
| 79 | EX(s32i, a3, a5, 12, memset_fixup) |
| 80 | addi a5, a5, 16 |
| 81 | #if !XCHAL_HAVE_LOOPS |
| 82 | blt a5, a6, .Loop1 |
| 83 | #endif /* !XCHAL_HAVE_LOOPS */ |
| 84 | .Loop1done: |
| 85 | bbci.l a4, 3, .L2 |
| 86 | # set 8 bytes |
| 87 | EX(s32i, a3, a5, 0, memset_fixup) |
| 88 | EX(s32i, a3, a5, 4, memset_fixup) |
| 89 | addi a5, a5, 8 |
| 90 | .L2: |
| 91 | bbci.l a4, 2, .L3 |
| 92 | # set 4 bytes |
| 93 | EX(s32i, a3, a5, 0, memset_fixup) |
| 94 | addi a5, a5, 4 |
| 95 | .L3: |
| 96 | bbci.l a4, 1, .L4 |
| 97 | # set 2 bytes |
| 98 | EX(s16i, a3, a5, 0, memset_fixup) |
| 99 | addi a5, a5, 2 |
| 100 | .L4: |
| 101 | bbci.l a4, 0, .L5 |
| 102 | # set 1 byte |
| 103 | EX(s8i, a3, a5, 0, memset_fixup) |
| 104 | .L5: |
| 105 | .Lret1: |
| 106 | retw |
| 107 | |
| 108 | /* |
| 109 | * Destination is unaligned |
| 110 | */ |
| 111 | |
| 112 | .Ldstunaligned: |
| 113 | bltui a4, 8, .Lbyteset # do short copies byte by byte |
| 114 | bbci.l a5, 0, .L20 # branch if dst alignment half-aligned |
| 115 | # dst is only byte aligned |
| 116 | # set 1 byte |
| 117 | EX(s8i, a3, a5, 0, memset_fixup) |
| 118 | addi a5, a5, 1 |
| 119 | addi a4, a4, -1 |
| 120 | # now retest if dst aligned |
| 121 | bbci.l a5, 1, .L0 # if now aligned, return to main algorithm |
| 122 | .L20: |
| 123 | # dst half-aligned |
| 124 | # set 2 bytes |
| 125 | EX(s16i, a3, a5, 0, memset_fixup) |
| 126 | addi a5, a5, 2 |
| 127 | addi a4, a4, -2 |
| 128 | j .L0 # dst is now aligned, return to main algorithm |
| 129 | |
| 130 | /* |
| 131 | * Byte by byte set |
| 132 | */ |
| 133 | .align 4 |
| 134 | .byte 0 # 1 mod 4 alignment for LOOPNEZ |
| 135 | # (0 mod 4 alignment for LBEG) |
| 136 | .Lbyteset: |
| 137 | #if XCHAL_HAVE_LOOPS |
| 138 | loopnez a4, .Lbytesetdone |
| 139 | #else /* !XCHAL_HAVE_LOOPS */ |
| 140 | beqz a4, .Lbytesetdone |
| 141 | add a6, a5, a4 # a6 = ending address |
| 142 | #endif /* !XCHAL_HAVE_LOOPS */ |
| 143 | .Lbyteloop: |
| 144 | EX(s8i, a3, a5, 0, memset_fixup) |
| 145 | addi a5, a5, 1 |
| 146 | #if !XCHAL_HAVE_LOOPS |
| 147 | blt a5, a6, .Lbyteloop |
| 148 | #endif /* !XCHAL_HAVE_LOOPS */ |
| 149 | .Lbytesetdone: |
| 150 | retw |
| 151 | |
| 152 | |
| 153 | .section .fixup, "ax" |
| 154 | .align 4 |
| 155 | |
| 156 | /* We return zero if a failure occurred. */ |
| 157 | |
| 158 | memset_fixup: |
| 159 | movi a2, 0 |
| 160 | retw |