1*412f47f9SXin Li/* 2*412f47f9SXin Li * strrchr - find the last of a character in a string 3*412f47f9SXin Li * 4*412f47f9SXin Li * Copyright (c) 2019-2022, Arm Limited. 5*412f47f9SXin Li * SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception 6*412f47f9SXin Li */ 7*412f47f9SXin Li 8*412f47f9SXin Li#include "asmdefs.h" 9*412f47f9SXin Li 10*412f47f9SXin Li#if __ARM_FEATURE_SVE 11*412f47f9SXin Li/* Assumptions: 12*412f47f9SXin Li * 13*412f47f9SXin Li * ARMv8-a, AArch64 14*412f47f9SXin Li * SVE Available. 15*412f47f9SXin Li */ 16*412f47f9SXin Li 17*412f47f9SXin LiENTRY (__strrchr_aarch64_sve) 18*412f47f9SXin Li PTR_ARG (0) 19*412f47f9SXin Li dup z1.b, w1 /* replicate byte across vector */ 20*412f47f9SXin Li setffr /* initialize FFR */ 21*412f47f9SXin Li ptrue p1.b /* all ones; loop invariant */ 22*412f47f9SXin Li mov x2, 0 /* no match found so far */ 23*412f47f9SXin Li pfalse p2.b 24*412f47f9SXin Li 25*412f47f9SXin Li .p2align 4 26*412f47f9SXin Li /* Read a vector's worth of bytes, stopping on first fault. */ 27*412f47f9SXin Li0: ldff1b z0.b, p1/z, [x0, xzr] 28*412f47f9SXin Li rdffrs p0.b, p1/z 29*412f47f9SXin Li b.nlast 1f 30*412f47f9SXin Li 31*412f47f9SXin Li /* First fault did not fail: the whole vector is valid. 32*412f47f9SXin Li Avoid depending on the contents of FFR beyond the branch. */ 33*412f47f9SXin Li incb x0, all /* skip bytes this round */ 34*412f47f9SXin Li cmpeq p3.b, p1/z, z0.b, 0 /* search for 0 */ 35*412f47f9SXin Li b.any 3f 36*412f47f9SXin Li 37*412f47f9SXin Li cmpeq p3.b, p1/z, z0.b, z1.b /* search for c; no eos */ 38*412f47f9SXin Li b.none 0b 39*412f47f9SXin Li 40*412f47f9SXin Li mov x2, x0 /* save advanced base */ 41*412f47f9SXin Li mov p2.b, p3.b /* save current search */ 42*412f47f9SXin Li b 0b 43*412f47f9SXin Li 44*412f47f9SXin Li /* First fault failed: only some of the vector is valid. 45*412f47f9SXin Li Perform the comparisions only on the valid bytes. */ 46*412f47f9SXin Li1: cmpeq p3.b, p0/z, z0.b, 0 /* search for 0 */ 47*412f47f9SXin Li b.any 2f 48*412f47f9SXin Li 49*412f47f9SXin Li cmpeq p3.b, p0/z, z0.b, z1.b /* search for c; no eos */ 50*412f47f9SXin Li mov x3, x0 51*412f47f9SXin Li incp x0, p0.b /* skip bytes this round */ 52*412f47f9SXin Li setffr /* re-init FFR */ 53*412f47f9SXin Li b.none 0b 54*412f47f9SXin Li 55*412f47f9SXin Li addvl x2, x3, 1 /* save advanced base */ 56*412f47f9SXin Li mov p2.b, p3.b /* save current search */ 57*412f47f9SXin Li b 0b 58*412f47f9SXin Li 59*412f47f9SXin Li /* Found end-of-string. */ 60*412f47f9SXin Li2: incb x0, all /* advance base */ 61*412f47f9SXin Li3: brka p3.b, p1/z, p3.b /* mask after first 0 */ 62*412f47f9SXin Li cmpeq p3.b, p3/z, z0.b, z1.b /* search for c not after eos */ 63*412f47f9SXin Li b.any 4f 64*412f47f9SXin Li 65*412f47f9SXin Li /* No C within last vector. Did we have one before? */ 66*412f47f9SXin Li cbz x2, 5f 67*412f47f9SXin Li mov x0, x2 /* restore advanced base */ 68*412f47f9SXin Li mov p3.b, p2.b /* restore saved search */ 69*412f47f9SXin Li 70*412f47f9SXin Li /* Find the *last* match in the predicate. This is slightly 71*412f47f9SXin Li more complicated than finding the first match. */ 72*412f47f9SXin Li4: rev p3.b, p3.b /* reverse the bits */ 73*412f47f9SXin Li brka p3.b, p1/z, p3.b /* find position of last match */ 74*412f47f9SXin Li decp x0, p3.b /* retard pointer to last match */ 75*412f47f9SXin Li ret 76*412f47f9SXin Li 77*412f47f9SXin Li /* No C whatsoever. Return NULL. */ 78*412f47f9SXin Li5: mov x0, 0 79*412f47f9SXin Li ret 80*412f47f9SXin Li 81*412f47f9SXin LiEND (__strrchr_aarch64_sve) 82*412f47f9SXin Li 83*412f47f9SXin Li#endif 84*412f47f9SXin Li 85