memcmp.s revision 7257d1b4d25bfac0c802847390e98a464fd787ac
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
.file "%M%"
/*
* memcmp(s1, s2, len)
*
* Compare n bytes: s1>s2: >0 s1==s2: 0 s1<s2: <0
*
* Fast assembler language version of the following C-program for memcmp
* which represents the `standard' for the C-library.
*
* int
* memcmp(const void *s1, const void *s2, size_t n)
* {
* if (s1 != s2 && n != 0) {
* const char *ps1 = s1;
* const char *ps2 = s2;
* do {
* if (*ps1++ != *ps2++)
* return (ps1[-1] - ps2[-1]);
* } while (--n != 0);
* }
* return (0);
* }
*/
#include <sys/asm_linkage.h>
ANSI_PRAGMA_WEAK(memcmp,function)
ENTRY(memcmp)
cmp %o0, %o1 ! s1 == s2?
be,pn %xcc, .cmpeq
cmp %o2, 17
bleu,a,pn %xcc, .cmpbyt ! for small counts go do bytes
sub %o1, %o0, %o1
andcc %o0, 3, %o3 ! is s1 aligned?
bz,a,pn %icc, .iss2 ! if so go check s2
andcc %o1, 3, %o4 ! is s2 aligned?
cmp %o3, 2
be,pn %icc, .algn2
cmp %o3, 3
.algn1: ldub [%o0], %o4 ! cmp one byte
inc %o0
ldub [%o1], %o5
inc %o1
dec %o2
be,pn %icc, .algn3
cmp %o4, %o5
be,pt %icc, .algn2
nop
b,a .noteq
.algn2: lduh [%o0], %o4
inc 2, %o0
ldub [%o1], %o5
inc 1, %o1
srl %o4, 8, %o3
cmp %o3, %o5
be,a,pt %icc, 1f
ldub [%o1], %o5 ! delay slot, get next byte from s2
b .noteq
mov %o3, %o4 ! delay slot, move *s1 to %o4
1: inc %o1
dec 2, %o2
and %o4, 0xff, %o4
cmp %o4, %o5
.algn3: be,a,pt %icc, .iss2
andcc %o1, 3, %o4 ! delay slot, is s2 aligned?
b,a .noteq
.cmpbyt:b .bytcmp
deccc %o2
1: ldub [%o0 + %o1], %o5 ! byte compare loop
inc %o0
cmp %o4, %o5
be,a,pt %icc, .bytcmp
deccc %o2 ! delay slot, compare count (len)
b,a .noteq
.bytcmp:bgeu,a,pt %xcc, 1b
ldub [%o0], %o4
.cmpeq:
retl ! strings compare equal
clr %o0
.noteq_word: ! words aren't equal. find unequal byte
srl %o4, 24, %o1 ! first byte
srl %o5, 24, %o2
cmp %o1, %o2
bne,pn %icc, 1f
sll %o4, 8, %o4
sll %o5, 8, %o5
srl %o4, 24, %o1
srl %o5, 24, %o2
cmp %o1, %o2
bne,pn %icc, 1f
sll %o4, 8, %o4
sll %o5, 8, %o5
srl %o4, 24, %o1
srl %o5, 24, %o2
cmp %o1, %o2
bne,pn %icc, 1f
sll %o4, 8, %o4
sll %o5, 8, %o5
srl %o4, 24, %o1
srl %o5, 24, %o2
1:
retl
sub %o1, %o2, %o0 ! delay slot
.noteq:
retl ! strings aren't equal
sub %o4, %o5, %o0 ! delay slot, return(*s1 - *s2)
.iss2: andn %o2, 3, %o3 ! count of aligned bytes
and %o2, 3, %o2 ! remaining bytes
bz,pn %icc, .w4cmp ! if s2 word aligned, compare words
cmp %o4, 2
be,pn %icc, .w2cmp ! s2 half aligned
cmp %o4, 1
.w3cmp:
dec 4, %o3 ! avoid reading beyond the last byte
inc 4, %o2
ldub [%o1], %g1 ! read a byte to align for word reads
inc 1, %o1
be,pt %icc, .w1cmp ! aligned to 1 or 3 bytes
sll %g1, 24, %o5
sub %o1, %o0, %o1
2: lduw [%o0 + %o1], %g1
lduw [%o0], %o4
inc 4, %o0
srl %g1, 8, %g5 ! merge with the other half
or %g5, %o5, %o5
cmp %o4, %o5
bne,pt %icc, .noteq_word
deccc 4, %o3
bnz,pt %xcc, 2b
sll %g1, 24, %o5
sub %o1, 1, %o1 ! used 3 bytes of the last word read
b .bytcmp
deccc %o2
.w1cmp:
dec 4, %o3 ! avoid reading beyond the last byte
inc 4, %o2
lduh [%o1], %g1 ! read 3 bytes to word align
inc 2, %o1
sll %g1, 8, %g5
or %o5, %g5, %o5
sub %o1, %o0, %o1
3: lduw [%o0 + %o1], %g1
lduw [%o0], %o4
inc 4, %o0
srl %g1, 24, %g5 ! merge with the other half
or %g5, %o5, %o5
cmp %o4, %o5
bne,pt %icc, .noteq_word
deccc 4, %o3
bnz,pt %xcc, 3b
sll %g1, 8, %o5
sub %o1, 3, %o1 ! used 1 byte of the last word read
b .bytcmp
deccc %o2
.w2cmp:
dec 4, %o3 ! avoid reading beyond the last byte
inc 4, %o2
lduh [%o1], %g1 ! read a halfword to align s2
inc 2, %o1
sll %g1, 16, %o5
sub %o1, %o0, %o1
4: lduw [%o0 + %o1], %g1 ! read a word from s2
lduw [%o0], %o4 ! read a word from s1
inc 4, %o0
srl %g1, 16, %g5 ! merge with the other half
or %g5, %o5, %o5
cmp %o4, %o5
bne,pn %icc, .noteq_word
deccc 4, %o3
bnz,pt %xcc, 4b
sll %g1, 16, %o5
sub %o1, 2, %o1 ! only used half of the last read word
b .bytcmp
deccc %o2
.w4cmp:
sub %o1, %o0, %o1
lduw [%o0 + %o1], %o5
5: lduw [%o0], %o4
inc 4, %o0
cmp %o4, %o5
bne,pt %icc, .noteq_word
deccc 4, %o3
bnz,a,pt %xcc, 5b
lduw [%o0 + %o1], %o5
b .bytcmp ! compare remaining bytes, if any
deccc %o2
SET_SIZE(memcmp)