/* Compare two strings for differences. For SPARC v9. Copyright (C) 2011-2024 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, see . */ #include #include #ifndef XCC .register %g2, #scratch .register %g3, #scratch .register %g6, #scratch #endif #define rSTR1 %o0 #define rSTR2 %o1 #define r0101 %o2 /* 0x0101010101010101 */ #define r8080 %o3 /* 0x8080808080808080 */ #define rSTRXOR %o4 #define rWORD1 %o5 #define rTMP1 %g1 #define rTMP2 %g2 #define rWORD2 %g3 #define rSLL %g4 #define rSRL %g5 #define rBARREL %g6 /* There are two cases, either the two pointers are aligned * identically or they are not. If they have the same * alignment we can use the normal full speed loop. Otherwise * we have to use the barrel-shifter version. */ .text .align 32 ENTRY(strcmp) or rSTR2, rSTR1, rTMP1 sethi %hi(0x80808080), r8080 andcc rTMP1, 0x7, %g0 bne,pn %icc, .Lmaybe_barrel_shift or r8080, %lo(0x80808080), r8080 ldx [rSTR1], rWORD1 sub rSTR2, rSTR1, rSTR2 sllx r8080, 32, rTMP1 ldx [rSTR1 + rSTR2], rWORD2 or r8080, rTMP1, r8080 ba,pt %xcc, .Laligned_loop_entry srlx r8080, 7, r0101 .align 32 .Laligned_loop_entry: .Laligned_loop: add rSTR1, 8, rSTR1 sub rWORD1, r0101, rTMP2 xorcc rWORD1, rWORD2, rSTRXOR bne,pn %xcc, .Lcommon_endstring andn r8080, rWORD1, rTMP1 ldxa [rSTR1] ASI_PNF, rWORD1 andcc rTMP1, rTMP2, %g0 be,a,pt %xcc, .Laligned_loop ldxa [rSTR1 + rSTR2] ASI_PNF, rWORD2 .Lcommon_equal: retl mov 0, %o0 /* All loops terminate here once they find an unequal word. * If a zero byte appears in the word before the first unequal * byte, we must report zero. Otherwise we report '1' or '-1' * depending upon whether the first mis-matching byte is larger * in the first string or the second, respectively. * * First we compute a 64-bit mask value that has "0x01" in * each byte where a zero exists in rWORD1. rSTRXOR holds the * value (rWORD1 ^ rWORD2). Therefore, if considered as an * unsigned quantity, our "0x01" mask value is "greater than" * rSTRXOR then a zero terminating byte comes first and * therefore we report '0'. * * The formula for this mask is: * * mask_tmp1 = ~rWORD1 & 0x8080808080808080; * mask_tmp2 = ((rWORD1 & 0x7f7f7f7f7f7f7f7f) + * 0x7f7f7f7f7f7f7f7f); * * mask = ((mask_tmp1 & ~mask_tmp2) >> 7); */ .Lcommon_endstring: andn rWORD1, r8080, rTMP2 or r8080, 1, %o1 mov 1, %o0 sub rTMP2, %o1, rTMP2 cmp rWORD1, rWORD2 andn rTMP1, rTMP2, rTMP1 movleu %xcc, -1, %o0 srlx rTMP1, 7, rTMP1 /* In order not to be influenced by bytes after the zero byte, we * have to retain only the highest bit in the mask for the comparison * with rSTRXOR to work properly. */ mov 0, rTMP2 andcc rTMP1, 0x0100, %g0 movne %xcc, 8, rTMP2 sllx rTMP1, 63 - 16, %o1 movrlz %o1, 16, rTMP2 sllx rTMP1, 63 - 24, %o1 movrlz %o1, 24, rTMP2 sllx rTMP1, 63 - 32, %o1 movrlz %o1, 32, rTMP2 sllx rTMP1, 63 - 40, %o1 movrlz %o1, 40, rTMP2 sllx rTMP1, 63 - 48, %o1 movrlz %o1, 48, rTMP2 sllx rTMP1, 63 - 56, %o1 movrlz %o1, 56, rTMP2 srlx rTMP1, rTMP2, rTMP1 sllx rTMP1, rTMP2, rTMP1 cmp rTMP1, rSTRXOR retl movgu %xcc, 0, %o0 .Lmaybe_barrel_shift: sub rSTR2, rSTR1, rSTR2 sllx r8080, 32, rTMP1 or r8080, rTMP1, r8080 and rSTR1, 0x7, rTMP2 srlx r8080, 7, r0101 andn rSTR1, 0x7, rSTR1 ldxa [rSTR1] ASI_PNF, rWORD1 andcc rSTR2, 0x7, rSLL sll rTMP2, 3, rSTRXOR bne,pn %icc, .Lneed_barrel_shift mov -1, rTMP1 ldxa [rSTR1 + rSTR2] ASI_PNF, rBARREL srlx rTMP1, rSTRXOR, rTMP2 orn rWORD1, rTMP2, rWORD1 ba,pt %xcc, .Laligned_loop_entry orn rBARREL, rTMP2, rWORD2 .Lneed_barrel_shift: sllx rSLL, 3, rSLL andn rSTR2, 0x7, rSTR2 ldxa [rSTR1 + rSTR2] ASI_PNF, rBARREL mov 64, rTMP2 sub rTMP2, rSLL, rSRL srlx rTMP1, rSTRXOR, rTMP1 add rSTR2, 8, rSTR2 orn rWORD1, rTMP1, rWORD1 sllx rBARREL, rSLL, rWORD2 ldxa [rSTR1 + rSTR2] ASI_PNF, rBARREL add rSTR1, 8, rSTR1 sub rWORD1, r0101, rTMP2 srlx rBARREL, rSRL, rSTRXOR or rWORD2, rSTRXOR, rWORD2 orn rWORD2, rTMP1, rWORD2 ba,pt %xcc, .Lbarrel_shift_loop_entry andn r8080, rWORD1, rTMP1 .Lbarrel_shift_loop: sllx rBARREL, rSLL, rWORD2 ldxa [rSTR1 + rSTR2] ASI_PNF, rBARREL add rSTR1, 8, rSTR1 sub rWORD1, r0101, rTMP2 srlx rBARREL, rSRL, rSTRXOR andn r8080, rWORD1, rTMP1 or rWORD2, rSTRXOR, rWORD2 .Lbarrel_shift_loop_entry: xorcc rWORD1, rWORD2, rSTRXOR bne,pn %xcc, .Lcommon_endstring andcc rTMP1, rTMP2, %g0 be,a,pt %xcc, .Lbarrel_shift_loop ldxa [rSTR1] ASI_PNF, rWORD1 retl mov 0, %o0 END(strcmp) libc_hidden_builtin_def (strcmp)