diff options
Diffstat (limited to 'string/aarch64/experimental/strnlen-sve.S')
| -rw-r--r-- | string/aarch64/experimental/strnlen-sve.S | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/string/aarch64/experimental/strnlen-sve.S b/string/aarch64/experimental/strnlen-sve.S new file mode 100644 index 000000000000..11d835a1b13c --- /dev/null +++ b/string/aarch64/experimental/strnlen-sve.S @@ -0,0 +1,70 @@ +/* + * strnlen - calculate the length of a string with limit. + * + * Copyright (c) 2019-2022, Arm Limited. + * SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception + */ + +#include "asmdefs.h" + +.arch armv8-a+sve + +/* Assumptions: + * + * ARMv8-a, AArch64 + * SVE Available. + */ + +ENTRY (__strnlen_aarch64_sve) + setffr /* initialize FFR */ + mov x2, 0 /* initialize len */ + b 1f + + .p2align 4 + /* We have off + vl <= max, and so may read the whole vector. */ +0: ldff1b z0.b, p0/z, [x0, x2] + rdffrs p1.b, p0/z + b.nlast 2f + + /* First fault did not fail: the whole vector is valid. + Avoid depending on the contents of FFR beyond the branch. */ + cmpeq p2.b, p0/z, z0.b, 0 + b.any 8f + incb x2 + +1: whilelo p0.b, x2, x1 + b.last 0b + + /* We have off + vl < max. Test for off == max before proceeding. */ + b.none 9f + + ldff1b z0.b, p0/z, [x0, x2] + rdffrs p1.b, p0/z + b.nlast 2f + + /* First fault did not fail: the vector up to max is valid. + Avoid depending on the contents of FFR beyond the branch. + Compare for end-of-string, but there are no more bytes. */ + cmpeq p2.b, p0/z, z0.b, 0 + + /* Found end-of-string or zero. */ +8: brkb p2.b, p0/z, p2.b + mov x0, x2 + incp x0, p2.b + ret + + /* First fault failed: only some of the vector is valid. + Perform the comparison only on the valid bytes. */ +2: cmpeq p2.b, p1/z, z0.b, 0 + b.any 8b + + /* No inequality or zero found. Re-init FFR, incr and loop. */ + setffr + incp x2, p1.b + b 1b + + /* End of count. Return max. */ +9: mov x0, x1 + ret + +END (__strnlen_aarch64_sve) |
