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