1/* strchr (str, ch) -- Return pointer to first occurrence of CH in STR. 2 For Motorola 68000. 3 Copyright (C) 1999-2022 Free Software Foundation, Inc. 4 This file is part of the GNU C Library. 5 6 The GNU C Library is free software; you can redistribute it and/or 7 modify it under the terms of the GNU Lesser General Public 8 License as published by the Free Software Foundation; either 9 version 2.1 of the License, or (at your option) any later version. 10 11 The GNU C Library is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 Lesser General Public License for more details. 15 16 You should have received a copy of the GNU Lesser General Public 17 License along with the GNU C Library. If not, see 18 <https://www.gnu.org/licenses/>. */ 19 20#include <sysdep.h> 21#include "asm-syntax.h" 22 23 TEXT 24ENTRY(strchr) 25 /* Save the callee-saved registers we use. */ 26 movel R(d2),MEM_PREDEC(sp) 27 cfi_adjust_cfa_offset (4) 28 movel R(d3),MEM_PREDEC(sp) 29 cfi_adjust_cfa_offset (4) 30 cfi_rel_offset (R(d2),4) 31 cfi_rel_offset (R(d3),0) 32 33 /* Get string pointer and character. */ 34 movel MEM_DISP(sp,12),R(a0) 35 moveb MEM_DISP(sp,19),R(d0) 36 37 /* Distribute the character to all bytes of a longword. */ 38 movel R(d0),R(d1) 39 lsll #8,R(d1) 40 moveb R(d0),R(d1) 41 movel R(d1),R(d0) 42 swap R(d0) 43 movew R(d1),R(d0) 44 45 /* First search for the character one byte at a time until the 46 pointer is aligned to a longword boundary. */ 47 movel R(a0),R(d1) 48#ifdef __mcoldfire__ 49 andl #3,R(d1) 50#else 51 andw #3,R(d1) 52#endif 53 beq L(L1) 54 moveb MEM(a0),R(d2) 55 cmpb R(d0),R(d2) 56 beq L(L9) 57 tstb R(d2) 58 beq L(L3) 59 addql #1,R(a0) 60 61#ifdef __mcoldfire__ 62 subql #3,R(d1) 63#else 64 subqw #3,R(d1) 65#endif 66 beq L(L1) 67 moveb MEM(a0),R(d2) 68 cmpb R(d0),R(d2) 69 beq L(L9) 70 tstb R(d2) 71 beq L(L3) 72 addql #1,R(a0) 73 74#ifdef __mcoldfire__ 75 addql #1,R(d1) 76#else 77 addqw #1,R(d1) 78#endif 79 beq L(L1) 80 moveb MEM(a0),R(d2) 81 cmpb R(d0),R(d2) 82 beq L(L9) 83 tstb R(d2) 84 beq L(L3) 85 addql #1,R(a0) 86 87L(L1:) 88 /* Load the magic bits. Unlike the generic implementation we can 89 use the carry bit as the fourth hole. */ 90 movel #0xfefefeff,R(d3) 91 92 /* We exit the loop if adding MAGIC_BITS to LONGWORD fails to 93 change any of the hole bits of LONGWORD. 94 95 1) Is this safe? Will it catch all the zero bytes? 96 Suppose there is a byte with all zeros. Any carry bits 97 propagating from its left will fall into the hole at its 98 least significant bit and stop. Since there will be no 99 carry from its most significant bit, the LSB of the 100 byte to the left will be unchanged, and the zero will be 101 detected. 102 103 2) Is this worthwhile? Will it ignore everything except 104 zero bytes? Suppose every byte of LONGWORD has a bit set 105 somewhere. There will be a carry into bit 8. If bit 8 106 is set, this will carry into bit 16. If bit 8 is clear, 107 one of bits 9-15 must be set, so there will be a carry 108 into bit 16. Similarly, there will be a carry into bit 109 24. If one of bits 24-31 is set, there will be a carry 110 into bit 32 (=carry flag), so all of the hole bits will 111 be changed. 112 113 3) But wait! Aren't we looking for C, not zero? 114 Good point. So what we do is XOR LONGWORD with a longword, 115 each of whose bytes is C. This turns each byte that is C 116 into a zero. */ 117 118L(L2:) 119 /* Get the longword in question. */ 120 movel MEM_POSTINC(a0),R(d1) 121 /* XOR with the byte we search for. */ 122 eorl R(d0),R(d1) 123 124 /* Add the magic value. We get carry bits reported for each byte 125 which is not C. */ 126 movel R(d3),R(d2) 127 addl R(d1),R(d2) 128 129 /* Check the fourth carry bit before it is clobbered by the next 130 XOR. If it is not set we have a hit. */ 131 bcc L(L8) 132 133 /* We are only interested in carry bits that change due to the 134 previous add, so remove original bits. */ 135 eorl R(d1),R(d2) 136 137 /* Now test for the other three overflow bits. 138 Set all non-carry bits. */ 139 orl R(d3),R(d2) 140 /* Add 1 to get zero if all carry bits were set. */ 141 addql #1,R(d2) 142 143 /* If we don't get zero then at least one byte of the word equals 144 C. */ 145 bne L(L8) 146 147 /* Next look for a NUL byte. 148 Restore original longword without reload. */ 149 eorl R(d0),R(d1) 150 /* Add the magic value. We get carry bits reported for each byte 151 which is not NUL. */ 152 movel R(d3),R(d2) 153 addl R(d1),R(d2) 154 155 /* Check the fourth carry bit before it is clobbered by the next 156 XOR. If it is not set we have a hit, and return NULL. */ 157 bcc L(L3) 158 159 /* We are only interested in carry bits that change due to the 160 previous add, so remove original bits. */ 161 eorl R(d1),R(d2) 162 163 /* Now test for the other three overflow bits. 164 Set all non-carry bits. */ 165 orl R(d3),R(d2) 166 /* Add 1 to get zero if all carry bits were set. */ 167 addql #1,R(d2) 168 169 /* If we don't get zero then at least one byte of the word was NUL 170 and we return NULL. Otherwise continue with the next longword. */ 171 bne L(L3) 172 173 /* Get the longword in question. */ 174 movel MEM_POSTINC(a0),R(d1) 175 /* XOR with the byte we search for. */ 176 eorl R(d0),R(d1) 177 178 /* Add the magic value. We get carry bits reported for each byte 179 which is not C. */ 180 movel R(d3),R(d2) 181 addl R(d1),R(d2) 182 183 /* Check the fourth carry bit before it is clobbered by the next 184 XOR. If it is not set we have a hit. */ 185 bcc L(L8) 186 187 /* We are only interested in carry bits that change due to the 188 previous add, so remove original bits */ 189 eorl R(d1),R(d2) 190 191 /* Now test for the other three overflow bits. 192 Set all non-carry bits. */ 193 orl R(d3),R(d2) 194 /* Add 1 to get zero if all carry bits were set. */ 195 addql #1,R(d2) 196 197 /* If we don't get zero then at least one byte of the word equals 198 C. */ 199 bne L(L8) 200 201 /* Next look for a NUL byte. 202 Restore original longword without reload. */ 203 eorl R(d0),R(d1) 204 /* Add the magic value. We get carry bits reported for each byte 205 which is not NUL. */ 206 movel R(d3),R(d2) 207 addl R(d1),R(d2) 208 209 /* Check the fourth carry bit before it is clobbered by the next 210 XOR. If it is not set we have a hit, and return NULL. */ 211 bcc L(L3) 212 213 /* We are only interested in carry bits that change due to the 214 previous add, so remove original bits */ 215 eorl R(d1),R(d2) 216 217 /* Now test for the other three overflow bits. 218 Set all non-carry bits. */ 219 orl R(d3),R(d2) 220 /* Add 1 to get zero if all carry bits were set. */ 221 addql #1,R(d2) 222 223 /* If we don't get zero then at least one byte of the word was NUL 224 and we return NULL. Otherwise continue with the next longword. */ 225 beq L(L2) 226 227L(L3:) 228 /* Return NULL. */ 229 clrl R(d0) 230 movel R(d0),R(a0) 231 movel MEM_POSTINC(sp),R(d3) 232 cfi_remember_state 233 cfi_adjust_cfa_offset (-4) 234 cfi_restore (R(d3)) 235 movel MEM_POSTINC(sp),R(d2) 236 cfi_adjust_cfa_offset (-4) 237 cfi_restore (R(d2)) 238 rts 239 240 cfi_restore_state 241L(L8:) 242 /* We have a hit. Check to see which byte it was. First 243 compensate for the autoincrement in the loop. */ 244 subql #4,R(a0) 245 246 moveb MEM(a0),R(d1) 247 cmpb R(d0),R(d1) 248 beq L(L9) 249 tstb R(d1) 250 beq L(L3) 251 addql #1,R(a0) 252 253 moveb MEM(a0),R(d1) 254 cmpb R(d0),R(d1) 255 beq L(L9) 256 tstb R(d1) 257 beq L(L3) 258 addql #1,R(a0) 259 260 moveb MEM(a0),R(d1) 261 cmpb R(d0),R(d1) 262 beq L(L9) 263 tstb R(d1) 264 beq L(L3) 265 addql #1,R(a0) 266 267 /* Otherwise the fourth byte must equal C. */ 268L(L9:) 269 movel R(a0),R(d0) 270 movel MEM_POSTINC(sp),R(d3) 271 cfi_adjust_cfa_offset (-4) 272 cfi_restore (R(d3)) 273 movel MEM_POSTINC(sp),R(d2) 274 cfi_adjust_cfa_offset (-4) 275 cfi_restore (R(d2)) 276 rts 277END(strchr) 278 279weak_alias (strchr, index) 280libc_hidden_builtin_def (strchr) 281