1 /* SPDX-License-Identifier: GPL-2.0-only */ !! 1 /* SPDX-License-Identifier: GPL-2.0 */ 2 << 3 #include <linux/linkage.h> << 4 #include <asm/asm.h> << 5 #include <asm/alternative-macros.h> << 6 #include <asm/hwcap.h> << 7 << 8 /* int strlen(const char *s) */ << 9 SYM_FUNC_START(strlen) << 10 << 11 ALTERNATIVE("nop", "j strlen_zbb", 0, << 12 << 13 /* << 14 * Returns << 15 * a0 - string length << 16 * << 17 * Parameters << 18 * a0 - String to measure << 19 * << 20 * Clobbers: << 21 * t0, t1 << 22 */ << 23 mv t1, a0 << 24 1: << 25 lbu t0, 0(t1) << 26 beqz t0, 2f << 27 addi t1, t1, 1 << 28 j 1b << 29 2: << 30 sub a0, t1, a0 << 31 ret << 32 << 33 /* 2 /* 34 * Variant of strlen using the ZBB extension i !! 3 * strlen.S (c) 1995 David Mosberger (davidm@cs.arizona.edu) >> 4 * >> 5 * Finds length of a 0-terminated string. Optimized for the >> 6 * Alpha architecture: >> 7 * >> 8 * - memory accessed as aligned quadwords only >> 9 * - uses bcmpge to compare 8 bytes in parallel >> 10 * - does binary search to find 0 byte in last >> 11 * quadword (HAKMEM needed 12 instructions to >> 12 * do this instead of the 9 instructions that >> 13 * binary search needs). 35 */ 14 */ 36 #ifdef CONFIG_RISCV_ISA_ZBB !! 15 #include <linux/export.h> 37 strlen_zbb: !! 16 .set noreorder >> 17 .set noat >> 18 >> 19 .align 3 >> 20 >> 21 .globl strlen >> 22 .ent strlen >> 23 >> 24 strlen: >> 25 ldq_u $1, 0($16) # load first quadword ($16 may be misaligned) >> 26 lda $2, -1($31) >> 27 insqh $2, $16, $2 >> 28 andnot $16, 7, $0 >> 29 or $2, $1, $1 >> 30 cmpbge $31, $1, $2 # $2 <- bitmask: bit i == 1 <==> i-th byte == 0 >> 31 bne $2, found >> 32 >> 33 loop: ldq $1, 8($0) >> 34 addq $0, 8, $0 # addr += 8 >> 35 nop # helps dual issue last two insns >> 36 cmpbge $31, $1, $2 >> 37 beq $2, loop >> 38 >> 39 found: blbs $2, done # make aligned case fast >> 40 negq $2, $3 >> 41 and $2, $3, $2 >> 42 >> 43 and $2, 0x0f, $1 >> 44 addq $0, 4, $3 >> 45 cmoveq $1, $3, $0 >> 46 >> 47 and $2, 0x33, $1 >> 48 addq $0, 2, $3 >> 49 cmoveq $1, $3, $0 >> 50 >> 51 and $2, 0x55, $1 >> 52 addq $0, 1, $3 >> 53 cmoveq $1, $3, $0 >> 54 >> 55 done: subq $0, $16, $0 >> 56 ret $31, ($26) 38 57 39 #ifdef CONFIG_CPU_BIG_ENDIAN !! 58 .end strlen 40 # define CZ clz !! 59 EXPORT_SYMBOL(strlen) 41 # define SHIFT sll << 42 #else << 43 # define CZ ctz << 44 # define SHIFT srl << 45 #endif << 46 << 47 .option push << 48 .option arch,+zbb << 49 << 50 /* << 51 * Returns << 52 * a0 - string length << 53 * << 54 * Parameters << 55 * a0 - String to measure << 56 * << 57 * Clobbers << 58 * t0, t1, t2, t3 << 59 */ << 60 << 61 /* Number of irrelevant bytes in the f << 62 andi t2, a0, SZREG-1 << 63 << 64 /* Align pointer. */ << 65 andi t0, a0, -SZREG << 66 << 67 li t3, SZREG << 68 sub t3, t3, t2 << 69 slli t2, t2, 3 << 70 << 71 /* Get the first word. */ << 72 REG_L t1, 0(t0) << 73 << 74 /* << 75 * Shift away the partial data we load << 76 * preceding the string with the effec << 77 * end of the string's first word. << 78 */ << 79 SHIFT t1, t1, t2 << 80 << 81 /* Convert non-NUL into 0xff and NUL i << 82 orc.b t1, t1 << 83 << 84 /* Convert non-NUL into 0x00 and NUL i << 85 not t1, t1 << 86 << 87 /* << 88 * Search for the first set bit (corre << 89 * original chunk). << 90 */ << 91 CZ t1, t1 << 92 << 93 /* << 94 * The first chunk is special: compare << 95 * of valid bytes in this chunk. << 96 */ << 97 srli a0, t1, 3 << 98 bgtu t3, a0, 2f << 99 << 100 /* Prepare for the word comparison loo << 101 addi t2, t0, SZREG << 102 li t3, -1 << 103 << 104 /* << 105 * Our critical loop is 4 instructions << 106 * 4 byte or 8 byte chunks. << 107 */ << 108 .p2align 3 << 109 1: << 110 REG_L t1, SZREG(t0) << 111 addi t0, t0, SZREG << 112 orc.b t1, t1 << 113 beq t1, t3, 1b << 114 << 115 not t1, t1 << 116 CZ t1, t1 << 117 srli t1, t1, 3 << 118 << 119 /* Get number of processed bytes. */ << 120 sub t2, t0, t2 << 121 << 122 /* Add number of characters in the fir << 123 add a0, a0, t2 << 124 << 125 /* Add number of characters in the las << 126 add a0, a0, t1 << 127 2: << 128 ret << 129 << 130 .option pop << 131 #endif << 132 SYM_FUNC_END(strlen) << 133 SYM_FUNC_ALIAS(__pi_strlen, strlen) << 134 EXPORT_SYMBOL(strlen) <<
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.