18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * arch/alpha/lib/strrchr.S 48c2ecf20Sopenharmony_ci * Contributed by Richard Henderson (rth@tamu.edu) 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Return the address of the last occurrence of a given character 78c2ecf20Sopenharmony_ci * within a null-terminated string, or null if it is not found. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci#include <asm/export.h> 108c2ecf20Sopenharmony_ci#include <asm/regdef.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci .set noreorder 138c2ecf20Sopenharmony_ci .set noat 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci .align 3 168c2ecf20Sopenharmony_ci .ent strrchr 178c2ecf20Sopenharmony_ci .globl strrchr 188c2ecf20Sopenharmony_cistrrchr: 198c2ecf20Sopenharmony_ci .frame sp, 0, ra 208c2ecf20Sopenharmony_ci .prologue 0 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci zapnot a1, 1, a1 # e0 : zero extend our test character 238c2ecf20Sopenharmony_ci mov zero, t6 # .. e1 : t6 is last match aligned addr 248c2ecf20Sopenharmony_ci sll a1, 8, t5 # e0 : replicate our test character 258c2ecf20Sopenharmony_ci mov zero, t8 # .. e1 : t8 is last match byte compare mask 268c2ecf20Sopenharmony_ci or t5, a1, a1 # e0 : 278c2ecf20Sopenharmony_ci ldq_u t0, 0(a0) # .. e1 : load first quadword 288c2ecf20Sopenharmony_ci sll a1, 16, t5 # e0 : 298c2ecf20Sopenharmony_ci andnot a0, 7, v0 # .. e1 : align source addr 308c2ecf20Sopenharmony_ci or t5, a1, a1 # e0 : 318c2ecf20Sopenharmony_ci lda t4, -1 # .. e1 : build garbage mask 328c2ecf20Sopenharmony_ci sll a1, 32, t5 # e0 : 338c2ecf20Sopenharmony_ci cmpbge zero, t0, t1 # .. e1 : bits set iff byte == zero 348c2ecf20Sopenharmony_ci mskqh t4, a0, t4 # e0 : 358c2ecf20Sopenharmony_ci or t5, a1, a1 # .. e1 : character replication complete 368c2ecf20Sopenharmony_ci xor t0, a1, t2 # e0 : make bytes == c zero 378c2ecf20Sopenharmony_ci cmpbge zero, t4, t4 # .. e1 : bits set iff byte is garbage 388c2ecf20Sopenharmony_ci cmpbge zero, t2, t3 # e0 : bits set iff byte == c 398c2ecf20Sopenharmony_ci andnot t1, t4, t1 # .. e1 : clear garbage from null test 408c2ecf20Sopenharmony_ci andnot t3, t4, t3 # e0 : clear garbage from char test 418c2ecf20Sopenharmony_ci bne t1, $eos # .. e1 : did we already hit the terminator? 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci /* Character search main loop */ 448c2ecf20Sopenharmony_ci$loop: 458c2ecf20Sopenharmony_ci ldq t0, 8(v0) # e0 : load next quadword 468c2ecf20Sopenharmony_ci cmovne t3, v0, t6 # .. e1 : save previous comparisons match 478c2ecf20Sopenharmony_ci cmovne t3, t3, t8 # e0 : 488c2ecf20Sopenharmony_ci addq v0, 8, v0 # .. e1 : 498c2ecf20Sopenharmony_ci xor t0, a1, t2 # e0 : 508c2ecf20Sopenharmony_ci cmpbge zero, t0, t1 # .. e1 : bits set iff byte == zero 518c2ecf20Sopenharmony_ci cmpbge zero, t2, t3 # e0 : bits set iff byte == c 528c2ecf20Sopenharmony_ci beq t1, $loop # .. e1 : if we havnt seen a null, loop 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci /* Mask out character matches after terminator */ 558c2ecf20Sopenharmony_ci$eos: 568c2ecf20Sopenharmony_ci negq t1, t4 # e0 : isolate first null byte match 578c2ecf20Sopenharmony_ci and t1, t4, t4 # e1 : 588c2ecf20Sopenharmony_ci subq t4, 1, t5 # e0 : build a mask of the bytes up to... 598c2ecf20Sopenharmony_ci or t4, t5, t4 # e1 : ... and including the null 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci and t3, t4, t3 # e0 : mask out char matches after null 628c2ecf20Sopenharmony_ci cmovne t3, t3, t8 # .. e1 : save it, if match found 638c2ecf20Sopenharmony_ci cmovne t3, v0, t6 # e0 : 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci /* Locate the address of the last matched character */ 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci /* Retain the early exit for the ev4 -- the ev5 mispredict penalty 688c2ecf20Sopenharmony_ci is 5 cycles -- the same as just falling through. */ 698c2ecf20Sopenharmony_ci beq t8, $retnull # .. e1 : 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci and t8, 0xf0, t2 # e0 : binary search for the high bit set 728c2ecf20Sopenharmony_ci cmovne t2, t2, t8 # .. e1 (zdb) 738c2ecf20Sopenharmony_ci cmovne t2, 4, t2 # e0 : 748c2ecf20Sopenharmony_ci and t8, 0xcc, t1 # .. e1 : 758c2ecf20Sopenharmony_ci cmovne t1, t1, t8 # e0 : 768c2ecf20Sopenharmony_ci cmovne t1, 2, t1 # .. e1 : 778c2ecf20Sopenharmony_ci and t8, 0xaa, t0 # e0 : 788c2ecf20Sopenharmony_ci cmovne t0, 1, t0 # .. e1 (zdb) 798c2ecf20Sopenharmony_ci addq t2, t1, t1 # e0 : 808c2ecf20Sopenharmony_ci addq t6, t0, v0 # .. e1 : add our aligned base ptr to the mix 818c2ecf20Sopenharmony_ci addq v0, t1, v0 # e0 : 828c2ecf20Sopenharmony_ci ret # .. e1 : 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci$retnull: 858c2ecf20Sopenharmony_ci mov zero, v0 # e0 : 868c2ecf20Sopenharmony_ci ret # .. e1 : 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci .end strrchr 898c2ecf20Sopenharmony_ci EXPORT_SYMBOL(strrchr) 90