diff options
| author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
|---|---|---|
| committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
| commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
| tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/libc/sparc/gen | |
| download | illumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz | |
OpenSolaris Launch
Diffstat (limited to 'usr/src/lib/libc/sparc/gen')
36 files changed, 4653 insertions, 0 deletions
diff --git a/usr/src/lib/libc/sparc/gen/_getsp.s b/usr/src/lib/libc/sparc/gen/_getsp.s new file mode 100644 index 0000000000..fc5515217d --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/_getsp.s @@ -0,0 +1,47 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 1989-2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +.ident "%Z%%M% %I% %E% SMI" + + .file "_getsp.s" + +#include <sys/asm_linkage.h> + +/* + * Return the stack pointer + */ + ENTRY(_getsp) + retl + mov %sp, %o0 + SET_SIZE(_getsp) + +/* + * Return the frame pointer + */ + ENTRY(_getfp) + retl + mov %fp, %o0 + SET_SIZE(_getfp) diff --git a/usr/src/lib/libc/sparc/gen/_stack_grow.s b/usr/src/lib/libc/sparc/gen/_stack_grow.s new file mode 100644 index 0000000000..293769fd68 --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/_stack_grow.s @@ -0,0 +1,112 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + + .file "%M%" + +#include <sys/asm_linkage.h> +#include "SYS.h" +#include <../assym.h> + +/* + * void * + * _stack_grow(void *addr) + * { + * uintptr_t base = (uintptr_t)curthread->ul_ustack.ss_sp; + * size_t size = curthread->ul_ustack.ss_size; + * + * if (size > (uintptr_t)addr - (base - STACK_BIAS)) + * return (addr); + * + * if (size == 0) + * return (addr); + * + * if (size > %sp - (base - STACK_BIAS)) + * %sp = base - STACK_BIAS - STACK_ALIGN; + * + * *((char *)(base - 1)); + * + * _lwp_kill(_lwp_self(), SIGSEGV); + * } + */ + +#if defined(__sparcv9) +#define PN ,pn %xcc, +#else +#define PN +#endif + + /* + * o0: address to which the stack will be grown (biased) + */ + ENTRY(_stack_grow) + ldn [%g7 + UL_USTACK + SS_SP], %o1 + ldn [%g7 + UL_USTACK + SS_SIZE], %o2 + sub %o1, STACK_BIAS, %o3 + + sub %o0, %o3, %o4 + cmp %o2, %o4 + bleu PN 1f + tst %o2 + + retl + nop +1: + /* + * If the stack size is 0, stack checking is disabled. + */ + bnz PN 2f + nop + retl + nop +2: + /* + * Move the stack pointer outside the stack bounds if it isn't already. + */ + sub %sp, %o3, %o4 + cmp %o2, %o4 + bleu PN 3f + nop + sub %o3, STACK_ALIGN, %sp +3: + /* + * Dereference an address in the guard page. + */ + ldub [%o1 - 1], %g0 + + /* + * If the above load doesn't raise a SIGSEGV then do it ourselves. + */ + SYSTRAP_RVAL1(lwp_self) + mov SIGSEGV, %o1 + SYSTRAP_RVAL1(lwp_kill) + + /* + * We should never get here; explode if we do. + */ + illtrap + SET_SIZE(_stack_grow) diff --git a/usr/src/lib/libc/sparc/gen/_xregs_clrptr.c b/usr/src/lib/libc/sparc/gen/_xregs_clrptr.c new file mode 100644 index 0000000000..9be916fec2 --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/_xregs_clrptr.c @@ -0,0 +1,44 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include "synonyms.h" +#include <ucontext.h> +#include <sys/types.h> +#include "libc.h" + +/* + * clear the struct ucontext extra register state pointer + */ +void +_xregs_clrptr(ucontext_t *uc) +{ +#ifndef __LP64 + uc->uc_mcontext.xrs.xrs_id = 0; + uc->uc_mcontext.xrs.xrs_ptr = NULL; +#endif +} diff --git a/usr/src/lib/libc/sparc/gen/abs.s b/usr/src/lib/libc/sparc/gen/abs.s new file mode 100644 index 0000000000..6a555d8dca --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/abs.s @@ -0,0 +1,45 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 (c) 1987 Sun Microsystems, Inc. + */ + +.ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.5 */ + + .file "abs.s" + +#include <sys/asm_linkage.h> + +/* + * int abs(register int arg); + * long labs(register long int arg); + */ + ENTRY2(abs,labs) + tst %o0 + bl,a 1f + neg %o0 +1: + retl + nop + + SET_SIZE(abs) + SET_SIZE(labs) diff --git a/usr/src/lib/libc/sparc/gen/alloca.s b/usr/src/lib/libc/sparc/gen/alloca.s new file mode 100644 index 0000000000..2c5bba3af4 --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/alloca.s @@ -0,0 +1,58 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 (c) 1987 Sun Microsystems, Inc. + */ + +#ident "%Z%%M% %I% %E% SMI" + + .file "alloca.s" + +#include <sys/asm_linkage.h> + + ! + ! o0: # bytes of space to allocate, already rounded to 0 mod 8 + ! o1: %sp-relative offset of tmp area + ! o2: %sp-relative offset of end of tmp area + ! + ! we want to bump %sp by the requested size + ! then copy the tmp area to its new home + ! this is necessasy as we could theoretically + ! be in the middle of a compilicated expression. + ! + ENTRY(__builtin_alloca) + mov %sp, %o3 ! save current sp + sub %sp, %o0, %sp ! bump to new value + ! copy loop: should do nothing gracefully + b 2f + subcc %o2, %o1, %o5 ! number of bytes to move +1: + ld [%o3 + %o1], %o4 ! load from old temp area + st %o4, [%sp + %o1] ! store to new temp area + add %o1, 4, %o1 +2: bg 1b + subcc %o5, 4, %o5 + ! now return new %sp + end-of-temp + retl + add %sp, %o2, %o0 + + SET_SIZE(__builtin_alloca) diff --git a/usr/src/lib/libc/sparc/gen/cuexit.s b/usr/src/lib/libc/sparc/gen/cuexit.s new file mode 100644 index 0000000000..e6e7fbe00f --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/cuexit.s @@ -0,0 +1,47 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 (c) 1988 AT&T */ +/* All Rights Reserved */ + + +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +.ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.7 */ + +/* C library -- exit */ +/* void exit (int status); */ + + .file "cuexit.s" + +#include "SYS.h" + + ENTRY(exit) + save %sp, -SA(MINFRAME), %sp + call _exithandle + nop + restore + SYSTRAP_RVAL1(exit) + + SET_SIZE(exit) diff --git a/usr/src/lib/libc/sparc/gen/ecvt.c b/usr/src/lib/libc/sparc/gen/ecvt.c new file mode 100644 index 0000000000..18807b1eca --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/ecvt.c @@ -0,0 +1,109 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* Copyright (c) 1988 AT&T */ +/* All Rights Reserved */ + + +/* + * ecvt converts to decimal + * the number of digits is specified by ndigit + * decpt is set to the position of the decimal point + * sign is set to 0 for positive, 1 for negative + * + */ +#pragma weak ecvt = _ecvt +#pragma weak fcvt = _fcvt +#pragma weak qecvt = _qecvt +#pragma weak qfcvt = _qfcvt +#pragma weak qgcvt = _qgcvt + +#include "synonyms.h" +#include <sys/types.h> +#include <stdlib.h> +#include <floatingpoint.h> +#include "tsd.h" + +char * +ecvt(double number, int ndigits, int *decpt, int *sign) +{ + char *buf = tsdalloc(_T_ECVT, DECIMAL_STRING_LENGTH, NULL); + + return (econvert(number, ndigits, decpt, sign, buf)); +} + +char * +fcvt(double number, int ndigits, int *decpt, int *sign) +{ + char *buf = tsdalloc(_T_ECVT, DECIMAL_STRING_LENGTH, NULL); + char *ptr, *val; + char ch; + int deci_val; + + ptr = fconvert(number, ndigits, decpt, sign, buf); + + val = ptr; + deci_val = *decpt; + + while ((ch = *ptr) != 0) { + if (ch != '0') { /* You execute this if there are no */ + /* leading zero's remaining. */ + *decpt = deci_val; /* If there are leading zero's */ + return (ptr); /* gets updated. */ + } + ptr++; + deci_val--; + } + return (val); +} + +char * +qecvt( + long double number, + int ndigits, + int *decpt, + int *sign) +{ + char *buf = tsdalloc(_T_ECVT, DECIMAL_STRING_LENGTH, NULL); + + return (qeconvert(&number, ndigits, decpt, sign, buf)); +} + +char * +qfcvt(long double number, int ndigits, int *decpt, int *sign) +{ + char *buf = tsdalloc(_T_ECVT, DECIMAL_STRING_LENGTH, NULL); + + return (qfconvert(&number, ndigits, decpt, sign, buf)); +} + +char * +qgcvt(long double number, int ndigits, char *buffer) +{ + return (qgconvert(&number, ndigits, 0, buffer)); +} diff --git a/usr/src/lib/libc/sparc/gen/getctxt.c b/usr/src/lib/libc/sparc/gen/getctxt.c new file mode 100644 index 0000000000..d751462234 --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/getctxt.c @@ -0,0 +1,65 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 (c) 1988 AT&T */ +/* All Rights Reserved */ + + +/* + * Copyright 1996-2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#pragma weak _private_getcontext = _getcontext +#pragma weak getcontext = _getcontext + +#include "synonyms.h" +#include <ucontext.h> +#include <sys/types.h> +#include "libc.h" + +int +getcontext(ucontext_t *ucp) +{ + greg_t *reg; + + ucp->uc_flags = UC_ALL; + if (__getcontext_syscall(ucp)) + return (-1); + + /* + * Note that %o1 and %g1 are modified by the system call + * routine. ABI calling conventions specify that the caller + * cannot depend upon %o0 through %o5 nor %g1, so no effort is + * made to maintain these registers. %o0 is forced to reflect + * an affirmative return code. + */ + reg = ucp->uc_mcontext.gregs; + reg[REG_SP] = getfp(); + reg[REG_O7] = caller(); + reg[REG_PC] = reg[REG_O7] + 8; + reg[REG_nPC] = reg[REG_PC] + 4; + reg[REG_O0] = 0; + + return (0); +} diff --git a/usr/src/lib/libc/sparc/gen/ladd.s b/usr/src/lib/libc/sparc/gen/ladd.s new file mode 100644 index 0000000000..a5ddacc329 --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/ladd.s @@ -0,0 +1,71 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 (c) 1988 AT&T */ +/* All Rights Reserved */ + + +/* Copyright (c) 1989 by Sun Microsystems, Inc. */ + +.ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */ + +/* + * Double long add routine. Ported from pdp 11/70 version + * with considerable effort. All supplied comments were ported. + * + * Ported from m32 version to sparc. No comments about difficulty. + * + * dl_t + * ladd (lop, rop) + * dl_t lop; + * dl_t rop; + */ + + .file "ladd.s" + +#include <sys/asm_linkage.h> + + ANSI_PRAGMA_WEAK(ladd,function) + +#include "synonyms.h" + + ENTRY(ladd) + + ld [%o7+8],%o4 ! Instruction at ret-addr should be a + cmp %o4,8 ! 'unimp 8' indicating a valid call. + be 1f ! if OK, go forward. + nop ! delay instruction. + jmp %o7+8 ! return + nop ! delay instruction. + +1: + ld [%o0+0],%o2 ! fetch lop.dl_hop + ld [%o0+4],%o3 ! fetch lop.dl_lop + ld [%o1+0],%o4 ! fetch rop.dl_hop + ld [%o1+4],%o5 ! fetch rop.dl_lop + addcc %o3,%o5,%o3 ! lop.dl_lop + rop.dl_lop (set carry) + addxcc %o2,%o4,%o2 ! lop.dl_hop + rop.dl_hop + <carry> + ld [%sp+(16*4)],%o0 ! address to store result into + st %o2,[%o0+0] ! store result, dl_hop + jmp %o7+12 ! return + st %o3,[%o0+4] ! store result, dl_lop + + SET_SIZE(ladd) diff --git a/usr/src/lib/libc/sparc/gen/lexp10.c b/usr/src/lib/libc/sparc/gen/lexp10.c new file mode 100644 index 0000000000..28152a5b8f --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/lexp10.c @@ -0,0 +1,52 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* Copyright (c) 1988 AT&T */ +/* All Rights Reserved */ + + +#pragma weak lexp10 = _lexp10 + +#include "synonyms.h" +#include <sys/types.h> +#include <sys/dl.h> + +dl_t +lexp10(dl_t exp) +{ + dl_t result; + + result = lone; + + while (exp.dl_hop != 0 || exp.dl_lop != 0) { + result = lmul(result, lten); + exp = lsub(exp, lone); + } + + return (result); +} diff --git a/usr/src/lib/libc/sparc/gen/llog10.c b/usr/src/lib/libc/sparc/gen/llog10.c new file mode 100644 index 0000000000..14f690c61b --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/llog10.c @@ -0,0 +1,53 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* Copyright (c) 1988 AT&T */ +/* All Rights Reserved */ + + +#pragma weak llog10 = _llog10 + +#include "synonyms.h" +#include <sys/types.h> +#include <sys/dl.h> + +dl_t +llog10(dl_t val) +{ + dl_t result; + + result = lzero; + val = ldivide(val, lten); + + while (val.dl_hop != 0 || val.dl_lop != 0) { + val = ldivide(val, lten); + result = ladd(result, lone); + } + + return (result); +} diff --git a/usr/src/lib/libc/sparc/gen/lmul.c b/usr/src/lib/libc/sparc/gen/lmul.c new file mode 100644 index 0000000000..7f6aa0f079 --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/lmul.c @@ -0,0 +1,57 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* Copyright (c) 1988 AT&T */ +/* All Rights Reserved */ + + +#pragma weak lmul = _lmul + +#include "synonyms.h" +#include "sys/types.h" +#include "sys/dl.h" + +dl_t +lmul(dl_t lop, dl_t rop) +{ + dl_t ans; + dl_t tmp; + int jj; + + ans = lzero; + + for (jj = 0; jj <= 63; jj++) { + if ((lshiftl(rop, -jj).dl_lop & 1) == 0) + continue; + tmp = lshiftl(lop, jj); + tmp.dl_hop &= 0x7fffffff; + ans = ladd(ans, tmp); + }; + + return (ans); +} diff --git a/usr/src/lib/libc/sparc/gen/lock.s b/usr/src/lib/libc/sparc/gen/lock.s new file mode 100644 index 0000000000..a96043767d --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/lock.s @@ -0,0 +1,52 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + + .file "%M%" + +#include <sys/asm_linkage.h> + +/* + * lock_try(lp) + * - returns non-zero on success. + */ + ENTRY(_lock_try) + ldstub [%o0], %o1 ! try to set lock, get value in %o1 + membar #LoadLoad + retl + xor %o1, 0xff, %o0 ! delay - return non-zero if success + SET_SIZE(_lock_try) + +/* + * lock_clear(lp) + * - clear lock. + */ + ENTRY(_lock_clear) + membar #LoadStore|#StoreStore + retl + clrb [%o0] + SET_SIZE(_lock_clear) diff --git a/usr/src/lib/libc/sparc/gen/lshiftl.s b/usr/src/lib/libc/sparc/gen/lshiftl.s new file mode 100644 index 0000000000..820c91f8ea --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/lshiftl.s @@ -0,0 +1,102 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 (c) 1988 AT&T */ +/* All Rights Reserved */ + + +/* Copyright (c) 1989 by Sun Microsystems, Inc. */ + +.ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */ + +/* + * Shift a double long value. Ported from m32 version to sparc. + * + * dl_t + * lshiftl (op, cnt) + * dl_t op; + * int cnt; + */ + + .file "lshiftl.s" + +#include <sys/asm_linkage.h> + + ANSI_PRAGMA_WEAK(lshiftl,function) + +#include "synonyms.h" + + + ENTRY(lshiftl) + + ld [%o7+8],%o4 ! Instruction at ret-addr should be a + cmp %o4,8 ! 'unimp 8' indicating a valid call. + be 1f ! if OK, go forward. + nop ! delay instruction. + jmp %o7+8 ! return + nop ! delay instruction. + +1: + ld [%o0+0],%o2 ! fetch op.dl_hop + ld [%o0+4],%o3 ! fetch op.dl_lop + subcc %g0,%o1,%o4 ! test cnt < 0 and save reciprocol + bz .done + ld [%sp+(16*4)],%o0 ! address to store result into + bg .right ! + nop + ! Positive (or null) shift (left) + and %o1,0x3f,%o1 ! Reduce range to 0..63 + subcc %o1,32,%o5 ! cnt - 32 (also test cnt >= 32) + bneg,a .leftsmall ! + add %o4,32,%o4 ! 32 - cnt (actually ((-cnt) + 32) + sll %o3,%o5,%o2 ! R.h = R.l << (cnt - 32) + ba .done ! + or %g0,%g0,%o3 ! R.l = 0 + +.leftsmall: + srl %o3,%o4,%o5 ! temp = R.l >> (31 - cnt) + sll %o3,%o1,%o3 ! R.l = R.l << cnt + sll %o2,%o1,%o2 ! R.h = R.h << cnt + ba .done ! + or %o2,%o5,%o2 ! R.h = R.h | temp + +.right: ! Negative shift (right) + and %o4,0x3f,%o4 ! Reduce range to 0..63 + subcc %o4,32,%o5 ! cnt - 32 (also test cnt >= 32) + bneg,a .rightsmall ! + add %o1,32,%o1 ! 32 - cnt (actually ((-cnt) + 32) + srl %o2,%o5,%o3 ! R.l = R.h >> (cnt - 32) + ba .done ! + or %g0,%g0,%o2 ! R.h = 0 + +.rightsmall: + sll %o2,%o1,%o5 ! temp = R.h << (31 - cnt) + srl %o3,%o4,%o3 ! R.l = R.l >> cnt + srl %o2,%o4,%o2 ! R.h = R.h >> cnt + ba .done ! + or %o3,%o5,%o3 ! R.l = R.l | temp + +.done: + st %o2,[%o0+0] ! store result, dl_hop + jmp %o7+12 ! return + st %o3,[%o0+4] ! store result, dl_lop + + SET_SIZE(lshiftl) diff --git a/usr/src/lib/libc/sparc/gen/lsign.s b/usr/src/lib/libc/sparc/gen/lsign.s new file mode 100644 index 0000000000..1269fbe551 --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/lsign.s @@ -0,0 +1,53 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 (c) 1988 AT&T */ +/* All Rights Reserved */ + + +/* Copyright (c) 1989 by Sun Microsystems, Inc. */ + +.ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */ + +/* + * Determine the sign of a double-long number. + * Ported from m32 version to sparc. + * + * int + * lsign (op) + * dl_t op; + */ + + .file "lsign.s" + +#include <sys/asm_linkage.h> + + ANSI_PRAGMA_WEAK(lsign,function) + +#include "synonyms.h" + + ENTRY(lsign) + + ld [%o0],%o0 ! fetch op (high word only) + jmp %o7+8 ! return + srl %o0,31,%o0 ! shift letf logical to isolate sign + + SET_SIZE(lsign) diff --git a/usr/src/lib/libc/sparc/gen/lsub.s b/usr/src/lib/libc/sparc/gen/lsub.s new file mode 100644 index 0000000000..e6457b9abe --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/lsub.s @@ -0,0 +1,70 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 (c) 1988 AT&T */ +/* All Rights Reserved */ + + +/* Copyright (c) 1989 by Sun Microsystems, Inc. */ + +.ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */ + +/* + * Double long subtraction routine. Ported from pdp 11/70 version + * with considerable effort. All supplied comments were ported. + * Ported from m32 version to sparc. No comments about difficulty. + * + * dl_t + * lsub (lop, rop) + * dl_t lop; + * dl_t rop; + */ + + .file "lsub.s" + +#include <sys/asm_linkage.h> + + ANSI_PRAGMA_WEAK(lsub,function) + +#include "synonyms.h" + + ENTRY(lsub) + + ld [%o7+8],%o4 ! Instruction at ret-addr should be a + cmp %o4,8 ! 'unimp 8' indicating a valid call. + be 1f ! if OK, go forward. + nop ! delay instruction. + jmp %o7+8 ! return + nop ! delay instruction. + +1: + ld [%o0+0],%o2 ! fetch lop.dl_hop + ld [%o0+4],%o3 ! fetch lop.dl_lop + ld [%o1+0],%o4 ! fetch rop.dl_hop + ld [%o1+4],%o5 ! fetch rop.dl_lop + subcc %o3,%o5,%o3 ! lop.dl_lop - rop.dl_lop (set carry) + subxcc %o2,%o4,%o2 ! lop.dl_hop - rop.dl_hop - <carry> + ld [%sp+(16*4)],%o0 ! address to store result into + st %o2,[%o0] ! store result.dl_hop + jmp %o7+12 ! return + st %o3,[%o0+4] ! store result.dl_lop + + SET_SIZE(lsub) diff --git a/usr/src/lib/libc/sparc/gen/makectxt.c b/usr/src/lib/libc/sparc/gen/makectxt.c new file mode 100644 index 0000000000..9dc4c64697 --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/makectxt.c @@ -0,0 +1,168 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* Copyright (c) 1988 AT&T */ +/* All Rights Reserved */ + + +#pragma weak makecontext = _makecontext +#pragma weak __makecontext_v2 = ___makecontext_v2 + +#include "synonyms.h" +#include <stdarg.h> +#include <strings.h> +#include <sys/ucontext.h> +#include <sys/stack.h> +#include <sys/frame.h> + +/* + * The ucontext_t that the user passes in must have been primed with a + * call to getcontext(2), have the uc_stack member set to reflect the + * stack which this context will use, and have the uc_link member set + * to the context which should be resumed when this context returns. + * When makecontext() returns, the ucontext_t will be set to run the + * given function with the given parameters on the stack specified by + * uc_stack, and which will return to the ucontext_t specified by uc_link. + */ + +static void resumecontext(void); + +void +_makecontext(ucontext_t *ucp, void (*func)(), int argc, ...) +{ + greg_t *reg; + long *tsp; + char *sp; + int argno; + va_list ap; + size_t size; + + reg = ucp->uc_mcontext.gregs; + reg[REG_PC] = (greg_t)func; + reg[REG_nPC] = reg[REG_PC] + 0x4; + + /* + * Reserve enough space for a frame and the arguments beyond the + * sixth; round to stack alignment. + */ + size = sizeof (struct frame); + size += (argc > 6 ? argc - 6 : 0) * sizeof (long); + + /* + * The legacy implemenation of makecontext() on sparc has been to + * interpret the uc_stack.ss_sp member incorrectly as the top of the + * stack rather than the base. We preserve this behavior here, but + * provide the correct semantics in __makecontext_v2(). + */ + sp = (char *)(((uintptr_t)ucp->uc_stack.ss_sp - size) & + ~(STACK_ALIGN - 1)); + + /* + * Copy all args to the stack, and put the first 6 args into the + * ucontext_t. Zero the other fields of the frame. + */ + /* LINTED pointer cast may result in improper alignment */ + tsp = &((struct frame *)sp)->fr_argd[0]; + bzero(sp, sizeof (struct frame)); + + va_start(ap, argc); + + for (argno = 0; argno < argc; argno++) { + if (argno < 6) + *tsp++ = reg[REG_O0 + argno] = va_arg(ap, long); + else + *tsp++ = va_arg(ap, long); + } + + va_end(ap); + + reg[REG_SP] = (greg_t)sp - STACK_BIAS; /* sp (when done) */ + reg[REG_O7] = (greg_t)resumecontext - 8; /* return pc */ +} + +void +__makecontext_v2(ucontext_t *ucp, void (*func)(), int argc, ...) +{ + greg_t *reg; + long *tsp; + char *sp; + int argno; + va_list ap; + size_t size; + + reg = ucp->uc_mcontext.gregs; + reg[REG_PC] = (greg_t)func; + reg[REG_nPC] = reg[REG_PC] + 0x4; + + /* + * Reserve enough space for a frame and the arguments beyond the + * sixth; round to stack alignment. + */ + size = sizeof (struct frame); + size += (argc > 6 ? argc - 6 : 0) * sizeof (long); + + sp = (char *)(((uintptr_t)ucp->uc_stack.ss_sp + + ucp->uc_stack.ss_size - size) & ~(STACK_ALIGN - 1)); + + /* + * Copy all args to the stack, and put the first 6 args into the + * ucontext_t. Zero the other fields of the frame. + */ + /* LINTED pointer cast may result in improper alignment */ + tsp = &((struct frame *)sp)->fr_argd[0]; + bzero(sp, sizeof (struct frame)); + + va_start(ap, argc); + + for (argno = 0; argno < argc; argno++) { + if (argno < 6) + *tsp++ = reg[REG_O0 + argno] = va_arg(ap, long); + else + *tsp++ = va_arg(ap, long); + } + + va_end(ap); + + reg[REG_SP] = (greg_t)sp - STACK_BIAS; /* sp (when done) */ + reg[REG_O7] = (greg_t)resumecontext - 8; /* return pc */ +} + +static void +resumecontext(void) +{ + /* + * We can't include ucontext.h (where these functions are defined) + * because it remaps the symbol makecontext. + */ + extern int getcontext(ucontext_t *); + extern int setcontext(const ucontext_t *); + ucontext_t uc; + + (void) getcontext(&uc); + (void) setcontext(uc.uc_link); +} diff --git a/usr/src/lib/libc/sparc/gen/memchr.s b/usr/src/lib/libc/sparc/gen/memchr.s new file mode 100644 index 0000000000..0f38ad2c77 --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/memchr.s @@ -0,0 +1,177 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +.ident "%Z%%M% %I% %E% SMI" + + .file "%M%" +/* + * Return the ptr in sptr at which the character c1 appears; + * or NULL if not found in n chars; don't stop at \0. + * void * + * memchr(const void *sptr, int c1, size_t n) + * { + * if (n != 0) { + * unsigned char c = (unsigned char)c1; + * const unsigned char *sp = sptr; + * + * do { + * if (*sp++ == c) + * return ((void *)--sp); + * } while (--n != 0); + * } + * return (NULL); + * } + */ + +#include <sys/asm_linkage.h> +#include "synonyms.h" + + ! The first part of this algorithm focuses on determining + ! whether or not the desired character is in the first few bytes + ! of memory, aligning the memory for word-wise copies, and + ! initializing registers to detect zero bytes + + ENTRY(memchr) + + .align 32 + + tst %o2 ! n == 0 ? + bz .notfound ! yup, c not found, return null ptr + andcc %o0, 3, %o4 ! s word aligned ? + add %o0, %o2, %o0 ! s + n + sub %g0, %o2, %o2 ! n = -n + bz .prepword ! yup, prepare for word-wise search + and %o1, 0xff, %o1 ! search only for this one byte + + ldub [%o0 + %o2], %o3 ! s[0] + cmp %o3, %o1 ! s[0] == c ? + be .done ! yup, done + nop ! + addcc %o2, 1, %o2 ! n++, s++ + bz .notfound ! c not found in first n bytes + cmp %o4, 3 ! only one byte needed to align? + bz .prepword2 ! yup, prepare for word-wise search + sll %o1, 8, %g1 ! start spreading c across word + ldub [%o0 + %o2], %o3 ! s[1] + cmp %o3, %o1 ! s[1] == c ? + be .done ! yup, done + nop ! + addcc %o2, 1, %o2 ! n++, s++ + bz .notfound ! c not found in first n bytes + cmp %o4, 2 ! only two bytes needed to align? + bz .prepword3 ! yup, prepare for word-wise search + sethi %hi(0x01010101), %o4 ! start loading Alan Mycroft's magic1 + ldub [%o0 + %o2], %o3 ! s[1] + cmp %o3, %o1 ! s[1] == c ? + be .done ! yup, done + nop + addcc %o2, 1, %o2 ! n++, s++ + bz .notfound ! c not found in first n bytes + nop + +.prepword: + sll %o1, 8, %g1 ! spread c -------------+ +.prepword2: ! ! + sethi %hi(0x01010101), %o4 ! Alan Mycroft's magic1 ! +.prepword3: ! ! + or %o1, %g1, %o1 ! across all <---------+ + or %o4, %lo(0x01010101),%o4! finish loading magic1 ! + sll %o1, 16, %g1 ! four bytes <--------+ + sll %o4, 7, %o5 ! Alan Mycroft's magic2 ! + or %o1, %g1, %o1 ! of a word <--------+ + +.searchchar: + lduw [%o0 + %o2], %o3 ! src word +.searchchar2: + addcc %o2, 4, %o2 ! s+=4, n+=4 + bcs .lastword ! if counter wraps, last word + xor %o3, %o1, %g1 ! tword = word ^ c + andn %o5, %g1, %o3 ! ~tword & 0x80808080 + sub %g1, %o4, %g1 ! (tword - 0x01010101) + andcc %o3, %g1, %g0 ! ((tword - 0x01010101) & ~tword & 0x80808080) + bz,a .searchchar2 ! c not found if magic expression == 0 + lduw [%o0 + %o2], %o3 ! src word + + ! here we know "word" contains the searched character, and no byte in + ! "word" exceeds n. If we had exceeded n, we would have gone to label + ! .lastword. "tword" has null bytes where "word" had c. After + ! restoring "tword" from "(tword - 0x01010101)" in %g1, examine "tword" + +.foundchar: + add %g1, %o4, %g1 ! restore tword + set 0xff000000, %o4 ! mask for 1st byte + andcc %g1, %o4, %g0 ! first byte zero (= found c) ? + bz,a .done ! yup, done + sub %o2, 4, %o2 ! n -= 4 (undo counter bumping) + set 0x00ff0000, %o5 ! mask for 2nd byte + andcc %g1, %o5, %g0 ! second byte zero (= found c) ? + bz,a .done ! yup, done + sub %o2, 3, %o2 ! n -= 3 (undo counter bumping) + srl %o4, 16, %o4 ! 0x0000ff00 = mask for 3rd byte + andcc %g1, %o4, %g0 ! third byte zero (= found c) ? + bz,a .done ! nope, must be fourth byte + sub %o2, 2, %o2 ! n -= 2 (undo counter bumping) + sub %o2, 1, %o2 ! n -= 1, if fourth byte + retl ! done with leaf function + add %o0, %o2, %o0 ! return pointer to c in s +.done: + retl ! done with leaf function + add %o0, %o2, %o0 ! return pointer to c in s + nop + nop + + ! Here we know that "word" is the last word in the search, and that + ! some bytes possibly exceed n. However, "word" might also contain c. + ! "tword" (in %g1) has null bytes where "word" had c. Examine "tword" + ! while keeping track of number of remaining bytes + +.lastword: + set 0xff000000, %o4 ! mask for 1st byte + sub %o2, 4, %o2 ! n -= 4 (undo counter bumping) + andcc %g1, %o4, %g0 ! first byte zero (= found c) ? + bz .done ! yup, done + set 0x00ff0000, %o5 ! mask for 2nd byte + addcc %o2, 1, %o2 ! n += 1 + bz .notfound ! c not found in first n bytes + andcc %g1, %o5, %g0 ! second byte zero (= found c) ? + bz .done ! yup, done + srl %o4, 16, %o4 ! 0x0000ff00 = mask for 3rd byte + addcc %o2, 1, %o2 ! n += 1 + bz .notfound ! c not found in first n bytes + andcc %g1, %o4, %g0 ! third byte zero (= found c) ? + bz .done ! yup, done + nop ! + addcc %o2, 1, %o2 ! n += 1 + bz .notfound ! c not found in first n bytes + andcc %g1, 0xff, %g0 ! fourth byte zero (= found c) ? + bz .done ! yup, done + nop + +.notfound: + retl ! done with leaf function + mov %g0, %o0 ! return null pointer + + SET_SIZE(memchr) diff --git a/usr/src/lib/libc/sparc/gen/memcmp.s b/usr/src/lib/libc/sparc/gen/memcmp.s new file mode 100644 index 0000000000..1ba5cc454b --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/memcmp.s @@ -0,0 +1,237 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 (c) 1989-1995,1998 by Sun Microsystems, Inc. + * All rights reserved. + */ + +.ident "%Z%%M% %I% %E% SMI" /* SunOS 4.1 1.2 */ + + .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 (NULL); + * } + */ + +#include <sys/asm_linkage.h> + + ANSI_PRAGMA_WEAK(memcmp,function) + +#include "synonyms.h" + + ENTRY(memcmp) + st %g2, [%sp + 68] ! g2 must be restored before retl + cmp %o0, %o1 ! s1 == s2? + be .cmpeq + cmp %o2, 17 + bleu,a .cmpbyt ! for small counts go do bytes + sub %o1, %o0, %o1 + + andcc %o0, 3, %o3 ! is s1 aligned? + bz,a .iss2 ! if so go check s2 + andcc %o1, 3, %o4 ! is s2 aligned? + cmp %o3, 2 + be .algn2 + cmp %o3, 3 + +.algn1: ldub [%o0], %o4 ! cmp one byte + inc %o0 + ldub [%o1], %o5 + inc %o1 + dec %o2 + be .algn3 + cmp %o4, %o5 + be .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 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 .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 .bytcmp + deccc %o2 ! delay slot, compare count (len) + b,a .noteq +.bytcmp:bgeu,a 1b + ldub [%o0], %o4 +.cmpeq: ld [%sp + 68], %g2 + 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 1f + sll %o4, 8, %o4 + sll %o5, 8, %o5 + srl %o4, 24, %o1 + srl %o5, 24, %o2 + cmp %o1, %o2 + bne 1f + sll %o4, 8, %o4 + sll %o5, 8, %o5 + srl %o4, 24, %o1 + srl %o5, 24, %o2 + cmp %o1, %o2 + bne 1f + sll %o4, 8, %o4 + sll %o5, 8, %o5 + srl %o4, 24, %o1 + srl %o5, 24, %o2 +1: + ld [%sp + 68], %g2 + retl + sub %o1, %o2, %o0 ! delay slot + +.noteq: + ld [%sp + 68], %g2 + 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 .w4cmp ! if s2 word aligned, compare words + cmp %o4, 2 + be .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 .w1cmp ! aligned to 1 or 3 bytes + sll %g1, 24, %o5 + + sub %o1, %o0, %o1 +2: ld [%o0 + %o1], %g1 + ld [%o0], %o4 + inc 4, %o0 + srl %g1, 8, %g2 ! merge with the other half + or %g2, %o5, %o5 + cmp %o4, %o5 + bne .noteq_word + deccc 4, %o3 + bnz 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, %g2 + or %o5, %g2, %o5 + + sub %o1, %o0, %o1 +3: ld [%o0 + %o1], %g1 + ld [%o0], %o4 + inc 4, %o0 + srl %g1, 24, %g2 ! merge with the other half + or %g2, %o5, %o5 + cmp %o4, %o5 + bne .noteq_word + deccc 4, %o3 + bnz 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: ld [%o0 + %o1], %g1 ! read a word from s2 + ld [%o0], %o4 ! read a word from s1 + inc 4, %o0 + srl %g1, 16, %g2 ! merge with the other half + or %g2, %o5, %o5 + cmp %o4, %o5 + bne .noteq_word + deccc 4, %o3 + bnz 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 + ld [%o0 + %o1], %o5 +5: ld [%o0], %o4 + inc 4, %o0 + cmp %o4, %o5 + bne .noteq_word + deccc 4, %o3 + bnz,a 5b + ld [%o0 + %o1], %o5 + b .bytcmp ! compare remaining bytes, if any + deccc %o2 + + SET_SIZE(memcmp) diff --git a/usr/src/lib/libc/sparc/gen/memcpy.s b/usr/src/lib/libc/sparc/gen/memcpy.s new file mode 100644 index 0000000000..bfa751fd6e --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/memcpy.s @@ -0,0 +1,189 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 1987-2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + + .ident "%Z%%M% %I% %E% SMI" + + .file "%M%" + +/* + * memcpy(s1, s2, len) + * + * Copy s2 to s1, always copy n bytes. + * Note: this does not work for overlapped copies, bcopy() does + * + * Fast assembler language version of the following C-program for memcpy + * which represents the `standard' for the C-library. + * + * void * + * memcpy(void *s, const void *s0, size_t n) + * { + * if (n != 0) { + * char *s1 = s; + * const char *s2 = s0; + * do { + * *s1++ = *s2++; + * } while (--n != 0); + * } + * return (s); + * } + */ + +#include <sys/asm_linkage.h> + + ANSI_PRAGMA_WEAK(memcpy,function) + +#include "synonyms.h" + + .weak _private_memcpy + .type _private_memcpy, #function + _private_memcpy = memcpy + + ENTRY(memcpy) + st %o0, [%sp + 68] ! save des address for return val + cmp %o2, 17 ! for small counts copy bytes + bleu .dbytecp + andcc %o1, 3, %o5 ! is src word aligned + bz .aldst + cmp %o5, 2 ! is src half-word aligned + be .s2algn + cmp %o5, 3 ! src is byte aligned +.s1algn:ldub [%o1], %o3 ! move 1 or 3 bytes to align it + inc 1, %o1 + stb %o3, [%o0] ! move a byte to align src + inc 1, %o0 + bne .s2algn + dec %o2 + b .ald ! now go align dest + andcc %o0, 3, %o5 + +.s2algn:lduh [%o1], %o3 ! know src is 2 byte alinged + inc 2, %o1 + srl %o3, 8, %o4 + stb %o4, [%o0] ! have to do bytes, + stb %o3, [%o0 + 1] ! don't know dst alingment + inc 2, %o0 + dec 2, %o2 + +.aldst: andcc %o0, 3, %o5 ! align the destination address +.ald: bz .w4cp + cmp %o5, 2 + bz .w2cp + cmp %o5, 3 +.w3cp: ld [%o1], %o4 + inc 4, %o1 + srl %o4, 24, %o5 + stb %o5, [%o0] + bne .w1cp + inc %o0 + dec 1, %o2 + andn %o2, 3, %o3 ! o3 is aligned word count + dec 4, %o3 ! avoid reading beyond tail of src + sub %o1, %o0, %o1 ! o1 gets the difference + +1: sll %o4, 8, %g1 ! save residual bytes + ld [%o1+%o0], %o4 + deccc 4, %o3 + srl %o4, 24, %o5 ! merge with residual + or %o5, %g1, %g1 + st %g1, [%o0] + bnz 1b + inc 4, %o0 + sub %o1, 3, %o1 ! used one byte of last word read + and %o2, 3, %o2 + b 7f + inc 4, %o2 + +.w1cp: srl %o4, 8, %o5 + sth %o5, [%o0] + inc 2, %o0 + dec 3, %o2 + andn %o2, 3, %o3 ! o3 is aligned word count + dec 4, %o3 ! avoid reading beyond tail of src + sub %o1, %o0, %o1 ! o1 gets the difference + +2: sll %o4, 24, %g1 ! save residual bytes + ld [%o1+%o0], %o4 + deccc 4, %o3 + srl %o4, 8, %o5 ! merge with residual + or %o5, %g1, %g1 + st %g1, [%o0] + bnz 2b + inc 4, %o0 + sub %o1, 1, %o1 ! used three bytes of last word read + and %o2, 3, %o2 + b 7f + inc 4, %o2 + +.w2cp: ld [%o1], %o4 + inc 4, %o1 + srl %o4, 16, %o5 + sth %o5, [%o0] + inc 2, %o0 + dec 2, %o2 + andn %o2, 3, %o3 ! o3 is aligned word count + dec 4, %o3 ! avoid reading beyond tail of src + sub %o1, %o0, %o1 ! o1 gets the difference + +3: sll %o4, 16, %g1 ! save residual bytes + ld [%o1+%o0], %o4 + deccc 4, %o3 + srl %o4, 16, %o5 ! merge with residual + or %o5, %g1, %g1 + st %g1, [%o0] + bnz 3b + inc 4, %o0 + sub %o1, 2, %o1 ! used two bytes of last word read + and %o2, 3, %o2 + b 7f + inc 4, %o2 + +.w4cp: andn %o2, 3, %o3 ! o3 is aligned word count + sub %o1, %o0, %o1 ! o1 gets the difference + +1: ld [%o1+%o0], %o4 ! read from address + deccc 4, %o3 ! decrement count + st %o4, [%o0] ! write at destination address + bgu 1b + inc 4, %o0 ! increment to address + b 7f + and %o2, 3, %o2 ! number of leftover bytes, if any + + ! + ! differenced byte copy, works with any alignment + ! +.dbytecp: + b 7f + sub %o1, %o0, %o1 ! o1 gets the difference + +4: stb %o4, [%o0] ! write to address + inc %o0 ! inc to address +7: deccc %o2 ! decrement count + bgeu,a 4b ! loop till done + ldub [%o1+%o0], %o4 ! read from address + retl + ld [%sp + 68], %o0 ! return s1, destination address + + SET_SIZE(memcpy) diff --git a/usr/src/lib/libc/sparc/gen/memmove.s b/usr/src/lib/libc/sparc/gen/memmove.s new file mode 100644 index 0000000000..e57650f6ab --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/memmove.s @@ -0,0 +1,193 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 (c) 1987-1995, by Sun Microsystems, Inc. + * All rights reserved. + */ + +.ident "%Z%%M% %I% %E% SMI" + + .file "%M%" + +#include <sys/asm_linkage.h> + + ANSI_PRAGMA_WEAK(memmove,function) + +#include "synonyms.h" + +/* + * memmove(s1, s2, len) + * Copy s2 to s1, always copy n bytes. + * For overlapped copies it does the right thing. + */ + ENTRY(memmove) + save %sp, -SA(MINFRAME), %sp ! not a leaf routine any more + mov %i0, %l6 ! Save pointer to destination + cmp %i1, %i0 ! if from address is >= to use forward copy + bgeu,a 2f ! else use backward if ... + cmp %i2, 17 ! delay slot, for small counts copy bytes + + sub %i0, %i1, %i4 ! get difference of two addresses + cmp %i2, %i4 ! compare size and difference of addresses + bgu ovbc ! if size is bigger, have do overlapped copy + cmp %i2, 17 ! delay slot, for small counts copy bytes + ! + ! normal, copy forwards + ! +2: ble dbytecp + andcc %i1, 3, %i5 ! is src word aligned + bz aldst + cmp %i5, 2 ! is src half-word aligned + be s2algn + cmp %i5, 3 ! src is byte aligned +s1algn: ldub [%i1], %i3 ! move 1 or 3 bytes to align it + inc 1, %i1 + stb %i3, [%i0] ! move a byte to align src + inc 1, %i0 + bne s2algn + dec %i2 + b ald ! now go align dest + andcc %i0, 3, %i5 + +s2algn: lduh [%i1], %i3 ! know src is 2 byte alinged + inc 2, %i1 + srl %i3, 8, %i4 + stb %i4, [%i0] ! have to do bytes, + stb %i3, [%i0 + 1] ! don't know dst alingment + inc 2, %i0 + dec 2, %i2 + +aldst: andcc %i0, 3, %i5 ! align the destination address +ald: bz w4cp + cmp %i5, 2 + bz w2cp + cmp %i5, 3 +w3cp: ld [%i1], %i4 + inc 4, %i1 + srl %i4, 24, %i5 + stb %i5, [%i0] + bne w1cp + inc %i0 + dec 1, %i2 + andn %i2, 3, %i3 ! i3 is aligned word count + dec 4, %i3 ! avoid reading beyond tail of src + sub %i1, %i0, %i1 ! i1 gets the difference + +1: sll %i4, 8, %g1 ! save residual bytes + ld [%i1+%i0], %i4 + deccc 4, %i3 + srl %i4, 24, %i5 ! merge with residual + or %i5, %g1, %g1 + st %g1, [%i0] + bnz 1b + inc 4, %i0 + sub %i1, 3, %i1 ! used one byte of last word read + and %i2, 3, %i2 + b 7f + inc 4, %i2 + +w1cp: srl %i4, 8, %i5 + sth %i5, [%i0] + inc 2, %i0 + dec 3, %i2 + andn %i2, 3, %i3 + dec 4, %i3 ! avoid reading beyond tail of src + sub %i1, %i0, %i1 ! i1 gets the difference + +2: sll %i4, 24, %g1 ! save residual bytes + ld [%i1+%i0], %i4 + deccc 4, %i3 + srl %i4, 8, %i5 ! merge with residual + or %i5, %g1, %g1 + st %g1, [%i0] + bnz 2b + inc 4, %i0 + sub %i1, 1, %i1 ! used three bytes of last word read + and %i2, 3, %i2 + b 7f + inc 4, %i2 + +w2cp: ld [%i1], %i4 + inc 4, %i1 + srl %i4, 16, %i5 + sth %i5, [%i0] + inc 2, %i0 + dec 2, %i2 + andn %i2, 3, %i3 ! i3 is aligned word count + dec 4, %i3 ! avoid reading beyond tail of src + sub %i1, %i0, %i1 ! i1 gets the difference + +3: sll %i4, 16, %g1 ! save residual bytes + ld [%i1+%i0], %i4 + deccc 4, %i3 + srl %i4, 16, %i5 ! merge with residual + or %i5, %g1, %g1 + st %g1, [%i0] + bnz 3b + inc 4, %i0 + sub %i1, 2, %i1 ! used two bytes of last word read + and %i2, 3, %i2 + b 7f + inc 4, %i2 + +w4cp: andn %i2, 3, %i3 ! i3 is aligned word count + sub %i1, %i0, %i1 ! i1 gets the difference + +1: ld [%i1+%i0], %i4 ! read from address + deccc 4, %i3 ! decrement count + st %i4, [%i0] ! write at destination address + bg 1b + inc 4, %i0 ! increment to address + b 7f + and %i2, 3, %i2 ! number of leftover bytes, if any + + ! + ! differenced byte copy, works with any alignment + ! +dbytecp: + b 7f + sub %i1, %i0, %i1 ! i1 gets the difference + +4: stb %i4, [%i0] ! write to address + inc %i0 ! inc to address +7: deccc %i2 ! decrement count + bge,a 4b ! loop till done + ldub [%i1+%i0], %i4 ! read from address + ret + restore %l6, %g0, %o0 ! return pointer to destination + + ! + ! an overlapped copy that must be done "backwards" + ! +ovbc: add %i1, %i2, %i1 ! get to end of source space + add %i0, %i2, %i0 ! get to end of destination space + sub %i1, %i0, %i1 ! i1 gets the difference + +5: dec %i0 ! decrement to address + ldub [%i1+%i0], %i3 ! read a byte + deccc %i2 ! decrement count + bg 5b ! loop until done + stb %i3, [%i0] ! write byte + ret + restore %l6, %g0, %o0 ! return pointer to destination + + SET_SIZE(memmove) diff --git a/usr/src/lib/libc/sparc/gen/memset.s b/usr/src/lib/libc/sparc/gen/memset.s new file mode 100644 index 0000000000..a1f9c223c1 --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/memset.s @@ -0,0 +1,96 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 1987-2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + + .ident "%Z%%M% %I% %E% SMI" + + .file "%M%" + +/* + * char *memset(sp, c, n) + * + * Set an array of n chars starting at sp to the character c. + * Return sp. + * + * Fast assembler language version of the following C-program for memset + * which represents the `standard' for the C-library. + * + * void * + * memset(void *sp1, int c, size_t n) + * { + * if (n != 0) { + * char *sp = sp1; + * do { + * *sp++ = (char)c; + * } while (--n != 0); + * } + * return (sp1); + * } + */ + +#include <sys/asm_linkage.h> + + ANSI_PRAGMA_WEAK(memset,function) + +#include "synonyms.h" + + .weak _private_memset + .type _private_memset, #function + _private_memset = memset + + ENTRY(memset) + mov %o0, %o5 ! copy sp before using it + cmp %o2, 7 ! if small counts, just write bytes + blu .wrchar + .empty ! following lable is ok in delay slot + +.walign:btst 3, %o5 ! if bigger, align to 4 bytes + bz .wrword + andn %o2, 3, %o3 ! create word sized count in %o3 + dec %o2 ! decrement count + stb %o1, [%o5] ! clear a byte + b .walign + inc %o5 ! next byte + +.wrword:and %o1, 0xff, %o1 ! generate a word filled with c + sll %o1, 8, %o4 + or %o1, %o4, %o1 + sll %o1, 16, %o4 + or %o1, %o4, %o1 +1: st %o1, [%o5] ! word writing loop + subcc %o3, 4, %o3 + bnz 1b + inc 4, %o5 + + and %o2, 3, %o2 ! leftover count, if any +.wrchar:deccc %o2 ! byte clearing loop + inc %o5 + bgeu,a .wrchar + stb %o1, [%o5 + -1] ! we've already incremented the address + + retl + nop + + SET_SIZE(memset) diff --git a/usr/src/lib/libc/sparc/gen/setjmp.s b/usr/src/lib/libc/sparc/gen/setjmp.s new file mode 100644 index 0000000000..264e9be602 --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/setjmp.s @@ -0,0 +1,121 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 (c) 1988 AT&T */ +/* All Rights Reserved */ + + +/* + * Copyright 1987-2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +.ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.4 */ + + .file "setjmp.s" + +#include <sys/asm_linkage.h> + + ANSI_PRAGMA_WEAK(setjmp,function) + ANSI_PRAGMA_WEAK(longjmp,function) + +#include "synonyms.h" + +#include <sys/trap.h> + +JB_FLAGS = (0*4) ! offsets in jmpbuf (see siglonglmp.c) +JB_SP = (1*4) ! words 5 through 11 are unused! +JB_PC = (2*4) +JB_FP = (3*4) +JB_I7 = (4*4) + +/* + * setjmp(buf_ptr) + * buf_ptr points to a twelve word array (jmp_buf) + */ + ENTRY(setjmp) + clr [%o0 + JB_FLAGS] ! clear flags (used by sigsetjmp) + st %sp, [%o0 + JB_SP] ! save caller's sp + add %o7, 8, %o1 ! comupte return pc + st %o1, [%o0 + JB_PC] ! save pc + st %fp, [%o0 + JB_FP] ! save fp + st %i7, [%o0 + JB_I7] ! save %i7 + retl + clr %o0 ! return (0) + + SET_SIZE(setjmp) + +/* + * longjmp(buf_ptr, val) + * buf_ptr points to a jmpbuf which has been initialized by setjmp. + * val is the value we wish to return to setjmp's caller + * + * We flush the register file to the stack by doing a kernel call. + * This is necessary to ensure that the registers we want to + * pick up are stored on the stack, and that subsequent restores + * will function correctly. + * + * sp, fp, and %i7, the caller's return address, are all restored + * to the values they had at the time of the call to setjmp(). All + * other locals, ins and outs are set to potentially random values + * (as per the man page). This is sufficient to permit the correct + * operation of normal code. + * + * Actually, the above description is not quite correct. If the routine + * that called setjmp() has not altered the sp value of their frame we + * will restore the remaining locals and ins to the values these + * registers had in the this frame at the time of the call to longjmp() + * (not setjmp()!). This is intended to help compilers, typically not + * C compilers, that have some registers assigned to fixed purposes, + * and that only alter the values of these registers on function entry + * and exit. + * + * Since a C routine could call setjmp() followed by alloca() and thus + * alter the sp this feature will typically not be helpful for a C + * compiler. + * + * Note also that because the caller of a routine compiled "flat" (without + * register windows) assumes that their ins and locals are preserved, + * routines that call setjmp() must not be flat. + */ + ENTRY(longjmp) + ta ST_FLUSH_WINDOWS ! flush all reg windows to the stack. + ld [%o0 + JB_SP], %o2 ! sp in %o2 until safe to puke there + ldd [%o2 + (0*8)], %l0 ! restore locals and ins if we can + ldd [%o2 + (1*8)], %l2 + ldd [%o2 + (2*8)], %l4 + ldd [%o2 + (3*8)], %l6 + ldd [%o2 + (4*8)], %i0 + ldd [%o2 + (5*8)], %i2 + ldd [%o2 + (6*8)], %i4 + ld [%o0 + JB_FP], %fp ! restore fp + mov %o2, %sp ! restore sp + ld [%o0 + JB_I7], %i7 ! restore %i7 + ld [%o0 + JB_PC], %o3 ! get new return pc + tst %o1 ! is return value 0? + bnz 1f ! no - leave it alone + sub %o3, 8, %o7 ! normalize return (for adb) (dly slot) + mov 1, %o1 ! yes - set it to one +1: + retl + mov %o1, %o0 ! return (val) + + SET_SIZE(longjmp) diff --git a/usr/src/lib/libc/sparc/gen/siginfolst.c b/usr/src/lib/libc/sparc/gen/siginfolst.c new file mode 100644 index 0000000000..8939850c60 --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/siginfolst.c @@ -0,0 +1,187 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* Copyright (c) 1988 AT&T */ +/* All Rights Reserved */ + + +#include "synonyms.h" +#include <signal.h> +#include <siginfo.h> + +#undef _sys_siginfolist +#define OLDNSIG 34 + +const char *_sys_traplist[NSIGTRAP] = { + "breakpoint trap", + "trace trap", + "read access trap", + "write access trap", + "execute access trap", + "dtrace trap" +}; + +const char *_sys_illlist[NSIGILL] = { + "illegal opcode", + "illegal operand", + "illegal addressing mode", + "illegal trap", + "privileged opcode", + "privileged register", + "co-processor", + "bad stack" +}; + +const char *_sys_fpelist[NSIGFPE] = { + "integer divide by zero", + "integer overflow", + "floating point divide by zero", + "floating point overflow", + "floating point underflow", + "floating point inexact result", + "invalid floating point operation", + "subscript out of range" +}; + +const char *_sys_segvlist[NSIGSEGV] = { + "address not mapped to object", + "invalid permissions" +}; + +const char *_sys_buslist[NSIGBUS] = { + "invalid address alignment", + "non-existent physical address", + "object specific" +}; + +const char *_sys_cldlist[NSIGCLD] = { + "child has exited", + "child was killed", + "child has coredumped", + "traced child has trapped", + "child has stopped", + "stopped child has continued" +}; + +const char *_sys_polllist[NSIGPOLL] = { + "input available", + "output possible", + "message available", + "I/O error", + "high priority input available", + "device disconnected" +}; + +struct siginfolist _sys_siginfolist[OLDNSIG-1] = { + 0, 0, /* SIGHUP */ + 0, 0, /* SIGINT */ + 0, 0, /* SIGQUIT */ + NSIGILL, (char **)_sys_illlist, /* SIGILL */ + NSIGTRAP, (char **)_sys_traplist, /* SIGTRAP */ + 0, 0, /* SIGABRT */ + 0, 0, /* SIGEMT */ + NSIGFPE, (char **)_sys_fpelist, /* SIGFPE */ + 0, 0, /* SIGKILL */ + NSIGBUS, (char **)_sys_buslist, /* SIGBUS */ + NSIGSEGV, (char **)_sys_segvlist, /* SIGSEGV */ + 0, 0, /* SIGSYS */ + 0, 0, /* SIGPIPE */ + 0, 0, /* SIGALRM */ + 0, 0, /* SIGTERM */ + 0, 0, /* SIGUSR1 */ + 0, 0, /* SIGUSR2 */ + NSIGCLD, (char **)_sys_cldlist, /* SIGCLD */ + 0, 0, /* SIGPWR */ + 0, 0, /* SIGWINCH */ + 0, 0, /* SIGURG */ + NSIGPOLL, (char **)_sys_polllist, /* SIGPOLL */ + 0, 0, /* SIGSTOP */ + 0, 0, /* SIGTSTP */ + 0, 0, /* SIGCONT */ + 0, 0, /* SIGTTIN */ + 0, 0, /* SIGTTOU */ + 0, 0, /* SIGVTALRM */ + 0, 0, /* SIGPROF */ + 0, 0, /* SIGXCPU */ + 0, 0, /* SIGXFSZ */ + 0, 0, /* SIGWAITING */ + 0, 0, /* SIGLWP */ +}; + +static const struct siginfolist _sys_siginfolist_data[NSIG-1] = { + 0, 0, /* SIGHUP */ + 0, 0, /* SIGINT */ + 0, 0, /* SIGQUIT */ + NSIGILL, (char **)_sys_illlist, /* SIGILL */ + NSIGTRAP, (char **)_sys_traplist, /* SIGTRAP */ + 0, 0, /* SIGABRT */ + 0, 0, /* SIGEMT */ + NSIGFPE, (char **)_sys_fpelist, /* SIGFPE */ + 0, 0, /* SIGKILL */ + NSIGBUS, (char **)_sys_buslist, /* SIGBUS */ + NSIGSEGV, (char **)_sys_segvlist, /* SIGSEGV */ + 0, 0, /* SIGSYS */ + 0, 0, /* SIGPIPE */ + 0, 0, /* SIGALRM */ + 0, 0, /* SIGTERM */ + 0, 0, /* SIGUSR1 */ + 0, 0, /* SIGUSR2 */ + NSIGCLD, (char **)_sys_cldlist, /* SIGCLD */ + 0, 0, /* SIGPWR */ + 0, 0, /* SIGWINCH */ + 0, 0, /* SIGURG */ + NSIGPOLL, (char **)_sys_polllist, /* SIGPOLL */ + 0, 0, /* SIGSTOP */ + 0, 0, /* SIGTSTP */ + 0, 0, /* SIGCONT */ + 0, 0, /* SIGTTIN */ + 0, 0, /* SIGTTOU */ + 0, 0, /* SIGVTALRM */ + 0, 0, /* SIGPROF */ + 0, 0, /* SIGXCPU */ + 0, 0, /* SIGXFSZ */ + 0, 0, /* SIGWAITING */ + 0, 0, /* SIGLWP */ + 0, 0, /* SIGFREEZE */ + 0, 0, /* SIGTHAW */ + 0, 0, /* SIGCANCEL */ + 0, 0, /* SIGLOST */ + 0, 0, /* SIGXRES */ + 0, 0, /* SIGJVM1 */ + 0, 0, /* SIGJVM2 */ + 0, 0, /* SIGRTMIN */ + 0, 0, /* SIGRTMIN+1 */ + 0, 0, /* SIGRTMIN+2 */ + 0, 0, /* SIGRTMIN+3 */ + 0, 0, /* SIGRTMAX-3 */ + 0, 0, /* SIGRTMAX-2 */ + 0, 0, /* SIGRTMAX-1 */ + 0, 0, /* SIGRTMAX */ +}; + +const struct siginfolist *_sys_siginfolistp = _sys_siginfolist_data; diff --git a/usr/src/lib/libc/sparc/gen/siglongjmp.c b/usr/src/lib/libc/sparc/gen/siglongjmp.c new file mode 100644 index 0000000000..3b90f52164 --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/siglongjmp.c @@ -0,0 +1,100 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* Copyright (c) 1988 AT&T */ +/* All Rights Reserved */ + + +#pragma weak siglongjmp = _siglongjmp + +#include "lint.h" +#include <sys/types.h> +#include <sys/stack.h> +#include <sys/frame.h> +#include <memory.h> +#include <ucontext.h> +#include <setjmp.h> +#include "sigjmp_struct.h" +#include "libc.h" + +void +_siglongjmp(sigjmp_buf env, int val) +{ + extern void _fetch_globals(greg_t *); + ucontext_t uc; + greg_t *reg = uc.uc_mcontext.gregs; + volatile sigjmp_struct_t *bp = (sigjmp_struct_t *)env; + greg_t fp = bp->sjs_fp; + greg_t i7 = bp->sjs_i7; + + /* + * Create a ucontext_t structure from scratch. + * We only need to fetch the globals. + * The outs are assumed to be trashed on return from sigsetjmp(). + * The ins and locals are restored from the resumed register window. + * The floating point state is unmodified. + * Everything else is in the sigjmp_struct_t buffer. + */ + (void) memset(&uc, 0, sizeof (uc)); + uc.uc_flags = UC_STACK | UC_CPU; + _fetch_globals(®[REG_G1]); + uc.uc_stack = bp->sjs_stack; + uc.uc_link = bp->sjs_uclink; + reg[REG_PC] = bp->sjs_pc; + reg[REG_nPC] = reg[REG_PC] + 0x4; + reg[REG_SP] = bp->sjs_sp; + + if (bp->sjs_flags & JB_SAVEMASK) { + uc.uc_flags |= UC_SIGMASK; + uc.uc_sigmask = bp->sjs_sigmask; + } + + if (val) + reg[REG_O0] = (greg_t)val; + else + reg[REG_O0] = (greg_t)1; + + /* + * Copy the fp and i7 values into the register window save area. + * These may have been clobbered between calls to sigsetjmp + * and siglongjmp. For example, the save area could have been + * relocated to lower addresses and the original save area + * given to an alloca() call. Notice that all reads from + * the sigjmp_struct_t buffer should take place before the + * following two writes. It is possible that user code may + * move/copy the sigjmpbuf around, and overlap the original + * register window save area. + */ + if (bp->sjs_sp != 0 && (bp->sjs_flags & JB_FRAMEPTR)) { + struct frame *sp = (struct frame *)(bp->sjs_sp + STACK_BIAS); + sp->fr_savfp = (struct frame *)fp; + sp->fr_savpc = i7; + } + + (void) setcontext(&uc); +} diff --git a/usr/src/lib/libc/sparc/gen/sparc_data.s b/usr/src/lib/libc/sparc/gen/sparc_data.s new file mode 100644 index 0000000000..dbaece392c --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/sparc_data.s @@ -0,0 +1,33 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 (c) 1988 AT&T */ +/* All Rights Reserved */ + + +/* Copyright (c) 1989 by Sun Microsystems, Inc. */ + +.ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.10 */ + + .file "sparc_data.s" + + .global errno + .common errno,4,4 diff --git a/usr/src/lib/libc/sparc/gen/strcasecmp.s b/usr/src/lib/libc/sparc/gen/strcasecmp.s new file mode 100644 index 0000000000..8efc518ab4 --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/strcasecmp.s @@ -0,0 +1,353 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +.ident "%Z%%M% %I% %E% SMI" + + .file "%M%" +/* + * The strcasecmp() function is a case insensitive versions of strcmp(). + * It assumes the ASCII character set and ignores differences in case + * when comparing lower and upper case characters. In other words, it + * behaves as if both strings had been converted to lower case using + * tolower() in the "C" locale on each byte, and the results had then + * been compared using strcmp(). + * + * The assembly code below is an optimized version of the following C + * reference: + * + * static const char charmap[] = { + * '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', + * '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017', + * '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027', + * '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037', + * '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047', + * '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057', + * '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067', + * '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077', + * '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147', + * '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', + * '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', + * '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137', + * '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147', + * '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', + * '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', + * '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177', + * '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207', + * '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217', + * '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227', + * '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237', + * '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247', + * '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257', + * '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267', + * '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277', + * '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307', + * '\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317', + * '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327', + * '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337', + * '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347', + * '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', + * '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', + * '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377', + * }; + * + * int + * strcasecmp(const char *s1, const char *s2) + * { + * const unsigned char *cm = (const unsigned char *)charmap; + * const unsigned char *us1 = (const unsigned char *)s1; + * const unsigned char *us2 = (const unsigned char *)s2; + * + * while (cm[*us1] == cm[*us2++]) + * if (*us1++ == '\0') + * return (0); + * return (cm[*us1] - cm[*(us2 - 1)]); + * } + * + * The following algorithm, from a 1987 news posting by Alan Mycroft, is + * used for finding null bytes in a word: + * + * #define has_null(word) ((word - 0x01010101) & (~word & 0x80808080)) + * + * The following algorithm is used for a wordwise tolower() operation: + * + * unsigned int + * parallel_tolower (unsigned int x) + * { + * unsigned int p; + * unsigned int q; + * + * unsigned int m1 = 0x80808080; + * unsigned int m2 = 0x3f3f3f3f; + * unsigned int m3 = 0x25252525; + * + * q = x & ~m1;// newb = byte & 0x7F + * p = q + m2; // newb > 0x5A --> MSB set + * q = q + m3; // newb < 0x41 --> MSB clear + * p = p & ~q; // newb > 0x40 && newb < 0x5B --> MSB set + * q = m1 & ~x;// byte < 0x80 --> 0x80 + * q = p & q; // newb > 0x40 && newb < 0x5B && byte < 0x80 -> 0x80,else 0 + * q = q >> 2; // newb > 0x40 && newb < 0x5B && byte < 0x80 -> 0x20,else 0 + * return (x + q); // translate uppercase characters to lowercase + * } + * + * Both algorithms have been tested exhaustively for all possible 2^32 inputs. + */ + + +#include <sys/asm_linkage.h> +#include "synonyms.h" + + ! The first part of this algorithm walks through the beginning of + ! both strings a byte at a time until the source ptr is aligned to + ! a word boundary. During these steps, the bytes are translated to + ! lower-case if they are upper-case, and are checked against + ! the source string. + + ENTRY(strcasecmp) + + .align 32 + + save %sp, -SA(WINDOWSIZE), %sp + subcc %i0, %i1, %i2 ! s1 == s2 ? + bz .stringsequal ! yup, done, strings equal + andcc %i0, 3, %i3 ! s1 word-aligned ? + bz .s1aligned1 ! yup + sethi %hi(0x80808080), %i4 ! start loading Mycroft's magic1 + + ldub [%i1 + %i2], %i0 ! s1[0] + ldub [%i1], %g1 ! s2[0] + sub %i0, 'A', %l0 ! transform for faster uppercase check + sub %g1, 'A', %l1 ! transform for faster uppercase check + cmp %l0, ('Z' - 'A') ! s1[0] uppercase? + bleu,a .noxlate11 ! yes + add %i0, ('a' - 'A'), %i0 ! s1[0] = tolower(s1[0]) +.noxlate11: + cmp %l1, ('Z' - 'A') ! s2[0] uppercase? + bleu,a .noxlate12 ! yes + add %g1, ('a' - 'A'), %g1 ! s2[0] = tolower(s2[0]) +.noxlate12: + subcc %i0, %g1, %i0 ! tolower(s1[0]) != tolower(s2[0]) ? + bne .done ! yup, done + inc %i1 ! s1++, s2++ + addcc %i0, %g1, %i0 ! s1[0] == 0 ? + bz .done ! yup, done, strings equal + cmp %i3, 3 ! s1 aligned now? + bz .s1aligned2 ! yup + sethi %hi(0x01010101), %i5 ! start loading Mycroft's magic2 + + ldub [%i1 + %i2], %i0 ! s1[1] + ldub [%i1], %g1 ! s2[1] + sub %i0, 'A', %l0 ! transform for faster uppercase check + sub %g1, 'A', %l1 ! transform for faster uppercase check + cmp %l0, ('Z' - 'A') ! s1[1] uppercase? + bleu,a .noxlate21 ! yes + add %i0, ('a' - 'A'), %i0 ! s1[1] = tolower(s1[1]) +.noxlate21: + cmp %l1, ('Z' - 'A') ! s2[1] uppercase? + bleu,a .noxlate22 ! yes + add %g1, ('a' - 'A'), %g1 ! s2[1] = tolower(s2[1]) +.noxlate22: + subcc %i0, %g1, %i0 ! tolower(s1[1]) != tolower(s2[1]) ? + bne .done ! yup, done + inc %i1 ! s1++, s2++ + addcc %i0, %g1, %i0 ! s1[1] == 0 ? + bz .done ! yup, done, strings equal + cmp %i3, 2 ! s1 aligned now? + bz .s1aligned3 ! yup + or %i4, %lo(0x80808080),%i4! finish loading Mycroft's magic1 + + ldub [%i1 + %i2], %i0 ! s1[2] + ldub [%i1], %g1 ! s2[2] + sub %i0, 'A', %l0 ! transform for faster uppercase check + sub %g1, 'A', %l1 ! transform for faster uppercase check + cmp %l0, ('Z' - 'A') ! s1[2] uppercase? + bleu,a .noxlate31 ! yes + add %i0, ('a' - 'A'), %i0 ! s1[2] = tolower(s1[2]) +.noxlate31: + cmp %l1, ('Z' - 'A') ! s2[2] uppercase? + bleu,a .noxlate32 ! yes + add %g1, ('a' - 'A'), %g1 ! s2[2] = tolower(s2[2]) +.noxlate32: + subcc %i0, %g1, %i0 ! tolower(s1[2]) != tolower(s2[2]) ? + bne .done ! yup, done + inc %i1 ! s1++, s2++ + addcc %i0, %g1, %i0 ! s1[2] == 0 ? + bz .done ! yup, done, strings equal + or %i5, %lo(0x01010101),%i5! finish loading Mycroft's magic2 + ba .s1aligned4 ! s1 aligned now + andcc %i1, 3, %i3 ! s2 word-aligned ? + + ! Here, we initialize our checks for a zero byte and decide + ! whether or not we can optimize further if we're fortunate + ! enough to have a word aligned desintation + +.s1aligned1: + sethi %hi(0x01010101), %i5 ! start loading Mycroft's magic2 +.s1aligned2: + or %i4, %lo(0x80808080),%i4! finish loading Mycroft's magic1 +.s1aligned3: + or %i5, %lo(0x01010101),%i5! finish loading Mycroft's magic2 + andcc %i1, 3, %i3 ! s2 word aligned ? +.s1aligned4: + sethi %hi(0x3f3f3f3f), %l2 ! load m2 for parallel tolower() + sethi %hi(0x25252525), %l3 ! load m3 for parallel tolower() + or %l2, %lo(0x3f3f3f3f),%l2! finish loading m2 + bz .word4 ! yup, s2 word-aligned + or %l3, %lo(0x25252525),%l3! finish loading m3 + + add %i2, %i3, %i2 ! start adjusting offset s1-s2 + sll %i3, 3, %l6 ! shift factor for left shifts + andn %i1, 3, %i1 ! round s1 pointer down to next word + sub %g0, %l6, %l7 ! shift factor for right shifts + orn %i3, %g0, %i3 ! generate all ones + lduw [%i1], %i0 ! new lower word from s2 + srl %i3, %l6, %i3 ! mask for fixing up bytes + sll %i0, %l6, %g1 ! partial unaligned word from s2 + orn %i0, %i3, %i0 ! force start bytes to non-zero + nop ! pad to align loop to 16-byte boundary + nop ! pad to align loop to 16-byte boundary + + ! This is the comparision procedure used if the destination is not + ! word aligned, if it is, we use word4 & cmp4 + +.cmp: + andn %i4, %i0, %l4 ! ~word & 0x80808080 + sub %i0, %i5, %l5 ! word - 0x01010101 + andcc %l5, %l4, %g0 ! (word - 0x01010101) & ~word & 0x80808080 + bz,a .doload ! null byte in previous aligned s2 word + lduw [%i1 + 4], %i0 ! load next aligned word from s2 +.doload: + srl %i0, %l7, %i3 ! byte(s) from new aligned word from s2 + or %g1, %i3, %g1 ! merge to get unaligned word from s2 + lduw [%i1 + %i2], %i3 ! x1 = word from s1 + andn %i3, %i4, %l0 ! q1 = x1 & ~m1 + andn %g1, %i4, %l4 ! q2 = x2 & ~m1 + add %l0, %l2, %l1 ! p1 = q1 + m2 + add %l4, %l2, %l5 ! p2 = q2 + m2 + add %l0, %l3, %l0 ! q1 = q1 + m3 + add %l4, %l3, %l4 ! q2 = q2 + m3 + andn %l1, %l0, %l1 ! p1 = p1 & ~q1 + andn %l5, %l4, %l5 ! p2 = p2 & ~q2 + andn %i4, %i3, %l0 ! q1 = m1 & ~x1 + andn %i4, %g1, %l4 ! q2 = m1 & ~x2 + and %l0, %l1, %l0 ! q1 = p1 & q1 + and %l4, %l5, %l4 ! q2 = p2 & q2 + srl %l0, 2, %l0 ! q1 = q1 >> 2 + srl %l4, 2, %l4 ! q2 = q2 >> 2 + add %l0, %i3, %i3 ! lowercase word from s1 + add %l4, %g1, %g1 ! lowercase word from s2 + cmp %i3, %g1 ! tolower(*s1) != tolower(*s2) ? + bne .wordsdiffer ! yup, now find byte that is different + add %i1, 4, %i1 ! s1+=4, s2+=4 + andn %i4, %i3, %l4 ! ~word & 0x80808080 + sub %i3, %i5, %l5 ! word - 0x01010101 + andcc %l5, %l4, %g0 ! (word - 0x01010101) & ~word & 0x80808080 + bz .cmp ! no null-byte in s1 yet + sll %i0, %l6, %g1 ! bytes from old aligned word from s2 + + ! words are equal but the end of s1 has been reached + ! this means the strings must be equal +.stringsequal: + ret ! return + restore %g0, %g0, %o0 ! return 0, i.e. strings are equal + nop ! pad + + ! we have a word aligned source and destination! This means + ! things get to go fast! + +.word4: + lduw [%i1 + %i2], %i3 ! x1 = word from s1 + +.cmp4: + andn %i3, %i4, %l0 ! q1 = x1 & ~m1 + lduw [%i1], %g1 ! x2 = word from s2 + andn %g1, %i4, %l4 ! q2 = x2 & ~m1 + add %l0, %l2, %l1 ! p1 = q1 + m2 + add %l4, %l2, %l5 ! p2 = q2 + m2 + add %l0, %l3, %l0 ! q1 = q1 + m3 + add %l4, %l3, %l4 ! q2 = q2 + m3 + andn %l1, %l0, %l1 ! p1 = p1 & ~q1 + andn %l5, %l4, %l5 ! p2 = p2 & ~q2 + andn %i4, %i3, %l0 ! q1 = m1 & ~x1 + andn %i4, %g1, %l4 ! q2 = m1 & ~x2 + and %l0, %l1, %l0 ! q1 = p1 & q1 + and %l4, %l5, %l4 ! q2 = p2 & q2 + srl %l0, 2, %l0 ! q1 = q1 >> 2 + srl %l4, 2, %l4 ! q2 = q2 >> 2 + add %l0, %i3, %i3 ! lowercase word from s1 + add %l4, %g1, %g1 ! lowercase word from s2 + cmp %i3, %g1 ! tolower(*s1) != tolower(*s2) ? + bne .wordsdiffer ! yup, now find mismatching character + add %i1, 4, %i1 ! s1+=4, s2+=4 + andn %i4, %i3, %l4 ! ~word & 0x80808080 + sub %i3, %i5, %l5 ! word - 0x01010101 + andcc %l5, %l4, %g0 ! (word - 0x01010101) & ~word & 0x80808080 + bz,a .cmp4 ! no null-byte in s1 yet + lduw [%i1 + %i2], %i3 ! load word from s1 + + ! words are equal but the end of s1 has been reached + ! this means the strings must be equal +.stringsequal4: + ret ! return + restore %g0, %g0, %o0 ! return 0, i.e. strings are equal + +.wordsdiffer: + srl %g1, 24, %i2 ! first byte of mismatching word in s2 + srl %i3, 24, %i1 ! first byte of mismatching word in s1 + subcc %i1, %i2, %i0 ! *s1-*s2 + bnz .done ! bytes differ, return difference + srl %g1, 16, %i2 ! second byte of mismatching word in s2 + andcc %i1, 0xff, %i0 ! *s1 == 0 ? + bz .done ! yup, done, strings equal + + ! we know byte 1 is equal, so can compare bytes 1,2 as a group + + srl %i3, 16, %i1 ! second byte of mismatching word in s1 + subcc %i1, %i2, %i0 ! *s1-*s2 + bnz .done ! bytes differ, return difference + srl %g1, 8, %i2 ! third byte of mismatching word in s2 + andcc %i1, 0xff, %i0 ! *s1 == 0 ? + bz .done ! yup, done, strings equal + + ! we know bytes 1, 2 are equal, so can compare bytes 1,2,3 as a group + + srl %i3, 8, %i1 ! third byte of mismatching word in s1 + subcc %i1, %i2, %i0 ! *s1-*s2 + bnz .done ! bytes differ, return difference + andcc %i1, 0xff, %g0 ! *s1 == 0 ? + bz .stringsequal ! yup, done, strings equal + + ! we know bytes 1,2,3 are equal, so can compare bytes 1,2,3,4 as group + + subcc %i3, %g1, %i0 ! *s1-*s2 + bz,a .done ! bytes differ, return difference + andcc %i3, 0xff, %i0 ! *s1 == 0, strings equal + +.done: + ret ! return + restore %i0, %g0, %o0 ! return 0 or byte difference + + SET_SIZE(strcasecmp) diff --git a/usr/src/lib/libc/sparc/gen/strchr.s b/usr/src/lib/libc/sparc/gen/strchr.s new file mode 100644 index 0000000000..6a7ee9008b --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/strchr.s @@ -0,0 +1,219 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +.ident "%Z%%M% %I% %E% SMI" + + .file "%M%" + +/* + * The strchr() function returns a pointer to the first occurrence of c + * (converted to a char) in string s, or a null pointer if c does not occur + * in the string. + */ + +#include <sys/asm_linkage.h> +#include "synonyms.h" + + ! Here, we start by checking to see if we're searching the dest + ! string for a null byte. We have fast code for this, so it's + ! an important special case. Otherwise, if the string is not + ! word aligned, we check a for the search char a byte at a time + ! until we've reached a word boundary. Once this has happened + ! some zero-byte finding values are initialized and the string + ! is checked a word at a time + + ENTRY(strchr) + + .align 32 + + andcc %o1, 0xff, %o1 ! search only for this one byte + bz .searchnullbyte ! faster code for searching null + andcc %o0, 3, %o4 ! str word aligned ? + bz,a .prepword2 ! yup, prepare for word-wise search + sll %o1, 8, %g1 ! start spreading findchar across word + + ldub [%o0], %o2 ! str[0] + cmp %o2, %o1 ! str[0] == findchar ? + be .done ! yup, done + tst %o2 ! str[0] == 0 ? + bz .notfound ! yup, return null pointer + cmp %o4, 3 ! only one byte needed to align? + bz .prepword ! yup, prepare for word-wise search + inc %o0 ! str++ + ldub [%o0], %o2 ! str[1] + cmp %o2, %o1 ! str[1] == findchar ? + be .done ! yup, done + tst %o2 ! str[1] == 0 ? + bz .notfound ! yup, return null pointer + cmp %o4, 2 ! only two bytes needed to align? + bz .prepword ! yup, prepare for word-wise search + inc %o0 ! str++ + ldub [%o0], %o2 ! str[2] + cmp %o2, %o1 ! str[2] == findchar ? + be .done ! yup, done + tst %o2 ! str[2] == 0 ? + bz .notfound ! yup, return null pointer + inc %o0 ! str++ + +.prepword: + sll %o1, 8, %g1 ! spread findchar ------+ +.prepword2: ! + sethi %hi(0x01010101), %o4 ! Alan Mycroft's magic1 ! + or %o1, %g1, %o1 ! across all <---------+ + sethi %hi(0x80808080), %o5 ! Alan Mycroft's magic2 ! + sll %o1, 16, %g1 ! four bytes <--------+ + or %o4, %lo(0x01010101), %o4 ! + or %o1, %g1, %o1 ! of a word <--------+ + or %o5, %lo(0x80808080), %o5 + +.searchchar: + lduw [%o0], %o2 ! src word + andn %o5, %o2, %o3 ! ~word & 0x80808080 + sub %o2, %o4, %g1 ! word = (word - 0x01010101) + andcc %o3, %g1, %g0 ! ((word - 0x01010101) & ~word & 0x80808080) + bnz .haszerobyte ! zero byte if magic expression != 0 + xor %o2, %o1, %g1 ! tword = word ^ findchar + andn %o5, %g1, %o3 ! ~tword & 0x80808080 + sub %g1, %o4, %o2 ! (tword - 0x01010101) + andcc %o3, %o2, %g0 ! ((tword - 0x01010101) & ~tword & 0x80808080) + bz,a .searchchar ! no findchar if magic expression == 0 + add %o0, 4, %o0 ! str += 4 + + ! here we know "word" contains the searched character, but no null + ! byte. if there was a null byte, we would have gone to .haszerobyte + ! "tword" has null bytes where "word" had findchar. Examine "tword" + +.foundchar: + set 0xff000000, %o4 ! mask for 1st byte + andcc %g1, %o4, %g0 ! first byte zero (= found search char) ? + bz .done ! yup, done + set 0x00ff0000, %o5 ! mask for 2nd byte + inc %o0 ! str++ + andcc %g1, %o5, %g0 ! second byte zero (= found search char) ? + bz .done ! yup, done + srl %o4, 16, %o4 ! 0x0000ff00 = mask for 3rd byte + inc %o0 ! str++ + andcc %g1, %o4, %g0 ! third byte zero (= found search char) ? + bnz,a .done ! nope, increment in delay slot + inc %o0 ! str++ + +.done: + retl ! done with leaf function + nop ! padding + + ! Here we know that "word" contains a null byte indicating the + ! end of the string. However, "word" might also contain findchar + ! "tword" (in %g1) has null bytes where "word" had findchar. So + ! check both "tword" and "word" + +.haszerobyte: + set 0xff000000, %o4 ! mask for 1st byte + andcc %g1, %o4, %g0 ! first byte == findchar ? + bz .done ! yup, done + andcc %o2, %o4, %g0 ! first byte == 0 ? + bz .notfound ! yup, return null pointer + set 0x00ff0000, %o4 ! mask for 2nd byte + inc %o0 ! str++ + andcc %g1, %o4, %g0 ! second byte == findchar ? + bz .done ! yup, done + andcc %o2, %o4, %g0 ! second byte == 0 ? + bz .notfound ! yup, return null pointer + srl %o4, 8, %o4 ! mask for 3rd byte = 0x0000ff00 + inc %o0 ! str++ + andcc %g1, %o4, %g0 ! third byte == findchar ? + bz .done ! yup, done + andcc %o2, %o4, %g0 ! third byte == 0 ? + bz .notfound ! yup, return null pointer + andcc %g1, 0xff, %g0 ! fourth byte == findchar ? + bz .done ! yup, done + inc %o0 ! str++ + +.notfound: + retl ! done with leaf function + xor %o0, %o0, %o0 ! return null pointer + + ! since findchar == 0, we only have to do one test per item + ! instead of two. This makes the search much faster. + +.searchnullbyte: + bz .straligned ! str is word aligned + nop ! padding + + cmp %o4, 2 ! str halfword aligned ? + be .s2aligned ! yup + ldub [%o0], %o1 ! str[0] + tst %o1 ! byte zero? + bz .done2 ! yup, done + cmp %o4, 3 ! only one byte needed to align? + bz .straligned ! yup + inc %o0 ! str++ + + ! check to see if we're half word aligned, which it better than + ! not being aligned at all. Search the first half of the word + ! if we are, and then search by whole word. + +.s2aligned: + lduh [%o0], %o1 ! str[] + srl %o1, 8, %o4 ! %o4<7:0> = first byte + tst %o4 ! first byte zero ? + bz .done2 ! yup, done + andcc %o1, 0xff, %g0 ! second byte zero ? + bz,a .done2 ! yup, done + inc %o0 ! str++ + add %o0, 2, %o0 ! str+=2 + +.straligned: + sethi %hi(0x01010101), %o4 ! Alan Mycroft's magic1 + sethi %hi(0x80808080), %o5 ! Alan Mycroft's magic2 + or %o4, %lo(0x01010101), %o4 + or %o5, %lo(0x80808080), %o5 + +.searchword: + lduw [%o0], %o1 ! src word + andn %o5, %o1, %o3 ! ~word & 0x80808080 + sub %o1, %o4, %g1 ! word = (word - 0x01010101) + andcc %o3, %g1, %g0 ! ((word - 0x01010101) & ~word & 0x80808080) + bz,a .searchword ! no zero byte if magic expression == 0 + add %o0, 4, %o0 ! str += 4 + +.zerobyte: + set 0xff000000, %o4 ! mask for 1st byte + andcc %o1, %o4, %g0 ! first byte zero? + bz .done2 ! yup, done + set 0x00ff0000, %o5 ! mask for 2nd byte + inc %o0 ! str++ + andcc %o1, %o5, %g0 ! second byte zero? + bz .done2 ! yup, done + srl %o4, 16, %o4 ! 0x0000ff00 = mask for 3rd byte + inc %o0 ! str++ + andcc %o1, %o4, %g0 ! third byte zero? + bnz,a .done2 ! nope, increment in delay slot + inc %o0 ! str++ +.done2: + retl ! return from leaf function + nop ! padding + + SET_SIZE(strchr) diff --git a/usr/src/lib/libc/sparc/gen/strcmp.s b/usr/src/lib/libc/sparc/gen/strcmp.s new file mode 100644 index 0000000000..a1b7065a04 --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/strcmp.s @@ -0,0 +1,247 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +.ident "%Z%%M% %I% %E% SMI" + + .file "%M%" + +/* strcmp(s1, s2) + * + * Compare strings: s1>s2: >0 s1==s2: 0 s1<s2: <0 + * + * Fast assembler language version of the following C-program for strcmp + * which represents the `standard' for the C-library. + * + * int + * strcmp(s1, s2) + * register const char *s1; + * register const char *s2; + * { + * + * if(s1 == s2) + * return(0); + * while(*s1 == *s2++) + * if(*s1++ == '\0') + * return(0); + * return(*s1 - s2[-1]); + * } + */ + +#include <sys/asm_linkage.h> +#include "synonyms.h" + + ! This strcmp implementation first determines whether s1 is aligned. + ! If it is not, it attempts to align it and then checks the + ! alignment of the destination string. If it is possible to + ! align s2, this also happens and then the compare begins. Otherwise, + ! a different compare for non-aligned strings is used. + ! In this case, we have multiple routines depending upon the + ! degree to which a string is mis-aligned. + + ENTRY(strcmp) + + .align 32 + + subcc %o0, %o1, %o2 ! s1 == s2 ? + bz .stringsequal1 ! yup, same string, done + sethi %hi(0x01010101), %o5 ! start loading Mycroft's magic2 + andcc %o0, 3, %o3 ! s1 word-aligned ? + or %o5, %lo(0x01010101),%o5! finish loading Mycroft's magic2 + bz .s1aligned ! yup + sll %o5, 7, %o4 ! load Mycroft's magic1 + sub %o3, 4, %o3 ! number of bytes till aligned + +.aligns1: + ldub [%o1 + %o2], %o0 ! s1[] + ldub [%o1], %g1 ! s2[] + subcc %o0, %g1, %o0 ! s1[] != s2[] ? + bne .done ! yup, done + addcc %o0, %g1, %g0 ! s1[] == 0 ? + bz .done ! yup, done + inccc %o3 ! s1 aligned yet? + bnz .aligns1 ! nope, compare another pair of bytes + inc %o1 ! s1++, s2++ + +.s1aligned: + andcc %o1, 3, %o3 ! s2 word aligned ? + bz .word4 ! yup + cmp %o3, 2 ! s2 half-word aligned ? + be .word2 ! yup + cmp %o3, 3 ! s2 offset to dword == 3 ? + be,a .word3 ! yup + ldub [%o1], %o0 ! new lower word in s2 + +.word1: + lduw [%o1 - 1], %o0 ! new lower word in s2 + sethi %hi(0xff000000), %o3 ! mask for forcing byte 1 non-zero + sll %o0, 8, %g1 ! partial unaligned word from s2 + or %o0, %o3, %o0 ! force byte 1 non-zero + +.cmp1: + andn %o4, %o0, %o3 ! ~word & 0x80808080 + sub %o0, %o5, %o0 ! word - 0x01010101 + andcc %o0, %o3, %g0 ! (word - 0x01010101) & ~word & 0x80808080 + bz,a .doload1 ! no null byte in previous word from s2 + lduw [%o1 + 3], %o0 ! load next aligned word from s2 +.doload1: + srl %o0, 24, %o3 ! byte 1 of new aligned word from s2 + or %g1, %o3, %g1 ! merge to get unaligned word from s2 + lduw [%o1 + %o2], %o3 ! word from s1 + cmp %o3, %g1 ! *s1 != *s2 ? + bne .wordsdiffer ! yup, find the byte that is different + add %o1, 4, %o1 ! s1+=4, s2+=4 + andn %o4, %o3, %g1 ! ~word & 0x80808080 + sub %o3, %o5, %o3 ! word - 0x01010101 + andcc %o3, %g1, %g0 ! (word - 0x01010101) & ~word & 0x80808080 + bz .cmp1 ! no null-byte in s1 yet + sll %o0, 8, %g1 ! partial unaligned word from s2 + + ! words are equal but the end of s1 has been reached + ! this means the strings must be equal +.stringsequal1: + retl ! return from leaf function + mov %g0, %o0 ! return 0, i.e. strings are equal + nop ! pad for optimal alignment of .cmp2 + nop ! pad for optimal alignment of .cmp2 + +.word2: + lduh [%o1], %o0 ! new lower word in s2 + sethi %hi(0xffff0000), %o3 ! mask for forcing bytes 1,2 non-zero + sll %o0, 16, %g1 ! partial unaligned word from s2 + or %o0, %o3, %o0 ! force bytes 1,2 non-zero + +.cmp2: + andn %o4, %o0, %o3 ! ~word & 0x80808080 + sub %o0, %o5, %o0 ! word - 0x01010101 + andcc %o0, %o3, %g0 ! (word - 0x01010101) & ~word & 0x80808080 + bz,a .doload2 ! no null byte in previous word from s2 + lduw [%o1 + 2], %o0 ! load next aligned word from s2 +.doload2: + srl %o0, 16, %o3 ! bytes 1,2 of new aligned word from s2 + or %g1, %o3, %g1 ! merge to get unaligned word from s2 + lduw [%o1 + %o2], %o3 ! word from s1 + cmp %o3, %g1 ! *s1 != *s2 ? + bne .wordsdiffer ! yup, find the byte that is different + add %o1, 4, %o1 ! s1+=4, s2+=4 + andn %o4, %o3, %g1 ! ~word & 0x80808080 + sub %o3, %o5, %o3 ! word - 0x01010101 + andcc %o3, %g1, %g0 ! (word - 0x01010101) & ~word & 0x80808080 + bz .cmp2 ! no null-byte in s1 yet + sll %o0, 16, %g1 ! partial unaligned word from s2 + + ! words are equal but the end of s1 has been reached + ! this means the strings must be equal +.stringsequal2: + retl ! return from leaf function + mov %g0, %o0 ! return 0, i.e. strings are equal + +.word3: + sll %o0, 24, %g1 ! partial unaligned word from s2 + nop ! pad for optimal alignment of .cmp3 +.cmp3: + andcc %o0, 0xff, %g0 ! did previous word contain null-byte ? + bnz,a .doload3 ! nope, load next word from s2 + lduw [%o1 + 1], %o0 ! load next aligned word from s2 +.doload3: + srl %o0, 8, %o3 ! bytes 1,2,3 from new aligned s2 word + or %g1, %o3, %g1 ! merge to get unaligned word from s2 + lduw [%o1 + %o2], %o3 ! word from s1 + cmp %o3, %g1 ! *s1 != *s2 ? + bne .wordsdiffer ! yup, find the byte that is different + add %o1, 4, %o1 ! s1+=4, s2+=4 + andn %o4, %o3, %g1 ! ~word & 0x80808080 + sub %o3, %o5, %o3 ! word - 0x01010101 + andcc %o3, %g1, %g0 ! (word - 0x01010101) & ~word & 0x80808080 + bz .cmp3 ! no null-byte in s1 yet + sll %o0, 24, %g1 ! partial unaligned word from s2 + + ! words are equal but the end of s1 has been reached + ! this means the strings must be equal +.stringsequal3: + retl ! return from leaf function + mov %g0, %o0 ! return 0, i.e. strings are equal + +.word4: + lduw [%o1 + %o2], %o3 ! load word from s1 + nop ! pad for optimal alignment of .cmp4 + nop ! pad for optimal alignment of .cmp4 + nop ! pad for optimal alignment of .cmp4 + +.cmp4: + lduw [%o1], %g1 ! load word from s2 + cmp %o3, %g1 ! *scr1 == *src2 ? + bne .wordsdiffer ! nope, find mismatching character + add %o1, 4, %o1 ! src1 += 4, src2 += 4 + andn %o4, %o3, %o0 ! ~word & 0x80808080 + sub %o3, %o5, %o3 ! word - 0x01010101 + andcc %o3, %o0, %g0 ! (word - 0x01010101) & ~word & 0x80808080 + bz,a .cmp4 ! no null-byte in s1 yet + lduw [%o1 + %o2], %o3 ! load word from s1 + + ! words are equal but the end of s1 has been reached + ! this means the strings must be equal +.stringsequal4: + retl ! return from leaf function + mov %g0, %o0 ! return 0, i.e. strings are equal + +.wordsdiffer: + srl %g1, 24, %o2 ! first byte of mismatching word in s2 + srl %o3, 24, %o1 ! first byte of mismatching word in s1 + subcc %o1, %o2, %o0 ! *s1-*s2 + bnz .done ! bytes differ, return difference + srl %g1, 16, %o2 ! second byte of mismatching word in s2 + andcc %o1, 0xff, %o0 ! *s1 == 0 ? + bz .done ! yup + + ! we know byte 1 is equal, so can compare bytes 1,2 as a group + + srl %o3, 16, %o1 ! second byte of mismatching word in s1 + subcc %o1, %o2, %o0 ! *s1-*s2 + bnz .done ! bytes differ, return difference + srl %g1, 8, %o2 ! third byte of mismatching word in s2 + andcc %o1, 0xff, %o0 ! *s1 == 0 ? + bz .done ! yup + + ! we know bytes 1, 2 are equal, so can compare bytes 1,2,3 as a group + + srl %o3, 8, %o1 ! third byte of mismatching word in s1 + subcc %o1, %o2, %o0 ! *s1-*s2 + bnz .done ! bytes differ, return difference + andcc %o1, 0xff, %g0 ! *s1 == 0 ? + bz .stringsequal1 ! yup + + ! we know bytes 1,2,3 are equal, so can compare bytes 1,2,3,4 as group + + subcc %o3, %g1, %o0 ! *s1-*s2 + bz,a .done ! bytes differ, return difference + andcc %o3, 0xff, %o0 ! *s1 == 0 ? + +.done: + retl ! return from leaf routine + nop ! padding + + + SET_SIZE(strcmp) diff --git a/usr/src/lib/libc/sparc/gen/strcpy.s b/usr/src/lib/libc/sparc/gen/strcpy.s new file mode 100644 index 0000000000..63de6cfe8c --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/strcpy.s @@ -0,0 +1,172 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +.ident "%Z%%M% %I% %E% SMI" + + .file "%M%" + +/* + * strcpy(s1, s2) + * + * Copy string s2 to s1. s1 must be large enough. Return s1. + * + * Fast assembler language version of the following C-program strcpy + * which represents the `standard' for the C-library. + * + * char * + * strcpy(s1, s2) + * register char *s1; + * register const char *s2; + * { + * char *os1 = s1; + * + * while(*s1++ = *s2++) + * ; + * return(os1); + * } + * + */ + +#include <sys/asm_linkage.h> +#include "synonyms.h" + + ! This is a 32-bit implementation of strcpy. It works by + ! first checking the alignment of its source pointer. And, + ! if it is not aligned, attempts to copy bytes until it is. + ! once this has occurred, the copy takes place, while checking + ! for zero bytes, based upon destination alignment. + ! Methods exist to handle per-byte, half-word, and word sized + ! copies. + + ENTRY(strcpy) + + .align 32 + + sub %o1, %o0, %o3 ! src - dst + andcc %o1, 3, %o4 ! src word aligned ? + bz .srcaligned ! yup + mov %o0, %o2 ! save dst + + cmp %o4, 2 ! src halfword aligned + be .s2aligned ! yup + ldub [%o2 + %o3], %o1 ! src[0] + tst %o1 ! byte zero? + stb %o1, [%o2] ! store first byte + bz .done ! yup, done + cmp %o4, 3 ! only one byte needed to align? + bz .srcaligned ! yup + inc %o2 ! src++, dst++ + +.s2aligned: + lduh [%o2 + %o3], %o1 ! src[] + srl %o1, 8, %o4 ! %o4<7:0> = first byte + tst %o4 ! first byte zero ? + bz .done ! yup, done + stb %o4, [%o2] ! store first byte + andcc %o1, 0xff, %g0 ! second byte zero ? + bz .done ! yup, done + stb %o1, [%o2 + 1] ! store second byte + add %o2, 2, %o2 ! src += 2, dst += 2 + +.srcaligned: + sethi %hi(0x01010101), %o4 ! Alan Mycroft's magic1 + sethi %hi(0x80808080), %o5 ! Alan Mycroft's magic2 + or %o4, %lo(0x01010101), %o4 + andcc %o2, 3, %o1 ! destination word aligned? + bnz .dstnotaligned ! nope + or %o5, %lo(0x80808080), %o5 + +.copyword: + lduw [%o2 + %o3], %o1 ! src word + add %o2, 4, %o2 ! src += 4, dst += 4 + andn %o5, %o1, %g1 ! ~word & 0x80808080 + sub %o1, %o4, %o1 ! word - 0x01010101 + andcc %o1, %g1, %g0 ! ((word - 0x01010101) & ~word & 0x80808080) + add %o1, %o4, %o1 ! restore word + bz,a .copyword ! no zero byte if magic expression == 0 + st %o1, [%o2 - 4] ! store word to dst (address pre-incremented) + +.zerobyte: + set 0xff000000, %o4 ! mask for 1st byte + srl %o1, 24, %o3 ! %o3<7:0> = first byte + andcc %o1, %o4, %g0 ! first byte zero? + bz .done ! yup, done + stb %o3, [%o2 - 4] ! store first byte + set 0x00ff0000, %o5 ! mask for 2nd byte + srl %o1, 16, %o3 ! %o3<7:0> = second byte + andcc %o1, %o5, %g0 ! second byte zero? + bz .done ! yup, done + stb %o3, [%o2 - 3] ! store second byte + srl %o4, 16, %o4 ! 0x0000ff00 = mask for 3rd byte + andcc %o1, %o4, %g0 ! third byte zero? + srl %o1, 8, %o3 ! %o3<7:0> = third byte + bz .done ! yup, done + stb %o3, [%o2 - 2] ! store third byte + stb %o1, [%o2 - 1] ! store fourth byte + +.done: + retl ! done with leaf function + .empty + +.dstnotaligned: + cmp %o1, 2 ! dst half word aligned? + be,a .storehalfword2 ! yup, store half word at a time + lduw [%o2 + %o3], %o1 ! src word + +.storebyte: + lduw [%o2 + %o3], %o1 ! src word + add %o2, 4, %o2 ! src += 4, dst += 4 + sub %o1, %o4, %g1 ! x - 0x01010101 + andn %g1, %o1, %g1 ! (x - 0x01010101) & ~x + andcc %g1, %o5, %g0 ! ((x - 0x01010101) & ~x & 0x80808080) + bnz .zerobyte ! word has zero byte, handle end cases + srl %o1, 24, %g1 ! %g1<7:0> = first byte + stb %g1, [%o2 - 4] ! store first byte; half-word aligned now + srl %o1, 8, %g1 ! %g1<15:0> = byte 2, 3 + sth %g1, [%o2 - 3] ! store bytes 2, 3 + ba .storebyte ! next word + stb %o1, [%o2 - 1] ! store fourth byte + +.storehalfword: + lduw [%o2 + %o3], %o1 ! src word +.storehalfword2: + add %o2, 4, %o2 ! src += 4, dst += 4 + sub %o1, %o4, %g1 ! x - 0x01010101 + andn %g1, %o1, %g1 ! (x - 0x01010101) & ~x + andcc %g1, %o5, %g0 ! ((x - 0x01010101) & ~x & 0x80808080) + bnz .zerobyte ! word has zero byte, handle end cases + srl %o1, 16, %g1 ! get first and second byte + sth %g1, [%o2 - 4] ! store first and second byte + ba .storehalfword ! next word + sth %o1, [%o2 - 2] ! store third and fourth byte + + ! DO NOT remove these NOPs. It will slow down the halfword loop by 15% + + nop ! padding + nop ! padding + + SET_SIZE(strcpy) + diff --git a/usr/src/lib/libc/sparc/gen/strlcpy.s b/usr/src/lib/libc/sparc/gen/strlcpy.s new file mode 100644 index 0000000000..0dd5366dd3 --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/strlcpy.s @@ -0,0 +1,236 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +.ident "%Z%%M% %I% %E% SMI" + + .file "%M%" +/* + * The strlcpy() function copies at most dstsize-1 characters + * (dstsize being the size of the string buffer dst) from src + * to dst, truncating src if necessary. The result is always + * null-terminated. The function returns strlen(src). Buffer + * overflow can be checked as follows: + * + * if (strlcpy(dst, src, dstsize) >= dstsize) + * return -1; + */ + +#include <sys/asm_linkage.h> +#include "synonyms.h" + + ! strlcpy implementation is similar to that of strcpy, except + ! in this case, the maximum size of the detination must be + ! tracked since it bounds our maximum copy size. However, + ! we must still continue to check for zero since the routine + ! is expected to null-terminate any string that is within + ! the dest size bound. + ! + ! this method starts by checking for and arranging source alignment. + ! Once this has occurred, we copy based upon destination alignment. + ! This is either by word, halfword, or byte. As this occurs, we + ! check for a zero-byte. If one is found, we branch to a method + ! which checks for the exact location of a zero-byte within a + ! larger word/half-word quantity. + + ENTRY(strlcpy) + + .align 32 + save %sp, -SA(WINDOWSIZE), %sp + subcc %g0, %i2, %g4 ! n = -n or n == 0 ? + bz,pn %icc, .getstrlen ! if 0 do nothing but strlen(src) + add %i1, %i2, %i3 ! i3 = src + n + andcc %i1, 3, %i4 ! word aligned? + bz,pn %icc, .wordaligned + add %i0, %i2, %i2 ! n = dst + n + sub %i4, 4, %i4 ! bytes until src aligned + +.alignsrc: + ldub [%i3 + %g4], %l1 ! l1 = src[] + andcc %l1, 0xff, %g0 ! null byte reached? + stub %l1, [%i2 + %g4] ! dst[] = src[] + bz,a %icc, .done + add %i2, %g4, %i2 ! get single dest ptr for strlen + addcc %g4, 1, %g4 ! src++ dest++ n-- + bz,pn %icc, .forcenullunalign ! n == 0, append null byte + addcc %i4, 1, %i4 ! incr, check align + bnz,a %icc, .alignsrc + nop + +.wordaligned: + sethi %hi(0x01010101), %i4 + add %i2, %g4, %l0 ! l0 = dest + or %i4, %lo(0x01010101), %i4 + sub %i2, 4, %i2 ! pre-incr for in cpy loop + andcc %l0, 3, %g1 ! word aligned? + bnz %icc, .dstnotaligned + sll %i4, 7, %i5 ! Mycroft part deux + +.storeword: + ld [%i3 + %g4], %l1 ! l1 = src[] + addcc %g4, 4, %g4 ! n += 4, src += 4, dst +=4 + bcs,pn %icc, .lastword + andn %i5, %l1, %g1 ! ~word & 0x80808080 + sub %l1, %i4, %l0 ! word - 0x01010101 + andcc %l0, %g1, %g0 ! doit + bz,a,pt %icc, .storeword ! if expr == 0, no zero byte + st %l1, [%i2 + %g4] ! dst[] = src[] + +.zerobyte: + add %i2, %g4, %i2 ! ptr to dest + srl %l1, 24, %g1 ! 1st byte + andcc %g1, 0xff, %g0 ! test for end + bz,pn %icc, .done + stb %g1, [%i2] ! store byte + add %i2, 1, %i2 ! dst ++ + srl %l1, 16, %g1 ! 2nd byte + andcc %g1, 0xff, %g0 ! zero byte ? + bz,pn %icc, .done + stb %g1, [%i2] ! store byte + add %i2, 1, %i2 ! dst ++ + srl %l1, 8, %g1 ! 3rd byte + andcc %g1, 0xff, %g0 ! zero byte ? + bz,pn %icc, .done + stb %g1, [%i2] ! store byte + stb %l1, [%i2 + 1] ! store last byte + add %i2, 1, %i2 ! dst ++ + +.done: + sub %i2, %i0, %i0 ! len = dst - orig dst + ret + restore %i0, %g0, %o0 + +.lastword: + add %i2, %g4, %i2 + sub %g4, 4, %g4 ! undo pre-incr + add %i3, %g4, %i3 + + srl %l1, 24, %g1 ! 1st byte + andcc %g1, 0xff, %g0 ! zero byte? + bz,pn %icc, .done + stb %g1, [%i2] ! store byte + inccc %g4 ! n-- + bz .forcenull + srl %l1, 16, %g1 ! 2nd byte + add %i2, 1, %i2 ! dst++ + andcc %g1, 0xff, %g0 ! zero? + bz,pn %icc, .done + stb %g1, [%i2] ! store + inccc %g4 + bz .forcenull + srl %l1, 8, %g1 ! 3rd byte + add %i2, 1, %i2 ! dst++ + andcc %g1, 0xff, %g0 ! zero? + bz,pn %icc, .done + stb %g1, [%i2] ! store + inccc %g4 ! n-- + bz .forcenull + andcc %l1, 0xff, %g0 ! zero? + add %i2, 1, %i2 ! dst++ + bz,pn %ncc, .done + stb %l1, [%i2] + +.forcenull: + stb %g0, [%i2] + +.searchword: + ld [%i3], %l1 +.searchword2: + andn %i5, %l1, %g1 ! word & 0x80808080 + sub %l1, %i4, %l0 ! word - 0x01010101 + andcc %l0, %g1, %g0 ! do it + bz,a,pt %icc, .searchword + add %i3, 4, %i3 ! src += 4 + + mov 0xff, %i5 + sll %i5, 24, %i5 ! mask 1st byte = 0xff000000 +.searchbyte: + andcc %l1, %i5, %g0 ! cur byte 0? + srl %i5, 8, %i5 ! mask next byte + bnz,a %icc, .searchbyte ! cur !=0 continue + add %i3, 1, %i3 + +.endfound: + sub %i3, %i1, %i0 ! len = src - orig src + ret + restore %i0, %g0, %o0 + nop + +.dstnotaligned: + cmp %g1, 2 ! halfword aligned? + be .storehalfword2 + .empty +.storebyte: + ld [%i3 + %g4], %l1 ! load src word + addcc %g4, 4, %g4 ! src +=4 dst +=4 + bcs,pn %icc, .lastword + andn %i5, %l1, %g1 ! ~x & 0x80808080 + sub %l1, %i4, %l0 ! x - 0x01010101 + andcc %l0, %g1, %g0 ! get your Mycroft on + bnz,pn %icc, .zerobyte ! non-zero, we have zero byte + add %i2, %g4, %l0 ! dst in ptr form + srl %l1, 24, %g1 ! get 1st byte, then be hw aligned + stb %g1, [%l0] + srl %l1, 8, %g1 ! 2nd & 3rd bytes + sth %g1, [%l0 + 1] + ba .storebyte + stb %l1, [%l0 + 3] ! store 4th byte + +.storehalfword: + ld [%i3 + %g4], %l1 ! src word +.storehalfword2: + addcc %g4, 4, %g4 ! src += 4 dst += 4 + bcs,pn %icc, .lastword + andn %i5, %l1, %g1 ! ~x & 0x80808080 + sub %l1, %i4, %l0 ! x - 0x01010101 + andcc %l0, %g1, %g0 ! Mycroft again... + bnz,pn %icc, .zerobyte ! non-zer, we have zero byte + add %i2, %g4, %l0 ! dst in ptr form + srl %l1, 16, %g1 ! first two bytes + sth %g1, [%l0] + ba .storehalfword + sth %l1, [%l0 + 2] + +.forcenullunalign: + add %i2, %g4, %i2 ! single dst ptr + stb %g0, [%i2 - 1] ! store terminating null byte + +.getstrlen: + sethi %hi(0x01010101), %i4 ! Mycroft... + or %i4, %lo(0x01010101), %i4 + sll %i4, 7, %i5 + +.getstrlenloop: + andcc %i3, 3, %g0 ! word aligned? + bz,a,pn %icc, .searchword2 ! search word at a time + ld [%i3], %l1 ! src word + ldub [%i3], %l1 ! src byte + andcc %l1, 0xff, %g0 ! end of src? + bnz,a %icc, .getstrlenloop + add %i3, 1, %i3 ! src ++ + sub %i3, %i1, %i0 ! len = src - orig src + ret + restore %i0, %g0, %o0 + SET_SIZE(strlcpy) diff --git a/usr/src/lib/libc/sparc/gen/strlen.s b/usr/src/lib/libc/sparc/gen/strlen.s new file mode 100644 index 0000000000..09da4ed196 --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/strlen.s @@ -0,0 +1,141 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + + +.ident "%Z%%M% %I% %E% SMI" + + .file "%M%" + +/* + * strlen(s) + * + * Given string s, return length (not including the terminating null). + * + * Fast assembler language version of the following C-program strlen + * which represents the `standard' for the C-library. + * + * size_t + * strlen(s) + * register const char *s; + * { + * register const char *s0 = s + 1; + * + * while (*s++ != '\0') + * ; + * return (s - s0); + * } + */ + +#include <sys/asm_linkage.h> +#include "synonyms.h" + + ! The object of strlen is to, as quickly as possible, find the + ! null byte. To this end, we attempt to get our string aligned + ! and then blast across it using Alan Mycroft's algorithm for + ! finding null bytes. If we are not aligned, the string is + ! checked a byte at a time until it is. Once this occurs, + ! we can proceed word-wise across it. Once a word with a + ! zero byte has been found, we then check the word a byte + ! at a time until we've located the zero byte, and return + ! the proper length. + + .align 32 + ENTRY(strlen) + andcc %o0, 3, %o4 ! is src word aligned + bz,pt %icc, .nowalgnd + mov %o0, %o2 + + cmp %o4, 2 ! is src half-word aligned + be,a,pn %icc, .s2algn + lduh [%o2], %o1 + + ldub [%o2], %o1 + tst %o1 ! byte zero? + bz,pn %icc, .done + cmp %o4, 3 ! src is byte aligned + + be,pn %icc, .nowalgnd + inc 1, %o2 + + lduh [%o2], %o1 + +.s2algn: + srl %o1, 8, %o4 + tst %o4 + bz,pn %icc, .done + andcc %o1, 0xff, %g0 + + bz,pn %icc, .done + inc 1, %o2 + + inc 1, %o2 + +.nowalgnd: + ld [%o2], %o1 + sethi %hi(0x01010101), %o4 + sethi %hi(0x80808080), %o5 + or %o4, %lo(0x01010101), %o4 + or %o5, %lo(0x80808080), %o5 + + andn %o5, %o1, %o3 + sub %o1, %o4, %g1 + andcc %o3, %g1, %g0 + bnz,a,pn %icc, .nullfound + sethi %hi(0xff000000), %o4 + + ld [%o2+4], %o1 + inc 4, %o2 + +.loop: ! this should be aligned to 32 + inc 4, %o2 + andn %o5, %o1, %o3 ! %o5 = ~word & 0x80808080 + sub %o1, %o4, %g1 ! %g1 = word - 0x01010101 + andcc %o3, %g1, %g0 + bz,a,pt %icc, .loop + ld [%o2], %o1 + + dec 4, %o2 + sethi %hi(0xff000000), %o4 +.nullfound: + andcc %o1, %o4, %g0 + bz,pn %icc, .done ! first byte zero + srl %o4, 8, %o4 + + andcc %o1, %o4, %g0 + bz,pn %icc, .done ! second byte zero + inc 1, %o2 + + srl %o4, 8, %o4 + andcc %o1, %o4, %g0 + bz,pn %icc, .done ! thrid byte zero + inc 1, %o2 + + inc 1, %o2 ! fourth byte zero +.done: + retl + sub %o2, %o0, %o0 + SET_SIZE(strlen) + diff --git a/usr/src/lib/libc/sparc/gen/strncmp.s b/usr/src/lib/libc/sparc/gen/strncmp.s new file mode 100644 index 0000000000..2d9c138ce0 --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/strncmp.s @@ -0,0 +1,315 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 (c) 1989,1998 by Sun Microsystems, Inc. + * All rights reserved. + * + * .seg "data" + * .asciz "@(#)strncmp.s 1.2 89/08/16" + */ + +.ident "%Z%%M% %I% %E% SMI" /* SunOS 4.1 1.4 */ + + .file "strncmp.s" + +/* + * strncmp(s1, s2, n) + * + * Compare strings (at most n bytes): s1>s2: >0 s1==s2: 0 s1<s2: <0 + * + * Fast assembler language version of the following C-program for strncmp + * which represents the `standard' for the C-library. + * + * int + * strncmp(const char *s1, const char *s2, size_t n) + * { + * n++; + * if (s1 == s2) + * return (0); + * while (--n != 0 && *s1 == *s2++) + * if (*s1++ == '\0') + * return (0); + * return ((n == 0) ? 0 : (*s1 - s2[-1])); + * } + */ + +#include <sys/asm_linkage.h> +#include "synonyms.h" + + ENTRY(strncmp) + save %sp, -SA(WINDOWSIZE), %sp + cmp %i2, 8 + blu,a .cmp_bytes ! for small counts go do bytes + sub %i0, %i1, %i0 ! delay slot, get diff from s1 - s2 + andcc %i0, 3, %g0 ! is s1 aligned +1: bz .iss2 ! if so go check s2 + andcc %i1, 3, %i3 ! is s2 aligned + + deccc %i2 ! --n >= 0 ? + bcs .doneq + nop ! delay slot + + ldub [%i0], %i4 ! else cmp one byte + ldub [%i1], %i5 + inc %i0 + cmp %i4, %i5 + bne .noteqb + inc %i1 + tst %i4 ! terminating zero + bnz 1b + andcc %i0, 3, %g0 + b,a .doneq + +.iss2: + set 0x7efefeff, %l6 + set 0x81010100, %l7 + sethi %hi(0xff000000), %l0 ! masks to test for terminating null + sethi %hi(0x00ff0000), %l1 + srl %l1, 8, %l2 ! generate 0x0000ff00 mask + + bz .w4cmp ! if s2 word aligned, compare words + cmp %i3, 2 ! check if s2 half aligned + be .w2cmp + cmp %i3, 1 ! check if aligned to 1 or 3 bytes +.w3cmp: ldub [%i1], %i5 + inc 1, %i1 + be .w1cmp + sll %i5, 24, %i5 + sub %i0, %i1, %i0 +2: + deccc 4, %i2 ! n >= 4 ? + bgeu,a 3f + ld [%i1], %i3 ! delay slot + dec %i1 ! reset s2 + inc %i0 ! reset s1 diff + b .cmp_bytes ! do a byte at a time if n < 4 + inc 4, %i2 +3: + ld [%i0 + %i1], %i4 + inc 4, %i1 + srl %i3, 8, %l4 ! merge with the other half + or %l4, %i5, %i5 + cmp %i4, %i5 + be 1f + + add %i4, %l6, %l3 + b,a .noteq +1: xor %l3, %i4, %l3 + and %l3, %l7, %l3 + cmp %l3, %l7 + be,a 2b + sll %i3, 24, %i5 + + ! + ! For 7-bit characters, we know one of the bytes is zero, but for + ! 8-bit characters, the zero detection algorithm gives some false + ! triggers ... check every byte individually. + ! + andcc %i4, %l0, %g0 ! check if first byte was zero + bnz 1f + andcc %i4, %l1, %g0 ! check if second byte was zero + b,a .doneq +1: bnz 1f + andcc %i4, %l2, %g0 ! check if third byte was zero + b,a .doneq +1: bnz 1f + andcc %i4, 0xff, %g0 ! check if last byte is zero + b,a .doneq +1: bnz 2b + sll %i3, 24, %i5 + b,a .doneq + +.w1cmp: clr %l4 + lduh [%i1], %l4 + inc 2, %i1 + sll %l4, 8, %l4 + or %i5, %l4, %i5 + + sub %i0, %i1, %i0 +3: + deccc 4, %i2 ! n >= 4 ? + bgeu,a 4f + ld [%i1], %i3 ! delay slot + dec 3, %i1 ! reset s2 + inc 3, %i0 ! reset s1 diff + b .cmp_bytes ! do a byte at a time if n < 4 + inc 4, %i2 +4: + ld [%i0 + %i1], %i4 + inc 4, %i1 + srl %i3, 24, %l4 ! merge with the other half + or %l4, %i5, %i5 + cmp %i4, %i5 + be 1f + + add %i4, %l6, %l3 + b,a .noteq +1: xor %l3, %i4, %l3 + and %l3, %l7, %l3 + cmp %l3, %l7 + be,a 3b + sll %i3, 8, %i5 + + andcc %i4, %l0, %g0 ! check if first byte was zero + bnz 1f + andcc %i4, %l1, %g0 ! check if second byte was zero + b,a .doneq +1: bnz 1f + andcc %i4, %l2, %g0 ! check if third byte was zero + b,a .doneq +1: bnz 1f + andcc %i4, 0xff, %g0 ! check if last byte is zero + b,a .doneq +1: bnz 3b + sll %i3, 8, %i5 + b,a .doneq + +.w2cmp: + lduh [%i1], %i5 ! read a halfword to align s2 + inc 2, %i1 + sll %i5, 16, %i5 + + sub %i0, %i1, %i0 +4: + deccc 4, %i2 ! n >= 4 ? + bgeu,a 5f + ld [%i1], %i3 ! delay slot + dec 2, %i1 ! reset s2 + inc 2, %i0 ! reset s1 diff + b .cmp_bytes ! do a byte at a time if n < 4 + inc 4, %i2 ! delay slot +5: + ld [%i1 + %i0], %i4 ! read a word from s2 + inc 4, %i1 + srl %i3, 16, %l4 ! merge with the other half + or %l4, %i5, %i5 + cmp %i4, %i5 + be 1f + + add %i4, %l6, %l3 + b,a .noteq +1: xor %l3, %i4, %l3 ! are any bytes 0? + and %l3, %l7, %l3 + cmp %l3, %l7 + be,a 4b + sll %i3, 16, %i5 + + andcc %i4, %l0, %g0 ! check if first byte was zero + bnz 1f + andcc %i4, %l1, %g0 ! check if second byte was zero + b,a .doneq +1: bnz 1f + andcc %i4, %l2, %g0 ! check if third byte was zero + b,a .doneq +1: bnz 1f + andcc %i4, 0xff, %g0 ! check if last byte is zero + b,a .doneq +1: bnz 4b + sll %i3, 16, %i5 + b,a .doneq + +.w4cmp: sub %i0, %i1, %i0 + ld [%i1], %i5 ! read a word from s1 +5: cmp %i2,0 + be,a .doneq + nop + ld [%i1], %i5 ! read a word from s1 + deccc 4, %i2 ! n >= 4 ? + bcs,a .cmp_bytes ! do a byte at a time if n < 4 + inc 4, %i2 + + ld [%i1 + %i0], %i4 ! read a word from s2 + cmp %i4, %i5 + inc 4, %i1 + be 1f + + add %i4, %l6, %l3 + b,a .noteq +1: xor %l3, %i4, %l3 + and %l3, %l7, %l3 + cmp %l3, %l7 + be,a 5b + nop + + andcc %i4, %l0, %g0 ! check if first byte was zero + bnz 1f + andcc %i4, %l1, %g0 ! check if second byte was zero + b,a .doneq +1: bnz 1f + andcc %i4, %l2, %g0 ! check if third byte was zero + b,a .doneq +1: bnz 1f + andcc %i4, 0xff, %g0 ! check if last byte is zero + b,a .doneq +1: bnz,a 5b + ld [%i1], %i5 +.doneq: ret + restore %g0, %g0, %o0 ! equal return zero + +.noteq: srl %i4, 24, %l4 + srl %i5, 24, %l5 + subcc %l4, %l5, %i0 + bne 6f + andcc %l4, 0xff, %g0 + bz .doneq + sll %i4, 8, %l4 + sll %i5, 8, %l5 + srl %l4, 24, %l4 + srl %l5, 24, %l5 + subcc %l4, %l5, %i0 + bne 6f + andcc %l4, 0xff, %g0 + bz .doneq + sll %i4, 16, %l4 + sll %i5, 16, %l5 + srl %l4, 24, %l4 + srl %l5, 24, %l5 + subcc %l4, %l5, %i0 + bne 6f + andcc %l4, 0xff, %g0 + bz .doneq + nop +.noteqb: + and %i4, 0xff, %l4 + and %i5, 0xff, %l5 + subcc %l4, %l5, %i0 +6: ret + restore %i0, %g0, %o0 + + ! Do a byte by byte comparison, disregarding alignments +.cmp_bytes: + deccc %i2 ! --n >= 0 ? +1: + bcs .doneq + nop ! delay slot + ldub [%i1 + %i0], %i4 ! read a word from s1 + ldub [%i1], %i5 ! read a word from s2 + + inc %i1 + cmp %i4, %i5 + bne .noteqb + tst %i4 ! terminating zero + bnz 1b + deccc %i2 ! --n >= 0 + b,a .doneq + + SET_SIZE(strncmp) diff --git a/usr/src/lib/libc/sparc/gen/strncpy.s b/usr/src/lib/libc/sparc/gen/strncpy.s new file mode 100644 index 0000000000..11afb2ac4b --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/strncpy.s @@ -0,0 +1,290 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + + +.ident "%Z%%M% %I% %E% SMI" + + .file "%M%" + +/* + * strncpy(s1, s2) + * + * Copy string s2 to s1, truncating or null-padding to always copy n bytes + * return s1. + * + * Fast assembler language version of the following C-program for strncpy + * which represents the `standard' for the C-library. + * + * char * + * strncpy(char *s1, const char *s2, size_t n) + * { + * char *os1 = s1; + * + * n++; + * while ((--n != 0) && ((*s1++ = *s2++) != '\0')) + * ; + * if (n != 0) + * while (--n != 0) + * *s1++ = '\0'; + * return (os1); + * } + */ + +#include <sys/asm_linkage.h> +#include "synonyms.h" + + ! strncpy works similarly to strcpy, except that n bytes of s2 + ! are copied to s1. If a null character is reached in s2 yet more + ! bytes remain to be copied, strncpy will copy null bytes into + ! the destination string. + ! + ! This implementation works by first aligning the src ptr and + ! performing small copies until it is aligned. Then, the string + ! is copied based upon destination alignment. (byte, half-word, + ! word, etc.) + + ENTRY(strncpy) + + .align 32 + subcc %g0, %o2, %o4 ! n = -n + bz .doneshort ! if n == 0, done + cmp %o2, 7 ! n < 7 ? + add %o1, %o2, %o3 ! src = src + n + blu .shortcpy ! n < 7, use byte-wise copy + add %o0, %o2, %o2 ! dst = dst + n + andcc %o1, 3, %o5 ! src word aligned ? + bz .wordaligned ! yup + save %sp, -0x40, %sp ! create new register window + sub %i5, 4, %i5 ! bytes until src aligned + nop ! align loop on 16-byte boundary + nop ! align loop on 16-byte boundary + +.alignsrc: + ldub [%i3 + %i4], %i1 ! src[] + stb %i1, [%i2 + %i4] ! dst[] = src[] + inccc %i4 ! src++, dst++, n-- + bz .done ! n == 0, done + tst %i1 ! end of src reached (null byte) ? + bz,a .bytepad ! yes, at least one byte to pad here + add %i2, %i4, %l0 ! need single dest pointer for fill + inccc %i5 ! src aligned now? + bnz .alignsrc ! no, copy another byte + .empty + +.wordaligned: + add %i2, %i4, %l0 ! dst + sethi %hi(0x01010101), %l1 ! Alan Mycroft's magic1 + sub %i2, 4, %i2 ! adjust for dest pre-incr in cpy loops + or %l1, %lo(0x01010101),%l1! finish loading magic1 + andcc %l0, 3, %g1 ! destination word aligned ? + bnz .dstnotaligned ! nope + sll %l1, 7, %i5 ! create Alan Mycroft's magic2 + +.storeword: + lduw [%i3 + %i4], %i1 ! src dword + addcc %i4, 4, %i4 ! n += 4, src += 4, dst += 4 + bcs .lastword ! if counter wraps, last word + andn %i5, %i1, %g1 ! ~dword & 0x80808080 + sub %i1, %l1, %l0 ! dword - 0x01010101 + andcc %l0, %g1, %g0 ! ((dword - 0x01010101) & ~dword & 0x80808080) + bz,a .storeword ! no zero byte if magic expression == 0 + stw %i1, [%i2 + %i4] ! store word to dst (address pre-incremented) + + ! n has not expired, but src is at the end. we need to push out the + ! remaining src bytes and then start padding with null bytes + +.zerobyte: + add %i2, %i4, %l0 ! pointer to dest string + srl %i1, 24, %g1 ! first byte + stb %g1, [%l0] ! store it + sub %g1, 1, %g1 ! byte == 0 ? -1 : byte - 1 + sra %g1, 31, %g1 ! byte == 0 ? -1 : 0 + andn %i1, %g1, %i1 ! if byte == 0, start padding with null bytes + srl %i1, 16, %g1 ! second byte + stb %g1, [%l0 + 1] ! store it + and %g1, 0xff, %g1 ! isolate byte + sub %g1, 1, %g1 ! byte == 0 ? -1 : byte - 1 + sra %g1, 31, %g1 ! byte == 0 ? -1 : 0 + andn %i1, %g1, %i1 ! if byte == 0, start padding with null bytes + srl %i1, 8, %g1 ! third byte + stb %g1, [%l0 + 2] ! store it + and %g1, 0xff, %g1 ! isolate byte + sub %g1, 1, %g1 ! byte == 0 ? -1 : byte - 1 + sra %g1, 31, %g1 ! byte == 0 ? -1 : 0 + andn %i1, %g1, %i1 ! if byte == 0, start padding with null bytes + stb %i1, [%l0 + 3] ! store fourth byte + addcc %i4, 8, %g0 ! number of pad bytes < 8 ? + bcs .bytepad ! yes, do simple byte wise fill + add %l0, 4, %l0 ! dst += 4 + andcc %l0, 3, %l1 ! dst offset relative to word boundary + bz .fillaligned ! dst already word aligned + + ! here there is a least one more byte to zero out: otherwise we would + ! have exited through label .lastword + + sub %l1, 4, %l1 ! bytes to align dst to word boundary +.makealigned: + stb %g0, [%l0] ! dst[] = 0 + addcc %i4, 1, %i4 ! n-- + bz .done ! n == 0, we are done + addcc %l1, 1, %l1 ! any more byte needed to align + bnz .makealigned ! yup, pad another byte + add %l0, 1, %l0 ! dst++ + nop ! pad to align copy loop below + + ! here we know that there at least another 4 bytes to pad, since + ! we don't get here unless there were >= 8 bytes to pad to begin + ! with, and we have padded at most 3 bytes suring dst aligning + +.fillaligned: + add %i4, 3, %i2 ! round up to next word boundary + and %i2, -4, %l1 ! pointer to next word boundary + and %i2, 4, %i2 ! word count odd ? 4 : 0 + stw %g0, [%l0] ! store first word + addcc %l1, %i2, %l1 ! dword count == 1 ? + add %i4, %i2, %i4 ! if word count odd, n -= 4 + bz .bytepad ! if word count == 1, pad bytes left + add %l0, %i2, %l0 ! bump dst if word count odd + +.fillword: + addcc %l1, 8, %l1 ! count -= 8 + stw %g0, [%l0] ! dst[n] = 0 + stw %g0, [%l0 + 4] ! dst[n+4] = 0 + add %l0, 8, %l0 ! dst += 8 + bcc .fillword ! fill words until count == 0 + addcc %i4, 8, %i4 ! n -= 8 + bz .done ! if n == 0, we are done + .empty + +.bytepad: + and %i4, 1, %i2 ! byte count odd ? 1 : 0 + stb %g0, [%l0] ! store first byte + addcc %i4, %i2, %i4 ! byte count == 1 ? + bz .done ! yup, we are done + add %l0, %i2, %l0 ! bump pointer if odd + +.fillbyte: + addcc %i4, 2, %i4 ! n -= 2 + stb %g0, [%l0] ! dst[n] = 0 + stb %g0, [%l0 + 1] ! dst[n+1] = 0 + bnz .fillbyte ! fill until n == 0 + add %l0, 2, %l0 ! dst += 2 + +.done: + ret ! done + restore %i0, %g0, %o0 ! restore reg window, return dst + + ! this is the last word. It may contain null bytes. store bytes + ! until n == 0. if null byte encountered, continue + +.lastword: + sub %i4, 4, %i4 ! undo counter pre-increment + add %i2, 4, %i2 ! adjust dst for counter un-bumping + + srl %i1, 24, %g1 ! first byte + stb %g1, [%i2 + %i4] ! store it + inccc %i4 ! n-- + bz .done ! if n == 0, we're done + sub %g1, 1, %g1 ! byte == 0 ? -1 : byte - 1 + sra %g1, 31, %g1 ! byte == 0 ? -1 : 0 + andn %i1, %g1, %i1 ! if byte == 0, start padding with null + srl %i1, 16, %g1 ! second byte + stb %g1, [%i2 + %i4] ! store it + inccc %i4 ! n-- + bz .done ! if n == 0, we're done + and %g1, 0xff, %g1 ! isolate byte + sub %g1, 1, %g1 ! byte == 0 ? -1 : byte - 1 + sra %g1, 31, %g1 ! byte == 0 ? -1 : 0 + andn %i1, %g1, %i1 ! if byte == 0, start padding with null + srl %i1, 8, %g1 ! third byte + stb %g1, [%i2 + %i4] ! store it + inccc %i4 ! n-- + bz .done ! if n == 0, we're done + and %g1, 0xff, %g1 ! isolate byte + sub %g1, 1, %g1 ! byte == 0 ? -1 : byte - 1 + sra %g1, 31, %g1 ! byte == 0 ? -1 : 0 + andn %i1, %g1, %i1 ! if byte == 0, start padding with null + ba .done ! here n must be zero, we are done + stb %i1, [%i2 + %i4] ! store fourth byte + +.dstnotaligned: + cmp %g1, 2 ! dst half word aligned? + be .storehalfword2 ! yup, store half word at a time + .empty +.storebyte: + lduw [%i3 + %i4], %i1 ! x = src[] + addcc %i4, 4, %i4 ! src += 4, dst += 4, n -= 4 + bcs .lastword ! if counter wraps, last word + andn %i5, %i1, %g1 ! ~x & 0x80808080 + sub %i1, %l1, %l0 ! x - 0x01010101 + andcc %l0, %g1, %g0 ! ((x - 0x01010101) & ~x & 0x80808080) + bnz .zerobyte ! end of src found, may need to pad + add %i2, %i4, %l0 ! dst (in pointer form) + srl %i1, 24, %g1 ! %g1<7:0> = 1st byte; half-word aligned now + stb %g1, [%l0] ! store first byte + srl %i1, 8, %g1 ! %g1<15:0> = bytes 2, 3 + sth %g1, [%l0 + 1] ! store bytes 2, 3 + ba .storebyte ! next word + stb %i1, [%l0 + 3] ! store fourth byte + nop + nop + +.storehalfword: + lduw [%i3 + %i4], %i1 ! x = src[] +.storehalfword2: + addcc %i4, 4, %i4 ! src += 4, dst += 4, n -= 4 + bcs .lastword ! if counter wraps, last word + andn %i5, %i1, %g1 ! ~x & 0x80808080 + sub %i1, %l1, %l0 ! x - 0x01010101 + andcc %l0, %g1, %g0 ! ((x -0x01010101) & ~x & 0x8080808080) + bnz .zerobyte ! x has zero byte, handle end cases + add %i2, %i4, %l0 ! dst (in pointer form) + srl %i1, 16, %g1 ! %g1<15:0> = bytes 1, 2 + sth %g1, [%l0] ! store bytes 1, 2 + ba .storehalfword ! next dword + sth %i1, [%l0 + 2] ! store bytes 3, 4 + +.shortcpy: + ldub [%o3 + %o4], %o5 ! src[] + stb %o5, [%o2 + %o4] ! dst[] = src[] + inccc %o4 ! src++, dst++, n-- + bz .doneshort ! if n == 0, done + tst %o5 ! src[] == 0 ? + bnz,a .shortcpy ! nope, next byte + nop ! empty delay slot + +.padbyte: + stb %g0, [%o2 + %o4] ! dst[] = 0 +.padbyte2: + addcc %o4, 1, %o4 ! dst++, n-- + bnz,a .padbyte2 ! if n != 0, next byte + stb %g0, [%o2 + %o4] ! dst[] = 0 + nop ! align label below to 16-byte boundary + +.doneshort: + retl ! return from leaf + nop ! empty delay slot + SET_SIZE(strncpy) diff --git a/usr/src/lib/libc/sparc/gen/swapctxt.c b/usr/src/lib/libc/sparc/gen/swapctxt.c new file mode 100644 index 0000000000..881ff7b638 --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/swapctxt.c @@ -0,0 +1,63 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 (c) 1988 AT&T */ +/* All Rights Reserved */ + + +/* + * Copyright 1996-2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#pragma weak swapcontext = _swapcontext + +#include "synonyms.h" +#include <ucontext.h> +#include <sys/types.h> +#include "libc.h" + +int +swapcontext(ucontext_t *oucp, const ucontext_t *nucp) +{ + greg_t *reg; + + if (__getcontext_syscall(oucp)) + return (-1); + + /* + * Note that %o1 and %g1 are modified by the system call + * routine. ABI calling conventions specify that the caller + * can not depend upon %o0 thru %o5 nor g1, so no effort is + * made to maintain these registers. %o0 is forced to reflect + * an affirmative return code. + */ + reg = oucp->uc_mcontext.gregs; + reg[REG_SP] = getfp(); + reg[REG_O7] = caller(); + reg[REG_PC] = reg[REG_O7] + 8; + reg[REG_nPC] = reg[REG_PC] + 4; + reg[REG_O0] = 0; + + return (setcontext((ucontext_t *)nucp)); +} diff --git a/usr/src/lib/libc/sparc/gen/sync_instruction_memory.s b/usr/src/lib/libc/sparc/gen/sync_instruction_memory.s new file mode 100644 index 0000000000..d4cae952f5 --- /dev/null +++ b/usr/src/lib/libc/sparc/gen/sync_instruction_memory.s @@ -0,0 +1,79 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 (c) 1995-1997, by Sun Microsystems, Inc. + * All rights reserved. + */ + +.ident "%Z%%M% %I% %E% SMI" + + .file "%M%" + +#include <sys/asm_linkage.h> + +/* + * void sync_instruction_memory(caddr_t addr, int len) + * + * Make the memory at {addr, addr+len} valid for instruction execution. + */ + +#ifdef lint +#define nop +void +sync_instruction_memory(caddr_t addr, int len) +{ + caddr_t end = addr + len; + caddr_t start = addr & ~7; + for (; start < end; start += 8) + flush(start); + nop; nop; nop; nop; nop; + return; +} +#else + ENTRY(sync_instruction_memory) + add %o0, %o1, %o2 + andn %o0, 7, %o0 + + cmp %o0, %o2 + bgeu 2f + nop + flush %o0 +1: + add %o0, 8, %o0 + cmp %o0, %o2 + blu,a 1b + flush %o0 + ! + ! when we get here, we have executed 3 instructions after the + ! last flush; SPARC V8 requires 2 more for flush to be visible + ! The retl;nop pair will do it. + ! +2: + retl + clr %o0 + SET_SIZE(sync_instruction_memory) + + ENTRY(nop) + retl + nop + SET_SIZE(nop) +#endif |
