blob: 527ae6d35ed55b1a60f33e43268f858ecca804b9 [file] [log] [blame]
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "asm_riscv64.h"
#include "go_asm.h"
#include "textflag.h"
TEXT ·IndexByte<ABIInternal>(SB),NOSPLIT,$0-40
// X10 = b_base
// X11 = b_len
// X12 = b_cap (unused)
// X13 = byte to find
AND $0xff, X13, X12 // x12 byte to look for
SLTI $24, X11, X14
BNEZ X14, small
JMP indexByteBig<>(SB)
small:
MOV X10, X13 // store base for later
ADD X10, X11 // end
SUB $1, X10
loop:
ADD $1, X10
BEQ X10, X11, notfound
MOVBU (X10), X14
BNE X12, X14, loop
SUB X13, X10 // remove base
RET
notfound:
MOV $-1, X10
RET
TEXT ·IndexByteString<ABIInternal>(SB),NOSPLIT,$0-32
// X10 = b_base
// X11 = b_len
// X12 = byte to find
AND $0xff, X12 // x12 byte to look for
SLTI $24, X11, X14
BNEZ X14, small
JMP indexByteBig<>(SB)
small:
MOV X10, X13 // store base for later
ADD X10, X11 // end
SUB $1, X10
loop:
ADD $1, X10
BEQ X10, X11, notfound
MOVBU (X10), X14
BNE X12, X14, loop
SUB X13, X10 // remove base
RET
notfound:
MOV $-1, X10
RET
TEXT indexByteBig<>(SB),NOSPLIT|NOFRAME,$0
// On entry:
// X10 = b_base
// X11 = b_len (at least 16 bytes)
// X12 = byte to find
// On exit:
// X10 = index of first instance of sought byte, if found, or -1 otherwise
MOV X10, X13 // store base for later
#ifndef hasV
MOVB internal∕cpu·RISCV64+const_offsetRISCV64HasV(SB), X5
BEQZ X5, indexbyte_scalar
#endif
PCALIGN $16
vector_loop:
VSETVLI X11, E8, M8, TA, MA, X5
VLE8V (X10), V8
VMSEQVX X12, V8, V0
VFIRSTM V0, X6
BGEZ X6, vector_found
ADD X5, X10
SUB X5, X11
BNEZ X11, vector_loop
JMP notfound
vector_found:
SUB X13, X10
ADD X6, X10
RET
indexbyte_scalar:
ADD X10, X11 // end
// Process the first few bytes until we get to an 8 byte boundary
// No need to check for end here as we have at least 16 bytes in
// the buffer.
unalignedloop:
AND $7, X10, X14
BEQZ X14, aligned
MOVBU (X10), X14
BEQ X12, X14, found
ADD $1, X10
JMP unalignedloop
aligned:
AND $~7, X11, X15 // X15 = end of aligned data
// We have at least 9 bytes left
// Use 'Determine if a word has a byte equal to n' bit hack from
// https://graphics.stanford.edu/~seander/bithacks.html to determine
// whether the byte is present somewhere in the next 8 bytes of the
// array.
MOV $0x0101010101010101, X16
SLLI $7, X16, X17 // X17 = 0x8080808080808080
MUL X12, X16, X18 // broadcast X12 to every byte in X18
alignedloop:
MOV (X10), X14
XOR X14, X18, X19
// If the LSB in X12 is present somewhere in the 8 bytes we've just
// loaded into X14 then at least one of the bytes in X19 will be 0
// after the XOR. If any of the bytes in X19 are zero then
//
// ((X19 - X16) & (~X19) & X17)
//
// will be non-zero. The expression will evaluate to zero if none of
// the bytes in X19 are zero, i.e., X12 is not present in X14.
SUB X16, X19, X20
ANDN X19, X17, X21
AND X20, X21
BNEZ X21, tailloop // If X21 != 0 X12 is present in X14
ADD $8, X10
BNE X10, X15, alignedloop
tailloop:
SUB $1, X10
loop:
ADD $1, X10
BEQ X10, X11, notfound
MOVBU (X10), X14
BNE X12, X14, loop
found:
SUB X13, X10 // remove base
RET
notfound:
MOV $-1, X10
RET