summaryrefslogtreecommitdiff
path: root/usr/src/lib/libc/sparc
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/libc/sparc
downloadillumos-gate-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/lib/libc/sparc')
-rw-r--r--usr/src/lib/libc/sparc/Makefile1234
-rw-r--r--usr/src/lib/libc/sparc/crt/_ftou.c72
-rw-r--r--usr/src/lib/libc/sparc/crt/_rtboot.s247
-rw-r--r--usr/src/lib/libc/sparc/crt/_rtld.c341
-rw-r--r--usr/src/lib/libc/sparc/crt/alias_boot.h51
-rw-r--r--usr/src/lib/libc/sparc/crt/cerror.s57
-rw-r--r--usr/src/lib/libc/sparc/crt/cerror64.s52
-rw-r--r--usr/src/lib/libc/sparc/crt/divrem64.c404
-rw-r--r--usr/src/lib/libc/sparc/crt/hwmuldiv.s97
-rw-r--r--usr/src/lib/libc/sparc/crt/mul64.c89
-rw-r--r--usr/src/lib/libc/sparc/crt/muldiv64.il43
-rw-r--r--usr/src/lib/libc/sparc/crt/stret.s101
-rw-r--r--usr/src/lib/libc/sparc/fp/_D_cplx_div.c251
-rw-r--r--usr/src/lib/libc/sparc/fp/_D_cplx_div_ix.c211
-rw-r--r--usr/src/lib/libc/sparc/fp/_D_cplx_div_rx.c211
-rw-r--r--usr/src/lib/libc/sparc/fp/_D_cplx_mul.c142
-rw-r--r--usr/src/lib/libc/sparc/fp/_F_cplx_div.c172
-rw-r--r--usr/src/lib/libc/sparc/fp/_F_cplx_div_ix.c139
-rw-r--r--usr/src/lib/libc/sparc/fp/_F_cplx_div_rx.c139
-rw-r--r--usr/src/lib/libc/sparc/fp/_F_cplx_mul.c140
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_add.c161
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_cmp.c107
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_cmpe.c104
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_cplx_div.c202
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_cplx_div_ix.c189
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_cplx_div_rx.c189
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_cplx_lr_div.c72
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_cplx_lr_div_ix.c71
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_cplx_lr_div_rx.c71
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_cplx_lr_mul.c69
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_cplx_mul.c152
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_div.c549
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_dtoq.c97
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_fcc.c274
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_get_rp_rd.s40
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_itoq.c85
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_lltoq.c75
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_mul.c462
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_neg.c59
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_qtod.c182
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_qtoi.c104
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_qtos.c164
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_qtou.c157
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_scl.c129
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_set_except.c67
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_sqrt.c365
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_stoq.c96
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_sub.c166
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_ulltoq.c65
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_utoq.c75
-rw-r--r--usr/src/lib/libc/sparc/fp/__quad.il156
-rw-r--r--usr/src/lib/libc/sparc/fp/__quad_mag.c404
-rw-r--r--usr/src/lib/libc/sparc/fp/base.il71
-rw-r--r--usr/src/lib/libc/sparc/fp/fpgetmask.s48
-rw-r--r--usr/src/lib/libc/sparc/fp/fpgetrnd.s46
-rw-r--r--usr/src/lib/libc/sparc/fp/fpgetsticky.s48
-rw-r--r--usr/src/lib/libc/sparc/fp/fpsetmask.s64
-rw-r--r--usr/src/lib/libc/sparc/fp/fpsetrnd.s53
-rw-r--r--usr/src/lib/libc/sparc/fp/fpsetsticky.s55
-rw-r--r--usr/src/lib/libc/sparc/fp/quad.h163
-rw-r--r--usr/src/lib/libc/sparc/gen/_getsp.s47
-rw-r--r--usr/src/lib/libc/sparc/gen/_stack_grow.s112
-rw-r--r--usr/src/lib/libc/sparc/gen/_xregs_clrptr.c44
-rw-r--r--usr/src/lib/libc/sparc/gen/abs.s45
-rw-r--r--usr/src/lib/libc/sparc/gen/alloca.s58
-rw-r--r--usr/src/lib/libc/sparc/gen/cuexit.s47
-rw-r--r--usr/src/lib/libc/sparc/gen/ecvt.c109
-rw-r--r--usr/src/lib/libc/sparc/gen/getctxt.c65
-rw-r--r--usr/src/lib/libc/sparc/gen/ladd.s71
-rw-r--r--usr/src/lib/libc/sparc/gen/lexp10.c52
-rw-r--r--usr/src/lib/libc/sparc/gen/llog10.c53
-rw-r--r--usr/src/lib/libc/sparc/gen/lmul.c57
-rw-r--r--usr/src/lib/libc/sparc/gen/lock.s52
-rw-r--r--usr/src/lib/libc/sparc/gen/lshiftl.s102
-rw-r--r--usr/src/lib/libc/sparc/gen/lsign.s53
-rw-r--r--usr/src/lib/libc/sparc/gen/lsub.s70
-rw-r--r--usr/src/lib/libc/sparc/gen/makectxt.c168
-rw-r--r--usr/src/lib/libc/sparc/gen/memchr.s177
-rw-r--r--usr/src/lib/libc/sparc/gen/memcmp.s237
-rw-r--r--usr/src/lib/libc/sparc/gen/memcpy.s189
-rw-r--r--usr/src/lib/libc/sparc/gen/memmove.s193
-rw-r--r--usr/src/lib/libc/sparc/gen/memset.s96
-rw-r--r--usr/src/lib/libc/sparc/gen/setjmp.s121
-rw-r--r--usr/src/lib/libc/sparc/gen/siginfolst.c187
-rw-r--r--usr/src/lib/libc/sparc/gen/siglongjmp.c100
-rw-r--r--usr/src/lib/libc/sparc/gen/sparc_data.s33
-rw-r--r--usr/src/lib/libc/sparc/gen/strcasecmp.s353
-rw-r--r--usr/src/lib/libc/sparc/gen/strchr.s219
-rw-r--r--usr/src/lib/libc/sparc/gen/strcmp.s247
-rw-r--r--usr/src/lib/libc/sparc/gen/strcpy.s172
-rw-r--r--usr/src/lib/libc/sparc/gen/strlcpy.s236
-rw-r--r--usr/src/lib/libc/sparc/gen/strlen.s141
-rw-r--r--usr/src/lib/libc/sparc/gen/strncmp.s315
-rw-r--r--usr/src/lib/libc/sparc/gen/strncpy.s290
-rw-r--r--usr/src/lib/libc/sparc/gen/swapctxt.c63
-rw-r--r--usr/src/lib/libc/sparc/gen/sync_instruction_memory.s79
-rw-r--r--usr/src/lib/libc/sparc/genassym.c57
-rw-r--r--usr/src/lib/libc/sparc/inc/SYS.h264
-rw-r--r--usr/src/lib/libc/sparc/offsets.in64
-rw-r--r--usr/src/lib/libc/sparc/sys/__clock_gettime.s55
-rw-r--r--usr/src/lib/libc/sparc/sys/__getcontext.s47
-rw-r--r--usr/src/lib/libc/sparc/sys/_lwp_mutex_unlock.s59
-rw-r--r--usr/src/lib/libc/sparc/sys/door.s181
-rw-r--r--usr/src/lib/libc/sparc/sys/fork1.s56
-rw-r--r--usr/src/lib/libc/sparc/sys/forkall.s56
-rw-r--r--usr/src/lib/libc/sparc/sys/gettimeofday.s77
-rw-r--r--usr/src/lib/libc/sparc/sys/pipe.s52
-rw-r--r--usr/src/lib/libc/sparc/sys/ptrace.c748
-rw-r--r--usr/src/lib/libc/sparc/sys/syscall.s157
-rw-r--r--usr/src/lib/libc/sparc/sys/syssun.s44
-rw-r--r--usr/src/lib/libc/sparc/sys/uadmin.s44
-rw-r--r--usr/src/lib/libc/sparc/sys/uname.s44
-rw-r--r--usr/src/lib/libc/sparc/sys/vfork.s115
-rw-r--r--usr/src/lib/libc/sparc/threads/asm_subr.s173
-rw-r--r--usr/src/lib/libc/sparc/threads/machdep.c179
-rw-r--r--usr/src/lib/libc/sparc/threads/sparc.il105
-rw-r--r--usr/src/lib/libc/sparc/threads/tls_get_addr.s93
-rw-r--r--usr/src/lib/libc/sparc/unwind/unwind_frame.s79
118 files changed, 17301 insertions, 0 deletions
diff --git a/usr/src/lib/libc/sparc/Makefile b/usr/src/lib/libc/sparc/Makefile
new file mode 100644
index 0000000000..c9faccfbe8
--- /dev/null
+++ b/usr/src/lib/libc/sparc/Makefile
@@ -0,0 +1,1234 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libc/sparc/Makefile
+#
+
+LIBCBASE=.
+
+LIBRARY= libc.a
+LIB_PIC= libc_pic.a
+VERS= .1
+CPP= /usr/lib/cpp
+TARGET_ARCH= sparc
+
+# objects are grouped by source directory
+
+# local objects
+STRETS= \
+ stret1.o \
+ stret2.o \
+ stret4.o
+
+CRTOBJS= \
+ _ftou.o \
+ cerror.o \
+ cerror64.o \
+ divrem64.o \
+ hwmuldiv.o \
+ mul64.o
+
+DYNOBJS=
+
+FPOBJS= \
+ _D_cplx_div.o \
+ _D_cplx_div_ix.o \
+ _D_cplx_div_rx.o \
+ _D_cplx_mul.o \
+ _F_cplx_div.o \
+ _F_cplx_div_ix.o \
+ _F_cplx_div_rx.o \
+ _F_cplx_mul.o \
+ _Q_add.o \
+ _Q_cmp.o \
+ _Q_cmpe.o \
+ _Q_cplx_div.o \
+ _Q_cplx_div_ix.o \
+ _Q_cplx_div_rx.o \
+ _Q_cplx_lr_div.o \
+ _Q_cplx_lr_div_ix.o \
+ _Q_cplx_lr_div_rx.o \
+ _Q_cplx_lr_mul.o \
+ _Q_cplx_mul.o \
+ _Q_div.o \
+ _Q_dtoq.o \
+ _Q_fcc.o \
+ _Q_itoq.o \
+ _Q_lltoq.o \
+ _Q_mul.o \
+ _Q_neg.o \
+ _Q_qtod.o \
+ _Q_qtoi.o \
+ _Q_qtos.o \
+ _Q_qtou.o \
+ _Q_scl.o \
+ _Q_set_except.o \
+ _Q_sqrt.o \
+ _Q_stoq.o \
+ _Q_sub.o \
+ _Q_ulltoq.o \
+ _Q_utoq.o \
+ __quad_mag.o
+
+FPASMOBJS= \
+ _Q_get_rp_rd.o \
+ fpgetmask.o \
+ fpgetrnd.o \
+ fpgetsticky.o \
+ fpsetmask.o \
+ fpsetrnd.o \
+ fpsetsticky.o
+
+ATOMICOBJS= \
+ atomic.o
+
+COMOBJS= \
+ bcmp.o \
+ bcopy.o \
+ bzero.o \
+ bsearch.o \
+ memccpy.o \
+ qsort.o \
+ strtol.o \
+ strtoul.o
+
+GENOBJS= \
+ _getsp.o \
+ _xregs_clrptr.o \
+ abs.o \
+ alloca.o \
+ cuexit.o \
+ ecvt.o \
+ errlst.o \
+ getctxt.o \
+ ladd.o \
+ lexp10.o \
+ llog10.o \
+ lmul.o \
+ lock.o \
+ lshiftl.o \
+ lsign.o \
+ lsub.o \
+ makectxt.o \
+ memchr.o \
+ memcmp.o \
+ memcpy.o \
+ memmove.o \
+ memset.o \
+ new_list.o \
+ setjmp.o \
+ siginfolst.o \
+ siglongjmp.o \
+ sparc_data.o \
+ strcasecmp.o \
+ strchr.o \
+ strcmp.o \
+ strcpy.o \
+ strlcpy.o \
+ strlen.o \
+ strncmp.o \
+ strncpy.o \
+ swapctxt.o \
+ sync_instruction_memory.o
+
+# sysobjs that contain large-file interfaces
+COMSYSOBJS64= \
+ creat64.o \
+ fstat64.o \
+ fstatvfs64.o \
+ getdents64.o \
+ getrlimit64.o \
+ lseek64.o \
+ lstat64.o \
+ open64.o \
+ pread64.o \
+ pwrite64.o \
+ setrlimit64.o \
+ stat64.o \
+ statvfs64.o
+
+SYSOBJS64= \
+ mmap64.o
+
+COMSYSOBJS= \
+ __clock_timer.o \
+ __fcntl.o \
+ __getloadavg.o \
+ __rusagesys.o \
+ __signotify.o \
+ __sigrt.o \
+ __time.o \
+ _lgrp_home_fast.o \
+ _lgrpsys.o \
+ _nfssys.o \
+ _portfs.o \
+ _pset.o \
+ _rename.o \
+ _rpcsys.o \
+ _sigaction.o \
+ _so_accept.o \
+ _so_bind.o \
+ _so_connect.o \
+ _so_getpeername.o \
+ _so_getsockname.o \
+ _so_getsockopt.o \
+ _so_listen.o \
+ _so_recv.o \
+ _so_recvfrom.o \
+ _so_recvmsg.o \
+ _so_send.o \
+ _so_sendmsg.o \
+ _so_sendto.o \
+ _so_setsockopt.o \
+ _so_shutdown.o \
+ _so_socket.o \
+ _so_socketpair.o \
+ _sockconfig.o \
+ access.o \
+ acct.o \
+ acl.o \
+ adjtime.o \
+ alarm.o \
+ brk.o \
+ chdir.o \
+ chmod.o \
+ chown.o \
+ chroot.o \
+ cladm.o \
+ close.o \
+ creat.o \
+ dup.o \
+ execve.o \
+ exit.o \
+ facl.o \
+ fchdir.o \
+ fchmod.o \
+ fchown.o \
+ fchroot.o \
+ fdsync.o \
+ fpathconf.o \
+ fstat.o \
+ fstatfs.o \
+ fstatvfs.o \
+ getcpuid.o \
+ getdents.o \
+ getegid.o \
+ geteuid.o \
+ getgid.o \
+ getgroups.o \
+ gethrtime.o \
+ getitimer.o \
+ getmsg.o \
+ getpagesizes.o \
+ getpid.o \
+ getpmsg.o \
+ getppid.o \
+ getrlimit.o \
+ getuid.o \
+ gtty.o \
+ install_utrap.o \
+ ioctl.o \
+ kaio.o \
+ kill.o \
+ lchown.o \
+ link.o \
+ llseek.o \
+ lseek.o \
+ lstat.o \
+ memcntl.o \
+ mincore.o \
+ mkdir.o \
+ mknod.o \
+ mmap.o \
+ modctl.o \
+ mount.o \
+ mprotect.o \
+ munmap.o \
+ nice.o \
+ ntp_adjtime.o \
+ ntp_gettime.o \
+ open.o \
+ p_online.o \
+ pathconf.o \
+ pause.o \
+ pcsample.o \
+ pollsys.o \
+ pread.o \
+ priocntlset.o \
+ processor_bind.o \
+ processor_info.o \
+ profil.o \
+ putmsg.o \
+ putpmsg.o \
+ pwrite.o \
+ read.o \
+ readlink.o \
+ readv.o \
+ resolvepath.o \
+ rmdir.o \
+ seteguid.o \
+ setgid.o \
+ setgroups.o \
+ setitimer.o \
+ setreid.o \
+ setrlimit.o \
+ setuid.o \
+ sigaltstk.o \
+ sigprocmsk.o \
+ sigsendset.o \
+ sigsuspend.o \
+ stat.o \
+ statfs.o \
+ statvfs.o \
+ stty.o \
+ symlink.o \
+ sync.o \
+ sysconfig.o \
+ sysfs.o \
+ sysinfo.o \
+ syslwp.o \
+ times.o \
+ ulimit.o \
+ umask.o \
+ umount2.o \
+ unlink.o \
+ utime.o \
+ utimes.o \
+ utssys.o \
+ vhangup.o \
+ waitid.o \
+ write.o \
+ writev.o \
+ yield.o
+
+SYSOBJS= \
+ __clock_gettime.o \
+ __getcontext.o \
+ _lwp_mutex_unlock.o \
+ _stack_grow.o \
+ door.o \
+ fork1.o \
+ forkall.o \
+ gettimeofday.o \
+ pipe.o \
+ ptrace.o \
+ syscall.o \
+ syssun.o \
+ tls_get_addr.o \
+ uadmin.o \
+ umount.o \
+ uname.o \
+ vfork.o
+
+# objects under ../port which contain transitional large file interfaces
+PORTGEN64= \
+ _xftw64.o \
+ attropen64.o \
+ ftw64.o \
+ mkstemp64.o \
+ nftw64.o \
+ tell64.o \
+ truncate64.o
+
+# objects from source under ../port
+PORTFP= \
+ __flt_decim.o \
+ __flt_rounds.o \
+ __tbl_10_b.o \
+ __tbl_10_h.o \
+ __tbl_10_s.o \
+ __tbl_2_b.o \
+ __tbl_2_h.o \
+ __tbl_2_s.o \
+ __tbl_fdq.o \
+ __tbl_tens.o \
+ __x_power.o \
+ _base_sup.o \
+ aconvert.o \
+ decimal_bin.o \
+ double_decim.o \
+ econvert.o \
+ fconvert.o \
+ file_decim.o \
+ finite.o \
+ fp_data.o \
+ func_decim.o \
+ gconvert.o \
+ hex_bin.o \
+ ieee_globals.o \
+ pack_float.o \
+ sigfpe.o \
+ string_decim.o \
+ ashldi3.o \
+ ashrdi3.o \
+ cmpdi2.o \
+ divdi3.o \
+ floatdidf.o \
+ floatdisf.o \
+ lshrdi3.o \
+ moddi3.o \
+ muldi3.o \
+ qdivrem.o \
+ ucmpdi2.o \
+ udivdi3.o \
+ umoddi3.o
+
+PORTGEN= \
+ _env_data.o \
+ _ftoll.o \
+ _ftoull.o \
+ _xftw.o \
+ a64l.o \
+ abort.o \
+ addsev.o \
+ assert.o \
+ atof.o \
+ atoi.o \
+ atol.o \
+ atoll.o \
+ attropen.o \
+ atexit.o \
+ atfork.o \
+ basename.o \
+ calloc.o \
+ catgets.o \
+ catopen.o \
+ cfgetispeed.o \
+ cfgetospeed.o \
+ cfree.o \
+ cfsetispeed.o \
+ cfsetospeed.o \
+ cftime.o \
+ clock.o \
+ closedir.o \
+ closefrom.o \
+ confstr.o \
+ crypt.o \
+ csetlen.o \
+ ctime.o \
+ ctime_r.o \
+ directio.o \
+ dirname.o \
+ div.o \
+ drand48.o \
+ dup2.o \
+ env_data.o \
+ errno.o \
+ euclen.o \
+ event_port.o \
+ execvp.o \
+ fattach.o \
+ fdetach.o \
+ fdopendir.o \
+ ffs.o \
+ fmtmsg.o \
+ ftime.o \
+ ftok.o \
+ ftw.o \
+ gcvt.o \
+ getauxv.o \
+ getcwd.o \
+ getdate_err.o \
+ getdtblsize.o \
+ getenv.o \
+ getexecname.o \
+ getgrnam.o \
+ getgrnam_r.o \
+ gethostid.o \
+ gethostname.o \
+ gethz.o \
+ getisax.o \
+ getloadavg.o \
+ getlogin.o \
+ getmntent.o \
+ getnetgrent.o \
+ getopt.o \
+ getopt_long.o \
+ getpagesize.o \
+ getpw.o \
+ getpwnam.o \
+ getpwnam_r.o \
+ getrusage.o \
+ getspent.o \
+ getspent_r.o \
+ getsubopt.o \
+ gettxt.o \
+ getusershell.o \
+ getut.o \
+ getutx.o \
+ getvfsent.o \
+ getwd.o \
+ getwidth.o \
+ getxby_door.o \
+ gtxt.o \
+ hsearch.o \
+ iconv.o \
+ imaxabs.o \
+ imaxdiv.o \
+ index.o \
+ initgroups.o \
+ insque.o \
+ isaexec.o \
+ isastream.o \
+ isatty.o \
+ killpg.o \
+ l64a.o \
+ lckpwdf.o \
+ lconstants.o \
+ ldivide.o \
+ lfind.o \
+ lfmt.o \
+ lfmt_log.o \
+ llabs.o \
+ lldiv.o \
+ lltostr.o \
+ localtime.o \
+ lsearch.o \
+ madvise.o \
+ malloc.o \
+ memalign.o \
+ mkdev.o \
+ mkfifo.o \
+ mkstemp.o \
+ mktemp.o \
+ mlock.o \
+ mlockall.o \
+ mon.o \
+ msync.o \
+ munlock.o \
+ munlockall.o \
+ ndbm.o \
+ nftw.o \
+ nlspath_checks.o \
+ nsparse.o \
+ nss_common.o \
+ nss_dbdefs.o \
+ nss_deffinder.o \
+ opendir.o \
+ opt_data.o \
+ perror.o \
+ pfmt.o \
+ pfmt_data.o \
+ pfmt_print.o \
+ plock.o \
+ poll.o \
+ priocntl.o \
+ privlib.o \
+ priv_str_xlate.o \
+ psiginfo.o \
+ psignal.o \
+ pt.o \
+ putpwent.o \
+ putspent.o \
+ raise.o \
+ rand.o \
+ random.o \
+ rctlops.o \
+ readdir.o \
+ readdir_r.o \
+ realpath.o \
+ reboot.o \
+ regexpr.o \
+ rename.o \
+ rewinddir.o \
+ rindex.o \
+ scandir.o \
+ seekdir.o \
+ select.o \
+ select_large_fdset.o \
+ setlabel.o \
+ setpriority.o \
+ settimeofday.o \
+ sh_locks.o \
+ sigflag.o \
+ siglist.o \
+ sigsend.o \
+ sigsetops.o \
+ ssignal.o \
+ stack.o \
+ str2sig.o \
+ strcase_charmap.o \
+ strcat.o \
+ strcspn.o \
+ strdup.o \
+ strerror.o \
+ strncat.o \
+ strlcat.o \
+ strncasecmp.o \
+ strpbrk.o \
+ strrchr.o \
+ strsignal.o \
+ strspn.o \
+ strstr.o \
+ strtod.o \
+ strtoimax.o \
+ strtok.o \
+ strtok_r.o \
+ strtoll.o \
+ strtoull.o \
+ strtoumax.o \
+ swab.o \
+ swapctl.o \
+ sysconf.o \
+ syslog.o \
+ tcdrain.o \
+ tcflow.o \
+ tcflush.o \
+ tcgetattr.o \
+ tcgetpgrp.o \
+ tcgetsid.o \
+ tcsendbreak.o \
+ tcsetattr.o \
+ tcsetpgrp.o \
+ tell.o \
+ telldir.o \
+ tfind.o \
+ time_data.o \
+ time_gdata.o \
+ truncate.o \
+ tsdalloc.o \
+ tsearch.o \
+ ttyname.o \
+ ttyslot.o \
+ ualarm.o \
+ ucred.o \
+ valloc.o \
+ vlfmt.o \
+ vpfmt.o \
+ wait3.o \
+ wait4.o \
+ waitpid.o \
+ walkstack.o \
+ wdata.o \
+ xgetwidth.o \
+ xpg4.o \
+ xpg6.o
+
+PORTPRINT_W= \
+ doprnt_w.o
+
+PORTPRINT= \
+ doprnt.o \
+ fprintf.o \
+ printf.o \
+ snprintf.o \
+ sprintf.o \
+ vfprintf.o \
+ vprintf.o \
+ vsnprintf.o \
+ vsprintf.o \
+ vwprintf.o \
+ wprintf.o
+
+# c89 variants to support 32-bit size of c89 u/intmax_t (32-bit libc only)
+PORTPRINT_C89= \
+ vfprintf_c89.o \
+ vprintf_c89.o \
+ vsnprintf_c89.o \
+ vsprintf_c89.o \
+ vwprintf_c89.o
+
+PORTSTDIO_C89= \
+ vscanf_c89.o \
+ vwscanf_c89.o
+
+# portable stdio objects that contain large file interfaces.
+# Note: fopen64 is a special case, as we build it small.
+PORTSTDIO64= \
+ fopen64.o \
+ fpos64.o
+
+PORTSTDIO_W= \
+ doscan_w.o
+
+PORTSTDIO= \
+ __extensions.o \
+ _endopen.o \
+ _filbuf.o \
+ _findbuf.o \
+ _flsbuf.o \
+ _wrtchk.o \
+ clearerr.o \
+ ctermid.o \
+ ctermid_r.o \
+ cuserid.o \
+ data.o \
+ doscan.o \
+ fdopen.o \
+ feof.o \
+ ferror.o \
+ fgetc.o \
+ fgets.o \
+ fileno.o \
+ flockf.o \
+ flush.o \
+ fopen.o \
+ fpos.o \
+ fputc.o \
+ fputs.o \
+ fread.o \
+ fseek.o \
+ fseeko.o \
+ ftell.o \
+ ftello.o \
+ fwrite.o \
+ getc.o \
+ getchar.o \
+ getpass.o \
+ gets.o \
+ getw.o \
+ popen.o \
+ putc.o \
+ putchar.o \
+ puts.o \
+ putw.o \
+ rewind.o \
+ scanf.o \
+ setbuf.o \
+ setbuffer.o \
+ setvbuf.o \
+ system.o \
+ tempnam.o \
+ tmpfile.o \
+ tmpnam_r.o \
+ ungetc.o \
+ mse.o \
+ vscanf.o \
+ vwscanf.o \
+ wscanf.o
+
+PORTI18N= \
+ __fgetwc_xpg5.o \
+ __fgetws_xpg5.o \
+ __fputwc_xpg5.o \
+ __fputws_xpg5.o \
+ __ungetwc_xpg5.o \
+ getwchar.o \
+ putwchar.o \
+ putws.o \
+ strtows.o \
+ wcstoimax.o \
+ wcstol.o \
+ wcstoul.o \
+ wcswcs.o \
+ wscasecmp.o \
+ wscat.o \
+ wschr.o \
+ wscmp.o \
+ wscpy.o \
+ wscspn.o \
+ wsdup.o \
+ wslen.o \
+ wsncasecmp.o \
+ wsncat.o \
+ wsncmp.o \
+ wsncpy.o \
+ wspbrk.o \
+ wsprintf.o \
+ wsrchr.o \
+ wsscanf.o \
+ wsspn.o \
+ wstod.o \
+ wstok.o \
+ wstol.o \
+ wstoll.o \
+ wsxfrm.o \
+ wmemchr.o \
+ wmemcmp.o \
+ wmemcpy.o \
+ wmemmove.o \
+ wmemset.o \
+ wcsstr.o \
+ gettext.o \
+ gettext_real.o \
+ gettext_util.o \
+ gettext_gnu.o \
+ plural_parser.o \
+ wdresolve.o \
+ _ctype.o \
+ isascii.o \
+ toascii.o
+
+PORTI18N_COND= \
+ wcstol_longlong.o \
+ wcstoul_longlong.o
+
+THREADSOBJS= \
+ alloc.o \
+ assfail.o \
+ cancel.o \
+ door_calls.o \
+ pthr_attr.o \
+ pthr_barrier.o \
+ pthr_cond.o \
+ pthr_mutex.o \
+ pthr_rwlock.o \
+ pthread.o \
+ rtsched.o \
+ rwlock.o \
+ scalls.o \
+ sema.o \
+ sigaction.o \
+ spawn.o \
+ synch.o \
+ tdb_agent.o \
+ thr.o \
+ thread_interface.o \
+ tls.o \
+ tsd.o
+
+THREADSMACHOBJS= \
+ machdep.o
+
+THREADSASMOBJS= \
+ asm_subr.o
+
+UNWINDMACHOBJS= \
+ unwind.o
+
+UNWINDASMOBJS= \
+ unwind_frame.o
+
+# objects that implement the transitional large file API
+PORTSYS64= \
+ fstatat64.o \
+ lockf64.o \
+ openat64.o
+
+PORTSYS= \
+ _autofssys.o \
+ acctctl.o \
+ bsd_signal.o \
+ corectl.o \
+ exacctsys.o \
+ execl.o \
+ execle.o \
+ execv.o \
+ fcntl.o \
+ fsmisc.o \
+ fstatat.o \
+ fsync.o \
+ getpeerucred.o \
+ inst_sync.o \
+ issetugid.o \
+ libc_link.o \
+ libc_open.o \
+ lockf.o \
+ lwp.o \
+ lwp_cond.o \
+ lwp_rwlock.o \
+ lwp_sigmask.o \
+ meminfosys.o \
+ msgsys.o \
+ nfssys.o \
+ openat.o \
+ pgrpsys.o \
+ posix_sigwait.o \
+ ppriv.o \
+ psetsys.o \
+ rctlsys.o \
+ sbrk.o \
+ semsys.o \
+ set_errno.o \
+ shmsys.o \
+ siginterrupt.o \
+ signal.o \
+ sigpending.o \
+ sigstack.o \
+ tasksys.o \
+ time.o \
+ time_util.o \
+ ucontext.o \
+ ustat.o \
+ zone.o
+
+PORTREGEX= \
+ glob.o \
+ regcmp.o \
+ regex.o \
+ wordexp.o
+
+MOSTOBJS= \
+ $(STRETS) \
+ $(CRTOBJS) \
+ $(DYNOBJS) \
+ $(FPOBJS) \
+ $(FPASMOBJS) \
+ $(ATOMICOBJS) \
+ $(COMOBJS) \
+ $(GENOBJS) \
+ $(PORTFP) \
+ $(PORTGEN) \
+ $(PORTGEN64) \
+ $(PORTI18N) \
+ $(PORTI18N_COND) \
+ $(PORTPRINT) \
+ $(PORTPRINT_C89) \
+ $(PORTPRINT_W) \
+ $(PORTREGEX) \
+ $(PORTSTDIO) \
+ $(PORTSTDIO64) \
+ $(PORTSTDIO_C89) \
+ $(PORTSTDIO_W) \
+ $(PORTSYS) \
+ $(PORTSYS64) \
+ $(THREADSOBJS) \
+ $(THREADSMACHOBJS) \
+ $(THREADSASMOBJS) \
+ $(UNWINDMACHOBJS) \
+ $(UNWINDASMOBJS) \
+ $(COMSYSOBJS) \
+ $(SYSOBJS) \
+ $(COMSYSOBJS64) \
+ $(SYSOBJS64)
+
+TRACEOBJS= \
+ plockstat.o
+
+# NOTE: libc.so.1 must be linked with the minimal crti.o and crtn.o
+# modules whose source is provided in the $(SRC)/lib/common directory.
+# This must be done because otherwise the Sun C compiler would insert
+# its own versions of these modules and those versions contain code
+# to call out to C++ initialization functions. Such C++ initialization
+# functions can call back into libc before thread initialization is
+# complete and this leads to segmentation violations and other problems.
+# Since libc contains no C++ code, linking with the minimal crti.o and
+# crtn.o modules is safe and avoids the problems described above.
+OBJECTS= $(CRTI) $(MOSTOBJS) $(CRTN)
+CRTSRCS= ../../common/sparc
+
+# include common library definitions
+include ../../Makefile.lib
+
+# NOTE: libc_i18n.a will be part of libc.so.1. Therefore, the compilation
+# conditions such as the settings of CFLAGS and CPPFLAGS for the libc_i18n stuff
+# need to be compatible with the ones for the libc stuff. Whenever the changes
+# that affect the compilation conditions of libc happened, those for libc_i18n
+# also need to be updated.
+
+CFLAGS += $(CCVERBOSE)
+
+# This is necessary to avoid problems with calling _ex_unwind().
+# We probably don't want any inlining anyway.
+CFLAGS += -xinline=
+
+# Setting THREAD_DEBUG = -DTHREAD_DEBUG (make THREAD_DEBUG=-DTHREAD_DEBUG ...)
+# enables ASSERT() checking in the threads portion of the library.
+# This is automatically enabled for DEBUG builds, not for non-debug builds.
+THREAD_DEBUG =
+$(NOT_RELEASE_BUILD)THREAD_DEBUG = -DTHREAD_DEBUG
+
+CFLAGS += $(THREAD_DEBUG)
+
+ALTPICS= $(TRACEOBJS:%=pics/%)
+
+$(DYNLIB) := PICS += $(ROOTFS_LIBDIR)/libc_i18n.a
+$(DYNLIB) := BUILD.SO = $(LD) -o $@ -G $(DYNFLAGS) $(PICS) $(ALTPICS)
+
+MAPDIR= ../spec/sparc
+MAPFILE= $(MAPDIR)/mapfile
+
+CFLAGS += $(EXTN_CFLAGS)
+CPPFLAGS= -D_REENTRANT -Dsparc $(EXTN_CPPFLAGS) \
+ -I$(LIBCBASE)/inc -I../inc $(CPPFLAGS.master)
+ASFLAGS= -K pic -P -D__STDC__ -D_ASM $(CPPFLAGS) -xarch=v8plus
+
+# Inform the run-time linker about libc specialized initialization
+RTLDINFO = -z rtldinfo=tls_rtldinfo
+
+DYNFLAGS += -e __rtboot -M $(MAPFILE) $(RTLDINFO)
+DYNFLAGS += $(EXTN_DYNFLAGS)
+
+BUILD.s= $(AS) $(ASFLAGS) $< -o $@
+
+# Override this top level flag so the compiler builds in its native
+# C99 mode. This has been enabled to support the complex arithmetic
+# added to libc.
+C99MODE= $(C99_ENABLE)
+C99LMODE=
+
+# libc method of building an archive
+BUILD.AR= $(RM) $@ ; \
+ $(AR) q $@ `$(LORDER) $(MOSTOBJS:%=$(DIR)/%)| $(TSORT)`
+
+# extra files for the clean target
+CLEANFILES= \
+ ../port/gen/errlst.c \
+ ../port/gen/new_list.c \
+ assym.h \
+ genassym \
+ crt/_rtld.s \
+ crt/_rtbootld.s \
+ pics/_rtbootld.o \
+ pics/crti.o \
+ pics/crtn.o \
+ pics/values-Xa.o \
+ $(ALTPICS)
+
+CLOBBERFILES += $(MAPFILE) $(LIB_PIC)
+
+# list of C source for lint
+SRCS= \
+ $(ATOMICOBJS:%.o=$(SRC)/common/atomic/%.c) \
+ $(COMOBJS:%.o=$(SRC)/common/util/%.c) \
+ $(PORTFP:%.o=../port/fp/%.c) \
+ $(PORTGEN:%.o=../port/gen/%.c) \
+ $(PORTI18N:%.o=../port/i18n/%.c) \
+ $(PORTPRINT:%.o=../port/print/%.c) \
+ $(PORTREGEX:%.o=../port/regex/%.c) \
+ $(PORTSTDIO:%.o=../port/stdio/%.c) \
+ $(PORTSYS:%.o=../port/sys/%.c) \
+ $(THREADSOBJS:%.o=../port/threads/%.c) \
+ $(THREADSMACHOBJS:%.o=../$(MACH)/threads/%.c) \
+ $(UNWINDMACHOBJS:%.o=../port/unwind/%.c) \
+ $(FPOBJS:%.o=../$(MACH)/fp/%.c) \
+ $(LIBCBASE)/crt/_ftou.c \
+ $(LIBCBASE)/crt/divrem64.c \
+ $(LIBCBASE)/crt/mul64.c \
+ $(LIBCBASE)/gen/_xregs_clrptr.c \
+ $(LIBCBASE)/gen/ecvt.c \
+ $(LIBCBASE)/gen/getctxt.c \
+ $(LIBCBASE)/gen/lexp10.c \
+ $(LIBCBASE)/gen/llog10.c \
+ $(LIBCBASE)/gen/lmul.c \
+ $(LIBCBASE)/gen/makectxt.c \
+ $(LIBCBASE)/gen/siginfolst.c \
+ $(LIBCBASE)/gen/siglongjmp.c \
+ $(LIBCBASE)/gen/swapctxt.c \
+ $(LIBCBASE)/sys/ptrace.c
+
+# conditional assignments
+$(DYNLIB) $(LIB_PIC) := DYNOBJS = _rtbootld.o
+$(DYNLIB) := CRTI = crti.o values-Xa.o
+$(DYNLIB) := CRTN = crtn.o
+
+$(DYNLIB): $(MAPFILE)
+
+$(MAPFILE):
+ @cd $(MAPDIR); $(MAKE) mapfile
+
+# Files which need the threads .il inline template
+TIL= \
+ alloc.o \
+ assfail.o \
+ atexit.o \
+ atfork.o \
+ cancel.o \
+ door_calls.o \
+ errno.o \
+ getctxt.o \
+ lwp.o \
+ machdep.o \
+ pthr_attr.o \
+ pthr_barrier.o \
+ pthr_cond.o \
+ pthr_mutex.o \
+ pthr_rwlock.o \
+ pthread.o \
+ rand.o \
+ rtsched.o \
+ rwlock.o \
+ scalls.o \
+ sema.o \
+ sigaction.o \
+ spawn.o \
+ stack.o \
+ swapctxt.o \
+ synch.o \
+ tdb_agent.o \
+ thr.o \
+ thread_interface.o \
+ tls.o \
+ tsd.o \
+ unwind.o
+
+$(TIL:%=pics/%) := CFLAGS += $(LIBCBASE)/threads/sparc.il
+
+# Files in port/fp subdirectory that need base.il inline template
+IL= \
+ __flt_decim.o \
+ decimal_bin.o
+
+$(IL:%=pics/%) := CFLAGS += $(LIBCBASE)/fp/base.il
+
+# Files in fp subdirectory which need __quad.il inline template
+QIL= \
+ _Q_add.o \
+ _Q_cmp.o \
+ _Q_cmpe.o \
+ _Q_div.o \
+ _Q_dtoq.o \
+ _Q_fcc.o \
+ _Q_mul.o \
+ _Q_qtod.o \
+ _Q_qtoi.o \
+ _Q_qtos.o \
+ _Q_qtou.o \
+ _Q_sqrt.o \
+ _Q_stoq.o \
+ _Q_sub.o
+
+$(QIL:%=pics/%) := CFLAGS += ../$(MACH)/fp/__quad.il
+pics/_Q%.o := sparc_COPTFLAG = -xO4 -dalign
+pics/__quad%.o := sparc_COPTFLAG = -xO4 -dalign
+
+# Files in crt subdirectory which need muldiv64.il inline template
+CIL= mul64.o divrem64.o
+$(CIL:%=pics/%) := CFLAGS += $(LIBCBASE)/crt/muldiv64.il
+
+# large-file-aware components that should be built large
+
+$(COMSYSOBJS64:%=pics/%) := \
+ CPPFLAGS += -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
+
+$(SYSOBJS64:%=pics/%) := \
+ CPPFLAGS += -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
+
+$(PORTGEN64:%=pics/%) := \
+ CPPFLAGS += -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
+
+$(PORTSTDIO64:%=pics/%) := \
+ CPPFLAGS += -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
+
+$(PORTSYS64:%=pics/%) := \
+ CPPFLAGS += -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
+
+$(PORTSTDIO_W:%=pics/%) := \
+ CPPFLAGS += -D_WIDE
+
+$(PORTPRINT_W:%=pics/%) := \
+ CPPFLAGS += -D_WIDE
+
+# printf/scanf functions to support c89-sized intmax_t variables
+$(PORTPRINT_C89:%=pics/%) := \
+ CPPFLAGS += -D_C89_INTMAX32
+
+$(PORTSTDIO_C89:%=pics/%) := \
+ CPPFLAGS += -D_C89_INTMAX32
+
+$(PORTI18N_COND:%=pics/%) := \
+ CPPFLAGS += -D_WCS_LONGLONG
+
+# Files which need extra optimization
+pics/getenv.o := sparc_COPTFLAG = -xO4
+
+.KEEP_STATE:
+
+all: $(LIBS) $(LIB_PIC)
+
+lint := CPPFLAGS += -I../$(MACH)/fp
+lint := CPPFLAGS += -D_MSE_INT_H -D_LCONV_C99
+lint := LINTFLAGS += -mn
+
+lint:
+ @echo $(LINT.c) ... $(LDLIBS)
+ @$(LINT.c) $(SRCS) $(LDLIBS)
+
+# these aren't listed as $(PICS), so we need to force CTF
+pics/values-Xa.o := CFLAGS += $(CTF_FLAGS)
+pics/values-Xa.o := CTFCONVERT_POST = $(CTFCONVERT_O)
+
+$(LINTLIB):= SRCS=../port/llib-lc
+$(LINTLIB):= CPPFLAGS += -D_MSE_INT_H
+$(LINTLIB):= LINTFLAGS=-nvx
+
+# object files that depend on inline template
+$(TIL:%=pics/%): $(LIBCBASE)/threads/sparc.il
+$(IL:%=pics/%): $(LIBCBASE)/fp/base.il
+$(QIL:%=pics/%): ../$(MACH)/fp/__quad.il
+$(CIL:%=pics/%): $(LIBCBASE)/crt/muldiv64.il
+
+# include common libc targets
+include ../Makefile.targ
+
+pics/getxby_door.o := CCMODE =
+
+# We need to strip out all CTF and DOF data from the static library
+$(LIB_PIC) := DIR = pics
+$(LIB_PIC): pics $$(PICS)
+ $(BUILD.AR)
+ $(MCS) -d -n .SUNW_ctf $@ > /dev/null 2>&1
+ $(MCS) -d -n .SUNW_dof $@ > /dev/null 2>&1
+ $(AR) -ts $@ > /dev/null
+ $(POST_PROCESS_A)
+
+# special cases
+$(STRETS:%=pics/%): crt/stret.s
+ $(AS) $(ASFLAGS) -DSTRET$(@F:stret%.o=%) crt/stret.s -o $@
+ $(POST_PROCESS_O)
+
+crt/_rtbootld.s: crt/_rtboot.s crt/_rtld.c
+ $(CC) $(CPPFLAGS) $(CTF_FLAGS) -O -S -K pic \
+ crt/_rtld.c -o crt/_rtld.s
+ $(CAT) crt/_rtboot.s crt/_rtld.s > $@
+ $(RM) crt/_rtld.s
+
+# partially built from C source
+pics/_rtbootld.o: crt/_rtbootld.s
+ $(AS) $(ASFLAGS) crt/_rtbootld.s -o $@
+ $(CTFCONVERT_O)
+
+ASSYMDEP_OBJS= \
+ _lwp_mutex_unlock.o \
+ _stack_grow.o \
+ asm_subr.o \
+ tls_get_addr.o \
+ unwind_frame.o \
+ vfork.o
+
+$(ASSYMDEP_OBJS:%=pics/%) := CPPFLAGS += -I.
+
+$(ASSYMDEP_OBJS:%=pics/%): assym.h
+
+# assym.h build rules
+
+GENASSYM_C = ../$(MACH)/genassym.c
+
+# XXX A hack. Perhaps this should be 'CPPFLAGS.native' and
+# live in Makefile.master
+
+CPPFLAGS.genassym = \
+ $(ENVCPPFLAGS1) $(ENVCPPFLAGS2) $(ENVCPPFLAGS3) $(ENVCPPFLAGS4)
+
+genassym: $(GENASSYM_C)
+ $(NATIVECC) -I$(LIBCBASE)/inc -I../inc \
+ $(CPPFLAGS.genassym) -o $@ $(GENASSYM_C)
+
+OFFSETS = ../$(MACH)/offsets.in
+
+assym.h: $(OFFSETS) genassym
+ $(OFFSETS_CREATE) <$(OFFSETS) >$@
+ ./genassym >>$@
+
+# derived C source and related explicit dependencies
+../port/gen/errlst.c + \
+../port/gen/new_list.c: ../port/gen/errlist ../port/gen/errlist.awk
+ cd ../port/gen; pwd; $(AWK) -f errlist.awk < errlist
+
+pics/errlst.o: ../port/gen/errlst.c
+
+pics/new_list.o: ../port/gen/new_list.c
diff --git a/usr/src/lib/libc/sparc/crt/_ftou.c b/usr/src/lib/libc/sparc/crt/_ftou.c
new file mode 100644
index 0000000000..8f960205f3
--- /dev/null
+++ b/usr/src/lib/libc/sparc/crt/_ftou.c
@@ -0,0 +1,72 @@
+/*
+ * 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 <sys/types.h>
+#include "libc.h"
+
+unsigned
+__dtou(double d)
+{
+ /* Convert double to unsigned. */
+
+ int id;
+
+ /*
+ * id = d is correct if 0 <= d < 2**31, and good enough if d is NaN
+ * or d < 0 or d >= 2**32. Otherwise, since the result (int)d of
+ * converting 2**31 <= d < 2**32 is unknown, adjust d before the
+ * conversion.
+ */
+
+ if (d >= 2147483648.0)
+ id = 0x80000000 | (int)(d - 2147483648.0);
+ else
+ id = (int)d;
+ return ((unsigned)id);
+}
+
+unsigned
+__ftou(float d)
+{
+ /* Convert float to unsigned. */
+
+ int id;
+ /*
+ * id = d is correct if 0 <= d < 2**31, and good enough if d is NaN
+ * or d < 0 or d >= 2**32. Otherwise, since the result (int)d of
+ * converting 2**31 <= d < 2**32 is unknown, adjust d before the
+ * conversion.
+ */
+
+ if (d >= 2147483648.0)
+ id = 0x80000000 | (int)(d - 2147483648.0);
+ else
+ id = (int)d;
+ return ((unsigned)id);
+}
diff --git a/usr/src/lib/libc/sparc/crt/_rtboot.s b/usr/src/lib/libc/sparc/crt/_rtboot.s
new file mode 100644
index 0000000000..5ae8505d9a
--- /dev/null
+++ b/usr/src/lib/libc/sparc/crt/_rtboot.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 (c) 2000 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#ident "%Z%%M% %I% %E% SMI"
+
+ .file "_rtboot.s"
+
+! Bootstrap routine for alias ld.so. Control arrives here either directly
+! from exec() upon invocation of a dynamically linked program specifying our
+! alias as its interpreter.
+!
+! On entry, the stack appears as:
+!
+!_______________________! high addresses
+! !
+! Information !
+! Block !
+! (size varies) !
+!_______________________!
+! 0 word !
+!_______________________!
+! Auxiliary !
+! vector !
+! 2 word entries !
+! !
+!_______________________!
+! 0 word !
+!_______________________!
+! Environment !
+! pointers !
+! ... !
+! (one word each) !
+!_______________________!
+! 0 word !
+!_______________________!
+! Argument ! low addresses
+! pointers !
+! Argc words !
+!_______________________!
+! !
+! Argc !
+!_______________________!<- %sp +64
+! !
+! Window save area !
+!_______________________! <- %sp
+
+#include <sys/asm_linkage.h>
+#include <sys/param.h>
+#include <sys/syscall.h>
+#include <link.h>
+#include "alias_boot.h"
+
+ .section ".text"
+ .volatile
+ .global __rtboot
+ .local __rtld
+ .local s.LDSO, s.ZERO
+ .local f.PANIC, f.OPEN, f.MMAP, f.FSTAT, f.SYSCONFIG, f.CLOSE, f.EXIT
+ .local f.MUNMAP
+ .type __rtboot, #function
+ .align 4
+
+! Create a stack frame, perform PIC set up. If we're a "normal" start, we have
+! to determine a bunch of things from our "environment" and construct an ELF
+! boot attribute value vector. Otherwise, it's already been done and we can
+! skip it.
+
+__rtboot:
+ save %sp, -SA(MINFRAME + (EB_MAX * 8) + ((S_MAX + F_MAX) * 4)), %sp
+1: ! PIC prologue
+ call 2f ! get PIC for PIC work
+
+! Set up pointers to __rtld parameters. eb[], strings[] and funcs[] are on
+! the stack. Note that we will call ld.so with an entry vector that causes
+! it to use the stack frame we have.
+
+ add %sp, MINFRAME, %o0 ! &eb[0]
+2:
+ add %o0, (EB_MAX * 8), %o1 ! &strings[0] == &eb[EB_MAX]
+ add %o1, (S_MAX * 4), %o2 ! &funcs[0] == &strings[S_MAX]
+ set EB_ARGV, %l0 ! code for this entry
+ st %l0, [%o0] ! store it
+ add %fp, 68, %l0 ! argument vector is at %fp+68
+ st %l0, [%o0 + 4] ! store that
+ ld [%fp + 64], %l1 ! get argument count
+ inc %l1 ! account for last element of 0
+ sll %l1, 2, %l1 ! multiply by 4
+ add %l0, %l1, %l0 ! and get address of first env ptr
+ st %l0, [%o0 + 12] ! store it in the vector
+ set EB_ENVP, %l1 ! code for environment base
+ st %l1, [%o0 + 8] ! store it
+ set EB_AUXV, %l1 ! get code for auxiliary vector
+ st %l1, [%o0 + 16] ! store it
+2:
+ ld [%l0], %l1 ! get an entry
+ tst %l1 ! are we at a "0" entry in environment?
+ bne 2b ! no, go back and look again
+ add %l0, 4, %l0 ! incrementing pointer in delay
+ st %l0, [%o0 + 20] ! store aux vector pointer
+ set EB_NULL, %l0 ! set up for the last pointer
+ st %l0, [%o0 + 24] ! and store it
+
+! Initialize strings and functions as appropriate
+
+#define SI(n) \
+ set (s./**/n - 1b), %l0; \
+ add %o7, %l0, %l0; \
+ st %l0, [%o1 + (n/**/_S * 4)]
+#define FI(n) \
+ set (f./**/n - 1b), %l0; \
+ add %o7, %l0, %l0; \
+ st %l0, [%o2 + (n/**/_F * 4)]
+
+ SI(LDSO)
+ SI(ZERO)
+ SI(EMPTY)
+ FI(PANIC)
+ FI(OPEN)
+ FI(MMAP)
+ FI(FSTAT)
+ FI(SYSCONFIG)
+ FI(CLOSE)
+ FI(MUNMAP)
+
+! Call the startup function to get the real loader in here.
+
+ call __rtld ! call it
+ mov %o0, %l0 ! and save &eb[0] for later
+
+! On return, jump to the function in %o0, passing &eb[0] in %o0
+
+ jmpl %o0, %g0 ! call main program
+ mov %l0, %i0 ! set up parameter
+
+! Functions
+
+f.PANIC:
+ save %sp, -SA(MINFRAME), %sp ! make a frame
+ mov %i0, %o1 ! set up pointer
+ clr %o2 ! set up character counter
+1: ! loop over all characters
+ ldub [%i0 + %o2], %o0 ! get byte
+ tst %o0 ! end of string?
+ bne,a 1b ! no,
+ inc %o2 ! increment count
+ call f.WRITE ! write(2, buf, %o2)
+ mov 2, %o0
+2:
+ call 1f ! get PC
+ mov l.ERROR, %o2 ! same with constant message
+1:
+ set (s.ERROR - 2b), %o1 ! get PC-relative address
+ add %o7, %o1, %o1 ! and now make it absolute
+ call f.WRITE ! write it out
+ mov 2, %o0 ! to standard error
+ ba f.EXIT ! leave
+ nop
+
+f.OPEN:
+ ba __syscall
+ mov SYS_open, %g1
+
+f.MMAP:
+ sethi %hi(0x80000000), %g1 ! MAP_NEW
+ or %g1, %o3, %o3
+ ba __syscall
+ mov SYS_mmap, %g1
+
+f.MUNMAP:
+ ba __syscall
+ mov SYS_munmap, %g1
+
+f.READ:
+ ba __syscall
+ mov SYS_read, %g1
+
+f.WRITE:
+ ba __syscall
+ mov SYS_write, %g1
+
+f.LSEEK:
+ ba __syscall
+ mov SYS_lseek, %g1
+
+f.CLOSE:
+ ba __syscall
+ mov SYS_close, %g1
+
+f.FSTAT:
+ ba __syscall
+ mov SYS_fstat, %g1
+
+f.SYSCONFIG:
+ ba __syscall
+ mov SYS_sysconfig, %g1
+
+f.EXIT:
+ mov SYS_exit, %g1
+
+__syscall:
+ t 0x8 ! call the system call
+ bcs __err_exit ! test for error
+ nop
+ retl ! return
+ nop
+
+__err_exit:
+ retl ! return
+ mov -1, %o0
+
+! String constants
+
+s.LDSO: .asciz "/usr/lib/ld.so.1"
+s.ZERO: .asciz "/dev/zero"
+s.EMPTY:.asciz "(null)"
+s.ERROR:.asciz ": no (or bad) /usr/lib/ld.so.1\n"
+l.ERROR= . - s.ERROR
+ .align 4
+ .size __rtboot, . - __rtboot
+
+! During construction -- the assembly output of _rtld.c2s is placed here.
+
+ .section ".text"
+ .nonvolatile
diff --git a/usr/src/lib/libc/sparc/crt/_rtld.c b/usr/src/lib/libc/sparc/crt/_rtld.c
new file mode 100644
index 0000000000..596ce619e1
--- /dev/null
+++ b/usr/src/lib/libc/sparc/crt/_rtld.c
@@ -0,0 +1,341 @@
+/*
+ * 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"
+
+/*
+ * Redirection ld.so. Based on the 4.x binary compatibility ld.so, used
+ * to redirect aliases for ld.so to the real one.
+ */
+
+/*
+ * Import data structures
+ */
+#include "synonyms.h"
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+#include <sys/sysconfig.h>
+#include <sys/auxv.h>
+#include <elf.h>
+#include <link.h>
+#include <string.h>
+#include "alias_boot.h"
+
+/*
+ * Local manifest constants and macros.
+ */
+#define ALIGN(x, a) ((uintptr_t)(x) & ~((a) - 1))
+#define ROUND(x, a) (((uintptr_t)(x) + ((a) - 1)) & ~((a) - 1))
+
+#define EMPTY strings[EMPTY_S]
+#define LDSO strings[LDSO_S]
+#define ZERO strings[ZERO_S]
+#define CLOSE (*(funcs[CLOSE_F]))
+#define FSTAT (*(funcs[FSTAT_F]))
+#define MMAP (*(funcs[MMAP_F]))
+#define MUNMAP (*(funcs[MUNMAP_F]))
+#define OPEN (*(funcs[OPEN_F]))
+#define PANIC (*(funcs[PANIC_F]))
+#define SYSCONFIG (*(funcs[SYSCONFIG_F]))
+
+/*
+ * Alias ld.so entry point -- receives a bootstrap structure and a vector
+ * of strings. The vector is "well-known" to us, and consists of pointers
+ * to string constants. This aliasing bootstrap requires no relocation in
+ * order to run, save for the pointers of constant strings. This second
+ * parameter provides this. Note that this program is carefully coded in
+ * order to maintain the "no bootstrapping" requirement -- it calls only
+ * local functions, uses no intrinsics, etc.
+ */
+static void *
+__rtld(Elf32_Boot *ebp, const char *strings[], int (*funcs[])())
+{
+ int i, p; /* working */
+ long j; /* working */
+ long page_size = 0; /* size of a page */
+ const char *program_name = EMPTY; /* our name */
+ int ldfd; /* fd assigned to ld.so */
+ int dzfd = 0; /* fd assigned to /dev/zero */
+ Elf32_Ehdr *ehdr; /* ELF header of ld.so */
+ Elf32_Phdr *phdr; /* first Phdr in file */
+ Elf32_Phdr *pptr; /* working Phdr */
+ Elf32_Phdr *lph = NULL; /* last loadable Phdr */
+ Elf32_Phdr *fph = NULL; /* first loadable Phdr */
+ caddr_t maddr; /* pointer to mapping claim */
+ Elf32_Off mlen; /* total mapping claim */
+ caddr_t faddr; /* first program mapping of ld.so */
+ Elf32_Off foff; /* file offset for segment mapping */
+ Elf32_Off flen; /* file length for segment mapping */
+ caddr_t addr; /* working mapping address */
+ caddr_t zaddr; /* /dev/zero working mapping addr */
+ struct stat sb; /* stat buffer for sizing */
+ auxv_t *ap; /* working aux pointer */
+
+ /*
+ * Discover things about our environment: auxiliary vector (if
+ * any), arguments, program name, and the like.
+ */
+ while (ebp->eb_tag != NULL) {
+ switch (ebp->eb_tag) {
+ case EB_ARGV:
+ program_name = *((char **)ebp->eb_un.eb_ptr);
+ break;
+ case EB_AUXV:
+ for (ap = (auxv_t *)ebp->eb_un.eb_ptr;
+ ap->a_type != AT_NULL; ap++)
+ if (ap->a_type == AT_PAGESZ) {
+ page_size = ap->a_un.a_val;
+ break;
+ }
+ break;
+ }
+ ebp++;
+ }
+
+ /*
+ * If we didn't get a page size from looking in the auxiliary
+ * vector, we need to get one now.
+ */
+ if (page_size == 0) {
+ page_size = SYSCONFIG(_CONFIG_PAGESIZE);
+ ebp->eb_tag = EB_PAGESIZE, (ebp++)->eb_un.eb_val =
+ (Elf32_Word)page_size;
+ }
+
+ /*
+ * Map in the real ld.so. Note that we're mapping it as
+ * an ELF database, not as a program -- we just want to walk it's
+ * data structures. Further mappings will actually establish the
+ * program in the address space.
+ */
+ if ((ldfd = OPEN(LDSO, O_RDONLY)) == -1)
+ PANIC(program_name);
+ if (FSTAT(ldfd, &sb) == -1)
+ PANIC(program_name);
+ ehdr = (Elf32_Ehdr *)MMAP(0, sb.st_size, PROT_READ | PROT_EXEC,
+ MAP_SHARED, ldfd, 0);
+ if (ehdr == (Elf32_Ehdr *)-1)
+ PANIC(program_name);
+
+ /*
+ * Validate the file we're looking at, ensure it has the correct
+ * ELF structures, such as: ELF magic numbers, coded for SPARC,
+ * is a ".so", etc.
+ */
+ if (ehdr->e_ident[EI_MAG0] != ELFMAG0 ||
+ ehdr->e_ident[EI_MAG1] != ELFMAG1 ||
+ ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
+ ehdr->e_ident[EI_MAG3] != ELFMAG3)
+ PANIC(program_name);
+ if (ehdr->e_ident[EI_CLASS] != ELFCLASS32 ||
+ ehdr->e_ident[EI_DATA] != ELFDATA2MSB)
+ PANIC(program_name);
+ if (ehdr->e_type != ET_DYN)
+ PANIC(program_name);
+ if ((ehdr->e_machine != EM_SPARC) &&
+ (ehdr->e_machine != EM_SPARC32PLUS))
+ PANIC(program_name);
+ if (ehdr->e_version > EV_CURRENT)
+ PANIC(program_name);
+
+ /*
+ * Point at program headers and start figuring out what to load.
+ */
+ phdr = (Elf32_Phdr *)((caddr_t)ehdr + ehdr->e_phoff);
+ for (p = 0, pptr = phdr; p < (int)ehdr->e_phnum; p++,
+ pptr = (Elf32_Phdr *)((caddr_t)pptr + ehdr->e_phentsize))
+ if (pptr->p_type == PT_LOAD) {
+ if (fph == 0) {
+ fph = pptr;
+ } else if (pptr->p_vaddr <= lph->p_vaddr)
+ PANIC(program_name);
+ lph = pptr;
+ }
+
+ /*
+ * We'd better have at least one loadable segment.
+ */
+ if (fph == 0)
+ PANIC(program_name);
+
+ /*
+ * Map enough address space to hold the program (as opposed to the
+ * file) represented by ld.so. The amount to be assigned is the
+ * range between the end of the last loadable segment and the
+ * beginning of the first PLUS the alignment of the first segment.
+ * mmap() can assign us any page-aligned address, but the relocations
+ * assume the alignments included in the program header. As an
+ * optimization, however, let's assume that mmap() will actually
+ * give us an aligned address -- since if it does, we can save
+ * an munmap() later on. If it doesn't -- then go try it again.
+ */
+ mlen = ROUND((lph->p_vaddr + lph->p_memsz) -
+ ALIGN(fph->p_vaddr, page_size), page_size);
+ maddr = (caddr_t)MMAP(0, mlen, PROT_READ | PROT_EXEC,
+ MAP_SHARED, ldfd, 0);
+ if (maddr == (caddr_t)-1)
+ PANIC(program_name);
+ faddr = (caddr_t)ROUND(maddr, fph->p_align);
+
+ /*
+ * Check to see whether alignment skew was really needed.
+ */
+ if (faddr != maddr) {
+ (void) MUNMAP(maddr, mlen);
+ mlen = ROUND((lph->p_vaddr + lph->p_memsz) -
+ ALIGN(fph->p_vaddr, fph->p_align) + fph->p_align,
+ page_size);
+ maddr = (caddr_t)MMAP(0, mlen, PROT_READ | PROT_EXEC,
+ MAP_SHARED, ldfd, 0);
+ if (maddr == (caddr_t)-1)
+ PANIC(program_name);
+ faddr = (caddr_t)ROUND(maddr, fph->p_align);
+ }
+
+ /*
+ * We have the address space reserved, so map each loadable segment.
+ */
+ for (p = 0, pptr = phdr; p < (int)ehdr->e_phnum; p++,
+ pptr = (Elf32_Phdr *)((caddr_t)pptr + ehdr->e_phentsize)) {
+
+ /*
+ * Skip non-loadable segments or segments that don't occupy
+ * any memory.
+ */
+ if ((pptr->p_type != PT_LOAD) || (pptr->p_memsz == 0))
+ continue;
+
+ /*
+ * Determine the file offset to which the mapping will
+ * directed (must be aligned) and how much to map (might
+ * be more than the file in the case of .bss.)
+ */
+ foff = ALIGN(pptr->p_offset, page_size);
+ flen = pptr->p_memsz + (pptr->p_offset - foff);
+
+ /*
+ * Set address of this segment relative to our base.
+ */
+ addr = (caddr_t)ALIGN(faddr + pptr->p_vaddr, page_size);
+
+ /*
+ * If this is the first program header, record our base
+ * address for later use.
+ */
+ if (pptr == phdr) {
+ ebp->eb_tag = EB_LDSO_BASE;
+ (ebp++)->eb_un.eb_ptr = (Elf32_Addr)addr;
+ }
+
+ /*
+ * Unmap anything from the last mapping address to this
+ * one.
+ */
+ if (addr - maddr) {
+ (void) MUNMAP(maddr, addr - maddr);
+ mlen -= addr - maddr;
+ }
+
+ /*
+ * Determine the mapping protection from the section
+ * attributes.
+ */
+ i = 0;
+ if (pptr->p_flags & PF_R)
+ i |= PROT_READ;
+ if (pptr->p_flags & PF_W)
+ i |= PROT_WRITE;
+ if (pptr->p_flags & PF_X)
+ i |= PROT_EXEC;
+ if ((caddr_t)MMAP((caddr_t)addr, flen, i,
+ MAP_FIXED | MAP_PRIVATE, ldfd, foff) == (caddr_t)-1)
+ PANIC(program_name);
+
+ /*
+ * If the memory occupancy of the segment overflows the
+ * definition in the file, we need to "zero out" the
+ * end of the mapping we've established, and if necessary,
+ * map some more space from /dev/zero.
+ */
+ if (pptr->p_memsz > pptr->p_filesz) {
+ foff = (uintptr_t)faddr + pptr->p_vaddr +
+ pptr->p_filesz;
+ zaddr = (caddr_t)ROUND(foff, page_size);
+ for (j = 0; j < (int)(zaddr - foff); j++)
+ *((char *)foff + j) = 0;
+ j = (faddr + pptr->p_vaddr + pptr->p_memsz) - zaddr;
+ if (j > 0) {
+ if (dzfd == 0) {
+ dzfd = OPEN(ZERO, O_RDWR);
+ if (dzfd == -1)
+ PANIC(program_name);
+ }
+ if ((caddr_t)MMAP((caddr_t)zaddr, j, i,
+ MAP_FIXED | MAP_PRIVATE, dzfd,
+ 0) == (caddr_t)-1)
+ PANIC(program_name);
+ }
+ }
+
+ /*
+ * Update the mapping claim pointer.
+ */
+ maddr = addr + ROUND(flen, page_size);
+ mlen -= maddr - addr;
+ }
+
+ /*
+ * Unmap any final reservation.
+ */
+ if (mlen != 0)
+ (void) MUNMAP(maddr, mlen);
+
+ /*
+ * Clean up file descriptor space we've consumed. Pass along
+ * the /dev/zero file descriptor we got -- every cycle counts.
+ */
+ (void) CLOSE(ldfd);
+ if (dzfd != 0)
+ ebp->eb_tag = EB_DEVZERO, (ebp++)->eb_un.eb_val = dzfd;
+
+ /*
+ * The call itself. Note that we start 1 instruction word in.
+ * The ELF ld.so contains an "entry vector" of branch instructions,
+ * which, for our interest are:
+ * +0: ba, a <normal startup>
+ * +4: ba, a <compatibility startup>
+ * +8: ba, a <alias startup>
+ * By starting at the alias startup, the ELF ld.so knows
+ * that a pointer to "eb" is available to it and further knows
+ * how to calculate the offset to the program's arguments and
+ * other structures. We do the "call" by returning to our
+ * bootstrap and then jumping to the address that we return.
+ */
+ ebp->eb_tag = EB_NULL, ebp->eb_un.eb_val = 0;
+ return ((void *)(ehdr->e_entry + faddr + 8));
+}
diff --git a/usr/src/lib/libc/sparc/crt/alias_boot.h b/usr/src/lib/libc/sparc/crt/alias_boot.h
new file mode 100644
index 0000000000..754d480841
--- /dev/null
+++ b/usr/src/lib/libc/sparc/crt/alias_boot.h
@@ -0,0 +1,51 @@
+/*
+ * 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) 1991 Sun Microsystems, Inc.
+ */
+
+#ifndef _ALIAS_BOOT_H
+#define _ALIAS_BOOT_H
+
+#ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Offsets for string constants used in alias bootstrap.
+ */
+#define LDSO_S 0 /* "/usr/lib/ld.so.n" */
+#define ZERO_S 1 /* "/dev/zero" */
+#define EMPTY_S 2 /* "(null)" */
+#define S_MAX 3 /* count of strings */
+
+/*
+ * Offsets for function pointers used in alias bootstrap.
+ */
+#define PANIC_F 0 /* panic() */
+#define OPEN_F 1 /* open() */
+#define MMAP_F 2 /* mmap() */
+#define FSTAT_F 3 /* fstat() */
+#define SYSCONFIG_F 4 /* sysconfig() */
+#define CLOSE_F 5 /* close() */
+#define MUNMAP_F 6 /* munmap() */
+#define F_MAX 7 /* count of functions */
+
+#endif /* _ALIAS_BOOT_H */
diff --git a/usr/src/lib/libc/sparc/crt/cerror.s b/usr/src/lib/libc/sparc/crt/cerror.s
new file mode 100644
index 0000000000..7caf5d1bf0
--- /dev/null
+++ b/usr/src/lib/libc/sparc/crt/cerror.s
@@ -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 (c) 1988 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+.ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.6 */
+
+ .file "cerror.s"
+
+#include "SYS.h"
+
+ /*
+ * All system call wrappers call __cerror on error.
+ * __cerror is private to libc and must remain so.
+ * _cerror is exported from libc and is retained
+ * only for historical reasons.
+ */
+ ENTRY2(_cerror,__cerror)
+ cmp %o0, ERESTART
+ be,a 1f
+ mov EINTR, %o0
+1:
+ save %sp, -SA(MINFRAME), %sp
+ call _private___errno
+ nop
+ st %i0, [%o0]
+ restore
+ retl
+ mov -1, %o0
+
+ SET_SIZE(_cerror)
+ SET_SIZE(__cerror)
diff --git a/usr/src/lib/libc/sparc/crt/cerror64.s b/usr/src/lib/libc/sparc/crt/cerror64.s
new file mode 100644
index 0000000000..821e3e78db
--- /dev/null
+++ b/usr/src/lib/libc/sparc/crt/cerror64.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 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+.ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * cerror() for system calls that return 64-bit values.
+ */
+
+ .file "cerror64.s"
+
+#include "SYS.h"
+
+ ENTRY2(_cerror64,__cerror64)
+ cmp %o0, ERESTART
+ be,a 1f
+ mov EINTR, %o0
+1:
+ save %sp, -SA(MINFRAME), %sp
+ call _private___errno
+ nop
+ st %i0, [%o0]
+ restore
+ mov -1, %o1
+ retl
+ mov -1, %o0
+
+ SET_SIZE(_cerror64)
+ SET_SIZE(__cerror64)
diff --git a/usr/src/lib/libc/sparc/crt/divrem64.c b/usr/src/lib/libc/sparc/crt/divrem64.c
new file mode 100644
index 0000000000..9fbdab1055
--- /dev/null
+++ b/usr/src/lib/libc/sparc/crt/divrem64.c
@@ -0,0 +1,404 @@
+/*
+ * 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) 1991-1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "synonyms.h"
+
+/*
+ * These routines are to support the compiler run-time only, and
+ * should NOT be called directly from C!
+ */
+
+#define W 64 /* bits in a word */
+#define B 4 /* number base of division (must be a power of 2) */
+#define N 2 /* log2(B) */
+#define WB (W/N) /* base B digits in a word */
+#define Q dividend /* re-use the dividend as the partial quotient */
+#define Big_value (1ull<<(W-N-1)) /* (B ^ WB-1)/2 */
+
+/*
+ * An 'inline' routine that does a 'ta 2' to simulate the effects of
+ * a hardware divide-by-zero.
+ */
+extern long long __raise_divide_by_zero(void);
+
+long long
+__div64(long long dividend, long long divisor)
+{
+ long long R; /* partial remainder */
+ unsigned long long V; /* multiple of the divisor */
+ int iter, sign = 0;
+
+ if (divisor == 0)
+ return (__raise_divide_by_zero());
+ if (dividend < 0) {
+ dividend = -dividend;
+ sign = 1;
+ }
+ if (divisor < 0) {
+ divisor = -divisor;
+ sign ^= 1;
+ }
+
+ /*
+ * -(-2^63) == -2^63, so compare unsigned long long, so that
+ * -2^63 as divisor, or -2^63 as dividend, works.
+ */
+ if (dividend < (unsigned long long)divisor)
+ return ((long long)0);
+
+ if (!((unsigned)(dividend >> 32) | (unsigned)(divisor >> 32))) {
+ Q = (unsigned long long)((unsigned)dividend/(unsigned)divisor);
+ goto ret;
+ }
+
+ R = dividend;
+ V = divisor;
+ iter = 0;
+ if (R >= Big_value) {
+ int SC;
+
+ for (; V < Big_value; iter++)
+ V <<= N;
+ for (SC = 0; V < R; SC++) {
+ if ((long long)V < 0)
+ break;
+ V <<= 1;
+ }
+ R -= V;
+ Q = 1;
+ while (--SC >= 0) {
+ Q <<= 1;
+ V >>= 1;
+ if (R >= 0) {
+ R -= V;
+ Q += 1;
+ } else {
+ R += V;
+ Q -= 1;
+ }
+ }
+ } else {
+ Q = 0;
+ do {
+ V <<= N;
+ iter++;
+ } while (V <= R);
+ }
+
+ while (--iter >= 0) {
+ Q <<= N;
+ /* N-deep, B-wide decision tree */
+ V >>= 1;
+ if (R >= 0) {
+ R -= V;
+ V >>= 1;
+ if (R >= 0) {
+ R -= V;
+ Q += 3;
+ } else {
+ R += V;
+ Q += 1;
+ }
+ } else {
+ R += V;
+ V >>= 1;
+ if (R >= 0) {
+ R -= V;
+ Q -= 1;
+ } else {
+ R += V;
+ Q -= 3;
+ }
+ }
+ }
+ if (R < 0)
+ Q -= 1;
+ret:
+ return (sign ? -Q : Q);
+}
+
+long long
+__rem64(long long dividend, long long divisor)
+{
+ long long R; /* partial remainder */
+ unsigned long long V; /* multiple of the divisor */
+ int iter, sign = 0;
+
+ if (divisor == 0)
+ return (__raise_divide_by_zero());
+ if (dividend < 0) {
+ dividend = -dividend;
+ sign = 1;
+ }
+ if (divisor < 0)
+ divisor = -divisor;
+
+ /*
+ * -(-2^63) == -2^63, so compare unsigned long long so that
+ * x % -2^63 works.
+ */
+ if ((unsigned long long)divisor == 1)
+ return ((long long)0);
+
+ /* Compare unsigned long long, so that -2^63 % x works. */
+ if ((unsigned long long)dividend < divisor) {
+ R = dividend;
+ goto ret;
+ }
+ if (!((unsigned)(dividend >> 32) | (unsigned)(divisor >> 32))) {
+ R = (unsigned long long)((unsigned)dividend%(unsigned)divisor);
+ goto ret;
+ }
+
+ R = dividend;
+ V = divisor;
+ iter = 0;
+ if (R >= Big_value) {
+ int SC;
+
+ for (; V < Big_value; iter++)
+ V <<= N;
+ for (SC = 0; V < R; SC++) {
+ if ((long long)V < 0)
+ break;
+ V <<= 1;
+ }
+ R -= V;
+ Q = 1;
+ while (--SC >= 0) {
+ Q <<= 1;
+ V >>= 1;
+ if (R >= 0) {
+ R -= V;
+ Q += 1;
+ } else {
+ R += V;
+ Q -= 1;
+ }
+ }
+ } else {
+ Q = 0;
+ do {
+ V <<= N;
+ iter++;
+ } while (V <= R);
+ }
+
+ while (--iter >= 0) {
+ Q <<= N;
+ /* N-deep, B-wide decision tree */
+ V >>= 1;
+ if (R >= 0) {
+ R -= V;
+ V >>= 1;
+ if (R >= 0) {
+ R -= V;
+ Q += 3;
+ } else {
+ R += V;
+ Q += 1;
+ }
+ } else {
+ R += V;
+ V >>= 1;
+ if (R >= 0) {
+ R -= V;
+ Q -= 1;
+ } else {
+ R += V;
+ Q -= 3;
+ }
+ }
+ }
+ if (R < 0)
+ R += divisor;
+ret:
+ return (sign ? -R : R);
+}
+
+unsigned long long
+__udiv64(unsigned long long dividend, unsigned long long divisor)
+{
+ long long R; /* partial remainder */
+ unsigned long long V; /* multiple of the divisor */
+ int iter;
+
+ if (divisor == 0)
+ return (__raise_divide_by_zero());
+ if (dividend < divisor)
+ return ((unsigned long long)0);
+ if (!((unsigned)(dividend >> 32) | (unsigned)(divisor >> 32)))
+ return ((unsigned long long)
+ ((unsigned)dividend/(unsigned)divisor));
+
+ R = dividend;
+ V = divisor;
+ iter = 0;
+ if (R >= Big_value) {
+ int SC;
+
+ for (; V < Big_value; iter++)
+ V <<= N;
+ for (SC = 0; V < R; SC++) {
+ if ((long long)V < 0)
+ break;
+ V <<= 1;
+ }
+ R -= V;
+ Q = 1;
+ while (--SC >= 0) {
+ Q <<= 1;
+ V >>= 1;
+ if (R >= 0) {
+ R -= V;
+ Q += 1;
+ } else {
+ R += V;
+ Q -= 1;
+ }
+ }
+ } else {
+ Q = 0;
+ do {
+ V <<= N;
+ iter++;
+ } while (V <= R);
+ }
+
+ while (--iter >= 0) {
+ Q <<= N;
+ /* N-deep, B-wide decision tree */
+ V >>= 1;
+ if (R >= 0) {
+ R -= V;
+ V >>= 1;
+ if (R >= 0) {
+ R -= V;
+ Q += 3;
+ } else {
+ R += V;
+ Q += 1;
+ }
+ } else {
+ R += V;
+ V >>= 1;
+ if (R >= 0) {
+ R -= V;
+ Q -= 1;
+ } else {
+ R += V;
+ Q -= 3;
+ }
+ }
+ }
+ if (R < 0)
+ Q -= 1;
+ return (Q);
+}
+
+unsigned long long
+__urem64(unsigned long long dividend, unsigned long long divisor)
+{
+ long long R; /* parital remainder */
+ unsigned long long V; /* multiple of the divisor */
+ int iter;
+
+ if (divisor == 0)
+ return (__raise_divide_by_zero());
+ else if (divisor == 1)
+ return ((unsigned long long)0);
+ if (dividend < divisor)
+ return (dividend);
+ if (!((unsigned)(dividend >> 32) | (unsigned)(divisor >> 32)))
+ return ((unsigned long long)
+ ((unsigned)dividend%(unsigned)divisor));
+
+ R = dividend;
+ V = divisor;
+ iter = 0;
+ if (R >= Big_value) {
+ int SC;
+
+ for (; V < Big_value; iter++)
+ V <<= N;
+ for (SC = 0; V < R; SC++) {
+ if ((long long)V < 0)
+ break;
+ V <<= 1;
+ }
+ R -= V;
+ Q = 1;
+ while (--SC >= 0) {
+ Q <<= 1;
+ V >>= 1;
+ if (R >= 0) {
+ R -= V;
+ Q += 1;
+ } else {
+ R += V;
+ Q -= 1;
+ }
+ }
+ } else {
+ Q = 0;
+ do {
+ V <<= N;
+ iter++;
+ } while (V <= R);
+ }
+
+ while (--iter >= 0) {
+ Q <<= N;
+ /* N-deep, B-wide decision tree */
+ V >>= 1;
+ if (R >= 0) {
+ R -= V;
+ V >>= 1;
+ if (R >= 0) {
+ R -= V;
+ Q += 3;
+ } else {
+ R += V;
+ Q += 1;
+ }
+ } else {
+ R += V;
+ V >>= 1;
+ if (R >= 0) {
+ R -= V;
+ Q -= 1;
+ } else {
+ R += V;
+ Q -= 3;
+ }
+ }
+ }
+ if (R < 0)
+ R += divisor;
+ return (R);
+}
diff --git a/usr/src/lib/libc/sparc/crt/hwmuldiv.s b/usr/src/lib/libc/sparc/crt/hwmuldiv.s
new file mode 100644
index 0000000000..2d2a08e848
--- /dev/null
+++ b/usr/src/lib/libc/sparc/crt/hwmuldiv.s
@@ -0,0 +1,97 @@
+/*
+ * 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) 1994-2000 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+ .file "%M%"
+
+#include <sys/asm_linkage.h>
+
+/*
+ * Versions of .mul .umul .div .udiv .rem .urem written using
+ * appropriate SPARC V8 instructions.
+ */
+
+ ENTRY(.mul)
+ smul %o0, %o1, %o0
+ rd %y, %o1
+ sra %o0, 31, %o2
+ retl
+ cmp %o1, %o2 ! return with Z set if %y == (%o0 >> 31)
+ SET_SIZE(.mul)
+
+ ENTRY(.umul)
+ umul %o0, %o1, %o0
+ rd %y, %o1
+ retl
+ tst %o1 ! return with Z set if high order bits are zero
+ SET_SIZE(.umul)
+
+ ENTRY(.div)
+ sra %o0, 31, %o2
+ wr %g0, %o2, %y
+ nop
+ nop
+ nop
+ sdivcc %o0, %o1, %o0
+ bvs,a 1f
+ xnor %o0, %g0, %o0 ! Corbett Correction Factor
+1: retl
+ nop
+ SET_SIZE(.div)
+
+ ENTRY(.udiv)
+ wr %g0, %g0, %y
+ nop
+ nop
+ retl
+ udiv %o0, %o1, %o0
+ SET_SIZE(.udiv)
+
+ ENTRY(.rem)
+ sra %o0, 31, %o4
+ wr %o4, %g0, %y
+ nop
+ nop
+ nop
+ sdivcc %o0, %o1, %o2
+ bvs,a 1f
+ xnor %o2, %g0, %o2 ! Corbett Correction Factor
+1: smul %o2, %o1, %o2
+ retl
+ sub %o0, %o2, %o0
+ SET_SIZE(.rem)
+
+ ENTRY(.urem)
+ wr %g0, %g0, %y
+ nop
+ nop
+ nop
+ udiv %o0, %o1, %o2
+ umul %o2, %o1, %o2
+ retl
+ sub %o0, %o2, %o0
+ SET_SIZE(.urem)
diff --git a/usr/src/lib/libc/sparc/crt/mul64.c b/usr/src/lib/libc/sparc/crt/mul64.c
new file mode 100644
index 0000000000..16b10f1fec
--- /dev/null
+++ b/usr/src/lib/libc/sparc/crt/mul64.c
@@ -0,0 +1,89 @@
+/*
+ * 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) 1991-1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "synonyms.h"
+
+/*
+ * These routines are to support the compiler run-time only, and
+ * should NOT be called directly from C!
+ */
+
+extern unsigned long long __umul32x32to64(unsigned, unsigned);
+
+long long
+__mul64(long long i, long long j)
+{
+ unsigned i0, i1, j0, j1;
+ int sign = 0;
+ long long result = 0;
+
+ if (i < 0) {
+ i = -i;
+ sign = 1;
+ }
+ if (j < 0) {
+ j = -j;
+ sign ^= 1;
+ }
+
+ i1 = (unsigned)i;
+ j0 = j >> 32;
+ j1 = (unsigned)j;
+
+ if (j1) {
+ if (i1)
+ result = __umul32x32to64(i1, j1);
+ if ((i0 = i >> 32) != 0)
+ result += ((unsigned long long)(i0 * j1)) << 32;
+ }
+ if (j0 && i1)
+ result += ((unsigned long long)(i1 * j0)) << 32;
+ return (sign ? -result : result);
+}
+
+
+unsigned long long
+__umul64(unsigned long long i, unsigned long long j)
+{
+ unsigned i0, i1, j0, j1;
+ unsigned long long result = 0;
+
+ i1 = i;
+ j0 = j >> 32;
+ j1 = j;
+
+ if (j1) {
+ if (i1)
+ result = __umul32x32to64(i1, j1);
+ if ((i0 = i >> 32) != 0)
+ result += ((unsigned long long)(i0 * j1)) << 32;
+ }
+ if (j0 && i1)
+ result += ((unsigned long long)(i1 * j0)) << 32;
+ return (result);
+}
diff --git a/usr/src/lib/libc/sparc/crt/muldiv64.il b/usr/src/lib/libc/sparc/crt/muldiv64.il
new file mode 100644
index 0000000000..65460eeda4
--- /dev/null
+++ b/usr/src/lib/libc/sparc/crt/muldiv64.il
@@ -0,0 +1,43 @@
+!
+! Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+! Use is subject to license terms.
+!
+! 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
+!
+! ident "%Z%%M% %I% %E% SMI"
+
+! Reorder args from .umul to put them into 'long long' ordering
+
+ .inline __umul32x32to64,8
+ call .umul,2
+ nop
+ mov %o0, %o2
+ mov %o1, %o0
+ mov %o2, %o1
+ .end
+
+! Generates divide-by-zero trap from C
+
+ .inline __raise_divide_by_zero,8
+ ta 2
+ clr %o0
+ clr %o1
+ .end
diff --git a/usr/src/lib/libc/sparc/crt/stret.s b/usr/src/lib/libc/sparc/crt/stret.s
new file mode 100644
index 0000000000..de2c4d5908
--- /dev/null
+++ b/usr/src/lib/libc/sparc/crt/stret.s
@@ -0,0 +1,101 @@
+/*
+ * 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 "stret.s"
+
+#include <sys/asm_linkage.h>
+
+#define FROM %o0
+#define SIZE %o1
+#define TO %i0
+#define MEMWORD %o3 /* use o-registers as temps */
+#define TEMP %o4
+#define TEMP2 %o5
+#define UNIMP 0
+#define MASK 0x00000fff
+#define STRUCT_VAL_OFF (16*4)
+#if STRET4
+# define BYTES_PER_MOVE 4
+# define LD ld
+# define ST st
+ ENTRY2(.stret4,.stret8)
+#endif
+#if STRET2
+# define BYTES_PER_MOVE 2
+# define LD lduh
+# define ST sth
+ ENTRY(.stret2)
+#endif
+#if STRET1
+# define BYTES_PER_MOVE 1
+# define LD ldub
+# define ST stb
+ ENTRY(.stret1)
+#endif
+
+ /*
+ * see if key matches: if not,
+ * structure value not expected,
+ * so just return
+ */
+ ld [%i7+8],MEMWORD
+ and SIZE,MASK,TEMP
+ sethi %hi(UNIMP),TEMP2
+ or TEMP,TEMP2,TEMP2
+ cmp TEMP2,MEMWORD
+ bne .LE12
+ .empty
+ /*
+ * set expected return value
+ */
+.L14:
+ ld [%fp+STRUCT_VAL_OFF],TO /* (DELAY SLOT) */
+ /*
+ * copy the struct using the same loop the compiler does
+ * for large structure assignment
+ */
+.L15:
+ subcc SIZE,BYTES_PER_MOVE,SIZE
+ LD [FROM+SIZE],TEMP
+ bg .L15
+ ST TEMP,[TO+SIZE] /* (DELAY SLOT) */
+ /* bump return address */
+ add %i7,0x4,%i7
+.LE12:
+ jmp %i7+8
+ restore
+
+#if STRET4
+ SET_SIZE(.stret4)
+ SET_SIZE(.stret8)
+#endif
+#if STRET2
+ SET_SIZE(.stret2)
+#endif
+#if STRET1
+ SET_SIZE(.stret1)
+#endif
diff --git a/usr/src/lib/libc/sparc/fp/_D_cplx_div.c b/usr/src/lib/libc/sparc/fp/_D_cplx_div.c
new file mode 100644
index 0000000000..7144732968
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_D_cplx_div.c
@@ -0,0 +1,251 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * _D_cplx_div(z, w) returns z / w with infinities handled according
+ * to C99.
+ *
+ * If z and w are both finite and w is nonzero, _D_cplx_div(z, w)
+ * delivers the complex quotient q according to the usual formula:
+ * let a = Re(z), b = Im(z), c = Re(w), and d = Im(w); then q = x +
+ * I * y where x = (a * c + b * d) / r and y = (b * c - a * d) / r
+ * with r = c * c + d * d. This implementation scales to avoid
+ * premature underflow or overflow.
+ *
+ * If z is neither NaN nor zero and w is zero, or if z is infinite
+ * and w is finite and nonzero, _D_cplx_div delivers an infinite
+ * result. If z is finite and w is infinite, _D_cplx_div delivers
+ * a zero result.
+ *
+ * If z and w are both zero or both infinite, or if either z or w is
+ * a complex NaN, _D_cplx_div delivers NaN + I * NaN. C99 doesn't
+ * specify these cases.
+ *
+ * This implementation can raise spurious underflow, overflow, in-
+ * valid operation, inexact, and division-by-zero exceptions. C99
+ * allows this.
+ *
+ * Warning: Do not attempt to "optimize" this code by removing multi-
+ * plications by zero.
+ */
+
+#if !defined(sparc) && !defined(__sparc)
+#error This code is for SPARC only
+#endif
+
+static union {
+ int i[2];
+ double d;
+} inf = {
+ 0x7ff00000, 0
+};
+
+/*
+ * Return +1 if x is +Inf, -1 if x is -Inf, and 0 otherwise
+ */
+static int
+testinf(double x)
+{
+ union {
+ int i[2];
+ double d;
+ } xx;
+
+ xx.d = x;
+ return (((((xx.i[0] << 1) - 0xffe00000) | xx.i[1]) == 0)?
+ (1 | (xx.i[0] >> 31)) : 0);
+}
+
+double _Complex
+_D_cplx_div(double _Complex z, double _Complex w)
+{
+ double _Complex v;
+ union {
+ int i[2];
+ double d;
+ } aa, bb, cc, dd, ss;
+ double a, b, c, d, r;
+ int ha, hb, hc, hd, hz, hw, hs, i, j;
+
+ /*
+ * The following is equivalent to
+ *
+ * a = creal(z); b = cimag(z);
+ * c = creal(w); d = cimag(w);
+ */
+ a = ((double *)&z)[0];
+ b = ((double *)&z)[1];
+ c = ((double *)&w)[0];
+ d = ((double *)&w)[1];
+
+ /* extract high-order words to estimate |z| and |w| */
+ aa.d = a;
+ bb.d = b;
+ ha = aa.i[0] & ~0x80000000;
+ hb = bb.i[0] & ~0x80000000;
+ hz = (ha > hb)? ha : hb;
+
+ cc.d = c;
+ dd.d = d;
+ hc = cc.i[0] & ~0x80000000;
+ hd = dd.i[0] & ~0x80000000;
+ hw = (hc > hd)? hc : hd;
+
+ /* check for special cases */
+ if (hw >= 0x7ff00000) { /* w is inf or nan */
+ r = 0.0;
+ i = testinf(c);
+ j = testinf(d);
+ if (i | j) { /* w is infinite */
+ /*
+ * "factor out" infinity, being careful to preserve
+ * signs of finite values
+ */
+ c = i? i : ((cc.i[0] < 0)? -0.0 : 0.0);
+ d = j? j : ((dd.i[0] < 0)? -0.0 : 0.0);
+ if (hz >= 0x7fe00000) {
+ /* scale to avoid overflow below */
+ c *= 0.5;
+ d *= 0.5;
+ }
+ }
+ ((double *)&v)[0] = (a * c + b * d) * r;
+ ((double *)&v)[1] = (b * c - a * d) * r;
+ return (v);
+ }
+
+ if (hw < 0x00100000) {
+ /*
+ * This nonsense is needed to work around some SPARC
+ * implementations of nonstandard mode; if both parts
+ * of w are subnormal, multiply them by one to force
+ * them to be flushed to zero when nonstandard mode
+ * is enabled. Sheesh.
+ */
+ cc.d = c = c * 1.0;
+ dd.d = d = d * 1.0;
+ hc = cc.i[0] & ~0x80000000;
+ hd = dd.i[0] & ~0x80000000;
+ hw = (hc > hd)? hc : hd;
+ }
+
+ if (hw == 0 && (cc.i[1] | dd.i[1]) == 0) {
+ /* w is zero; multiply z by 1/Re(w) - I * Im(w) */
+ c = 1.0 / c;
+ i = testinf(a);
+ j = testinf(b);
+ if (i | j) { /* z is infinite */
+ a = i;
+ b = j;
+ }
+ ((double *)&v)[0] = a * c + b * d;
+ ((double *)&v)[1] = b * c - a * d;
+ return (v);
+ }
+
+ if (hz >= 0x7ff00000) { /* z is inf or nan */
+ r = 1.0;
+ i = testinf(a);
+ j = testinf(b);
+ if (i | j) { /* z is infinite */
+ a = i;
+ b = j;
+ r = inf.d;
+ }
+ ((double *)&v)[0] = (a * c + b * d) * r;
+ ((double *)&v)[1] = (b * c - a * d) * r;
+ return (v);
+ }
+
+ /*
+ * Scale c and d to compute 1/|w|^2 and the real and imaginary
+ * parts of the quotient.
+ *
+ * Note that for any s, if we let c' = sc, d' = sd, c'' = sc',
+ * and d'' = sd', then
+ *
+ * (ac'' + bd'') / (c'^2 + d'^2) = (ac + bd) / (c^2 + d^2)
+ *
+ * and similarly for the imaginary part of the quotient. We want
+ * to choose s such that (i) r := 1/(c'^2 + d'^2) can be computed
+ * without overflow or harmful underflow, and (ii) (ac'' + bd'')
+ * and (bc'' - ad'') can be computed without spurious overflow or
+ * harmful underflow. To avoid unnecessary rounding, we restrict
+ * s to a power of two.
+ *
+ * To satisfy (i), we need to choose s such that max(|c'|,|d'|)
+ * is not too far from one. To satisfy (ii), we need to choose
+ * s such that max(|c''|,|d''|) is also not too far from one.
+ * There is some leeway in our choice, but to keep the logic
+ * from getting overly complicated, we simply attempt to roughly
+ * balance these constraints by choosing s so as to make r about
+ * the same size as max(|c''|,|d''|). This corresponds to choos-
+ * ing s to be a power of two near |w|^(-3/4).
+ *
+ * Regarding overflow, observe that if max(|c''|,|d''|) <= 1/2,
+ * then the computation of (ac'' + bd'') and (bc'' - ad'') can-
+ * not overflow; otherwise, the computation of either of these
+ * values can only incur overflow if the true result would be
+ * within a factor of two of the overflow threshold. In other
+ * words, if we bias the choice of s such that at least one of
+ *
+ * max(|c''|,|d''|) <= 1/2 or r >= 2
+ *
+ * always holds, then no undeserved overflow can occur.
+ *
+ * To cope with underflow, note that if r < 2^-53, then any
+ * intermediate results that underflow are insignificant; either
+ * they will be added to normal results, rendering the under-
+ * flow no worse than ordinary roundoff, or they will contribute
+ * to a final result that is smaller than the smallest subnormal
+ * number. Therefore, we need only modify the preceding logic
+ * when z is very small and w is not too far from one. In that
+ * case, we can reduce the effect of any intermediate underflow
+ * to no worse than ordinary roundoff error by choosing s so as
+ * to make max(|c''|,|d''|) large enough that at least one of
+ * (ac'' + bd'') or (bc'' - ad'') is normal.
+ */
+ hs = (((hw >> 2) - hw) + 0x6fd7ffff) & 0xfff00000;
+ if (hz < 0x07200000) { /* |z| < 2^-909 */
+ if (((hw - 0x32800000) | (0x47100000 - hw)) >= 0)
+ hs = (((0x47100000 - hw) >> 1) & 0xfff00000)
+ + 0x3ff00000;
+ }
+ ss.i[0] = hs;
+ ss.i[1] = 0;
+
+ c *= ss.d;
+ d *= ss.d;
+ r = 1.0 / (c * c + d * d);
+
+ c *= ss.d;
+ d *= ss.d;
+ ((double *)&v)[0] = (a * c + b * d) * r;
+ ((double *)&v)[1] = (b * c - a * d) * r;
+ return (v);
+}
diff --git a/usr/src/lib/libc/sparc/fp/_D_cplx_div_ix.c b/usr/src/lib/libc/sparc/fp/_D_cplx_div_ix.c
new file mode 100644
index 0000000000..f674828c53
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_D_cplx_div_ix.c
@@ -0,0 +1,211 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * _D_cplx_div_ix(b, w) returns (I * b) / w with infinities handled
+ * according to C99.
+ *
+ * If b and w are both finite and w is nonzero, _D_cplx_div_ix(b, w)
+ * delivers the complex quotient q according to the usual formula:
+ * let c = Re(w), and d = Im(w); then q = x + I * y where x = (b * d)
+ * / r and y = (b * c) / r with r = c * c + d * d. This implementa-
+ * tion scales to avoid premature underflow or overflow.
+ *
+ * If b is neither NaN nor zero and w is zero, or if b is infinite
+ * and w is finite and nonzero, _D_cplx_div_ix delivers an infinite
+ * result. If b is finite and w is infinite, _D_cplx_div_ix delivers
+ * a zero result.
+ *
+ * If b and w are both zero or both infinite, or if either b or w is
+ * NaN, _D_cplx_div_ix delivers NaN + I * NaN. C99 doesn't specify
+ * these cases.
+ *
+ * This implementation can raise spurious underflow, overflow, in-
+ * valid operation, inexact, and division-by-zero exceptions. C99
+ * allows this.
+ *
+ * Warning: Do not attempt to "optimize" this code by removing multi-
+ * plications by zero.
+ */
+
+#if !defined(sparc) && !defined(__sparc)
+#error This code is for SPARC only
+#endif
+
+/*
+ * scl[i].d = 2^(250*(4-i)) for i = 0, ..., 9
+ */
+static const union {
+ int i[2];
+ double d;
+} scl[9] = {
+ { 0x7e700000, 0 },
+ { 0x6ed00000, 0 },
+ { 0x5f300000, 0 },
+ { 0x4f900000, 0 },
+ { 0x3ff00000, 0 },
+ { 0x30500000, 0 },
+ { 0x20b00000, 0 },
+ { 0x11100000, 0 },
+ { 0x01700000, 0 }
+};
+
+/*
+ * Return +1 if x is +Inf, -1 if x is -Inf, and 0 otherwise
+ */
+static int
+testinf(double x)
+{
+ union {
+ int i[2];
+ double d;
+ } xx;
+
+ xx.d = x;
+ return (((((xx.i[0] << 1) - 0xffe00000) | xx.i[1]) == 0)?
+ (1 | (xx.i[0] >> 31)) : 0);
+}
+
+double _Complex
+_D_cplx_div_ix(double b, double _Complex w)
+{
+ double _Complex v;
+ union {
+ int i[2];
+ double d;
+ } bb, cc, dd;
+ double c, d, sc, sd, r;
+ int hb, hc, hd, hw, i, j;
+
+ /*
+ * The following is equivalent to
+ *
+ * c = creal(w); d = cimag(w);
+ */
+ c = ((double *)&w)[0];
+ d = ((double *)&w)[1];
+
+ /* extract high-order words to estimate |b| and |w| */
+ bb.d = b;
+ hb = bb.i[0] & ~0x80000000;
+
+ cc.d = c;
+ dd.d = d;
+ hc = cc.i[0] & ~0x80000000;
+ hd = dd.i[0] & ~0x80000000;
+ hw = (hc > hd)? hc : hd;
+
+ /* check for special cases */
+ if (hw >= 0x7ff00000) { /* w is inf or nan */
+ i = testinf(c);
+ j = testinf(d);
+ if (i | j) { /* w is infinite */
+ c = (cc.i[0] < 0)? -0.0 : 0.0;
+ d = (dd.i[0] < 0)? -0.0 : 0.0;
+ } else /* w is nan */
+ b *= c * d;
+ ((double *)&v)[0] = b * d;
+ ((double *)&v)[1] = b * c;
+ return (v);
+ }
+
+ if (hw < 0x00100000) {
+ /*
+ * This nonsense is needed to work around some SPARC
+ * implementations of nonstandard mode; if both parts
+ * of w are subnormal, multiply them by one to force
+ * them to be flushed to zero when nonstandard mode
+ * is enabled. Sheesh.
+ */
+ cc.d = c = c * 1.0;
+ dd.d = d = d * 1.0;
+ hc = cc.i[0] & ~0x80000000;
+ hd = dd.i[0] & ~0x80000000;
+ hw = (hc > hd)? hc : hd;
+ }
+
+ if (hw == 0 && (cc.i[1] | dd.i[1]) == 0) {
+ /* w is zero; multiply b by 1/Re(w) - I * Im(w) */
+ c = 1.0 / c;
+ j = testinf(b);
+ if (j) { /* b is infinite */
+ b = j;
+ }
+ ((double *)&v)[0] = (b == 0.0)? b * c : b * d;
+ ((double *)&v)[1] = b * c;
+ return (v);
+ }
+
+ if (hb >= 0x7ff00000) { /* a is inf or nan */
+ ((double *)&v)[0] = b * d;
+ ((double *)&v)[1] = b * c;
+ return (v);
+ }
+
+ /*
+ * Compute the real and imaginary parts of the quotient,
+ * scaling to avoid overflow or underflow.
+ */
+ hw = (hw - 0x38000000) >> 28;
+ sc = c * scl[hw + 4].d;
+ sd = d * scl[hw + 4].d;
+ r = sc * sc + sd * sd;
+
+ hb = (hb - 0x38000000) >> 28;
+ b = (b * scl[hb + 4].d) / r;
+ hb -= (hw + hw);
+
+ hc = (hc - 0x38000000) >> 28;
+ c = (c * scl[hc + 4].d) * b;
+ hc += hb;
+
+ hd = (hd - 0x38000000) >> 28;
+ d = (d * scl[hd + 4].d) * b;
+ hd += hb;
+
+ /* compensate for scaling */
+ sc = scl[3].d; /* 2^250 */
+ if (hc < 0) {
+ hc = -hc;
+ sc = scl[5].d; /* 2^-250 */
+ }
+ while (hc--)
+ c *= sc;
+
+ sd = scl[3].d;
+ if (hd < 0) {
+ hd = -hd;
+ sd = scl[5].d;
+ }
+ while (hd--)
+ d *= sd;
+
+ ((double *)&v)[0] = d;
+ ((double *)&v)[1] = c;
+ return (v);
+}
diff --git a/usr/src/lib/libc/sparc/fp/_D_cplx_div_rx.c b/usr/src/lib/libc/sparc/fp/_D_cplx_div_rx.c
new file mode 100644
index 0000000000..f84d15dcf9
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_D_cplx_div_rx.c
@@ -0,0 +1,211 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * _D_cplx_div_rx(a, w) returns a / w with infinities handled according
+ * to C99.
+ *
+ * If a and w are both finite and w is nonzero, _D_cplx_div_rx(a, w)
+ * delivers the complex quotient q according to the usual formula:
+ * let c = Re(w), and d = Im(w); then q = x + I * y where x = (a * c)
+ * / r and y = (-a * d) / r with r = c * c + d * d. This implementa-
+ * tion scales to avoid premature underflow or overflow.
+ *
+ * If a is neither NaN nor zero and w is zero, or if a is infinite
+ * and w is finite and nonzero, _D_cplx_div_rx delivers an infinite
+ * result. If a is finite and w is infinite, _D_cplx_div_rx delivers
+ * a zero result.
+ *
+ * If a and w are both zero or both infinite, or if either a or w is
+ * NaN, _D_cplx_div_rx delivers NaN + I * NaN. C99 doesn't specify
+ * these cases.
+ *
+ * This implementation can raise spurious underflow, overflow, in-
+ * valid operation, inexact, and division-by-zero exceptions. C99
+ * allows this.
+ *
+ * Warning: Do not attempt to "optimize" this code by removing multi-
+ * plications by zero.
+ */
+
+#if !defined(sparc) && !defined(__sparc)
+#error This code is for SPARC only
+#endif
+
+/*
+ * scl[i].d = 2^(250*(4-i)) for i = 0, ..., 9
+ */
+static const union {
+ int i[2];
+ double d;
+} scl[9] = {
+ { 0x7e700000, 0 },
+ { 0x6ed00000, 0 },
+ { 0x5f300000, 0 },
+ { 0x4f900000, 0 },
+ { 0x3ff00000, 0 },
+ { 0x30500000, 0 },
+ { 0x20b00000, 0 },
+ { 0x11100000, 0 },
+ { 0x01700000, 0 }
+};
+
+/*
+ * Return +1 if x is +Inf, -1 if x is -Inf, and 0 otherwise
+ */
+static int
+testinf(double x)
+{
+ union {
+ int i[2];
+ double d;
+ } xx;
+
+ xx.d = x;
+ return (((((xx.i[0] << 1) - 0xffe00000) | xx.i[1]) == 0)?
+ (1 | (xx.i[0] >> 31)) : 0);
+}
+
+double _Complex
+_D_cplx_div_rx(double a, double _Complex w)
+{
+ double _Complex v;
+ union {
+ int i[2];
+ double d;
+ } aa, cc, dd;
+ double c, d, sc, sd, r;
+ int ha, hc, hd, hw, i, j;
+
+ /*
+ * The following is equivalent to
+ *
+ * c = creal(w); d = cimag(w);
+ */
+ c = ((double *)&w)[0];
+ d = ((double *)&w)[1];
+
+ /* extract high-order words to estimate |a| and |w| */
+ aa.d = a;
+ ha = aa.i[0] & ~0x80000000;
+
+ cc.d = c;
+ dd.d = d;
+ hc = cc.i[0] & ~0x80000000;
+ hd = dd.i[0] & ~0x80000000;
+ hw = (hc > hd)? hc : hd;
+
+ /* check for special cases */
+ if (hw >= 0x7ff00000) { /* w is inf or nan */
+ i = testinf(c);
+ j = testinf(d);
+ if (i | j) { /* w is infinite */
+ c = (cc.i[0] < 0)? -0.0 : 0.0;
+ d = (dd.i[0] < 0)? -0.0 : 0.0;
+ } else /* w is nan */
+ a *= c * d;
+ ((double *)&v)[0] = a * c;
+ ((double *)&v)[1] = -a * d;
+ return (v);
+ }
+
+ if (hw < 0x00100000) {
+ /*
+ * This nonsense is needed to work around some SPARC
+ * implementations of nonstandard mode; if both parts
+ * of w are subnormal, multiply them by one to force
+ * them to be flushed to zero when nonstandard mode
+ * is enabled. Sheesh.
+ */
+ cc.d = c = c * 1.0;
+ dd.d = d = d * 1.0;
+ hc = cc.i[0] & ~0x80000000;
+ hd = dd.i[0] & ~0x80000000;
+ hw = (hc > hd)? hc : hd;
+ }
+
+ if (hw == 0 && (cc.i[1] | dd.i[1]) == 0) {
+ /* w is zero; multiply a by 1/Re(w) - I * Im(w) */
+ c = 1.0 / c;
+ i = testinf(a);
+ if (i) { /* a is infinite */
+ a = i;
+ }
+ ((double *)&v)[0] = a * c;
+ ((double *)&v)[1] = (a == 0.0)? a * c : -a * d;
+ return (v);
+ }
+
+ if (ha >= 0x7ff00000) { /* a is inf or nan */
+ ((double *)&v)[0] = a * c;
+ ((double *)&v)[1] = -a * d;
+ return (v);
+ }
+
+ /*
+ * Compute the real and imaginary parts of the quotient,
+ * scaling to avoid overflow or underflow.
+ */
+ hw = (hw - 0x38000000) >> 28;
+ sc = c * scl[hw + 4].d;
+ sd = d * scl[hw + 4].d;
+ r = sc * sc + sd * sd;
+
+ ha = (ha - 0x38000000) >> 28;
+ a = (a * scl[ha + 4].d) / r;
+ ha -= (hw + hw);
+
+ hc = (hc - 0x38000000) >> 28;
+ c = (c * scl[hc + 4].d) * a;
+ hc += ha;
+
+ hd = (hd - 0x38000000) >> 28;
+ d = -(d * scl[hd + 4].d) * a;
+ hd += ha;
+
+ /* compensate for scaling */
+ sc = scl[3].d; /* 2^250 */
+ if (hc < 0) {
+ hc = -hc;
+ sc = scl[5].d; /* 2^-250 */
+ }
+ while (hc--)
+ c *= sc;
+
+ sd = scl[3].d;
+ if (hd < 0) {
+ hd = -hd;
+ sd = scl[5].d;
+ }
+ while (hd--)
+ d *= sd;
+
+ ((double *)&v)[0] = c;
+ ((double *)&v)[1] = d;
+ return (v);
+}
diff --git a/usr/src/lib/libc/sparc/fp/_D_cplx_mul.c b/usr/src/lib/libc/sparc/fp/_D_cplx_mul.c
new file mode 100644
index 0000000000..6e32418f72
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_D_cplx_mul.c
@@ -0,0 +1,142 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * _D_cplx_mul(z, w) returns z * w with infinities handled according
+ * to C99.
+ *
+ * If z and w are both finite, _D_cplx_mul(z, w) delivers the complex
+ * product according to the usual formula: let a = Re(z), b = Im(z),
+ * c = Re(w), and d = Im(w); then _D_cplx_mul(z, w) delivers x + I * y
+ * where x = a * c - b * d and y = a * d + b * c. Note that if both
+ * ac and bd overflow, then at least one of ad or bc must also over-
+ * flow, and vice versa, so that if one component of the product is
+ * NaN, the other is infinite. (Such a value is considered infinite
+ * according to C99.)
+ *
+ * If one of z or w is infinite and the other is either finite nonzero
+ * or infinite, _D_cplx_mul delivers an infinite result. If one factor
+ * is infinite and the other is zero, _D_cplx_mul delivers NaN + I * NaN.
+ * C99 doesn't specify the latter case.
+ *
+ * C99 also doesn't specify what should happen if either z or w is a
+ * complex NaN (i.e., neither finite nor infinite). This implementation
+ * delivers NaN + I * NaN in this case.
+ *
+ * This implementation can raise spurious underflow, overflow, invalid
+ * operation, and inexact exceptions. C99 allows this.
+ */
+
+#if !defined(sparc) && !defined(__sparc)
+#error This code is for SPARC only
+#endif
+
+static union {
+ int i[2];
+ double d;
+} inf = {
+ 0x7ff00000, 0
+};
+
+/*
+ * Return +1 if x is +Inf, -1 if x is -Inf, and 0 otherwise
+ */
+static int
+testinf(double x)
+{
+ union {
+ int i[2];
+ double d;
+ } xx;
+
+ xx.d = x;
+ return (((((xx.i[0] << 1) - 0xffe00000) | xx.i[1]) == 0)?
+ (1 | (xx.i[0] >> 31)) : 0);
+}
+
+double _Complex
+_D_cplx_mul(double _Complex z, double _Complex w)
+{
+ double _Complex v;
+ double a, b, c, d, x, y;
+ int recalc, i, j;
+
+ /*
+ * The following is equivalent to
+ *
+ * a = creal(z); b = cimag(z);
+ * c = creal(w); d = cimag(w);
+ */
+ a = ((double *)&z)[0];
+ b = ((double *)&z)[1];
+ c = ((double *)&w)[0];
+ d = ((double *)&w)[1];
+
+ x = a * c - b * d;
+ y = a * d + b * c;
+
+ if (x != x && y != y) {
+ /*
+ * Both x and y are NaN, so z and w can't both be finite.
+ * If at least one of z or w is a complex NaN, and neither
+ * is infinite, then we might as well deliver NaN + I * NaN.
+ * So the only cases to check are when one of z or w is
+ * infinite.
+ */
+ recalc = 0;
+ i = testinf(a);
+ j = testinf(b);
+ if (i | j) { /* z is infinite */
+ /* "factor out" infinity */
+ a = i;
+ b = j;
+ recalc = 1;
+ }
+ i = testinf(c);
+ j = testinf(d);
+ if (i | j) { /* w is infinite */
+ /* "factor out" infinity */
+ c = i;
+ d = j;
+ recalc = 1;
+ }
+ if (recalc) {
+ x = inf.d * (a * c - b * d);
+ y = inf.d * (a * d + b * c);
+ }
+ }
+
+ /*
+ * The following is equivalent to
+ *
+ * return x + I * y;
+ */
+ ((double *)&v)[0] = x;
+ ((double *)&v)[1] = y;
+ return (v);
+}
diff --git a/usr/src/lib/libc/sparc/fp/_F_cplx_div.c b/usr/src/lib/libc/sparc/fp/_F_cplx_div.c
new file mode 100644
index 0000000000..e5f1fc6d1b
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_F_cplx_div.c
@@ -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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * _F_cplx_div(z, w) returns z / w with infinities handled according
+ * to C99.
+ *
+ * If z and w are both finite and w is nonzero, _F_cplx_div(z, w)
+ * delivers the complex quotient q according to the usual formula:
+ * let a = Re(z), b = Im(z), c = Re(w), and d = Im(w); then q = x +
+ * I * y where x = (a * c + b * d) / r and y = (b * c - a * d) / r
+ * with r = c * c + d * d. This implementation computes intermediate
+ * results in double precision to avoid premature underflow or over-
+ * flow.
+ *
+ * If z is neither NaN nor zero and w is zero, or if z is infinite
+ * and w is finite and nonzero, _F_cplx_div delivers an infinite
+ * result. If z is finite and w is infinite, _F_cplx_div delivers
+ * a zero result.
+ *
+ * If z and w are both zero or both infinite, or if either z or w is
+ * a complex NaN, _F_cplx_div delivers NaN + I * NaN. C99 doesn't
+ * specify these cases.
+ *
+ * This implementation can raise spurious invalid operation, inexact,
+ * and division-by-zero exceptions. C99 allows this.
+ *
+ * Warning: Do not attempt to "optimize" this code by removing multi-
+ * plications by zero.
+ */
+
+#if !defined(sparc) && !defined(__sparc)
+#error This code is for SPARC only
+#endif
+
+static union {
+ int i[2];
+ double d;
+} inf = {
+ 0x7ff00000, 0
+};
+
+/*
+ * Return +1 if x is +Inf, -1 if x is -Inf, and 0 otherwise
+ */
+static int
+testinff(float x)
+{
+ union {
+ int i;
+ float f;
+ } xx;
+
+ xx.f = x;
+ return ((((xx.i << 1) - 0xff000000) == 0)? (1 | (xx.i >> 31)) : 0);
+}
+
+float _Complex
+_F_cplx_div(float _Complex z, float _Complex w)
+{
+ float _Complex v;
+ union {
+ int i;
+ float f;
+ } cc, dd;
+ float a, b, c, d;
+ double r, x, y;
+ int i, j, recalc;
+
+ /*
+ * The following is equivalent to
+ *
+ * a = crealf(z); b = cimagf(z);
+ * c = crealf(w); d = cimagf(w);
+ */
+ a = ((float *)&z)[0];
+ b = ((float *)&z)[1];
+ c = ((float *)&w)[0];
+ d = ((float *)&w)[1];
+
+ r = (double)c * c + (double)d * d;
+
+ if (r == 0.0) {
+ /* w is zero; multiply z by 1/Re(w) - I * Im(w) */
+ c = 1.0f / c;
+ i = testinff(a);
+ j = testinff(b);
+ if (i | j) { /* z is infinite */
+ a = i;
+ b = j;
+ }
+ ((float *)&v)[0] = a * c + b * d;
+ ((float *)&v)[1] = b * c - a * d;
+ return (v);
+ }
+
+ r = 1.0 / r;
+ x = ((double)a * c + (double)b * d) * r;
+ y = ((double)b * c - (double)a * d) * r;
+
+ if (x != x && y != y) {
+ /*
+ * Both x and y are NaN, so z and w can't both be finite
+ * and nonzero. Since we handled the case w = 0 above,
+ * the only cases to check here are when one of z or w
+ * is infinite.
+ */
+ r = 1.0;
+ recalc = 0;
+ i = testinff(a);
+ j = testinff(b);
+ if (i | j) { /* z is infinite */
+ /* "factor out" infinity */
+ a = i;
+ b = j;
+ r = inf.d;
+ recalc = 1;
+ }
+ i = testinff(c);
+ j = testinff(d);
+ if (i | j) { /* w is infinite */
+ /*
+ * "factor out" infinity, being careful to preserve
+ * signs of finite values
+ */
+ cc.f = c;
+ dd.f = d;
+ c = i? i : ((cc.i < 0)? -0.0f : 0.0f);
+ d = j? j : ((dd.i < 0)? -0.0f : 0.0f);
+ r *= 0.0;
+ recalc = 1;
+ }
+ if (recalc) {
+ x = ((double)a * c + (double)b * d) * r;
+ y = ((double)b * c - (double)a * d) * r;
+ }
+ }
+
+ /*
+ * The following is equivalent to
+ *
+ * return x + I * y;
+ */
+ ((float *)&v)[0] = (float)x;
+ ((float *)&v)[1] = (float)y;
+ return (v);
+}
diff --git a/usr/src/lib/libc/sparc/fp/_F_cplx_div_ix.c b/usr/src/lib/libc/sparc/fp/_F_cplx_div_ix.c
new file mode 100644
index 0000000000..fcc900561a
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_F_cplx_div_ix.c
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * _F_cplx_div_ix(b, w) returns (I * b) / w with infinities handled
+ * according to C99.
+ *
+ * If b and w are both finite and w is nonzero, _F_cplx_div_ix(b, w)
+ * delivers the complex quotient q according to the usual formula:
+ * let c = Re(w), and d = Im(w); then q = x + I * y where x = (b * d)
+ * / r and y = (b * c) / r with r = c * c + d * d. This implementa-
+ * tion computes intermediate results in double precision to avoid
+ * premature underflow or overflow.
+ *
+ * If b is neither NaN nor zero and w is zero, or if b is infinite
+ * and w is finite and nonzero, _F_cplx_div_ix delivers an infinite
+ * result. If b is finite and w is infinite, _F_cplx_div_ix delivers
+ * a zero result.
+ *
+ * If b and w are both zero or both infinite, or if either b or w is
+ * NaN, _F_cplx_div_ix delivers NaN + I * NaN. C99 doesn't specify
+ * these cases.
+ *
+ * This implementation can raise spurious invalid operation, inexact,
+ * and division-by-zero exceptions. C99 allows this.
+ *
+ * Warning: Do not attempt to "optimize" this code by removing multi-
+ * plications by zero.
+ */
+
+#if !defined(sparc) && !defined(__sparc)
+#error This code is for SPARC only
+#endif
+
+/*
+ * Return +1 if x is +Inf, -1 if x is -Inf, and 0 otherwise
+ */
+static int
+testinff(float x)
+{
+ union {
+ int i;
+ float f;
+ } xx;
+
+ xx.f = x;
+ return ((((xx.i << 1) - 0xff000000) == 0)? (1 | (xx.i >> 31)) : 0);
+}
+
+float _Complex
+_F_cplx_div_ix(float b, float _Complex w)
+{
+ float _Complex v;
+ union {
+ int i;
+ float f;
+ } cc, dd;
+ float c, d;
+ double r, x, y;
+ int i, j;
+
+ /*
+ * The following is equivalent to
+ *
+ * c = crealf(w); d = cimagf(w);
+ */
+ c = ((float *)&w)[0];
+ d = ((float *)&w)[1];
+
+ r = (double)c * c + (double)d * d;
+
+ if (r == 0.0) {
+ /* w is zero; multiply b by 1/Re(w) - I * Im(w) */
+ c = 1.0f / c;
+ j = testinff(b);
+ if (j) { /* b is infinite */
+ b = j;
+ }
+ ((float *)&v)[0] = (b == 0.0f)? b * c : b * d;
+ ((float *)&v)[1] = b * c;
+ return (v);
+ }
+
+ r = (double)b / r;
+ x = (double)d * r;
+ y = (double)c * r;
+
+ if (x != x || y != y) {
+ /*
+ * x or y is NaN, so b and w can't both be finite and
+ * nonzero. Since we handled the case w = 0 above, the
+ * only case to check here is when w is infinite.
+ */
+ i = testinff(c);
+ j = testinff(d);
+ if (i | j) { /* w is infinite */
+ cc.f = c;
+ dd.f = d;
+ c = (cc.i < 0)? -0.0f : 0.0f;
+ d = (dd.i < 0)? -0.0f : 0.0f;
+ x = (double)d * b;
+ y = (double)c * b;
+ }
+ }
+
+ /*
+ * The following is equivalent to
+ *
+ * return x + I * y;
+ */
+ ((float *)&v)[0] = (float)x;
+ ((float *)&v)[1] = (float)y;
+ return (v);
+}
diff --git a/usr/src/lib/libc/sparc/fp/_F_cplx_div_rx.c b/usr/src/lib/libc/sparc/fp/_F_cplx_div_rx.c
new file mode 100644
index 0000000000..6eeee65716
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_F_cplx_div_rx.c
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * _F_cplx_div_rx(a, w) returns a / w with infinities handled according
+ * to C99.
+ *
+ * If a and w are both finite and w is nonzero, _F_cplx_div_rx(a, w)
+ * delivers the complex quotient q according to the usual formula:
+ * let c = Re(w), and d = Im(w); then q = x + I * y where x = (a * c)
+ * / r and y = (-a * d) / r with r = c * c + d * d. This implementa-
+ * tion computes intermediate results in double precision to avoid
+ * premature underflow or overflow.
+ *
+ * If a is neither NaN nor zero and w is zero, or if a is infinite
+ * and w is finite and nonzero, _F_cplx_div_rx delivers an infinite
+ * result. If a is finite and w is infinite, _F_cplx_div_rx delivers
+ * a zero result.
+ *
+ * If a and w are both zero or both infinite, or if either a or w is
+ * NaN, _F_cplx_div_rx delivers NaN + I * NaN. C99 doesn't specify
+ * these cases.
+ *
+ * This implementation can raise spurious invalid operation, inexact,
+ * and division-by-zero exceptions. C99 allows this.
+ *
+ * Warning: Do not attempt to "optimize" this code by removing multi-
+ * plications by zero.
+ */
+
+#if !defined(sparc) && !defined(__sparc)
+#error This code is for SPARC only
+#endif
+
+/*
+ * Return +1 if x is +Inf, -1 if x is -Inf, and 0 otherwise
+ */
+static int
+testinff(float x)
+{
+ union {
+ int i;
+ float f;
+ } xx;
+
+ xx.f = x;
+ return ((((xx.i << 1) - 0xff000000) == 0)? (1 | (xx.i >> 31)) : 0);
+}
+
+float _Complex
+_F_cplx_div_rx(float a, float _Complex w)
+{
+ float _Complex v;
+ union {
+ int i;
+ float f;
+ } cc, dd;
+ float c, d;
+ double r, x, y;
+ int i, j;
+
+ /*
+ * The following is equivalent to
+ *
+ * c = crealf(w); d = cimagf(w);
+ */
+ c = ((float *)&w)[0];
+ d = ((float *)&w)[1];
+
+ r = (double)c * c + (double)d * d;
+
+ if (r == 0.0) {
+ /* w is zero; multiply a by 1/Re(w) - I * Im(w) */
+ c = 1.0f / c;
+ i = testinff(a);
+ if (i) { /* a is infinite */
+ a = i;
+ }
+ ((float *)&v)[0] = a * c;
+ ((float *)&v)[1] = (a == 0.0f)? a * c : -a * d;
+ return (v);
+ }
+
+ r = (double)a / r;
+ x = (double)c * r;
+ y = (double)-d * r;
+
+ if (x != x || y != y) {
+ /*
+ * x or y is NaN, so a and w can't both be finite and
+ * nonzero. Since we handled the case w = 0 above, the
+ * only case to check here is when w is infinite.
+ */
+ i = testinff(c);
+ j = testinff(d);
+ if (i | j) { /* w is infinite */
+ cc.f = c;
+ dd.f = d;
+ c = (cc.i < 0)? -0.0f : 0.0f;
+ d = (dd.i < 0)? -0.0f : 0.0f;
+ x = (double)c * a;
+ y = (double)-d * a;
+ }
+ }
+
+ /*
+ * The following is equivalent to
+ *
+ * return x + I * y;
+ */
+ ((float *)&v)[0] = (float)x;
+ ((float *)&v)[1] = (float)y;
+ return (v);
+}
diff --git a/usr/src/lib/libc/sparc/fp/_F_cplx_mul.c b/usr/src/lib/libc/sparc/fp/_F_cplx_mul.c
new file mode 100644
index 0000000000..f4073e9327
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_F_cplx_mul.c
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * _F_cplx_mul(z, w) returns z * w with infinities handled according
+ * to C99.
+ *
+ * If z and w are both finite, _F_cplx_mul(z, w) delivers the complex
+ * product according to the usual formula: let a = Re(z), b = Im(z),
+ * c = Re(w), and d = Im(w); then _F_cplx_mul(z, w) delivers x + I * y
+ * where x = a * c - b * d and y = a * d + b * c. This implementation
+ * uses double precision to form these expressions, so none of the
+ * intermediate products can overflow.
+ *
+ * If one of z or w is infinite and the other is either finite nonzero
+ * or infinite, _F_cplx_mul delivers an infinite result. If one factor
+ * is infinite and the other is zero, _F_cplx_mul delivers NaN + I * NaN.
+ * C99 doesn't specify the latter case.
+ *
+ * C99 also doesn't specify what should happen if either z or w is a
+ * complex NaN (i.e., neither finite nor infinite). This implementation
+ * delivers NaN + I * NaN in this case.
+ *
+ * This implementation can raise spurious invalid operation and inexact
+ * exceptions. C99 allows this.
+ */
+
+#if !defined(sparc) && !defined(__sparc)
+#error This code is for SPARC only
+#endif
+
+static union {
+ int i[2];
+ double d;
+} inf = {
+ 0x7ff00000, 0
+};
+
+/*
+ * Return +1 if x is +Inf, -1 if x is -Inf, and 0 otherwise
+ */
+static int
+testinff(float x)
+{
+ union {
+ int i;
+ float f;
+ } xx;
+
+ xx.f = x;
+ return ((((xx.i << 1) - 0xff000000) == 0)? (1 | (xx.i >> 31)) : 0);
+}
+
+float _Complex
+_F_cplx_mul(float _Complex z, float _Complex w)
+{
+ float _Complex v;
+ float a, b, c, d;
+ double x, y;
+ int recalc, i, j;
+
+ /*
+ * The following is equivalent to
+ *
+ * a = crealf(z); b = cimagf(z);
+ * c = crealf(w); d = cimagf(w);
+ */
+ a = ((float *)&z)[0];
+ b = ((float *)&z)[1];
+ c = ((float *)&w)[0];
+ d = ((float *)&w)[1];
+
+ x = (double)a * c - (double)b * d;
+ y = (double)a * d + (double)b * c;
+
+ if (x != x && y != y) {
+ /*
+ * Both x and y are NaN, so z and w can't both be finite.
+ * If at least one of z or w is a complex NaN, and neither
+ * is infinite, then we might as well deliver NaN + I * NaN.
+ * So the only cases to check are when one of z or w is
+ * infinite.
+ */
+ recalc = 0;
+ i = testinff(a);
+ j = testinff(b);
+ if (i | j) { /* z is infinite */
+ /* "factor out" infinity */
+ a = i;
+ b = j;
+ recalc = 1;
+ }
+ i = testinff(c);
+ j = testinff(d);
+ if (i | j) { /* w is infinite */
+ /* "factor out" infinity */
+ c = i;
+ d = j;
+ recalc = 1;
+ }
+ if (recalc) {
+ x = inf.d * ((double)a * c - (double)b * d);
+ y = inf.d * ((double)a * d + (double)b * c);
+ }
+ }
+
+ /*
+ * The following is equivalent to
+ *
+ * return x + I * y;
+ */
+ ((float *)&v)[0] = (float)x;
+ ((float *)&v)[1] = (float)y;
+ return (v);
+}
diff --git a/usr/src/lib/libc/sparc/fp/_Q_add.c b/usr/src/lib/libc/sparc/fp/_Q_add.c
new file mode 100644
index 0000000000..94ba0bc9d0
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_Q_add.c
@@ -0,0 +1,161 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "quad.h"
+
+#ifdef __sparcv9
+
+/*
+ * _Qp_add(pz, ox, oy) sets *pz = *ox + *oy.
+ */
+void
+_Qp_add(union longdouble *pz, const union longdouble *ox,
+ const union longdouble *oy)
+
+#else
+
+/*
+ * _Q_add(ox, oy) returns *ox + *oy.
+ */
+union longdouble
+_Q_add(const union longdouble *ox, const union longdouble *oy)
+
+#endif /* __sparcv9 */
+
+{
+ union longdouble z;
+ const union longdouble *x, *y;
+ unsigned int xm, ym, tm, fsr;
+
+ /* sort so |x| >= |y| */
+ xm = ox->l.msw & 0x7fffffff;
+ ym = oy->l.msw & 0x7fffffff;
+ if (ym > xm || ym == xm && (oy->l.frac2 > ox->l.frac2 ||
+ oy->l.frac2 == ox->l.frac2 && (oy->l.frac3 > ox->l.frac3 ||
+ oy->l.frac3 == ox->l.frac3 && oy->l.frac4 > ox->l.frac4))) {
+ y = ox;
+ x = oy;
+ tm = xm;
+ xm = ym;
+ ym = tm;
+ } else {
+ x = ox;
+ y = oy;
+ }
+
+ /* get the fsr */
+ __quad_getfsrp(&fsr);
+
+ /* handle nan and inf cases */
+ if (xm >= 0x7fff0000) {
+ /* x is nan or inf */
+ if (ym >= 0x7fff0000) {
+ /* y is nan or inf */
+ if ((ym & 0xffff) | y->l.frac2 | y->l.frac3 |
+ y->l.frac4) {
+ /* y is nan; x must be nan too */
+ /* the following logic implements V9 app. B */
+ if (!(ym & 0x8000)) {
+ /* y is snan, signal invalid */
+ if (fsr & FSR_NVM) {
+ __quad_faddq(ox, oy, &Z);
+ } else {
+ Z = (xm & 0x8000)? *y : *oy;
+ Z.l.msw |= 0x8000;
+ fsr = (fsr & ~FSR_CEXC) |
+ FSR_NVA | FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ QUAD_RETURN(Z);
+ }
+ /* x and y are both qnan */
+ Z = *oy;
+ QUAD_RETURN(Z);
+ }
+ if (!((xm & 0xffff) | x->l.frac2 | x->l.frac3 |
+ x->l.frac4)) {
+ /* x and y are both inf */
+ if ((x->l.msw ^ y->l.msw) & 0x80000000) {
+ /* inf - inf, signal invalid */
+ if (fsr & FSR_NVM) {
+ __quad_faddq(ox, oy, &Z);
+ } else {
+ Z.l.msw = 0x7fffffff;
+ Z.l.frac2 = Z.l.frac3 =
+ Z.l.frac4 = 0xffffffff;
+ fsr = (fsr & ~FSR_CEXC) |
+ FSR_NVA | FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ QUAD_RETURN(Z);
+ }
+ /* inf + inf, return inf */
+ Z = *x;
+ QUAD_RETURN(Z);
+ }
+ }
+ if ((xm & 0xffff) | x->l.frac2 | x->l.frac3 | x->l.frac4) {
+ /* x is nan */
+ if (!(xm & 0x8000)) {
+ /* snan, signal invalid */
+ if (fsr & FSR_NVM) {
+ __quad_faddq(ox, oy, &Z);
+ } else {
+ Z = *x;
+ Z.l.msw |= 0x8000;
+ fsr = (fsr & ~FSR_CEXC) | FSR_NVA |
+ FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ QUAD_RETURN(Z);
+ }
+ Z = *x;
+ QUAD_RETURN(Z);
+ }
+ /* x is inf */
+ Z = *x;
+ QUAD_RETURN(Z);
+ }
+
+ /* now x and y are finite and |x| >= |y| */
+ fsr &= ~FSR_CEXC;
+ z.l.msw = (x->l.msw & 0x80000000);
+ if ((x->l.msw ^ y->l.msw) & 0x80000000)
+ __quad_mag_sub(x, y, &z, &fsr);
+ else
+ __quad_mag_add(x, y, &z, &fsr);
+ if ((fsr & FSR_CEXC) & (fsr >> 23)) {
+ __quad_setfsrp(&fsr);
+ __quad_faddq(ox, oy, &Z);
+ } else {
+ Z = z;
+ fsr |= (fsr & 0x1f) << 5;
+ __quad_setfsrp(&fsr);
+ }
+ QUAD_RETURN(Z);
+}
diff --git a/usr/src/lib/libc/sparc/fp/_Q_cmp.c b/usr/src/lib/libc/sparc/fp/_Q_cmp.c
new file mode 100644
index 0000000000..ca4337bbb5
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_Q_cmp.c
@@ -0,0 +1,107 @@
+/*
+ * 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) 1994-1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "quad.h"
+
+#ifdef __sparcv9
+#define _Q_cmp _Qp_cmp
+#endif
+
+/*
+ * _Q_cmp(x, y) returns the condition code that would result from
+ * fcmpq *x, *y (and raises the same exceptions).
+ */
+enum fcc_type
+_Q_cmp(const union longdouble *x, const union longdouble *y)
+{
+ unsigned int xm, ym, fsr;
+
+ if (QUAD_ISNAN(*x) || QUAD_ISNAN(*y)) {
+ if ((QUAD_ISNAN(*x) && !(x->l.msw & 0x8000)) ||
+ (QUAD_ISNAN(*y) && !(y->l.msw & 0x8000))) {
+ /* snan, signal invalid */
+ __quad_getfsrp(&fsr);
+ if (fsr & FSR_NVM) {
+ __quad_fcmpq(x, y, &fsr);
+ return ((fsr >> 10) & 3);
+ } else {
+ fsr = (fsr & ~FSR_CEXC) | FSR_NVA | FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ }
+ return (fcc_unordered);
+ }
+
+ /* ignore sign of zero */
+ xm = x->l.msw;
+ if (QUAD_ISZERO(*x))
+ xm &= 0x7fffffff;
+ ym = y->l.msw;
+ if (QUAD_ISZERO(*y))
+ ym &= 0x7fffffff;
+
+ if ((xm ^ ym) & 0x80000000) /* x and y have opposite signs */
+ return ((ym & 0x80000000)? fcc_greater : fcc_less);
+
+ if (xm & 0x80000000) {
+ if (xm > ym)
+ return (fcc_less);
+ if (xm < ym)
+ return (fcc_greater);
+ if (x->l.frac2 > y->l.frac2)
+ return (fcc_less);
+ if (x->l.frac2 < y->l.frac2)
+ return (fcc_greater);
+ if (x->l.frac3 > y->l.frac3)
+ return (fcc_less);
+ if (x->l.frac3 < y->l.frac3)
+ return (fcc_greater);
+ if (x->l.frac4 > y->l.frac4)
+ return (fcc_less);
+ if (x->l.frac4 < y->l.frac4)
+ return (fcc_greater);
+ return (fcc_equal);
+ }
+ if (xm < ym)
+ return (fcc_less);
+ if (xm > ym)
+ return (fcc_greater);
+ if (x->l.frac2 < y->l.frac2)
+ return (fcc_less);
+ if (x->l.frac2 > y->l.frac2)
+ return (fcc_greater);
+ if (x->l.frac3 < y->l.frac3)
+ return (fcc_less);
+ if (x->l.frac3 > y->l.frac3)
+ return (fcc_greater);
+ if (x->l.frac4 < y->l.frac4)
+ return (fcc_less);
+ if (x->l.frac4 > y->l.frac4)
+ return (fcc_greater);
+ return (fcc_equal);
+}
diff --git a/usr/src/lib/libc/sparc/fp/_Q_cmpe.c b/usr/src/lib/libc/sparc/fp/_Q_cmpe.c
new file mode 100644
index 0000000000..8606a3ad96
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_Q_cmpe.c
@@ -0,0 +1,104 @@
+/*
+ * 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) 1994-1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "quad.h"
+
+#ifdef __sparcv9
+#define _Q_cmpe _Qp_cmpe
+#endif
+
+/*
+ * _Q_cmpe(x, y) returns the condition code that would result from
+ * fcmpeq *x, *y (and raises the same exceptions).
+ */
+enum fcc_type
+_Q_cmpe(const union longdouble *x, const union longdouble *y)
+{
+ unsigned int xm, ym, fsr;
+
+ if (QUAD_ISNAN(*x) || QUAD_ISNAN(*y)) {
+ /* nan, signal invalid */
+ __quad_getfsrp(&fsr);
+ if (fsr & FSR_NVM) {
+ __quad_fcmpeq(x, y, &fsr);
+ return ((fsr >> 10) & 3);
+ } else {
+ fsr = (fsr & ~FSR_CEXC) | FSR_NVA | FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ return (fcc_unordered);
+ }
+
+ /* ignore sign of zero */
+ xm = x->l.msw;
+ if (QUAD_ISZERO(*x))
+ xm &= 0x7fffffff;
+ ym = y->l.msw;
+ if (QUAD_ISZERO(*y))
+ ym &= 0x7fffffff;
+
+ if ((xm ^ ym) & 0x80000000) /* x and y have opposite signs */
+ return ((ym & 0x80000000)? fcc_greater : fcc_less);
+
+ if (xm & 0x80000000) {
+ if (xm > ym)
+ return (fcc_less);
+ if (xm < ym)
+ return (fcc_greater);
+ if (x->l.frac2 > y->l.frac2)
+ return (fcc_less);
+ if (x->l.frac2 < y->l.frac2)
+ return (fcc_greater);
+ if (x->l.frac3 > y->l.frac3)
+ return (fcc_less);
+ if (x->l.frac3 < y->l.frac3)
+ return (fcc_greater);
+ if (x->l.frac4 > y->l.frac4)
+ return (fcc_less);
+ if (x->l.frac4 < y->l.frac4)
+ return (fcc_greater);
+ return (fcc_equal);
+ }
+ if (xm < ym)
+ return (fcc_less);
+ if (xm > ym)
+ return (fcc_greater);
+ if (x->l.frac2 < y->l.frac2)
+ return (fcc_less);
+ if (x->l.frac2 > y->l.frac2)
+ return (fcc_greater);
+ if (x->l.frac3 < y->l.frac3)
+ return (fcc_less);
+ if (x->l.frac3 > y->l.frac3)
+ return (fcc_greater);
+ if (x->l.frac4 < y->l.frac4)
+ return (fcc_less);
+ if (x->l.frac4 > y->l.frac4)
+ return (fcc_greater);
+ return (fcc_equal);
+}
diff --git a/usr/src/lib/libc/sparc/fp/_Q_cplx_div.c b/usr/src/lib/libc/sparc/fp/_Q_cplx_div.c
new file mode 100644
index 0000000000..b529c5eecf
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_Q_cplx_div.c
@@ -0,0 +1,202 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * On SPARC V8, _Q_cplx_div(v, z, w) sets *v = *z / *w with infin-
+ * ities handling according to C99.
+ *
+ * On SPARC V9, _Q_cplx_div(z, w) returns *z / *w with infinities
+ * handled according to C99.
+ *
+ * If z and w are both finite and w is nonzero, _Q_cplx_div delivers
+ * the complex quotient q according to the usual formula: let a =
+ * Re(z), b = Im(z), c = Re(w), and d = Im(w); then q = x + I * y
+ * where x = (a * c + b * d) / r and y = (b * c - a * d) / r with
+ * r = c * c + d * d. This implementation scales to avoid premature
+ * underflow or overflow.
+ *
+ * If z is neither NaN nor zero and w is zero, or if z is infinite
+ * and w is finite and nonzero, _Q_cplx_div delivers an infinite
+ * result. If z is finite and w is infinite, _Q_cplx_div delivers
+ * a zero result.
+ *
+ * If z and w are both zero or both infinite, or if either z or w is
+ * a complex NaN, _Q_cplx_div delivers NaN + I * NaN. C99 doesn't
+ * specify these cases.
+ *
+ * This implementation can raise spurious underflow, overflow, in-
+ * valid operation, inexact, and division-by-zero exceptions. C99
+ * allows this.
+ */
+
+#if !defined(sparc) && !defined(__sparc)
+#error This code is for SPARC only
+#endif
+
+static union {
+ int i[4];
+ long double q;
+} inf = {
+ 0x7fff0000, 0, 0, 0
+};
+
+/*
+ * Return +1 if x is +Inf, -1 if x is -Inf, and 0 otherwise
+ */
+static int
+testinfl(long double x)
+{
+ union {
+ int i[4];
+ long double q;
+ } xx;
+
+ xx.q = x;
+ return (((((xx.i[0] << 1) - 0xfffe0000) | xx.i[1] | xx.i[2] | xx.i[3])
+ == 0)? (1 | (xx.i[0] >> 31)) : 0);
+}
+
+#ifdef __sparcv9
+long double _Complex
+_Q_cplx_div(const long double _Complex *z, const long double _Complex *w)
+{
+ long double _Complex v;
+#else
+void
+_Q_cplx_div(long double _Complex *v, const long double _Complex *z,
+ const long double _Complex *w)
+{
+#endif
+ union {
+ int i[4];
+ long double q;
+ } aa, bb, cc, dd, ss;
+ long double a, b, c, d, r;
+ int ha, hb, hc, hd, hz, hw, hs, i, j;
+
+ /*
+ * The following is equivalent to
+ *
+ * a = creall(*z); b = cimagl(*z);
+ * c = creall(*w); d = cimagl(*w);
+ */
+ a = ((long double *)z)[0];
+ b = ((long double *)z)[1];
+ c = ((long double *)w)[0];
+ d = ((long double *)w)[1];
+
+ /* extract high-order words to estimate |z| and |w| */
+ aa.q = a;
+ bb.q = b;
+ ha = aa.i[0] & ~0x80000000;
+ hb = bb.i[0] & ~0x80000000;
+ hz = (ha > hb)? ha : hb;
+
+ cc.q = c;
+ dd.q = d;
+ hc = cc.i[0] & ~0x80000000;
+ hd = dd.i[0] & ~0x80000000;
+ hw = (hc > hd)? hc : hd;
+
+ /* check for special cases */
+ if (hw >= 0x7fff0000) { /* w is inf or nan */
+ r = 0.0l;
+ i = testinfl(c);
+ j = testinfl(d);
+ if (i | j) { /* w is infinite */
+ /*
+ * "factor out" infinity, being careful to preserve
+ * signs of finite values
+ */
+ c = i? i : ((cc.i[0] < 0)? -0.0l : 0.0l);
+ d = j? j : ((dd.i[0] < 0)? -0.0l : 0.0l);
+ if (hz >= 0x7ffe0000) {
+ /* scale to avoid overflow below */
+ c *= 0.5l;
+ d *= 0.5l;
+ }
+ }
+ goto done;
+ }
+
+ if (hw == 0 && (cc.i[1] | cc.i[2] | cc.i[3] |
+ dd.i[1] | dd.i[2] | dd.i[3]) == 0) {
+ /* w is zero; multiply z by 1/Re(w) - I * Im(w) */
+ r = 1.0l;
+ c = 1.0l / c;
+ i = testinfl(a);
+ j = testinfl(b);
+ if (i | j) { /* z is infinite */
+ a = i;
+ b = j;
+ }
+ goto done;
+ }
+
+ if (hz >= 0x7fff0000) { /* z is inf or nan */
+ r = 1.0l;
+ i = testinfl(a);
+ j = testinfl(b);
+ if (i | j) { /* z is infinite */
+ a = i;
+ b = j;
+ r = inf.q;
+ }
+ goto done;
+ }
+
+ /*
+ * Scale c and d to compute 1/|w|^2 and the real and imaginary
+ * parts of the quotient.
+ */
+ hs = (((hw >> 2) - hw) + 0x6ffd7fff) & 0xffff0000;
+ if (hz < 0x00ea0000) { /* |z| < 2^-16149 */
+ if (((hw - 0x3e380000) | (0x40e90000 - hw)) >= 0)
+ hs = (((0x40e90000 - hw) >> 1) & 0xffff0000)
+ + 0x3fff0000;
+ }
+ ss.i[0] = hs;
+ ss.i[1] = ss.i[2] = ss.i[3] = 0;
+
+ c *= ss.q;
+ d *= ss.q;
+ r = 1.0l / (c * c + d * d);
+
+ c *= ss.q;
+ d *= ss.q;
+
+done:
+#ifdef __sparcv9
+ ((long double *)&v)[0] = (a * c + b * d) * r;
+ ((long double *)&v)[1] = (b * c - a * d) * r;
+ return (v);
+#else
+ ((long double *)v)[0] = (a * c + b * d) * r;
+ ((long double *)v)[1] = (b * c - a * d) * r;
+#endif
+}
diff --git a/usr/src/lib/libc/sparc/fp/_Q_cplx_div_ix.c b/usr/src/lib/libc/sparc/fp/_Q_cplx_div_ix.c
new file mode 100644
index 0000000000..2d9c18ba02
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_Q_cplx_div_ix.c
@@ -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 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * On SPARC V8, _Q_cplx_div_ix(v, b, w) sets *v = (I * *b / *w) with
+ * infinities handling according to C99.
+ *
+ * On SPARC V9, _Q_cplx_div_ix(b, w) returns (I * *b) / *w with in-
+ * finities handled according to C99.
+ *
+ * If b and w are both finite and w is nonzero, _Q_cplx_div_ix de-
+ * livers the complex quotient q according to the usual formula: let
+ * c = Re(w), and d = Im(w); then q = x + I * y where x = (b * d) / r
+ * and y = (-b * d) / r with r = c * c + d * d. This implementation
+ * scales to avoid premature underflow or overflow.
+ *
+ * If b is neither NaN nor zero and w is zero, or if b is infinite
+ * and w is finite and nonzero, _Q_cplx_div_ix delivers an infinite
+ * result. If b is finite and w is infinite, _Q_cplx_div_ix delivers
+ * a zero result.
+ *
+ * If b and w are both zero or both infinite, or if either b or w is
+ * NaN, _Q_cplx_div_ix delivers NaN + I * NaN. C99 doesn't specify
+ * these cases.
+ *
+ * This implementation can raise spurious underflow, overflow, in-
+ * valid operation, inexact, and division-by-zero exceptions. C99
+ * allows this.
+ */
+
+#if !defined(sparc) && !defined(__sparc)
+#error This code is for SPARC only
+#endif
+
+extern void _Q_scl(long double *, int);
+extern void _Q_scle(long double *, int);
+
+/*
+ * Return +1 if x is +Inf, -1 if x is -Inf, and 0 otherwise
+ */
+static int
+testinfl(long double x)
+{
+ union {
+ int i[4];
+ long double q;
+ } xx;
+
+ xx.q = x;
+ return (((((xx.i[0] << 1) - 0xfffe0000) | xx.i[1] | xx.i[2] | xx.i[3])
+ == 0)? (1 | (xx.i[0] >> 31)) : 0);
+}
+
+#ifdef __sparcv9
+long double _Complex
+_Q_cplx_div_ix(const long double *pb, const long double _Complex *w)
+{
+ long double _Complex v;
+#else
+void
+_Q_cplx_div_ix(long double _Complex *v, const long double *pb,
+ const long double _Complex *w)
+{
+#endif
+ union {
+ int i[4];
+ long double q;
+ } bb, cc, dd;
+ long double b, c, d, sc, sd, r;
+ int hb, hc, hd, hw, i, j;
+
+ b = *pb;
+
+ /*
+ * The following is equivalent to
+ *
+ * c = creall(*w); d = cimagl(*w);
+ */
+ c = ((long double *)w)[0];
+ d = ((long double *)w)[1];
+
+ /* extract high-order words to estimate |b| and |w| */
+ bb.q = b;
+ hb = bb.i[0] & ~0x80000000;
+
+ cc.q = c;
+ dd.q = d;
+ hc = cc.i[0] & ~0x80000000;
+ hd = dd.i[0] & ~0x80000000;
+ hw = (hc > hd)? hc : hd;
+
+ /* check for special cases */
+ if (hw >= 0x7fff0000) { /* w is inf or nan */
+ i = testinfl(c);
+ j = testinfl(d);
+ if (i | j) { /* w is infinite */
+ c = (cc.i[0] < 0)? -0.0l : 0.0l;
+ d = (dd.i[0] < 0)? -0.0l : 0.0l;
+ } else /* w is nan */
+ b += c + d;
+ c *= b;
+ d *= b;
+ goto done;
+ }
+
+ if (hw == 0 && (cc.i[1] | cc.i[2] | cc.i[3] |
+ dd.i[1] | dd.i[2] | dd.i[3]) == 0) {
+ /* w is zero; multiply b by 1/Re(w) - I * Im(w) */
+ c = 1.0l / c;
+ j = testinfl(b);
+ if (j) { /* b is infinite */
+ b = j;
+ }
+ c *= b;
+ d = (b == 0.0l)? c : b * d;
+ goto done;
+ }
+
+ if (hb >= 0x7fff0000) { /* a is inf or nan */
+ c *= b;
+ d *= b;
+ goto done;
+ }
+
+ /*
+ * Compute the real and imaginary parts of the quotient,
+ * scaling to avoid overflow or underflow.
+ */
+ hw = (hw - 0x3fff0000) >> 16;
+ sc = c;
+ sd = d;
+ _Q_scl(&sc, -hw);
+ _Q_scl(&sd, -hw);
+ r = sc * sc + sd * sd;
+
+ hb = (hb - 0x3fff0000) >> 16;
+ _Q_scl(&b, -hb);
+ b /= r;
+ hb -= (hw + hw);
+
+ hc = (hc - 0x3fff0000) >> 16;
+ _Q_scl(&c, -hc);
+ c *= b;
+ hc += hb;
+
+ hd = (hd - 0x3fff0000) >> 16;
+ _Q_scl(&d, -hd);
+ d *= b;
+ hd += hb;
+
+ /* compensate for scaling */
+ _Q_scle(&c, hc);
+ _Q_scle(&d, hd);
+
+done:
+#ifdef __sparcv9
+ ((long double *)&v)[0] = d;
+ ((long double *)&v)[1] = c;
+ return (v);
+#else
+ ((long double *)v)[0] = d;
+ ((long double *)v)[1] = c;
+#endif
+}
diff --git a/usr/src/lib/libc/sparc/fp/_Q_cplx_div_rx.c b/usr/src/lib/libc/sparc/fp/_Q_cplx_div_rx.c
new file mode 100644
index 0000000000..80f050bd94
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_Q_cplx_div_rx.c
@@ -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 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * On SPARC V8, _Q_cplx_div_rx(v, a, w) sets *v = *a / *w with in-
+ * finities handling according to C99.
+ *
+ * On SPARC V9, _Q_cplx_div_rx(a, w) returns *a / *w with infinities
+ * handled according to C99.
+ *
+ * If a and w are both finite and w is nonzero, _Q_cplx_div_rx de-
+ * livers the complex quotient q according to the usual formula: let
+ * c = Re(w), and d = Im(w); then q = x + I * y where x = (a * c) / r
+ * and y = (-a * d) / r with r = c * c + d * d. This implementation
+ * scales to avoid premature underflow or overflow.
+ *
+ * If a is neither NaN nor zero and w is zero, or if a is infinite
+ * and w is finite and nonzero, _Q_cplx_div_rx delivers an infinite
+ * result. If a is finite and w is infinite, _Q_cplx_div_rx delivers
+ * a zero result.
+ *
+ * If a and w are both zero or both infinite, or if either a or w is
+ * NaN, _Q_cplx_div_rx delivers NaN + I * NaN. C99 doesn't specify
+ * these cases.
+ *
+ * This implementation can raise spurious underflow, overflow, in-
+ * valid operation, inexact, and division-by-zero exceptions. C99
+ * allows this.
+ */
+
+#if !defined(sparc) && !defined(__sparc)
+#error This code is for SPARC only
+#endif
+
+extern void _Q_scl(long double *, int);
+extern void _Q_scle(long double *, int);
+
+/*
+ * Return +1 if x is +Inf, -1 if x is -Inf, and 0 otherwise
+ */
+static int
+testinfl(long double x)
+{
+ union {
+ int i[4];
+ long double q;
+ } xx;
+
+ xx.q = x;
+ return (((((xx.i[0] << 1) - 0xfffe0000) | xx.i[1] | xx.i[2] | xx.i[3])
+ == 0)? (1 | (xx.i[0] >> 31)) : 0);
+}
+
+#ifdef __sparcv9
+long double _Complex
+_Q_cplx_div_rx(const long double *pa, const long double _Complex *w)
+{
+ long double _Complex v;
+#else
+void
+_Q_cplx_div_rx(long double _Complex *v, const long double *pa,
+ const long double _Complex *w)
+{
+#endif
+ union {
+ int i[4];
+ long double q;
+ } aa, cc, dd;
+ long double a, c, d, sc, sd, r;
+ int ha, hc, hd, hw, i, j;
+
+ a = *pa;
+
+ /*
+ * The following is equivalent to
+ *
+ * c = creall(*w); d = cimagl(*w);
+ */
+ c = ((long double *)w)[0];
+ d = ((long double *)w)[1];
+
+ /* extract high-order words to estimate |a| and |w| */
+ aa.q = a;
+ ha = aa.i[0] & ~0x80000000;
+
+ cc.q = c;
+ dd.q = d;
+ hc = cc.i[0] & ~0x80000000;
+ hd = dd.i[0] & ~0x80000000;
+ hw = (hc > hd)? hc : hd;
+
+ /* check for special cases */
+ if (hw >= 0x7fff0000) { /* w is inf or nan */
+ i = testinfl(c);
+ j = testinfl(d);
+ if (i | j) { /* w is infinite */
+ c = (cc.i[0] < 0)? -0.0l : 0.0l;
+ d = (dd.i[0] < 0)? -0.0l : 0.0l;
+ } else /* w is nan */
+ a += c + d;
+ c *= a;
+ d *= -a;
+ goto done;
+ }
+
+ if (hw == 0 && (cc.i[1] | cc.i[2] | cc.i[3] |
+ dd.i[1] | dd.i[2] | dd.i[3]) == 0) {
+ /* w is zero; multiply a by 1/Re(w) - I * Im(w) */
+ c = 1.0l / c;
+ i = testinfl(a);
+ if (i) { /* a is infinite */
+ a = i;
+ }
+ c *= a;
+ d = (a == 0.0l)? c : -a * d;
+ goto done;
+ }
+
+ if (ha >= 0x7fff0000) { /* a is inf or nan */
+ c *= a;
+ d *= -a;
+ goto done;
+ }
+
+ /*
+ * Compute the real and imaginary parts of the quotient,
+ * scaling to avoid overflow or underflow.
+ */
+ hw = (hw - 0x3fff0000) >> 16;
+ sc = c;
+ sd = d;
+ _Q_scl(&sc, -hw);
+ _Q_scl(&sd, -hw);
+ r = sc * sc + sd * sd;
+
+ ha = (ha - 0x3fff0000) >> 16;
+ _Q_scl(&a, -ha);
+ a /= r;
+ ha -= (hw + hw);
+
+ hc = (hc - 0x3fff0000) >> 16;
+ _Q_scl(&c, -hc);
+ c *= a;
+ hc += ha;
+
+ hd = (hd - 0x3fff0000) >> 16;
+ _Q_scl(&d, -hd);
+ d *= -a;
+ hd += ha;
+
+ /* compensate for scaling */
+ _Q_scle(&c, hc);
+ _Q_scle(&d, hd);
+
+done:
+#ifdef __sparcv9
+ ((long double *)&v)[0] = c;
+ ((long double *)&v)[1] = d;
+ return (v);
+#else
+ ((long double *)v)[0] = c;
+ ((long double *)v)[1] = d;
+#endif
+}
diff --git a/usr/src/lib/libc/sparc/fp/_Q_cplx_lr_div.c b/usr/src/lib/libc/sparc/fp/_Q_cplx_lr_div.c
new file mode 100644
index 0000000000..92473041e3
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_Q_cplx_lr_div.c
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * On SPARC V8, _Q_cplx_lr_div(v, z, w) sets *v = *z / *w computed
+ * by the textbook formula without regard to exceptions or special
+ * cases.
+ *
+ * On SPARC V9, _Q_cplx_lr_div(z, w) returns *z / *w.
+ *
+ * This code is intended to be used only when CX_LIMITED_RANGE is ON;
+ * otherwise use _Q_cplx_div.
+ */
+
+#if !defined(sparc) && !defined(__sparc)
+#error This code is for SPARC only
+#endif
+
+#ifdef __sparcv9
+long double _Complex
+_Q_cplx_lr_div(const long double _Complex *z, const long double _Complex *w)
+{
+ long double _Complex v;
+#else
+void
+_Q_cplx_lr_div(long double _Complex *v, const long double _Complex *z,
+ const long double _Complex *w)
+{
+#endif
+ long double a, b, c, d, r;
+
+ a = ((long double *)z)[0];
+ b = ((long double *)z)[1];
+ c = ((long double *)w)[0];
+ d = ((long double *)w)[1];
+
+ r = 1.0L / (c * c + d * d);
+
+#ifdef __sparcv9
+ ((long double *)&v)[0] = (a * c + b * d) * r;
+ ((long double *)&v)[1] = (b * c - a * d) * r;
+ return (v);
+#else
+ ((long double *)v)[0] = (a * c + b * d) * r;
+ ((long double *)v)[1] = (b * c - a * d) * r;
+#endif
+}
diff --git a/usr/src/lib/libc/sparc/fp/_Q_cplx_lr_div_ix.c b/usr/src/lib/libc/sparc/fp/_Q_cplx_lr_div_ix.c
new file mode 100644
index 0000000000..ca968d809a
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_Q_cplx_lr_div_ix.c
@@ -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 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * On SPARC V8, _Q_cplx_lr_div_ix(v, b, w) sets *v = (I * *b / *w)
+ * compute by the textbook formula without regard to exceptions or
+ * special cases.
+ *
+ * On SPARC V9, _Q_cplx_lr_div_ix(b, w) returns (I * *b) / *w.
+ *
+ * This code is intended to be used only when CX_LIMITED_RANGE is ON;
+ * otherwise use _Q_cplx_div_ix.
+ */
+
+#if !defined(sparc) && !defined(__sparc)
+#error This code is for SPARC only
+#endif
+
+#ifdef __sparcv9
+long double _Complex
+_Q_cplx_lr_div_ix(const long double *pb, const long double _Complex *w)
+{
+ long double _Complex v;
+#else
+void
+_Q_cplx_lr_div_ix(long double _Complex *v, const long double *pb,
+ const long double _Complex *w)
+{
+#endif
+ long double b, c, d;
+
+ b = *pb;
+ c = ((long double *)w)[0];
+ d = ((long double *)w)[1];
+
+ b /= (c * c + d * d);
+
+#ifdef __sparcv9
+ ((long double *)&v)[0] = b * d;
+ ((long double *)&v)[1] = b * c;
+ return (v);
+#else
+ ((long double *)v)[0] = b * d;
+ ((long double *)v)[1] = b * c;
+#endif
+}
diff --git a/usr/src/lib/libc/sparc/fp/_Q_cplx_lr_div_rx.c b/usr/src/lib/libc/sparc/fp/_Q_cplx_lr_div_rx.c
new file mode 100644
index 0000000000..b6b91ddf48
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_Q_cplx_lr_div_rx.c
@@ -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 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * On SPARC V8, _Q_cplx_lr_div_rx(v, a, w) sets *v = *a / *w computed
+ * by the textbook formula without regard to exceptions or special
+ * cases.
+ *
+ * On SPARC V9, _Q_cplx_lr_div_rx(a, w) returns *a / *w.
+ *
+ * This code is intended to be used only when CX_LIMITED_RANGE is ON;
+ * otherwise use _Q_cplx_div_rx.
+ */
+
+#if !defined(sparc) && !defined(__sparc)
+#error This code is for SPARC only
+#endif
+
+#ifdef __sparcv9
+long double _Complex
+_Q_cplx_lr_div_rx(const long double *pa, const long double _Complex *w)
+{
+ long double _Complex v;
+#else
+void
+_Q_cplx_lr_div_rx(long double _Complex *v, const long double *pa,
+ const long double _Complex *w)
+{
+#endif
+ long double a, c, d;
+
+ a = *pa;
+ c = ((long double *)w)[0];
+ d = ((long double *)w)[1];
+
+ a /= (c * c + d * d);
+
+#ifdef __sparcv9
+ ((long double *)&v)[0] = a * c;
+ ((long double *)&v)[1] = a * -d;
+ return (v);
+#else
+ ((long double *)v)[0] = a * c;
+ ((long double *)v)[1] = a * -d;
+#endif
+}
diff --git a/usr/src/lib/libc/sparc/fp/_Q_cplx_lr_mul.c b/usr/src/lib/libc/sparc/fp/_Q_cplx_lr_mul.c
new file mode 100644
index 0000000000..f2be5888df
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_Q_cplx_lr_mul.c
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * On SPARC V8, _Q_cplx_lr_mul(v, z, w) sets *v = *z * *w computed by
+ * the textbook formula without regard to exceptions or special cases.
+ *
+ * On SPARC V9, _Q_cplx_lr_mul(z, w) returns *z * *w.
+ *
+ * This code is intended to be used only when CX_LIMITED_RANGE is ON;
+ * otherwise use _Q_cplx_mul.
+ */
+
+#if !defined(sparc) && !defined(__sparc)
+#error This code is for SPARC only
+#endif
+
+#ifdef __sparcv9
+long double _Complex
+_Q_cplx_lr_mul(const long double _Complex *z, const long double _Complex *w)
+{
+ long double _Complex v;
+#else
+void
+_Q_cplx_lr_mul(long double _Complex *v, const long double _Complex *z,
+ const long double _Complex *w)
+{
+#endif
+ long double a, b, c, d;
+
+ a = ((long double *)z)[0];
+ b = ((long double *)z)[1];
+ c = ((long double *)w)[0];
+ d = ((long double *)w)[1];
+
+#ifdef __sparcv9
+ ((long double *)&v)[0] = (a * c - b * d);
+ ((long double *)&v)[1] = (a * d + b * c);
+ return (v);
+#else
+ ((long double *)v)[0] = (a * c - b * d);
+ ((long double *)v)[1] = (a * d + b * c);
+#endif
+}
diff --git a/usr/src/lib/libc/sparc/fp/_Q_cplx_mul.c b/usr/src/lib/libc/sparc/fp/_Q_cplx_mul.c
new file mode 100644
index 0000000000..9e4d41b2f7
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_Q_cplx_mul.c
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * On SPARC V8, _Q_cplx_mul(v, z, w) sets *v = *z * *w with infinities
+ * handled according to C99.
+ *
+ * On SPARC V9, _Q_cplx_mul(z, w) returns *z * *w with infinities
+ * handled according to C99.
+ *
+ * If z and w are both finite, _Q_cplx_mul delivers the complex
+ * product according to the usual formula: let a = Re(z), b = Im(z),
+ * c = Re(w), and d = Im(w); then _Q_cplx_mul delivers x + I * y
+ * where x = a * c - b * d and y = a * d + b * c. Note that if both
+ * ac and bd overflow, then at least one of ad or bc must also over-
+ * flow, and vice versa, so that if one component of the product is
+ * NaN, the other is infinite. (Such a value is considered infinite
+ * according to C99.)
+ *
+ * If one of z or w is infinite and the other is either finite nonzero
+ * or infinite, _Q_cplx_mul delivers an infinite result. If one factor
+ * is infinite and the other is zero, _Q_cplx_mul delivers NaN + I * NaN.
+ * C99 doesn't specify the latter case.
+ *
+ * C99 also doesn't specify what should happen if either z or w is a
+ * complex NaN (i.e., neither finite nor infinite). This implementation
+ * delivers NaN + I * NaN in this case.
+ *
+ * This implementation can raise spurious underflow, overflow, invalid
+ * operation, and inexact exceptions. C99 allows this.
+ */
+
+#if !defined(sparc) && !defined(__sparc)
+#error This code is for SPARC only
+#endif
+
+static union {
+ int i[4];
+ long double q;
+} inf = {
+ 0x7fff0000, 0, 0, 0
+};
+
+/*
+ * Return +1 if x is +Inf, -1 if x is -Inf, and 0 otherwise
+ */
+static int
+testinfl(long double x)
+{
+ union {
+ int i[4];
+ long double q;
+ } xx;
+
+ xx.q = x;
+ return (((((xx.i[0] << 1) - 0xfffe0000) | xx.i[1] | xx.i[2] | xx.i[3])
+ == 0)? (1 | (xx.i[0] >> 31)) : 0);
+}
+
+#ifdef __sparcv9
+long double _Complex
+_Q_cplx_mul(const long double _Complex *z, const long double _Complex *w)
+{
+ long double _Complex v;
+#else
+void
+_Q_cplx_mul(long double _Complex *v, const long double _Complex *z,
+ const long double _Complex *w)
+{
+#endif
+ long double a, b, c, d, x, y;
+ int recalc, i, j;
+
+ /*
+ * The following is equivalent to
+ *
+ * a = creall(*z); b = cimagl(*z);
+ * c = creall(*w); d = cimagl(*w);
+ */
+ a = ((long double *)z)[0];
+ b = ((long double *)z)[1];
+ c = ((long double *)w)[0];
+ d = ((long double *)w)[1];
+
+ x = a * c - b * d;
+ y = a * d + b * c;
+
+ if (x != x && y != y) {
+ /*
+ * Both x and y are NaN, so z and w can't both be finite.
+ * If at least one of z or w is a complex NaN, and neither
+ * is infinite, then we might as well deliver NaN + I * NaN.
+ * So the only cases to check are when one of z or w is
+ * infinite.
+ */
+ recalc = 0;
+ i = testinfl(a);
+ j = testinfl(b);
+ if (i | j) { /* z is infinite */
+ /* "factor out" infinity */
+ a = i;
+ b = j;
+ recalc = 1;
+ }
+ i = testinfl(c);
+ j = testinfl(d);
+ if (i | j) { /* w is infinite */
+ /* "factor out" infinity */
+ c = i;
+ d = j;
+ recalc = 1;
+ }
+ if (recalc) {
+ x = inf.q * (a * c - b * d);
+ y = inf.q * (a * d + b * c);
+ }
+ }
+
+#ifdef __sparcv9
+ ((long double *)&v)[0] = x;
+ ((long double *)&v)[1] = y;
+ return (v);
+#else
+ ((long double *)v)[0] = x;
+ ((long double *)v)[1] = y;
+#endif
+}
diff --git a/usr/src/lib/libc/sparc/fp/_Q_div.c b/usr/src/lib/libc/sparc/fp/_Q_div.c
new file mode 100644
index 0000000000..27871a6141
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_Q_div.c
@@ -0,0 +1,549 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "quad.h"
+
+static const double C[] = {
+ 0.0,
+ 1.0,
+ 68719476736.0,
+ 402653184.0,
+ 24.0,
+ 16.0,
+ 3.66210937500000000000e-04,
+ 1.52587890625000000000e-05,
+ 1.43051147460937500000e-06,
+ 5.96046447753906250000e-08,
+ 3.72529029846191406250e-09,
+ 2.18278728425502777100e-11,
+ 8.52651282912120223045e-14,
+ 3.55271367880050092936e-15,
+ 1.30104260698260532081e-18,
+ 8.67361737988403547206e-19,
+ 2.16840434497100886801e-19,
+ 3.17637355220362627151e-22,
+ 7.75481824268463445192e-26,
+ 4.62223186652936604733e-33,
+ 9.62964972193617926528e-35,
+ 4.70197740328915003187e-38,
+ 2.75506488473973634680e-40,
+};
+
+#define zero C[0]
+#define one C[1]
+#define two36 C[2]
+#define three2p27 C[3]
+#define three2p3 C[4]
+#define two4 C[5]
+#define three2m13 C[6]
+#define twom16 C[7]
+#define three2m21 C[8]
+#define twom24 C[9]
+#define twom28 C[10]
+#define three2m37 C[11]
+#define three2m45 C[12]
+#define twom48 C[13]
+#define three2m61 C[14]
+#define twom60 C[15]
+#define twom62 C[16]
+#define three2m73 C[17]
+#define three2m85 C[18]
+#define three2m109 C[19]
+#define twom113 C[20]
+#define twom124 C[21]
+#define three2m133 C[22]
+
+static const unsigned int
+ fsr_re = 0x00000000u,
+ fsr_rn = 0xc0000000u;
+
+#ifdef __sparcv9
+
+/*
+ * _Qp_div(pz, x, y) sets *pz = *x / *y.
+ */
+void
+_Qp_div(union longdouble *pz, const union longdouble *x,
+ const union longdouble *y)
+
+#else
+
+/*
+ * _Q_div(x, y) returns *x / *y.
+ */
+union longdouble
+_Q_div(const union longdouble *x, const union longdouble *y)
+
+#endif /* __sparcv9 */
+
+{
+ union longdouble z;
+ union xdouble u;
+ double c, d, ry, xx[4], yy[5], zz[5];
+ unsigned int xm, ym, fsr, lx, ly, wx[3], wy[3];
+ unsigned int msw, frac2, frac3, frac4, rm;
+ int ibit, ex, ey, ez, sign;
+
+ xm = x->l.msw & 0x7fffffff;
+ ym = y->l.msw & 0x7fffffff;
+ sign = (x->l.msw ^ y->l.msw) & ~0x7fffffff;
+
+ __quad_getfsrp(&fsr);
+
+ /* handle nan and inf cases */
+ if (xm >= 0x7fff0000 || ym >= 0x7fff0000) {
+ /* handle nan cases according to V9 app. B */
+ if (QUAD_ISNAN(*y)) {
+ if (!(y->l.msw & 0x8000)) {
+ /* snan, signal invalid */
+ if (fsr & FSR_NVM) {
+ __quad_fdivq(x, y, &Z);
+ } else {
+ Z = *y;
+ Z.l.msw |= 0x8000;
+ fsr = (fsr & ~FSR_CEXC) | FSR_NVA |
+ FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ QUAD_RETURN(Z);
+ } else if (QUAD_ISNAN(*x) && !(x->l.msw & 0x8000)) {
+ /* snan, signal invalid */
+ if (fsr & FSR_NVM) {
+ __quad_fdivq(x, y, &Z);
+ } else {
+ Z = *x;
+ Z.l.msw |= 0x8000;
+ fsr = (fsr & ~FSR_CEXC) | FSR_NVA |
+ FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ QUAD_RETURN(Z);
+ }
+ Z = *y;
+ QUAD_RETURN(Z);
+ }
+ if (QUAD_ISNAN(*x)) {
+ if (!(x->l.msw & 0x8000)) {
+ /* snan, signal invalid */
+ if (fsr & FSR_NVM) {
+ __quad_fdivq(x, y, &Z);
+ } else {
+ Z = *x;
+ Z.l.msw |= 0x8000;
+ fsr = (fsr & ~FSR_CEXC) | FSR_NVA |
+ FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ QUAD_RETURN(Z);
+ }
+ Z = *x;
+ QUAD_RETURN(Z);
+ }
+ if (xm == 0x7fff0000) {
+ /* x is inf */
+ if (ym == 0x7fff0000) {
+ /* inf / inf, signal invalid */
+ if (fsr & FSR_NVM) {
+ __quad_fdivq(x, y, &Z);
+ } else {
+ Z.l.msw = 0x7fffffff;
+ Z.l.frac2 = Z.l.frac3 =
+ Z.l.frac4 = 0xffffffff;
+ fsr = (fsr & ~FSR_CEXC) | FSR_NVA |
+ FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ QUAD_RETURN(Z);
+ }
+ /* inf / finite, return inf */
+ Z.l.msw = sign | 0x7fff0000;
+ Z.l.frac2 = Z.l.frac3 = Z.l.frac4 = 0;
+ QUAD_RETURN(Z);
+ }
+ /* y is inf */
+ Z.l.msw = sign;
+ Z.l.frac2 = Z.l.frac3 = Z.l.frac4 = 0;
+ QUAD_RETURN(Z);
+ }
+
+ /* handle zero cases */
+ if (xm == 0 || ym == 0) {
+ if (QUAD_ISZERO(*x)) {
+ if (QUAD_ISZERO(*y)) {
+ /* zero / zero, signal invalid */
+ if (fsr & FSR_NVM) {
+ __quad_fdivq(x, y, &Z);
+ } else {
+ Z.l.msw = 0x7fffffff;
+ Z.l.frac2 = Z.l.frac3 =
+ Z.l.frac4 = 0xffffffff;
+ fsr = (fsr & ~FSR_CEXC) | FSR_NVA |
+ FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ QUAD_RETURN(Z);
+ }
+ /* zero / nonzero, return zero */
+ Z.l.msw = sign;
+ Z.l.frac2 = Z.l.frac3 = Z.l.frac4 = 0;
+ QUAD_RETURN(Z);
+ }
+ if (QUAD_ISZERO(*y)) {
+ /* nonzero / zero, signal zero divide */
+ if (fsr & FSR_DZM) {
+ __quad_fdivq(x, y, &Z);
+ } else {
+ Z.l.msw = sign | 0x7fff0000;
+ Z.l.frac2 = Z.l.frac3 = Z.l.frac4 = 0;
+ fsr = (fsr & ~FSR_CEXC) | FSR_DZA | FSR_DZC;
+ __quad_setfsrp(&fsr);
+ }
+ QUAD_RETURN(Z);
+ }
+ }
+
+ /* now x and y are finite, nonzero */
+ __quad_setfsrp(&fsr_re);
+
+ /* get their normalized significands and exponents */
+ ex = (int)(xm >> 16);
+ lx = xm & 0xffff;
+ if (ex) {
+ lx |= 0x10000;
+ wx[0] = x->l.frac2;
+ wx[1] = x->l.frac3;
+ wx[2] = x->l.frac4;
+ } else {
+ if (lx | (x->l.frac2 & 0xfffe0000)) {
+ wx[0] = x->l.frac2;
+ wx[1] = x->l.frac3;
+ wx[2] = x->l.frac4;
+ ex = 1;
+ } else if (x->l.frac2 | (x->l.frac3 & 0xfffe0000)) {
+ lx = x->l.frac2;
+ wx[0] = x->l.frac3;
+ wx[1] = x->l.frac4;
+ wx[2] = 0;
+ ex = -31;
+ } else if (x->l.frac3 | (x->l.frac4 & 0xfffe0000)) {
+ lx = x->l.frac3;
+ wx[0] = x->l.frac4;
+ wx[1] = wx[2] = 0;
+ ex = -63;
+ } else {
+ lx = x->l.frac4;
+ wx[0] = wx[1] = wx[2] = 0;
+ ex = -95;
+ }
+ while ((lx & 0x10000) == 0) {
+ lx = (lx << 1) | (wx[0] >> 31);
+ wx[0] = (wx[0] << 1) | (wx[1] >> 31);
+ wx[1] = (wx[1] << 1) | (wx[2] >> 31);
+ wx[2] <<= 1;
+ ex--;
+ }
+ }
+ ez = ex;
+
+ ey = (int)(ym >> 16);
+ ly = ym & 0xffff;
+ if (ey) {
+ ly |= 0x10000;
+ wy[0] = y->l.frac2;
+ wy[1] = y->l.frac3;
+ wy[2] = y->l.frac4;
+ } else {
+ if (ly | (y->l.frac2 & 0xfffe0000)) {
+ wy[0] = y->l.frac2;
+ wy[1] = y->l.frac3;
+ wy[2] = y->l.frac4;
+ ey = 1;
+ } else if (y->l.frac2 | (y->l.frac3 & 0xfffe0000)) {
+ ly = y->l.frac2;
+ wy[0] = y->l.frac3;
+ wy[1] = y->l.frac4;
+ wy[2] = 0;
+ ey = -31;
+ } else if (y->l.frac3 | (y->l.frac4 & 0xfffe0000)) {
+ ly = y->l.frac3;
+ wy[0] = y->l.frac4;
+ wy[1] = wy[2] = 0;
+ ey = -63;
+ } else {
+ ly = y->l.frac4;
+ wy[0] = wy[1] = wy[2] = 0;
+ ey = -95;
+ }
+ while ((ly & 0x10000) == 0) {
+ ly = (ly << 1) | (wy[0] >> 31);
+ wy[0] = (wy[0] << 1) | (wy[1] >> 31);
+ wy[1] = (wy[1] << 1) | (wy[2] >> 31);
+ wy[2] <<= 1;
+ ey--;
+ }
+ }
+ ez -= ey - 0x3fff;
+
+ /* extract the significands into doubles */
+ c = twom16;
+ xx[0] = (double)((int)lx) * c;
+ yy[0] = (double)((int)ly) * c;
+
+ c *= twom24;
+ xx[0] += (double)((int)(wx[0] >> 8)) * c;
+ yy[1] = (double)((int)(wy[0] >> 8)) * c;
+
+ c *= twom24;
+ xx[1] = (double)((int)(((wx[0] << 16) |
+ (wx[1] >> 16)) & 0xffffff)) * c;
+ yy[2] = (double)((int)(((wy[0] << 16) |
+ (wy[1] >> 16)) & 0xffffff)) * c;
+
+ c *= twom24;
+ xx[2] = (double)((int)(((wx[1] << 8) |
+ (wx[2] >> 24)) & 0xffffff)) * c;
+ yy[3] = (double)((int)(((wy[1] << 8) |
+ (wy[2] >> 24)) & 0xffffff)) * c;
+
+ c *= twom24;
+ xx[3] = (double)((int)(wx[2] & 0xffffff)) * c;
+ yy[4] = (double)((int)(wy[2] & 0xffffff)) * c;
+
+ /* approximate the reciprocal of y */
+ ry = one / ((yy[0] + yy[1]) + yy[2]);
+
+ /* compute the first five "digits" of the quotient */
+ zz[0] = (ry * (xx[0] + xx[1]) + three2p27) - three2p27;
+ xx[0] = ((xx[0] - zz[0] * yy[0]) - zz[0] * yy[1]) + xx[1];
+ d = zz[0] * yy[2];
+ c = (d + three2m13) - three2m13;
+ xx[0] -= c;
+ xx[1] = xx[2] - (d - c);
+ d = zz[0] * yy[3];
+ c = (d + three2m37) - three2m37;
+ xx[1] -= c;
+ xx[2] = xx[3] - (d - c);
+ d = zz[0] * yy[4];
+ c = (d + three2m61) - three2m61;
+ xx[2] -= c;
+ xx[3] = c - d;
+
+ zz[1] = (ry * (xx[0] + xx[1]) + three2p3) - three2p3;
+ xx[0] = ((xx[0] - zz[1] * yy[0]) - zz[1] * yy[1]) + xx[1];
+ d = zz[1] * yy[2];
+ c = (d + three2m37) - three2m37;
+ xx[0] -= c;
+ xx[1] = xx[2] - (d - c);
+ d = zz[1] * yy[3];
+ c = (d + three2m61) - three2m61;
+ xx[1] -= c;
+ xx[2] = xx[3] - (d - c);
+ d = zz[1] * yy[4];
+ c = (d + three2m85) - three2m85;
+ xx[2] -= c;
+ xx[3] = c - d;
+
+ zz[2] = (ry * (xx[0] + xx[1]) + three2m21) - three2m21;
+ xx[0] = ((xx[0] - zz[2] * yy[0]) - zz[2] * yy[1]) + xx[1];
+ d = zz[2] * yy[2];
+ c = (d + three2m61) - three2m61;
+ xx[0] -= c;
+ xx[1] = xx[2] - (d - c);
+ d = zz[2] * yy[3];
+ c = (d + three2m85) - three2m85;
+ xx[1] -= c;
+ xx[2] = xx[3] - (d - c);
+ d = zz[2] * yy[4];
+ c = (d + three2m109) - three2m109;
+ xx[2] -= c;
+ xx[3] = c - d;
+
+ zz[3] = (ry * (xx[0] + xx[1]) + three2m45) - three2m45;
+ xx[0] = ((xx[0] - zz[3] * yy[0]) - zz[3] * yy[1]) + xx[1];
+ d = zz[3] * yy[2];
+ c = (d + three2m85) - three2m85;
+ xx[0] -= c;
+ xx[1] = xx[2] - (d - c);
+ d = zz[3] * yy[3];
+ c = (d + three2m109) - three2m109;
+ xx[1] -= c;
+ xx[2] = xx[3] - (d - c);
+ d = zz[3] * yy[4];
+ c = (d + three2m133) - three2m133;
+ xx[2] -= c;
+ xx[3] = c - d;
+
+ zz[4] = (ry * (xx[0] + xx[1]) + three2m73) - three2m73;
+
+ /* reduce to three doubles, making sure zz[1] is positive */
+ zz[0] += zz[1] - twom48;
+ zz[1] = twom48 + zz[2] + zz[3];
+ zz[2] = zz[4];
+
+ /* if the third term might lie on a rounding boundary, perturb it */
+ if (zz[2] == (twom62 + zz[2]) - twom62) {
+ /* here we just need to get the sign of the remainder */
+ c = (((((xx[0] - zz[4] * yy[0]) - zz[4] * yy[1]) + xx[1]) +
+ (xx[2] - zz[4] * yy[2])) + (xx[3] - zz[4] * yy[3]))
+ - zz[4] * yy[4];
+ if (c < zero)
+ zz[2] -= twom124;
+ else if (c > zero)
+ zz[2] += twom124;
+ }
+
+ /*
+ * propagate carries/borrows, using round-to-negative-infinity mode
+ * to make all terms nonnegative (note that we can't encounter a
+ * borrow so large that the roundoff is unrepresentable because
+ * we took care to make zz[1] positive above)
+ */
+ __quad_setfsrp(&fsr_rn);
+ c = zz[1] + zz[2];
+ zz[2] += (zz[1] - c);
+ zz[1] = c;
+ c = zz[0] + zz[1];
+ zz[1] += (zz[0] - c);
+ zz[0] = c;
+
+ /* check for borrow */
+ if (c < one) {
+ /* postnormalize */
+ zz[0] += zz[0];
+ zz[1] += zz[1];
+ zz[2] += zz[2];
+ ez--;
+ }
+
+ /* if exponent > 0 strip off integer bit, else denormalize */
+ if (ez > 0) {
+ ibit = 1;
+ zz[0] -= one;
+ } else {
+ ibit = 0;
+ if (ez > -128)
+ u.l.hi = (unsigned int)(0x3fe + ez) << 20;
+ else
+ u.l.hi = 0x37e00000;
+ u.l.lo = 0;
+ zz[0] *= u.d;
+ zz[1] *= u.d;
+ zz[2] *= u.d;
+ ez = 0;
+ }
+
+ /* the first 48 bits of fraction come from zz[0] */
+ u.d = d = two36 + zz[0];
+ msw = u.l.lo;
+ zz[0] -= (d - two36);
+
+ u.d = d = two4 + zz[0];
+ frac2 = u.l.lo;
+ zz[0] -= (d - two4);
+
+ /* the next 32 come from zz[0] and zz[1] */
+ u.d = d = twom28 + (zz[0] + zz[1]);
+ frac3 = u.l.lo;
+ zz[0] -= (d - twom28);
+
+ /* condense the remaining fraction; errors here won't matter */
+ c = zz[0] + zz[1];
+ zz[1] = ((zz[0] - c) + zz[1]) + zz[2];
+ zz[0] = c;
+
+ /* get the last word of fraction */
+ u.d = d = twom60 + (zz[0] + zz[1]);
+ frac4 = u.l.lo;
+ zz[0] -= (d - twom60);
+
+ /* keep track of what's left for rounding; note that the error */
+ /* in computing c will be non-negative due to rounding mode */
+ c = zz[0] + zz[1];
+
+ /* get the rounding mode, fudging directed rounding modes */
+ /* as though the result were positive */
+ rm = fsr >> 30;
+ if (sign)
+ rm ^= (rm >> 1);
+
+ /* round and raise exceptions */
+ fsr &= ~FSR_CEXC;
+ if (c != zero) {
+ fsr |= FSR_NXC;
+
+ /* decide whether to round the fraction up */
+ if (rm == FSR_RP || (rm == FSR_RN && (c > twom113 ||
+ (c == twom113 && ((frac4 & 1) || (c - zz[0] !=
+ zz[1])))))) {
+ /* round up and renormalize if necessary */
+ if (++frac4 == 0)
+ if (++frac3 == 0)
+ if (++frac2 == 0)
+ if (++msw == 0x10000) {
+ msw = 0;
+ ez++;
+ }
+ }
+ }
+
+ /* check for under/overflow */
+ if (ez >= 0x7fff) {
+ if (rm == FSR_RN || rm == FSR_RP) {
+ z.l.msw = sign | 0x7fff0000;
+ z.l.frac2 = z.l.frac3 = z.l.frac4 = 0;
+ } else {
+ z.l.msw = sign | 0x7ffeffff;
+ z.l.frac2 = z.l.frac3 = z.l.frac4 = 0xffffffff;
+ }
+ fsr |= FSR_OFC | FSR_NXC;
+ } else {
+ z.l.msw = sign | (ez << 16) | msw;
+ z.l.frac2 = frac2;
+ z.l.frac3 = frac3;
+ z.l.frac4 = frac4;
+
+ /* !ibit => exact result was tiny before rounding, */
+ /* t nonzero => result delivered is inexact */
+ if (!ibit) {
+ if (c != zero)
+ fsr |= FSR_UFC | FSR_NXC;
+ else if (fsr & FSR_UFM)
+ fsr |= FSR_UFC;
+ }
+ }
+
+ if ((fsr & FSR_CEXC) & (fsr >> 23)) {
+ __quad_setfsrp(&fsr);
+ __quad_fdivq(x, y, &Z);
+ } else {
+ Z = z;
+ fsr |= (fsr & 0x1f) << 5;
+ __quad_setfsrp(&fsr);
+ }
+ QUAD_RETURN(Z);
+}
diff --git a/usr/src/lib/libc/sparc/fp/_Q_dtoq.c b/usr/src/lib/libc/sparc/fp/_Q_dtoq.c
new file mode 100644
index 0000000000..9df3333c7a
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_Q_dtoq.c
@@ -0,0 +1,97 @@
+/*
+ * 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) 1994-1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "quad.h"
+
+#ifdef __sparcv9
+
+/*
+ * _Qp_dtoq(pz, x) sets *pz = (long double)x.
+ */
+void
+_Qp_dtoq(union longdouble *pz, double x)
+
+#else
+
+/*
+ * _Q_dtoq(x) returns (long double)x.
+ */
+union longdouble
+_Q_dtoq(double x)
+
+#endif /* __sparcv9 */
+
+{
+#ifndef __sparcv9
+ union longdouble z;
+#endif
+ union xdouble u;
+ unsigned int m, lhi, llo, fsr;
+
+ /* extract the exponent */
+ u.d = x;
+ m = ((u.l.hi & 0x7ff00000) >> 4) + 0x3c000000;
+ if (m == 0x3c000000) {
+ /* x is zero or denormal */
+ if ((u.l.hi & 0xfffff) | u.l.lo) {
+ /* x is denormal, normalize it */
+ m = 0x3c010000;
+ lhi = u.l.hi & 0xfffff;
+ llo = u.l.lo;
+ do {
+ lhi = (lhi << 1) | (llo >> 31);
+ llo <<= 1;
+ m -= 0x10000;
+ } while ((lhi & 0x7ff00000) == 0);
+ u.l.hi = (u.l.hi & 0x80000000) | lhi;
+ u.l.lo = llo;
+ } else {
+ m = 0;
+ }
+ } else if (m == 0x43ff0000) {
+ /* x is inf or nan */
+ m = 0x7fff0000;
+ if (((u.l.hi & 0x7ffff) | u.l.lo) && (u.l.hi & 0x80000) == 0) {
+ /* snan, signal invalid */
+ __quad_getfsrp(&fsr);
+ if (fsr & FSR_NVM) {
+ __quad_fdtoq(&x, &Z);
+ QUAD_RETURN(Z);
+ } else {
+ fsr = (fsr & ~FSR_CEXC) | FSR_NVA | FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ u.l.hi |= 0x80000;
+ }
+ }
+ Z.l.msw = m | (u.l.hi & 0x80000000) | ((u.l.hi & 0xffff0) >> 4);
+ Z.l.frac2 = (u.l.hi << 28) | (u.l.lo >> 4);
+ Z.l.frac3 = u.l.lo << 28;
+ Z.l.frac4 = 0;
+ QUAD_RETURN(Z);
+}
diff --git a/usr/src/lib/libc/sparc/fp/_Q_fcc.c b/usr/src/lib/libc/sparc/fp/_Q_fcc.c
new file mode 100644
index 0000000000..6b7777c883
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_Q_fcc.c
@@ -0,0 +1,274 @@
+/*
+ * 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) 1994-1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "quad.h"
+
+#ifdef __sparcv9
+#define _Q_feq _Qp_feq
+#define _Q_fne _Qp_fne
+#define _Q_flt _Qp_flt
+#define _Q_fle _Qp_fle
+#define _Q_fgt _Qp_fgt
+#define _Q_fge _Qp_fge
+#endif
+
+/*
+ * _Q_feq(x, y) returns nonzero if *x == *y and zero otherwise.
+ * If either *x or *y is a signaling NaN, the invalid operation
+ * exception is raised.
+ */
+int
+_Q_feq(const union longdouble *x, const union longdouble *y)
+{
+ unsigned int fsr;
+
+ if (QUAD_ISNAN(*x) || QUAD_ISNAN(*y)) {
+ if ((QUAD_ISNAN(*x) && !(x->l.msw & 0x8000)) ||
+ (QUAD_ISNAN(*y) && !(y->l.msw & 0x8000))) {
+ /* snan, signal invalid */
+ __quad_getfsrp(&fsr);
+ if (fsr & FSR_NVM) {
+ __quad_fcmpq(x, y, &fsr);
+ return (((fsr >> 10) & 3) == fcc_equal);
+ } else {
+ fsr = (fsr & ~FSR_CEXC) | FSR_NVA | FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ }
+ return (0);
+ }
+ if (QUAD_ISZERO(*x) && QUAD_ISZERO(*y))
+ return (1);
+ return ((x->l.msw ^ y->l.msw | x->l.frac2 ^ y->l.frac2 |
+ x->l.frac3 ^ y->l.frac3 | x->l.frac4 ^ y->l.frac4) == 0);
+}
+
+/*
+ * _Q_fne(x, y) returns nonzero if *x != *y and zero otherwise.
+ * If either *x or *y is a signaling NaN, the invalid operation
+ * exception is raised.
+ */
+int
+_Q_fne(const union longdouble *x, const union longdouble *y)
+{
+ unsigned int fsr;
+
+ if (QUAD_ISNAN(*x) || QUAD_ISNAN(*y)) {
+ if ((QUAD_ISNAN(*x) && !(x->l.msw & 0x8000)) ||
+ (QUAD_ISNAN(*y) && !(y->l.msw & 0x8000))) {
+ /* snan, signal invalid */
+ __quad_getfsrp(&fsr);
+ if (fsr & FSR_NVM) {
+ __quad_fcmpq(x, y, &fsr);
+ return (((fsr >> 10) & 3) != fcc_equal);
+ } else {
+ fsr = (fsr & ~FSR_CEXC) | FSR_NVA | FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ }
+ return (1); /* x != y is TRUE if x or y is NaN */
+ }
+ if (QUAD_ISZERO(*x) && QUAD_ISZERO(*y))
+ return (0);
+ return ((x->l.msw ^ y->l.msw | x->l.frac2 ^ y->l.frac2 |
+ x->l.frac3 ^ y->l.frac3 | x->l.frac4 ^ y->l.frac4) != 0);
+}
+
+/*
+ * _Q_flt(x, y) returns nonzero if *x < *y and zero otherwise. If
+ * either *x or *y is NaN, the invalid operation exception is raised.
+ */
+int
+_Q_flt(const union longdouble *x, const union longdouble *y)
+{
+ unsigned int xm, ym, fsr;
+
+ if (QUAD_ISNAN(*x) || QUAD_ISNAN(*y)) {
+ /* nan, signal invalid */
+ __quad_getfsrp(&fsr);
+ if (fsr & FSR_NVM) {
+ __quad_fcmpeq(x, y, &fsr);
+ return (((fsr >> 10) & 3) == fcc_less);
+ } else {
+ fsr = (fsr & ~FSR_CEXC) | FSR_NVA | FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ return (0);
+ }
+
+ /* ignore sign of zero */
+ xm = x->l.msw;
+ if (QUAD_ISZERO(*x))
+ xm &= 0x7fffffff;
+ ym = y->l.msw;
+ if (QUAD_ISZERO(*y))
+ ym &= 0x7fffffff;
+
+ if ((xm ^ ym) & 0x80000000) /* x and y have opposite signs */
+ return ((ym & 0x80000000) == 0);
+
+ if (xm & 0x80000000) {
+ return (xm > ym || xm == ym && (x->l.frac2 > y->l.frac2 ||
+ x->l.frac2 == y->l.frac2 && (x->l.frac3 > y->l.frac3 ||
+ x->l.frac3 == y->l.frac3 && x->l.frac4 > y->l.frac4)));
+ }
+ return (xm < ym || xm == ym && (x->l.frac2 < y->l.frac2 ||
+ x->l.frac2 == y->l.frac2 && (x->l.frac3 < y->l.frac3 ||
+ x->l.frac3 == y->l.frac3 && x->l.frac4 < y->l.frac4)));
+}
+
+/*
+ * _Q_fle(x, y) returns nonzero if *x <= *y and zero otherwise. If
+ * either *x or *y is NaN, the invalid operation exception is raised.
+ */
+int
+_Q_fle(const union longdouble *x, const union longdouble *y)
+{
+ unsigned int xm, ym, fsr;
+
+ if (QUAD_ISNAN(*x) || QUAD_ISNAN(*y)) {
+ /* nan, signal invalid */
+ __quad_getfsrp(&fsr);
+ if (fsr & FSR_NVM) {
+ __quad_fcmpeq(x, y, &fsr);
+ fsr = (fsr >> 10) & 3;
+ return (fsr == fcc_less || fsr == fcc_equal);
+ } else {
+ fsr = (fsr & ~FSR_CEXC) | FSR_NVA | FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ return (0);
+ }
+
+ /* ignore sign of zero */
+ xm = x->l.msw;
+ if (QUAD_ISZERO(*x))
+ xm &= 0x7fffffff;
+ ym = y->l.msw;
+ if (QUAD_ISZERO(*y))
+ ym &= 0x7fffffff;
+
+ if ((xm ^ ym) & 0x80000000) /* x and y have opposite signs */
+ return ((ym & 0x80000000) == 0);
+
+ if (xm & 0x80000000) {
+ return (xm > ym || xm == ym && (x->l.frac2 > y->l.frac2 ||
+ x->l.frac2 == y->l.frac2 && (x->l.frac3 > y->l.frac3 ||
+ x->l.frac3 == y->l.frac3 && x->l.frac4 >= y->l.frac4)));
+ }
+ return (xm < ym || xm == ym && (x->l.frac2 < y->l.frac2 ||
+ x->l.frac2 == y->l.frac2 && (x->l.frac3 < y->l.frac3 ||
+ x->l.frac3 == y->l.frac3 && x->l.frac4 <= y->l.frac4)));
+}
+
+/*
+ * _Q_fgt(x, y) returns nonzero if *x > *y and zero otherwise. If
+ * either *x or *y is NaN, the invalid operation exception is raised.
+ */
+int
+_Q_fgt(const union longdouble *x, const union longdouble *y)
+{
+ unsigned int xm, ym, fsr;
+
+ if (QUAD_ISNAN(*x) || QUAD_ISNAN(*y)) {
+ /* nan, signal invalid */
+ __quad_getfsrp(&fsr);
+ if (fsr & FSR_NVM) {
+ __quad_fcmpeq(x, y, &fsr);
+ return (((fsr >> 10) & 3) == fcc_greater);
+ } else {
+ fsr = (fsr & ~FSR_CEXC) | FSR_NVA | FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ return (0);
+ }
+
+ /* ignore sign of zero */
+ xm = x->l.msw;
+ if (QUAD_ISZERO(*x))
+ xm &= 0x7fffffff;
+ ym = y->l.msw;
+ if (QUAD_ISZERO(*y))
+ ym &= 0x7fffffff;
+
+ if ((xm ^ ym) & 0x80000000) /* x and y have opposite signs */
+ return ((ym & 0x80000000) != 0);
+
+ if (xm & 0x80000000) {
+ return (xm < ym || xm == ym && (x->l.frac2 < y->l.frac2 ||
+ x->l.frac2 == y->l.frac2 && (x->l.frac3 < y->l.frac3 ||
+ x->l.frac3 == y->l.frac3 && x->l.frac4 < y->l.frac4)));
+ }
+ return (xm > ym || xm == ym && (x->l.frac2 > y->l.frac2 ||
+ x->l.frac2 == y->l.frac2 && (x->l.frac3 > y->l.frac3 ||
+ x->l.frac3 == y->l.frac3 && x->l.frac4 > y->l.frac4)));
+}
+
+/*
+ * _Q_fge(x, y) returns nonzero if *x >= *y and zero otherwise. If
+ * either *x or *y is NaN, the invalid operation exception is raised.
+ */
+int
+_Q_fge(const union longdouble *x, const union longdouble *y)
+{
+ unsigned int xm, ym, fsr;
+
+ if (QUAD_ISNAN(*x) || QUAD_ISNAN(*y)) {
+ /* nan, signal invalid */
+ __quad_getfsrp(&fsr);
+ if (fsr & FSR_NVM) {
+ __quad_fcmpeq(x, y, &fsr);
+ fsr = (fsr >> 10) & 3;
+ return (fsr == fcc_greater || fsr == fcc_equal);
+ } else {
+ fsr = (fsr & ~FSR_CEXC) | FSR_NVA | FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ return (0);
+ }
+
+ /* ignore sign of zero */
+ xm = x->l.msw;
+ if (QUAD_ISZERO(*x))
+ xm &= 0x7fffffff;
+ ym = y->l.msw;
+ if (QUAD_ISZERO(*y))
+ ym &= 0x7fffffff;
+
+ if ((xm ^ ym) & 0x80000000) /* x and y have opposite signs */
+ return ((ym & 0x80000000) != 0);
+
+ if (xm & 0x80000000) {
+ return (xm < ym || xm == ym && (x->l.frac2 < y->l.frac2 ||
+ x->l.frac2 == y->l.frac2 && (x->l.frac3 < y->l.frac3 ||
+ x->l.frac3 == y->l.frac3 && x->l.frac4 <= y->l.frac4)));
+ }
+ return (xm > ym || xm == ym && (x->l.frac2 > y->l.frac2 ||
+ x->l.frac2 == y->l.frac2 && (x->l.frac3 > y->l.frac3 ||
+ x->l.frac3 == y->l.frac3 && x->l.frac4 >= y->l.frac4)));
+}
diff --git a/usr/src/lib/libc/sparc/fp/_Q_get_rp_rd.s b/usr/src/lib/libc/sparc/fp/_Q_get_rp_rd.s
new file mode 100644
index 0000000000..e62cfcdc08
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_Q_get_rp_rd.s
@@ -0,0 +1,40 @@
+/*
+ * 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"
+
+#include "synonyms.h"
+#include <sys/asm_linkage.h>
+
+ ENTRY(_QgetRD)
+ add %sp,-SA(MINFRAME),%sp
+ st %fsr,[%sp+ARGPUSH]
+ ld [%sp+ARGPUSH],%o0 ! o0 = fsr
+ srl %o0,30,%o0 ! return round control value
+ retl
+ add %sp,SA(MINFRAME),%sp
+
+ SET_SIZE(_QgetRD)
diff --git a/usr/src/lib/libc/sparc/fp/_Q_itoq.c b/usr/src/lib/libc/sparc/fp/_Q_itoq.c
new file mode 100644
index 0000000000..766faac4dc
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_Q_itoq.c
@@ -0,0 +1,85 @@
+/*
+ * 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) 1994-1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "quad.h"
+
+#ifdef __sparcv9
+
+/*
+ * _Qp_itoq(pz, x) sets *pz = (long double)x.
+ */
+void
+_Qp_itoq(union longdouble *pz, int x)
+
+#else
+
+/*
+ * _Q_itoq(x) returns (long double)x.
+ */
+union longdouble
+_Q_itoq(int x)
+
+#endif /* __sparcv9 */
+
+{
+#ifndef __sparcv9
+ union longdouble z;
+#endif
+ unsigned int s, e;
+
+ /* extract the sign */
+ s = 0;
+ if (x < 0) {
+ if ((unsigned) x == 0x80000000) {
+ /* largest negative int */
+ Z.l.msw = 0xc01e0000;
+ Z.l.frac2 = Z.l.frac3 = Z.l.frac4 = 0;
+ QUAD_RETURN(Z);
+ }
+ x = -x;
+ s = 0x80000000;
+ } else if (x == 0) {
+ Z.l.msw = Z.l.frac2 = Z.l.frac3 = Z.l.frac4 = 0;
+ QUAD_RETURN(Z);
+ }
+
+ /* find the most significant bit */
+ for (e = 30; (x & (1 << e)) == 0; e--)
+ ;
+
+ if (e > 16) {
+ Z.l.msw = ((unsigned) x >> (e - 16)) & 0xffff;
+ Z.l.frac2 = (unsigned) x << (48 - e);
+ } else {
+ Z.l.msw = ((unsigned) x << (16 - e)) & 0xffff;
+ Z.l.frac2 = 0;
+ }
+ Z.l.frac3 = Z.l.frac4 = 0;
+ Z.l.msw |= s | ((e + 0x3fff) << 16);
+ QUAD_RETURN(Z);
+}
diff --git a/usr/src/lib/libc/sparc/fp/_Q_lltoq.c b/usr/src/lib/libc/sparc/fp/_Q_lltoq.c
new file mode 100644
index 0000000000..edc0eecd25
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_Q_lltoq.c
@@ -0,0 +1,75 @@
+/*
+ * 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) 1994-1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "quad.h"
+
+/*
+ * _Q_lltoq(x) returns (long double)x.
+ */
+union longdouble
+_Q_lltoq(long long x)
+{
+ union longdouble z;
+ unsigned int s, e;
+
+ /* extract the sign */
+ s = 0;
+ if (x < 0) {
+ if ((unsigned long long) x == 0x8000000000000000ull) {
+ /* largest negative 64 bit int */
+ Z.l.msw = 0xc03e0000;
+ Z.l.frac2 = Z.l.frac3 = Z.l.frac4 = 0;
+ QUAD_RETURN(Z);
+ }
+ x = -x;
+ s = 0x80000000;
+ } else if (x == 0) {
+ Z.l.msw = Z.l.frac2 = Z.l.frac3 = Z.l.frac4 = 0;
+ QUAD_RETURN(Z);
+ }
+
+ /* find the most significant bit */
+ for (e = 62; (x & (1ll << e)) == 0; e--)
+ ;
+
+ if (e > 48) {
+ Z.l.msw = ((unsigned long long) x >> (e - 16)) & 0xffff;
+ Z.l.frac2 = (unsigned long long) x >> (e - 48);
+ Z.l.frac3 = (unsigned long long) x << (80 - e);
+ } else if (e > 16) {
+ Z.l.msw = ((unsigned long long) x >> (e - 16)) & 0xffff;
+ Z.l.frac2 = (unsigned long long) x << (48 - e);
+ Z.l.frac3 = 0;
+ } else {
+ Z.l.msw = ((unsigned long long) x << (16 - e)) & 0xffff;
+ Z.l.frac2 = Z.l.frac3 = 0;
+ }
+ Z.l.frac4 = 0;
+ Z.l.msw |= s | ((e + 0x3fff) << 16);
+ QUAD_RETURN(Z);
+}
diff --git a/usr/src/lib/libc/sparc/fp/_Q_mul.c b/usr/src/lib/libc/sparc/fp/_Q_mul.c
new file mode 100644
index 0000000000..37cd211c19
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_Q_mul.c
@@ -0,0 +1,462 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "quad.h"
+
+static const double C[] = {
+ 0.0,
+ 0.5,
+ 1.0,
+ 2.0,
+ 68719476736.0,
+ 1048576.0,
+ 16.0,
+ 1.52587890625000000000e-05,
+ 5.96046447753906250000e-08,
+ 3.72529029846191406250e-09,
+ 8.67361737988403547206e-19,
+ 2.16840434497100886801e-19,
+ 1.32348898008484427979e-23,
+ 9.62964972193617926528e-35,
+ 4.70197740328915003187e-38
+};
+
+#define zero C[0]
+#define half C[1]
+#define one C[2]
+#define two C[3]
+#define two36 C[4]
+#define two20 C[5]
+#define two4 C[6]
+#define twom16 C[7]
+#define twom24 C[8]
+#define twom28 C[9]
+#define twom60 C[10]
+#define twom62 C[11]
+#define twom76 C[12]
+#define twom113 C[13]
+#define twom124 C[14]
+
+static const unsigned fsr_rn = 0xc0000000u;
+
+#ifdef __sparcv9
+
+/*
+ * _Qp_mul(pz, x, y) sets *pz = *x * *y.
+ */
+void
+_Qp_mul(union longdouble *pz, const union longdouble *x,
+ const union longdouble *y)
+
+#else
+
+/*
+ * _Q_mul(x, y) returns *x * *y.
+ */
+union longdouble
+_Q_mul(const union longdouble *x, const union longdouble *y)
+
+#endif /* __sparcv9 */
+
+{
+ union longdouble z;
+ union xdouble u;
+ double xx[5], yy[5], c, d, zz[9];
+ unsigned int xm, ym, fsr, lx, ly, wx[3], wy[3];
+ unsigned int msw, frac2, frac3, frac4, rm;
+ int ibit, ex, ey, ez, sign;
+
+ xm = x->l.msw & 0x7fffffff;
+ ym = y->l.msw & 0x7fffffff;
+ sign = (x->l.msw ^ y->l.msw) & ~0x7fffffff;
+
+ __quad_getfsrp(&fsr);
+
+ /* handle nan and inf cases */
+ if (xm >= 0x7fff0000 || ym >= 0x7fff0000) {
+ /* handle nan cases according to V9 app. B */
+ if (QUAD_ISNAN(*y)) {
+ if (!(y->l.msw & 0x8000)) {
+ /* snan, signal invalid */
+ if (fsr & FSR_NVM) {
+ __quad_fmulq(x, y, &Z);
+ } else {
+ Z = *y;
+ Z.l.msw |= 0x8000;
+ fsr = (fsr & ~FSR_CEXC) | FSR_NVA |
+ FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ QUAD_RETURN(Z);
+ } else if (QUAD_ISNAN(*x) && !(x->l.msw & 0x8000)) {
+ /* snan, signal invalid */
+ if (fsr & FSR_NVM) {
+ __quad_fmulq(x, y, &Z);
+ } else {
+ Z = *x;
+ Z.l.msw |= 0x8000;
+ fsr = (fsr & ~FSR_CEXC) | FSR_NVA |
+ FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ QUAD_RETURN(Z);
+ }
+ Z = *y;
+ QUAD_RETURN(Z);
+ }
+ if (QUAD_ISNAN(*x)) {
+ if (!(x->l.msw & 0x8000)) {
+ /* snan, signal invalid */
+ if (fsr & FSR_NVM) {
+ __quad_fmulq(x, y, &Z);
+ } else {
+ Z = *x;
+ Z.l.msw |= 0x8000;
+ fsr = (fsr & ~FSR_CEXC) | FSR_NVA |
+ FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ QUAD_RETURN(Z);
+ }
+ Z = *x;
+ QUAD_RETURN(Z);
+ }
+ if (xm == 0x7fff0000) {
+ /* x is inf */
+ if (QUAD_ISZERO(*y)) {
+ /* zero * inf, signal invalid */
+ if (fsr & FSR_NVM) {
+ __quad_fmulq(x, y, &Z);
+ } else {
+ Z.l.msw = 0x7fffffff;
+ Z.l.frac2 = Z.l.frac3 =
+ Z.l.frac4 = 0xffffffff;
+ fsr = (fsr & ~FSR_CEXC) | FSR_NVA |
+ FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ QUAD_RETURN(Z);
+ }
+ /* inf * finite, return inf */
+ Z.l.msw = sign | 0x7fff0000;
+ Z.l.frac2 = Z.l.frac3 = Z.l.frac4 = 0;
+ QUAD_RETURN(Z);
+ }
+ /* y is inf */
+ if (QUAD_ISZERO(*x)) {
+ /* zero * inf, signal invalid */
+ if (fsr & FSR_NVM) {
+ __quad_fmulq(x, y, &Z);
+ } else {
+ Z.l.msw = 0x7fffffff;
+ Z.l.frac2 = Z.l.frac3 = Z.l.frac4 = 0xffffffff;
+ fsr = (fsr & ~FSR_CEXC) | FSR_NVA | FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ QUAD_RETURN(Z);
+ }
+ /* inf * finite, return inf */
+ Z.l.msw = sign | 0x7fff0000;
+ Z.l.frac2 = Z.l.frac3 = Z.l.frac4 = 0;
+ QUAD_RETURN(Z);
+ }
+
+ /* handle zero cases */
+ if (xm == 0 || ym == 0) {
+ if (QUAD_ISZERO(*x) || QUAD_ISZERO(*y)) {
+ Z.l.msw = sign;
+ Z.l.frac2 = Z.l.frac3 = Z.l.frac4 = 0;
+ QUAD_RETURN(Z);
+ }
+ }
+
+ /* now x and y are finite, nonzero */
+ __quad_setfsrp(&fsr_rn);
+
+ /* get their normalized significands and exponents */
+ ex = (int)(xm >> 16);
+ lx = xm & 0xffff;
+ if (ex) {
+ lx |= 0x10000;
+ wx[0] = x->l.frac2;
+ wx[1] = x->l.frac3;
+ wx[2] = x->l.frac4;
+ } else {
+ if (lx | (x->l.frac2 & 0xfffe0000)) {
+ wx[0] = x->l.frac2;
+ wx[1] = x->l.frac3;
+ wx[2] = x->l.frac4;
+ ex = 1;
+ } else if (x->l.frac2 | (x->l.frac3 & 0xfffe0000)) {
+ lx = x->l.frac2;
+ wx[0] = x->l.frac3;
+ wx[1] = x->l.frac4;
+ wx[2] = 0;
+ ex = -31;
+ } else if (x->l.frac3 | (x->l.frac4 & 0xfffe0000)) {
+ lx = x->l.frac3;
+ wx[0] = x->l.frac4;
+ wx[1] = wx[2] = 0;
+ ex = -63;
+ } else {
+ lx = x->l.frac4;
+ wx[0] = wx[1] = wx[2] = 0;
+ ex = -95;
+ }
+ while ((lx & 0x10000) == 0) {
+ lx = (lx << 1) | (wx[0] >> 31);
+ wx[0] = (wx[0] << 1) | (wx[1] >> 31);
+ wx[1] = (wx[1] << 1) | (wx[2] >> 31);
+ wx[2] <<= 1;
+ ex--;
+ }
+ }
+ ez = ex - 0x3fff;
+
+ ey = (int)(ym >> 16);
+ ly = ym & 0xffff;
+ if (ey) {
+ ly |= 0x10000;
+ wy[0] = y->l.frac2;
+ wy[1] = y->l.frac3;
+ wy[2] = y->l.frac4;
+ } else {
+ if (ly | (y->l.frac2 & 0xfffe0000)) {
+ wy[0] = y->l.frac2;
+ wy[1] = y->l.frac3;
+ wy[2] = y->l.frac4;
+ ey = 1;
+ } else if (y->l.frac2 | (y->l.frac3 & 0xfffe0000)) {
+ ly = y->l.frac2;
+ wy[0] = y->l.frac3;
+ wy[1] = y->l.frac4;
+ wy[2] = 0;
+ ey = -31;
+ } else if (y->l.frac3 | (y->l.frac4 & 0xfffe0000)) {
+ ly = y->l.frac3;
+ wy[0] = y->l.frac4;
+ wy[1] = wy[2] = 0;
+ ey = -63;
+ } else {
+ ly = y->l.frac4;
+ wy[0] = wy[1] = wy[2] = 0;
+ ey = -95;
+ }
+ while ((ly & 0x10000) == 0) {
+ ly = (ly << 1) | (wy[0] >> 31);
+ wy[0] = (wy[0] << 1) | (wy[1] >> 31);
+ wy[1] = (wy[1] << 1) | (wy[2] >> 31);
+ wy[2] <<= 1;
+ ey--;
+ }
+ }
+ ez += ey;
+
+ /* extract the significand into five doubles */
+ c = twom16;
+ xx[0] = (double)((int)lx) * c;
+ yy[0] = (double)((int)ly) * c;
+
+ c *= twom24;
+ xx[1] = (double)((int)(wx[0] >> 8)) * c;
+ yy[1] = (double)((int)(wy[0] >> 8)) * c;
+
+ c *= twom24;
+ xx[2] = (double)((int)(((wx[0] << 16) | (wx[1] >> 16)) &
+ 0xffffff)) * c;
+ yy[2] = (double)((int)(((wy[0] << 16) | (wy[1] >> 16)) &
+ 0xffffff)) * c;
+
+ c *= twom24;
+ xx[3] = (double)((int)(((wx[1] << 8) | (wx[2] >> 24)) &
+ 0xffffff)) * c;
+ yy[3] = (double)((int)(((wy[1] << 8) | (wy[2] >> 24)) &
+ 0xffffff)) * c;
+
+ c *= twom24;
+ xx[4] = (double)((int)(wx[2] & 0xffffff)) * c;
+ yy[4] = (double)((int)(wy[2] & 0xffffff)) * c;
+
+ /* form the "digits" of the product */
+ zz[0] = xx[0] * yy[0];
+ zz[1] = xx[0] * yy[1] + xx[1] * yy[0];
+ zz[2] = xx[0] * yy[2] + xx[1] * yy[1] + xx[2] * yy[0];
+ zz[3] = xx[0] * yy[3] + xx[1] * yy[2] + xx[2] * yy[1] +
+ xx[3] * yy[0];
+ zz[4] = xx[0] * yy[4] + xx[1] * yy[3] + xx[2] * yy[2] +
+ xx[3] * yy[1] + xx[4] * yy[0];
+ zz[5] = xx[1] * yy[4] + xx[2] * yy[3] + xx[3] * yy[2] +
+ xx[4] * yy[1];
+ zz[6] = xx[2] * yy[4] + xx[3] * yy[3] + xx[4] * yy[2];
+ zz[7] = xx[3] * yy[4] + xx[4] * yy[3];
+ zz[8] = xx[4] * yy[4];
+
+ /* collect the first few terms */
+ c = (zz[1] + two20) - two20;
+ zz[0] += c;
+ zz[1] = zz[2] + (zz[1] - c);
+ c = (zz[3] + twom28) - twom28;
+ zz[1] += c;
+ zz[2] = zz[4] + (zz[3] - c);
+
+ /* propagate carries into the third term */
+ d = zz[6] + (zz[7] + zz[8]);
+ zz[2] += zz[5] + d;
+
+ /* if the third term might lie on a rounding boundary, perturb it */
+ /* as need be */
+ if (zz[2] == (twom62 + zz[2]) - twom62)
+ {
+ c = (zz[5] + twom76) - twom76;
+ if ((zz[5] - c) + d != zero)
+ zz[2] += twom124;
+ }
+
+ /* propagate carries to the leading term */
+ c = zz[1] + zz[2];
+ zz[2] = zz[2] + (zz[1] - c);
+ zz[1] = c;
+ c = zz[0] + zz[1];
+ zz[1] = zz[1] + (zz[0] - c);
+ zz[0] = c;
+
+ /* check for carry out */
+ if (c >= two) {
+ /* postnormalize */
+ zz[0] *= half;
+ zz[1] *= half;
+ zz[2] *= half;
+ ez++;
+ }
+
+ /* if exponent > 0 strip off integer bit, else denormalize */
+ if (ez > 0) {
+ ibit = 1;
+ zz[0] -= one;
+ } else {
+ ibit = 0;
+ if (ez > -128)
+ u.l.hi = (unsigned)(0x3fe + ez) << 20;
+ else
+ u.l.hi = 0x37e00000;
+ u.l.lo = 0;
+ zz[0] *= u.d;
+ zz[1] *= u.d;
+ zz[2] *= u.d;
+ ez = 0;
+ }
+
+ /* the first 48 bits of fraction come from zz[0] */
+ u.d = d = two36 + zz[0];
+ msw = u.l.lo;
+ zz[0] -= (d - two36);
+
+ u.d = d = two4 + zz[0];
+ frac2 = u.l.lo;
+ zz[0] -= (d - two4);
+
+ /* the next 32 come from zz[0] and zz[1] */
+ u.d = d = twom28 + (zz[0] + zz[1]);
+ frac3 = u.l.lo;
+ zz[0] -= (d - twom28);
+
+ /* condense the remaining fraction; errors here won't matter */
+ c = zz[0] + zz[1];
+ zz[1] = ((zz[0] - c) + zz[1]) + zz[2];
+ zz[0] = c;
+
+ /* get the last word of fraction */
+ u.d = d = twom60 + (zz[0] + zz[1]);
+ frac4 = u.l.lo;
+ zz[0] -= (d - twom60);
+
+ /* keep track of what's left for rounding; note that the error */
+ /* in computing c will be non-negative due to rounding mode */
+ c = zz[0] + zz[1];
+
+ /* get the rounding mode, fudging directed rounding modes */
+ /* as though the result were positive */
+ rm = fsr >> 30;
+ if (sign)
+ rm ^= (rm >> 1);
+
+ /* round and raise exceptions */
+ fsr &= ~FSR_CEXC;
+ if (c != zero) {
+ fsr |= FSR_NXC;
+
+ /* decide whether to round the fraction up */
+ if (rm == FSR_RP || (rm == FSR_RN && (c > twom113 ||
+ (c == twom113 && ((frac4 & 1) || (c - zz[0] != zz[1])))))) {
+ /* round up and renormalize if necessary */
+ if (++frac4 == 0)
+ if (++frac3 == 0)
+ if (++frac2 == 0)
+ if (++msw == 0x10000) {
+ msw = 0;
+ ez++;
+ }
+ }
+ }
+
+ /* check for under/overflow */
+ if (ez >= 0x7fff) {
+ if (rm == FSR_RN || rm == FSR_RP) {
+ z.l.msw = sign | 0x7fff0000;
+ z.l.frac2 = z.l.frac3 = z.l.frac4 = 0;
+ } else {
+ z.l.msw = sign | 0x7ffeffff;
+ z.l.frac2 = z.l.frac3 = z.l.frac4 = 0xffffffff;
+ }
+ fsr |= FSR_OFC | FSR_NXC;
+ } else {
+ z.l.msw = sign | (ez << 16) | msw;
+ z.l.frac2 = frac2;
+ z.l.frac3 = frac3;
+ z.l.frac4 = frac4;
+
+ /* !ibit => exact result was tiny before rounding, */
+ /* t nonzero => result delivered is inexact */
+ if (!ibit) {
+ if (c != zero)
+ fsr |= FSR_UFC | FSR_NXC;
+ else if (fsr & FSR_UFM)
+ fsr |= FSR_UFC;
+ }
+ }
+
+ if ((fsr & FSR_CEXC) & (fsr >> 23)) {
+ __quad_setfsrp(&fsr);
+ __quad_fmulq(x, y, &Z);
+ } else {
+ Z = z;
+ fsr |= (fsr & 0x1f) << 5;
+ __quad_setfsrp(&fsr);
+ }
+ QUAD_RETURN(Z);
+}
diff --git a/usr/src/lib/libc/sparc/fp/_Q_neg.c b/usr/src/lib/libc/sparc/fp/_Q_neg.c
new file mode 100644
index 0000000000..cd1a532fcd
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_Q_neg.c
@@ -0,0 +1,59 @@
+/*
+ * 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) 1994-1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "quad.h"
+
+#ifdef __sparcv9
+
+/*
+ * _Qp_neg(pz, x) sets *pz = -*x.
+ */
+void
+_Qp_neg(union longdouble *pz, const union longdouble *x)
+
+#else
+
+/*
+ * _Q_neg(x) returns -*x.
+ */
+union longdouble
+_Q_neg(const union longdouble *x)
+
+#endif /* __sparcv9 */
+
+{
+#ifndef __sparcv9
+ union longdouble z;
+#endif
+
+ Z.l.msw = x->l.msw ^ 0x80000000;
+ Z.l.frac2 = x->l.frac2;
+ Z.l.frac3 = x->l.frac3;
+ Z.l.frac4 = x->l.frac4;
+ QUAD_RETURN(Z);
+}
diff --git a/usr/src/lib/libc/sparc/fp/_Q_qtod.c b/usr/src/lib/libc/sparc/fp/_Q_qtod.c
new file mode 100644
index 0000000000..4fab1e683e
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_Q_qtod.c
@@ -0,0 +1,182 @@
+/*
+ * 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) 1994-1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "quad.h"
+
+#ifdef __sparcv9
+#define _Q_qtod _Qp_qtod
+#endif
+
+/*
+ * _Q_qtod(x) returns (double)*x.
+ */
+double
+_Q_qtod(const union longdouble *x)
+{
+ union xdouble u;
+ unsigned int xm, round, sticky, fsr, rm;
+ int subnormal, e;
+
+ xm = x->l.msw & 0x7fffffff;
+
+ /* get the rounding mode, fudging directed rounding modes */
+ /* as though the result were positive */
+ __quad_getfsrp(&fsr);
+ rm = fsr >> 30;
+ if (x->l.msw & 0x80000000)
+ rm ^= (rm >> 1);
+
+ /* handle nan, inf, and out-of-range cases */
+ if (xm >= 0x43ff0000) {
+ if (xm >= 0x7fff0000) {
+ if ((xm & 0xffff) | x->l.frac2 | x->l.frac3 |
+ x->l.frac4) {
+ /* x is nan */
+ u.l.hi = (x->l.msw & 0x80000000) | 0x7ff80000;
+ u.l.hi |= ((xm & 0x7fff) << 4) |
+ (x->l.frac2 >> 28);
+ u.l.lo = (x->l.frac2 << 4) |
+ (x->l.frac3 >> 28);
+ if (!(xm & 0x8000)) {
+ /* snan, signal invalid */
+ if (fsr & FSR_NVM) {
+ __quad_fqtod(x, &u.d);
+ } else {
+ fsr = (fsr & ~FSR_CEXC) |
+ FSR_NVA | FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ }
+ return (u.d);
+ }
+ /* x is inf */
+ u.l.hi = (x->l.msw & 0x80000000) | 0x7ff00000;
+ u.l.lo = 0;
+ return (u.d);
+ }
+ /* x is too big, overflow */
+ if (rm == FSR_RN || rm == FSR_RP) {
+ u.l.hi = 0x7ff00000;
+ u.l.lo = 0;
+ } else {
+ u.l.hi = 0x7fefffff;
+ u.l.lo = 0xffffffff;
+ }
+ u.l.hi |= (x->l.msw & 0x80000000);
+ if (fsr & (FSR_OFM | FSR_NXM)) {
+ __quad_fqtod(x, &u.d);
+ } else {
+ fsr = (fsr & ~FSR_CEXC) | FSR_OFA | FSR_OFC |
+ FSR_NXA | FSR_NXC;
+ __quad_setfsrp(&fsr);
+ }
+ return (u.d);
+ }
+
+ subnormal = 0;
+ if (xm < 0x3c010000) {
+ if (xm < 0x3bcc0000) {
+ if (QUAD_ISZERO(*x)) {
+ u.l.hi = (x->l.msw & 0x80000000);
+ u.l.lo = 0;
+ return (u.d);
+ }
+ /* x is too small, underflow */
+ u.l.hi = (x->l.msw & 0x80000000);
+ u.l.lo = ((rm == FSR_RP)? 1 : 0);
+ if (fsr & (FSR_UFM | FSR_NXM)) {
+ __quad_fqtod(x, &u.d);
+ } else {
+ fsr = (fsr & ~FSR_CEXC) | FSR_UFA | FSR_UFC |
+ FSR_NXA | FSR_NXC;
+ __quad_setfsrp(&fsr);
+ }
+ return (u.d);
+ }
+
+ /* x is in the subnormal range for double */
+ subnormal = 1;
+ u.l.hi = 0x80000 | ((xm & 0xffff) << 3) | (x->l.frac2 >> 29);
+ u.l.lo = (x->l.frac2 << 3) | (x->l.frac3 >> 29);
+ round = x->l.frac3 & 0x10000000;
+ sticky = (x->l.frac3 & 0xfffffff) | x->l.frac4;
+ e = 0x3c00 - (xm >> 16);
+ if (e >= 32) {
+ sticky |= round | (u.l.lo & 0x7fffffff);
+ round = u.l.lo & 0x80000000;
+ u.l.lo = u.l.hi;
+ u.l.hi = 0;
+ e -= 32;
+ }
+ if (e) {
+ sticky |= round | (u.l.lo & ((1 << (e - 1)) - 1));
+ round = u.l.lo & (1 << (e - 1));
+ u.l.lo = (u.l.lo >> e) | (u.l.hi << (32 - e));
+ u.l.hi >>= e;
+ }
+ } else {
+ /* x is in the normal range for double */
+ u.l.hi = ((xm - 0x3c000000) << 4) | (x->l.frac2 >> 28);
+ u.l.lo = (x->l.frac2 << 4) | (x->l.frac3 >> 28);
+ round = x->l.frac3 & 0x8000000;
+ sticky = (x->l.frac3 & 0x7ffffff) | x->l.frac4;
+ }
+
+ /* see if we need to round */
+ fsr &= ~FSR_CEXC;
+ if (round | sticky) {
+ fsr |= FSR_NXC;
+ if (subnormal)
+ fsr |= FSR_UFC;
+
+ /* round up if necessary */
+ if (rm == FSR_RP || (rm == FSR_RN && round && (sticky ||
+ (u.l.lo & 1)))) {
+ /* round up and check for overflow */
+ if (++u.l.lo == 0)
+ if (++u.l.hi >= 0x7ff00000)
+ fsr |= FSR_OFC;
+ }
+ }
+
+ /* if result is exact and subnormal but underflow trapping is */
+ /* enabled, signal underflow */
+ else if (subnormal && (fsr & FSR_UFM))
+ fsr |= FSR_UFC;
+
+ /* attach the sign and raise exceptions as need be */
+ u.l.hi |= (x->l.msw & 0x80000000);
+ if ((fsr & FSR_CEXC) & (fsr >> 23)) {
+ __quad_setfsrp(&fsr);
+ __quad_fqtod(x, &u.d);
+ } else {
+ fsr |= (fsr & 0x1f) << 5;
+ __quad_setfsrp(&fsr);
+ }
+ return (u.d);
+}
diff --git a/usr/src/lib/libc/sparc/fp/_Q_qtoi.c b/usr/src/lib/libc/sparc/fp/_Q_qtoi.c
new file mode 100644
index 0000000000..15c73931d9
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_Q_qtoi.c
@@ -0,0 +1,104 @@
+/*
+ * 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) 1994-1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "quad.h"
+
+#ifdef __sparcv9
+#define _Q_qtoi _Qp_qtoi
+#endif
+
+/*
+ * _Q_qtoi(x) returns (int)*x.
+ */
+int
+_Q_qtoi(const union longdouble *x)
+{
+ unsigned int xm, fsr;
+ int i, round;
+
+ xm = x->l.msw & 0x7fffffff;
+
+ __quad_getfsrp(&fsr);
+
+ /* handle nan, inf, and out-of-range cases */
+ if (xm >= 0x401e0000) {
+ if (x->l.msw == 0xc01e0000 && (x->l.frac2 & 0xfffe0000) == 0) {
+ /* return largest negative int */
+ i = 0x80000000;
+ if ((x->l.frac2 & 0x1ffff) | x->l.frac3 | x->l.frac4) {
+ /* signal inexact */
+ if (fsr & FSR_NXM) {
+ __quad_fqtoi(x, &i);
+ } else {
+ fsr = (fsr & ~FSR_CEXC) | FSR_NXA |
+ FSR_NXC;
+ __quad_setfsrp(&fsr);
+ }
+ }
+ return (i);
+ }
+ i = ((x->l.msw & 0x80000000)? 0x80000000 : 0x7fffffff);
+ if (fsr & FSR_NVM) {
+ __quad_fqtoi(x, &i);
+ } else {
+ fsr = (fsr & ~FSR_CEXC) | FSR_NVA | FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ return (i);
+ }
+ if (xm < 0x3fff0000) {
+ i = 0;
+ if (xm | x->l.frac2 | x->l.frac3 | x->l.frac4) {
+ /* signal inexact */
+ if (fsr & FSR_NXM) {
+ __quad_fqtoi(x, &i);
+ } else {
+ fsr = (fsr & ~FSR_CEXC) | FSR_NXA | FSR_NXC;
+ __quad_setfsrp(&fsr);
+ }
+ }
+ return (i);
+ }
+
+ /* now x is in the range of int */
+ i = (int) (0x40000000 | ((xm & 0xffff) << 14) | (x->l.frac2 >> 18));
+ round = i & ((1 << (0x401d - (xm >> 16))) - 1);
+ i >>= (0x401d - (xm >> 16));
+ if (x->l.msw & 0x80000000)
+ i = -i;
+ if (round | (x->l.frac2 & 0x3ffff) | x->l.frac3 | x->l.frac4) {
+ /* signal inexact */
+ if (fsr & FSR_NXM) {
+ __quad_fqtoi(x, &i);
+ } else {
+ fsr = (fsr & ~FSR_CEXC) | FSR_NXA | FSR_NXC;
+ __quad_setfsrp(&fsr);
+ }
+ }
+ return (i);
+}
diff --git a/usr/src/lib/libc/sparc/fp/_Q_qtos.c b/usr/src/lib/libc/sparc/fp/_Q_qtos.c
new file mode 100644
index 0000000000..02bee09dc2
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_Q_qtos.c
@@ -0,0 +1,164 @@
+/*
+ * 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) 1994-1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "quad.h"
+
+#ifdef __sparcv9
+#define _Q_qtos _Qp_qtos
+#endif
+
+/*
+ * _Q_qtos(x) returns (float)*x.
+ */
+float
+_Q_qtos(const union longdouble *x)
+{
+ union {
+ float f;
+ unsigned int l;
+ } u;
+ unsigned int xm, round, sticky, fsr, rm;
+ int subnormal, e;
+
+ xm = x->l.msw & 0x7fffffff;
+
+ /* get the rounding mode, fudging directed rounding modes */
+ /* as though the result were positive */
+ __quad_getfsrp(&fsr);
+ rm = fsr >> 30;
+ if (x->l.msw & 0x80000000)
+ rm ^= (rm >> 1);
+
+ /* handle nan, inf, and out-of-range cases */
+ if (xm >= 0x407f0000) {
+ if (xm >= 0x7fff0000) {
+ if ((xm & 0xffff) | x->l.frac2 | x->l.frac3 |
+ x->l.frac4) {
+ /* x is nan */
+ u.l = (x->l.msw & 0x80000000) | 0x7fc00000;
+ u.l |= ((xm & 0x7fff) << 7) |
+ (x->l.frac2 >> 25);
+ if (!(xm & 0x8000)) {
+ /* snan, signal invalid */
+ if (fsr & FSR_NVM) {
+ __quad_fqtos(x, &u.f);
+ } else {
+ fsr = (fsr & ~FSR_CEXC) |
+ FSR_NVA | FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ }
+ return (u.f);
+ }
+ /* x is inf */
+ u.l = (x->l.msw & 0x80000000) | 0x7f800000;
+ return (u.f);
+ }
+ /* x is too big, overflow */
+ if (rm == FSR_RN || rm == FSR_RP)
+ u.l = 0x7f800000;
+ else
+ u.l = 0x7f7fffff;
+ u.l |= (x->l.msw & 0x80000000);
+ if (fsr & (FSR_OFM | FSR_NXM)) {
+ __quad_fqtos(x, &u.f);
+ } else {
+ fsr = (fsr & ~FSR_CEXC) | FSR_OFA | FSR_OFC |
+ FSR_NXA | FSR_NXC;
+ __quad_setfsrp(&fsr);
+ }
+ return (u.f);
+ }
+
+ subnormal = 0;
+ if (xm < 0x3f810000) {
+ if (xm < 0x3f690000) {
+ if (QUAD_ISZERO(*x)) {
+ u.l = (x->l.msw & 0x80000000);
+ return (u.f);
+ }
+ /* x is too small, underflow */
+ u.l = ((rm == FSR_RP)? 1 : 0);
+ u.l |= (x->l.msw & 0x80000000);
+ if (fsr & (FSR_UFM | FSR_NXM)) {
+ __quad_fqtos(x, &u.f);
+ } else {
+ fsr = (fsr & ~FSR_CEXC) | FSR_UFA | FSR_UFC |
+ FSR_NXA | FSR_NXC;
+ __quad_setfsrp(&fsr);
+ }
+ return (u.f);
+ }
+
+ /* x is in the subnormal range for single */
+ subnormal = 1;
+ u.l = 0x800000 | ((xm & 0xffff) << 7) | (x->l.frac2 >> 25);
+ e = 0x3f80 - (xm >> 16);
+ round = u.l & (1 << e);
+ sticky = (u.l & ((1 << e) - 1)) | (x->l.frac2 & 0x1ffffff) |
+ x->l.frac3 | x->l.frac4;
+ u.l >>= e + 1;
+ } else {
+ /* x is in the normal range for single */
+ u.l = ((xm - 0x3f800000) << 7) | (x->l.frac2 >> 25);
+ round = x->l.frac2 & 0x1000000;
+ sticky = (x->l.frac2 & 0xffffff) | x->l.frac3 | x->l.frac4;
+ }
+
+ /* see if we need to round */
+ fsr &= ~FSR_CEXC;
+ if (round | sticky) {
+ fsr |= FSR_NXC;
+ if (subnormal)
+ fsr |= FSR_UFC;
+
+ /* round up if necessary */
+ if (rm == FSR_RP || (rm == FSR_RN && round && (sticky ||
+ (u.l & 1)))) {
+ /* round up and check for overflow */
+ if (++u.l >= 0x7f800000)
+ fsr |= FSR_OFC;
+ }
+ }
+
+ /* if result is exact and subnormal but underflow trapping is */
+ /* enabled, signal underflow */
+ else if (subnormal && (fsr & FSR_UFM))
+ fsr |= FSR_UFC;
+
+ /* attach the sign and raise exceptions as need be */
+ u.l |= (x->l.msw & 0x80000000);
+ if ((fsr & FSR_CEXC) & (fsr >> 23)) {
+ __quad_setfsrp(&fsr);
+ __quad_fqtos(x, &u.f);
+ } else {
+ fsr |= (fsr & 0x1f) << 5;
+ __quad_setfsrp(&fsr);
+ }
+ return (u.f);
+}
diff --git a/usr/src/lib/libc/sparc/fp/_Q_qtou.c b/usr/src/lib/libc/sparc/fp/_Q_qtou.c
new file mode 100644
index 0000000000..4c24d62ad0
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_Q_qtou.c
@@ -0,0 +1,157 @@
+/*
+ * 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) 1994-1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "quad.h"
+
+#ifdef __sparcv9
+#define _Q_qtou _Qp_qtoui
+#endif
+
+/*
+ * _Q_qtou(x) returns (unsigned int)*x.
+ */
+unsigned
+_Q_qtou(const union longdouble *x)
+{
+ union longdouble z;
+ unsigned int xm, fsr;
+ int i, round;
+
+ xm = x->l.msw & 0x7fffffff;
+
+ __quad_getfsrp(&fsr);
+
+ /* handle nan, inf, and out-of-range cases */
+ if (xm >= 0x401e0000) {
+ if (x->l.msw < 0x401f0000) {
+ i = 0x80000000 | ((xm & 0xffff) << 15) |
+ (x->l.frac2 >> 17);
+ if ((x->l.frac2 & 0x1ffff) | x->l.frac3 | x->l.frac4) {
+ /* signal inexact */
+ if (fsr & FSR_NXM) {
+ /* z = x - 2^31 */
+ if (xm & 0xffff ||
+ x->l.frac2 & 0xffff0000) {
+ z.l.msw = xm & 0xffff;
+ z.l.frac2 = x->l.frac2;
+ z.l.frac3 = x->l.frac3;
+ z.l.frac4 = x->l.frac4;
+ } else if (x->l.frac2 & 0xffff ||
+ x->l.frac3 & 0xffff0000) {
+ z.l.msw = x->l.frac2;
+ z.l.frac2 = x->l.frac3;
+ z.l.frac3 = x->l.frac4;
+ z.l.frac4 = 0;
+ } else if (x->l.frac3 & 0xffff ||
+ x->l.frac4 & 0xffff0000) {
+ z.l.msw = x->l.frac3;
+ z.l.frac2 = x->l.frac4;
+ z.l.frac3 = z.l.frac4 = 0;
+ } else {
+ z.l.msw = x->l.frac4;
+ z.l.frac2 = z.l.frac3 =
+ z.l.frac4 = 0;
+ }
+ xm = 0x401e;
+ while ((z.l.msw & 0x10000) == 0) {
+ z.l.msw = (z.l.msw << 1) |
+ (z.l.frac2 >> 31);
+ z.l.frac2 = (z.l.frac2 << 1) |
+ (z.l.frac3 >> 31);
+ z.l.frac3 = (z.l.frac3 << 1) |
+ (z.l.frac4 >> 31);
+ z.l.frac4 <<= 1;
+ xm--;
+ }
+ z.l.msw |= (xm << 16);
+ __quad_fqtoi(&z, &i);
+ i |= 0x80000000;
+ } else {
+ fsr = (fsr & ~FSR_CEXC) | FSR_NXA |
+ FSR_NXC;
+ __quad_setfsrp(&fsr);
+ }
+ }
+ return (i);
+ }
+ if (x->l.msw == 0xc01e0000 && (x->l.frac2 & 0xfffe0000) == 0) {
+ /* return largest negative int */
+ i = 0x80000000;
+ if ((x->l.frac2 & 0x1ffff) | x->l.frac3 | x->l.frac4) {
+ /* signal inexact */
+ if (fsr & FSR_NXM) {
+ __quad_fqtoi(x, &i);
+ } else {
+ fsr = (fsr & ~FSR_CEXC) | FSR_NXA |
+ FSR_NXC;
+ __quad_setfsrp(&fsr);
+ }
+ }
+ return (i);
+ }
+ i = ((x->l.msw & 0x80000000)? 0x80000000 : 0x7fffffff);
+ if (fsr & FSR_NVM) {
+ __quad_fqtoi(x, &i);
+ } else {
+ fsr = (fsr & ~FSR_CEXC) | FSR_NVA | FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ return (i);
+ }
+ if (xm < 0x3fff0000) {
+ if (xm | x->l.frac2 | x->l.frac3 | x->l.frac4) {
+ /* signal inexact */
+ i = 0;
+ if (fsr & FSR_NXM) {
+ __quad_fqtoi(x, &i);
+ } else {
+ fsr = (fsr & ~FSR_CEXC) | FSR_NXA | FSR_NXC;
+ __quad_setfsrp(&fsr);
+ }
+ return (i);
+ }
+ return (0);
+ }
+
+ /* now x is in the range of int */
+ i = 0x40000000 | ((xm & 0xffff) << 14) | (x->l.frac2 >> 18);
+ round = i & ((1 << (0x401d - (xm >> 16))) - 1);
+ i >>= (0x401d - (xm >> 16));
+ if (x->l.msw & 0x80000000)
+ i = -i;
+ if (round | (x->l.frac2 & 0x3ffff) | x->l.frac3 | x->l.frac4) {
+ /* signal inexact */
+ if (fsr & FSR_NXM) {
+ __quad_fqtoi(x, &i);
+ } else {
+ fsr = (fsr & ~FSR_CEXC) | FSR_NXA | FSR_NXC;
+ __quad_setfsrp(&fsr);
+ }
+ }
+ return (i);
+}
diff --git a/usr/src/lib/libc/sparc/fp/_Q_scl.c b/usr/src/lib/libc/sparc/fp/_Q_scl.c
new file mode 100644
index 0000000000..7e4c3c999a
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_Q_scl.c
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#if !defined(sparc) && !defined(__sparc)
+#error This code is for SPARC only
+#endif
+
+/*
+ * _Q_scl(x, n) sets *x = *x * 2^n.
+ *
+ * This routine tacitly assumes the result will be either zero
+ * or normal, so there is no need to raise any exceptions.
+ */
+void
+_Q_scl(long double *x, int n)
+{
+ union {
+ unsigned int i[4];
+ long double q;
+ } xx;
+ int hx;
+
+ xx.q = *x;
+ hx = xx.i[0] & ~0x80000000;
+
+ if (hx < 0x10000) { /* x is zero or subnormal */
+ if ((hx | xx.i[1] | xx.i[2] | xx.i[3]) == 0)
+ return;
+
+ /* normalize x */
+ while (hx == 0 && xx.i[1] < 0x10000) {
+ hx = xx.i[1];
+ xx.i[1] = xx.i[2];
+ xx.i[2] = xx.i[3];
+ xx.i[3] = 0;
+ n -= 32;
+ }
+ while (hx < 0x10000) {
+ hx = (hx << 1) | (xx.i[1] >> 31);
+ xx.i[1] = (xx.i[1] << 1) | (xx.i[2] >> 31);
+ xx.i[2] = (xx.i[2] << 1) | (xx.i[3] >> 31);
+ xx.i[3] <<= 1;
+ n--;
+ }
+ xx.i[0] = hx | (xx.i[0] & 0x80000000);
+ }
+
+ if ((hx >> 16) + n < 1) {
+ /* for subnormal result, just deliver zero */
+ xx.i[0] = xx.i[0] & 0x80000000;
+ xx.i[1] = xx.i[2] = xx.i[3] = 0;
+ } else
+ xx.i[0] += (n << 16);
+ *x = xx.q;
+}
+
+static const union {
+ int i[4];
+ long double q;
+} consts[2] = {
+ { 0x7ffe0000, 0, 0, 0 },
+ { 0x00010000, 0, 0, 0 }
+};
+
+/*
+ * _Q_scle(x, n) sets *x = *x * 2^n, raising overflow or underflow
+ * as appropriate.
+ *
+ * This routine tacitly assumes the argument is either zero or normal.
+ */
+void
+_Q_scle(long double *x, int n)
+{
+ union {
+ unsigned int i[4];
+ long double q;
+ } xx;
+ int hx;
+
+ xx.q = *x;
+ hx = (xx.i[0] >> 16) & 0x7fff;
+
+ if (hx == 0) /* x must be zero */
+ return;
+
+ hx += n;
+ if (hx >= 0x7fff) { /* overflow */
+ xx.i[0] = 0x7ffe0000 | (xx.i[0] & 0x80000000);
+ xx.i[1] = xx.i[2] = xx.i[3] = 0;
+ xx.q *= consts[0].q;
+ } else if (hx < 1) { /* possible underflow */
+ if (hx < -112) {
+ xx.i[0] = 0x00010000 | (xx.i[0] & 0x80000000);
+ xx.i[1] = xx.i[2] = xx.i[3] = 0;
+ } else {
+ xx.i[0] = (0x3ffe0000 + (hx << 16)) |
+ (xx.i[0] & 0x8000ffff);
+ }
+ xx.q *= consts[1].q;
+ } else
+ xx.i[0] += (n << 16);
+
+ *x = xx.q;
+}
diff --git a/usr/src/lib/libc/sparc/fp/_Q_set_except.c b/usr/src/lib/libc/sparc/fp/_Q_set_except.c
new file mode 100644
index 0000000000..42a0419c01
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_Q_set_except.c
@@ -0,0 +1,67 @@
+/*
+ * 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 <sys/ieeefp.h>
+#include <ieeefp.h>
+
+static const double zero = 0.0, tiny = 1.0e-307, tiny2 = 1.001e-307,
+ huge = 1.0e300;
+
+/*
+ * _Q_set_exception(ex) simulates the floating point exceptions indicated by
+ * ex. This routine is not used by the new quad emulation routines but is
+ * still used by ../crt/_ftoll.c.
+ */
+int
+_Q_set_exception(unsigned int ex)
+{
+ /* LINTED set but not used */
+ volatile double t;
+
+ if (ex == 0)
+ t = zero - zero; /* clear cexc */
+ else {
+ if ((ex & (1 << fp_invalid)) != 0)
+ t = zero / zero;
+ if ((ex & (1 << fp_overflow)) != 0)
+ t = huge * huge;
+ if ((ex & (1 << fp_underflow)) != 0) {
+ if ((ex & (1 << fp_inexact)) != 0 ||
+ (fpgetmask() & FP_X_UFL) != 0)
+ t = tiny * tiny;
+ else
+ t = tiny2 - tiny; /* exact */
+ }
+ if ((ex & (1 << fp_division)) != 0)
+ t = tiny / zero;
+ if ((ex & (1 << fp_inexact)) != 0)
+ t = huge + tiny;
+ }
+ return (0);
+}
diff --git a/usr/src/lib/libc/sparc/fp/_Q_sqrt.c b/usr/src/lib/libc/sparc/fp/_Q_sqrt.c
new file mode 100644
index 0000000000..db3aa74eb8
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_Q_sqrt.c
@@ -0,0 +1,365 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "quad.h"
+
+static const double C[] = {
+ 0.0,
+ 0.5,
+ 1.0,
+ 68719476736.0,
+ 536870912.0,
+ 48.0,
+ 16.0,
+ 1.52587890625000000000e-05,
+ 2.86102294921875000000e-06,
+ 5.96046447753906250000e-08,
+ 3.72529029846191406250e-09,
+ 1.70530256582424044609e-13,
+ 7.10542735760100185871e-15,
+ 8.67361737988403547206e-19,
+ 2.16840434497100886801e-19,
+ 1.27054942088145050860e-21,
+ 1.21169035041947413311e-27,
+ 9.62964972193617926528e-35,
+ 4.70197740328915003187e-38
+};
+
+#define zero C[0]
+#define half C[1]
+#define one C[2]
+#define two36 C[3]
+#define two29 C[4]
+#define three2p4 C[5]
+#define two4 C[6]
+#define twom16 C[7]
+#define three2m20 C[8]
+#define twom24 C[9]
+#define twom28 C[10]
+#define three2m44 C[11]
+#define twom47 C[12]
+#define twom60 C[13]
+#define twom62 C[14]
+#define three2m71 C[15]
+#define three2m91 C[16]
+#define twom113 C[17]
+#define twom124 C[18]
+
+static const unsigned
+ fsr_re = 0x00000000u,
+ fsr_rn = 0xc0000000u;
+
+#ifdef __sparcv9
+
+/*
+ * _Qp_sqrt(pz, x) sets *pz = sqrt(*x).
+ */
+void
+_Qp_sqrt(union longdouble *pz, const union longdouble *x)
+
+#else
+
+/*
+ * _Q_sqrt(x) returns sqrt(*x).
+ */
+union longdouble
+_Q_sqrt(const union longdouble *x)
+
+#endif /* __sparcv9 */
+
+{
+ union longdouble z;
+ union xdouble u;
+ double c, d, rr, r[2], tt[3], xx[4], zz[5];
+ unsigned int xm, fsr, lx, wx[3];
+ unsigned int msw, frac2, frac3, frac4, rm;
+ int ex, ez;
+
+ if (QUAD_ISZERO(*x)) {
+ Z = *x;
+ QUAD_RETURN(Z);
+ }
+
+ xm = x->l.msw;
+
+ __quad_getfsrp(&fsr);
+
+ /* handle nan and inf cases */
+ if ((xm & 0x7fffffff) >= 0x7fff0000) {
+ if ((x->l.msw & 0xffff) | x->l.frac2 | x->l.frac3 |
+ x->l.frac4) {
+ if (!(x->l.msw & 0x8000)) {
+ /* snan, signal invalid */
+ if (fsr & FSR_NVM) {
+ __quad_fsqrtq(x, &Z);
+ } else {
+ Z = *x;
+ Z.l.msw |= 0x8000;
+ fsr = (fsr & ~FSR_CEXC) | FSR_NVA |
+ FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ QUAD_RETURN(Z);
+ }
+ Z = *x;
+ QUAD_RETURN(Z);
+ }
+ if (x->l.msw & 0x80000000) {
+ /* sqrt(-inf), signal invalid */
+ if (fsr & FSR_NVM) {
+ __quad_fsqrtq(x, &Z);
+ } else {
+ Z.l.msw = 0x7fffffff;
+ Z.l.frac2 = Z.l.frac3 = Z.l.frac4 = 0xffffffff;
+ fsr = (fsr & ~FSR_CEXC) | FSR_NVA | FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ QUAD_RETURN(Z);
+ }
+ /* sqrt(inf), return inf */
+ Z = *x;
+ QUAD_RETURN(Z);
+ }
+
+ /* handle negative numbers */
+ if (xm & 0x80000000) {
+ if (fsr & FSR_NVM) {
+ __quad_fsqrtq(x, &Z);
+ } else {
+ Z.l.msw = 0x7fffffff;
+ Z.l.frac2 = Z.l.frac3 = Z.l.frac4 = 0xffffffff;
+ fsr = (fsr & ~FSR_CEXC) | FSR_NVA | FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ QUAD_RETURN(Z);
+ }
+
+ /* now x is finite, positive */
+ __quad_setfsrp((unsigned *)&fsr_re);
+
+ /* get the normalized significand and exponent */
+ ex = (int)(xm >> 16);
+ lx = xm & 0xffff;
+ if (ex) {
+ lx |= 0x10000;
+ wx[0] = x->l.frac2;
+ wx[1] = x->l.frac3;
+ wx[2] = x->l.frac4;
+ } else {
+ if (lx | (x->l.frac2 & 0xfffe0000)) {
+ wx[0] = x->l.frac2;
+ wx[1] = x->l.frac3;
+ wx[2] = x->l.frac4;
+ ex = 1;
+ } else if (x->l.frac2 | (x->l.frac3 & 0xfffe0000)) {
+ lx = x->l.frac2;
+ wx[0] = x->l.frac3;
+ wx[1] = x->l.frac4;
+ wx[2] = 0;
+ ex = -31;
+ } else if (x->l.frac3 | (x->l.frac4 & 0xfffe0000)) {
+ lx = x->l.frac3;
+ wx[0] = x->l.frac4;
+ wx[1] = wx[2] = 0;
+ ex = -63;
+ } else {
+ lx = x->l.frac4;
+ wx[0] = wx[1] = wx[2] = 0;
+ ex = -95;
+ }
+ while ((lx & 0x10000) == 0) {
+ lx = (lx << 1) | (wx[0] >> 31);
+ wx[0] = (wx[0] << 1) | (wx[1] >> 31);
+ wx[1] = (wx[1] << 1) | (wx[2] >> 31);
+ wx[2] <<= 1;
+ ex--;
+ }
+ }
+ ez = ex - 0x3fff;
+ if (ez & 1) {
+ /* make exponent even */
+ lx = (lx << 1) | (wx[0] >> 31);
+ wx[0] = (wx[0] << 1) | (wx[1] >> 31);
+ wx[1] = (wx[1] << 1) | (wx[2] >> 31);
+ wx[2] <<= 1;
+ ez--;
+ }
+
+ /* extract the significands into doubles */
+ c = twom16;
+ xx[0] = (double)((int)lx) * c;
+
+ c *= twom24;
+ xx[0] += (double)((int)(wx[0] >> 8)) * c;
+
+ c *= twom24;
+ xx[1] = (double)((int)(((wx[0] << 16) | (wx[1] >> 16)) &
+ 0xffffff)) * c;
+
+ c *= twom24;
+ xx[2] = (double)((int)(((wx[1] << 8) | (wx[2] >> 24)) &
+ 0xffffff)) * c;
+
+ c *= twom24;
+ xx[3] = (double)((int)(wx[2] & 0xffffff)) * c;
+
+ /* approximate the divisor for the Newton iteration */
+ c = xx[0] + xx[1];
+ c = __quad_dp_sqrt(&c);
+ rr = half / c;
+
+ /* compute the first five "digits" of the square root */
+ zz[0] = (c + two29) - two29;
+ tt[0] = zz[0] + zz[0];
+ r[0] = (xx[0] - zz[0] * zz[0]) + xx[1];
+
+ zz[1] = (rr * (r[0] + xx[2]) + three2p4) - three2p4;
+ tt[1] = zz[1] + zz[1];
+ r[0] -= tt[0] * zz[1];
+ r[1] = xx[2] - zz[1] * zz[1];
+ c = (r[1] + three2m20) - three2m20;
+ r[0] += c;
+ r[1] = (r[1] - c) + xx[3];
+
+ zz[2] = (rr * (r[0] + r[1]) + three2m20) - three2m20;
+ tt[2] = zz[2] + zz[2];
+ r[0] -= tt[0] * zz[2];
+ r[1] -= tt[1] * zz[2];
+ c = (r[1] + three2m44) - three2m44;
+ r[0] += c;
+ r[1] = (r[1] - c) - zz[2] * zz[2];
+
+ zz[3] = (rr * (r[0] + r[1]) + three2m44) - three2m44;
+ r[0] = ((r[0] - tt[0] * zz[3]) + r[1]) - tt[1] * zz[3];
+ r[1] = -tt[2] * zz[3];
+ c = (r[1] + three2m91) - three2m91;
+ r[0] += c;
+ r[1] = (r[1] - c) - zz[3] * zz[3];
+
+ zz[4] = (rr * (r[0] + r[1]) + three2m71) - three2m71;
+
+ /* reduce to three doubles, making sure zz[1] is positive */
+ zz[0] += zz[1] - twom47;
+ zz[1] = twom47 + zz[2] + zz[3];
+ zz[2] = zz[4];
+
+ /* if the third term might lie on a rounding boundary, perturb it */
+ if (zz[2] == (twom62 + zz[2]) - twom62) {
+ /* here we just need to get the sign of the remainder */
+ c = (((((r[0] - tt[0] * zz[4]) - tt[1] * zz[4]) + r[1])
+ - tt[2] * zz[4]) - (zz[3] + zz[3]) * zz[4]) - zz[4] * zz[4];
+ if (c < zero)
+ zz[2] -= twom124;
+ else if (c > zero)
+ zz[2] += twom124;
+ }
+
+ /*
+ * propagate carries/borrows, using round-to-negative-infinity mode
+ * to make all terms nonnegative (note that we can't encounter a
+ * borrow so large that the roundoff is unrepresentable because
+ * we took care to make zz[1] positive above)
+ */
+ __quad_setfsrp(&fsr_rn);
+ c = zz[1] + zz[2];
+ zz[2] += (zz[1] - c);
+ zz[1] = c;
+ c = zz[0] + zz[1];
+ zz[1] += (zz[0] - c);
+ zz[0] = c;
+
+ /* adjust exponent and strip off integer bit */
+ ez = (ez >> 1) + 0x3fff;
+ zz[0] -= one;
+
+ /* the first 48 bits of fraction come from zz[0] */
+ u.d = d = two36 + zz[0];
+ msw = u.l.lo;
+ zz[0] -= (d - two36);
+
+ u.d = d = two4 + zz[0];
+ frac2 = u.l.lo;
+ zz[0] -= (d - two4);
+
+ /* the next 32 come from zz[0] and zz[1] */
+ u.d = d = twom28 + (zz[0] + zz[1]);
+ frac3 = u.l.lo;
+ zz[0] -= (d - twom28);
+
+ /* condense the remaining fraction; errors here won't matter */
+ c = zz[0] + zz[1];
+ zz[1] = ((zz[0] - c) + zz[1]) + zz[2];
+ zz[0] = c;
+
+ /* get the last word of fraction */
+ u.d = d = twom60 + (zz[0] + zz[1]);
+ frac4 = u.l.lo;
+ zz[0] -= (d - twom60);
+
+ /* keep track of what's left for rounding; note that the error */
+ /* in computing c will be non-negative due to rounding mode */
+ c = zz[0] + zz[1];
+
+ /* get the rounding mode */
+ rm = fsr >> 30;
+
+ /* round and raise exceptions */
+ fsr &= ~FSR_CEXC;
+ if (c != zero) {
+ fsr |= FSR_NXC;
+
+ /* decide whether to round the fraction up */
+ if (rm == FSR_RP || (rm == FSR_RN && (c > twom113 ||
+ (c == twom113 && ((frac4 & 1) || (c - zz[0] != zz[1])))))) {
+ /* round up and renormalize if necessary */
+ if (++frac4 == 0)
+ if (++frac3 == 0)
+ if (++frac2 == 0)
+ if (++msw == 0x10000) {
+ msw = 0;
+ ez++;
+ }
+ }
+ }
+
+ /* stow the result */
+ z.l.msw = (ez << 16) | msw;
+ z.l.frac2 = frac2;
+ z.l.frac3 = frac3;
+ z.l.frac4 = frac4;
+
+ if ((fsr & FSR_CEXC) & (fsr >> 23)) {
+ __quad_setfsrp(&fsr);
+ __quad_fsqrtq(x, &Z);
+ } else {
+ Z = z;
+ fsr |= (fsr & 0x1f) << 5;
+ __quad_setfsrp(&fsr);
+ }
+ QUAD_RETURN(Z);
+}
diff --git a/usr/src/lib/libc/sparc/fp/_Q_stoq.c b/usr/src/lib/libc/sparc/fp/_Q_stoq.c
new file mode 100644
index 0000000000..f70f34bd80
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_Q_stoq.c
@@ -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 (c) 1994-1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "quad.h"
+
+#ifdef __sparcv9
+
+/*
+ * _Qp_stoq(pz, x) sets *pz = (long double)x.
+ */
+void
+_Qp_stoq(union longdouble *pz, float x)
+
+#else
+
+/*
+ * _Qp_stoq(x) returns (long double)x.
+ */
+union longdouble
+_Q_stoq(float x)
+
+#endif /* __sparcv9 */
+
+{
+#ifndef __sparcv9
+ union longdouble z;
+#endif
+ union {
+ float f;
+ unsigned int l;
+ } u;
+ unsigned int m, f, fsr;
+
+ /* extract the exponent */
+ u.f = x;
+ m = ((u.l & 0x7f800000) >> 7) + 0x3f800000;
+ if (m == 0x3f800000) {
+ /* x is zero or denormal */
+ if (u.l & 0x7fffff) {
+ /* x is denormal, normalize it */
+ m = 0x3f810000;
+ f = u.l & 0x7fffff;
+ do {
+ f <<= 1;
+ m -= 0x10000;
+ } while ((f & 0x7f800000) == 0);
+ u.l = (u.l & 0x80000000) | f;
+ } else {
+ m = 0;
+ }
+ } else if (m == 0x407f0000) {
+ /* x is inf or nan */
+ m = 0x7fff0000;
+ if ((u.l & 0x3fffff) && (u.l & 0x400000) == 0) {
+ /* snan, signal invalid */
+ __quad_getfsrp(&fsr);
+ if (fsr & FSR_NVM) {
+ __quad_fstoq(&x, &Z);
+ QUAD_RETURN(Z);
+ } else {
+ fsr = (fsr & ~FSR_CEXC) | FSR_NVA | FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ u.l |= 0x400000;
+ }
+ }
+ Z.l.msw = m | (u.l & 0x80000000) | ((u.l & 0x7fff80) >> 7);
+ Z.l.frac2 = u.l << 25;
+ Z.l.frac3 = Z.l.frac4 = 0;
+ QUAD_RETURN(Z);
+}
diff --git a/usr/src/lib/libc/sparc/fp/_Q_sub.c b/usr/src/lib/libc/sparc/fp/_Q_sub.c
new file mode 100644
index 0000000000..b60aa13130
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_Q_sub.c
@@ -0,0 +1,166 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "quad.h"
+
+#ifdef __sparcv9
+
+/*
+ * _Qp_sub(pz, ox, oy) sets *pz = *ox - *oy.
+ */
+void
+_Qp_sub(union longdouble *pz, const union longdouble *ox,
+ const union longdouble *oy)
+
+#else
+
+/*
+ * _Q_sub(ox, oy) returns *ox - *oy.
+ */
+union longdouble
+_Q_sub(const union longdouble *ox, const union longdouble *oy)
+
+#endif /* __sparcv9 */
+
+{
+ union longdouble z;
+ const union longdouble *x, *y;
+ unsigned int xm, ym, tm, fsr;
+ int flip;
+
+ /* sort so |x| >= |y| */
+ xm = ox->l.msw & 0x7fffffff;
+ ym = oy->l.msw & 0x7fffffff;
+ if (ym > xm || ym == xm && (oy->l.frac2 > ox->l.frac2 ||
+ oy->l.frac2 == ox->l.frac2 && (oy->l.frac3 > ox->l.frac3 ||
+ oy->l.frac3 == ox->l.frac3 && oy->l.frac4 > ox->l.frac4))) {
+ y = ox;
+ x = oy;
+ tm = xm;
+ xm = ym;
+ ym = tm;
+ flip = 0x80000000;
+ } else {
+ x = ox;
+ y = oy;
+ flip = 0;
+ }
+
+ /* get the fsr */
+ __quad_getfsrp(&fsr);
+
+ /* handle nan and inf cases */
+ if (xm >= 0x7fff0000) {
+ /* x is nan or inf */
+ if (ym >= 0x7fff0000) {
+ /* y is nan or inf */
+ if ((ym & 0xffff) | y->l.frac2 | y->l.frac3 |
+ y->l.frac4) {
+ /* y is nan; x must be nan too */
+ /* the following logic implements V9 app. B */
+ if (!(ym & 0x8000)) {
+ /* y is snan, signal invalid */
+ if (fsr & FSR_NVM) {
+ __quad_fsubq(ox, oy, &Z);
+ } else {
+ Z = (xm & 0x8000)? *y : *oy;
+ Z.l.msw |= 0x8000;
+ fsr = (fsr & ~FSR_CEXC) |
+ FSR_NVA | FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ QUAD_RETURN(Z);
+ }
+ /* x and y are both qnan */
+ Z = *oy;
+ QUAD_RETURN(Z);
+ }
+ if (!((xm & 0xffff) | x->l.frac2 | x->l.frac3 |
+ x->l.frac4)) {
+ /* x and y are both inf */
+ if (!((x->l.msw ^ y->l.msw) & 0x80000000)) {
+ /* inf - inf, signal invalid */
+ if (fsr & FSR_NVM) {
+ __quad_fsubq(ox, oy, &Z);
+ } else {
+ Z.l.msw = 0x7fffffff;
+ Z.l.frac2 = Z.l.frac3 =
+ Z.l.frac4 = 0xffffffff;
+ fsr = (fsr & ~FSR_CEXC) |
+ FSR_NVA | FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ QUAD_RETURN(Z);
+ }
+ /* inf + inf, return inf */
+ Z = *x;
+ Z.l.msw ^= flip;
+ QUAD_RETURN(Z);
+ }
+ }
+ if ((xm & 0xffff) | x->l.frac2 | x->l.frac3 | x->l.frac4) {
+ /* x is nan */
+ if (!(xm & 0x8000)) {
+ /* snan, signal invalid */
+ if (fsr & FSR_NVM) {
+ __quad_fsubq(ox, oy, &Z);
+ } else {
+ Z = *x;
+ Z.l.msw |= 0x8000;
+ fsr = (fsr & ~FSR_CEXC) | FSR_NVA |
+ FSR_NVC;
+ __quad_setfsrp(&fsr);
+ }
+ QUAD_RETURN(Z);
+ }
+ Z = *x;
+ QUAD_RETURN(Z);
+ }
+ /* x is inf */
+ Z = *x;
+ Z.l.msw ^= flip;
+ QUAD_RETURN(Z);
+ }
+
+ /* now x and y are finite and |x| >= |y| */
+ fsr &= ~FSR_CEXC;
+ z.l.msw = (x->l.msw & 0x80000000) ^ flip;
+ if ((x->l.msw ^ y->l.msw) & 0x80000000)
+ __quad_mag_add(x, y, &z, &fsr);
+ else
+ __quad_mag_sub(x, y, &z, &fsr);
+ if ((fsr & FSR_CEXC) & (fsr >> 23)) {
+ __quad_setfsrp(&fsr);
+ __quad_fsubq(ox, oy, &Z);
+ } else {
+ Z = z;
+ fsr |= (fsr & 0x1f) << 5;
+ __quad_setfsrp(&fsr);
+ }
+ QUAD_RETURN(Z);
+}
diff --git a/usr/src/lib/libc/sparc/fp/_Q_ulltoq.c b/usr/src/lib/libc/sparc/fp/_Q_ulltoq.c
new file mode 100644
index 0000000000..2f7f6fc0f6
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_Q_ulltoq.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) 1994-1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "quad.h"
+
+/*
+ * _Q_ulltoq(x) returns (long double)x.
+ */
+union longdouble
+_Q_ulltoq(unsigned long long x)
+{
+ union longdouble z;
+ unsigned int e;
+
+ /* test for zero */
+ if (x == 0) {
+ Z.l.msw = Z.l.frac2 = Z.l.frac3 = Z.l.frac4 = 0;
+ QUAD_RETURN(Z);
+ }
+
+ /* find the most significant bit */
+ for (e = 63; (x & (1ll << e)) == 0; e--)
+ ;
+
+ if (e > 48) {
+ Z.l.msw = (x >> (e - 16)) & 0xffff;
+ Z.l.frac2 = x >> (e - 48);
+ Z.l.frac3 = x << (80 - e);
+ } else if (e > 16) {
+ Z.l.msw = (x >> (e - 16)) & 0xffff;
+ Z.l.frac2 = x << (48 - e);
+ Z.l.frac3 = 0;
+ } else {
+ Z.l.msw = (x << (16 - e)) & 0xffff;
+ Z.l.frac2 = Z.l.frac3 = 0;
+ }
+ Z.l.frac4 = 0;
+ Z.l.msw |= ((e + 0x3fff) << 16);
+ QUAD_RETURN(Z);
+}
diff --git a/usr/src/lib/libc/sparc/fp/_Q_utoq.c b/usr/src/lib/libc/sparc/fp/_Q_utoq.c
new file mode 100644
index 0000000000..6d2bf9d78f
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/_Q_utoq.c
@@ -0,0 +1,75 @@
+/*
+ * 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) 1994-1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "quad.h"
+
+#ifdef __sparcv9
+
+/*
+ * _Qp_uitoq(pz, x) sets *pz = (long double)x.
+ */
+void
+_Qp_uitoq(union longdouble *pz, unsigned int x)
+
+#else
+
+/*
+ * _Q_utoq(x) returns (long double)x.
+ */
+union longdouble
+_Q_utoq(unsigned int x)
+
+#endif /* __sparcv9 */
+
+{
+#ifndef __sparcv9
+ union longdouble z;
+#endif
+ unsigned int e;
+
+ /* test for zero */
+ if (x == 0) {
+ Z.l.msw = Z.l.frac2 = Z.l.frac3 = Z.l.frac4 = 0;
+ QUAD_RETURN(Z);
+ }
+
+ /* find the most significant bit */
+ for (e = 31; (x & (1 << e)) == 0; e--)
+ ;
+
+ if (e > 16) {
+ Z.l.msw = ((unsigned) x >> (e - 16)) & 0xffff;
+ Z.l.frac2 = (unsigned) x << (48 - e);
+ } else {
+ Z.l.msw = ((unsigned) x << (16 - e)) & 0xffff;
+ Z.l.frac2 = 0;
+ }
+ Z.l.frac3 = Z.l.frac4 = 0;
+ Z.l.msw |= ((e + 0x3fff) << 16);
+ QUAD_RETURN(Z);
+}
diff --git a/usr/src/lib/libc/sparc/fp/__quad.il b/usr/src/lib/libc/sparc/fp/__quad.il
new file mode 100644
index 0000000000..6750aea28f
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/__quad.il
@@ -0,0 +1,156 @@
+!
+! Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+! Use is subject to license terms.
+!
+! 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
+!
+!
+! .ident "%Z%%M% %I% %E% SMI"
+!
+! This file contains inline templates for the internal routines used
+! by the quad precision emulation code for SPARC. It should be used
+! in preference to __quad.s whenever possible.
+
+ .inline __quad_getfsrp,1
+ st %fsr,[%o0]
+ .end
+
+ .inline __quad_setfsrp,1
+ ld [%o0],%fsr
+ .end
+
+ .inline __quad_dp_sqrt,1
+ ldd [%o0],%f0
+ fsqrtd %f0,%f0
+ .end
+
+ .inline __quad_faddq,3
+ ldd [%o0],%f0
+ ldd [%o0+8],%f2
+ ldd [%o1],%f4
+ ldd [%o1+8],%f6
+ faddq %f0,%f4,%f8
+ std %f8,[%o2]
+ std %f10,[%o2+8]
+ .end
+
+ .inline __quad_fsubq,3
+ ldd [%o0],%f0
+ ldd [%o0+8],%f2
+ ldd [%o1],%f4
+ ldd [%o1+8],%f6
+ fsubq %f0,%f4,%f8
+ std %f8,[%o2]
+ std %f10,[%o2+8]
+ .end
+
+ .inline __quad_fmulq,3
+ ldd [%o0],%f0
+ ldd [%o0+8],%f2
+ ldd [%o1],%f4
+ ldd [%o1+8],%f6
+ fmulq %f0,%f4,%f8
+ std %f8,[%o2]
+ std %f10,[%o2+8]
+ .end
+
+ .inline __quad_fdivq,3
+ ldd [%o0],%f0
+ ldd [%o0+8],%f2
+ ldd [%o1],%f4
+ ldd [%o1+8],%f6
+ fdivq %f0,%f4,%f8
+ std %f8,[%o2]
+ std %f10,[%o2+8]
+ .end
+
+ .inline __quad_fsqrtq,2
+ ldd [%o0],%f0
+ ldd [%o0+8],%f2
+ fsqrtq %f0,%f4
+ std %f4,[%o1]
+ std %f6,[%o1+8]
+ .end
+
+ .inline __quad_fcmpq,3
+ ldd [%o0],%f0
+ ldd [%o0+8],%f2
+ ldd [%o1],%f4
+ ldd [%o1+8],%f6
+ .volatile
+ fcmpq %f0,%f4
+ st %fsr,[%o2]
+ .nonvolatile
+ .end
+
+ .inline __quad_fcmpeq,3
+ ldd [%o0],%f0
+ ldd [%o0+8],%f2
+ ldd [%o1],%f4
+ ldd [%o1+8],%f6
+ .volatile
+ fcmpeq %f0,%f4
+ st %fsr,[%o2]
+ .nonvolatile
+ .end
+
+ .inline __quad_fstoq,2
+ ld [%o0],%f0
+ fstoq %f0,%f4
+ std %f4,[%o1]
+ std %f6,[%o1+8]
+ .end
+
+ .inline __quad_fdtoq,2
+ ldd [%o0],%f0
+ fdtoq %f0,%f4
+ std %f4,[%o1]
+ std %f6,[%o1+8]
+ .end
+
+ .inline __quad_fqtoi,2
+ ldd [%o0],%f0
+ ldd [%o0+8],%f2
+ fqtoi %f0,%f4
+ st %f4,[%o1]
+ .end
+
+ .inline __quad_fqtos,2
+ ldd [%o0],%f0
+ ldd [%o0+8],%f2
+ fqtos %f0,%f4
+ st %f4,[%o1]
+ .end
+
+ .inline __quad_fqtod,2
+ ldd [%o0],%f0
+ ldd [%o0+8],%f2
+ fqtod %f0,%f4
+ std %f4,[%o1]
+ .end
+
+! only used in V9 code
+ .inline __quad_fqtox,2
+ ldd [%o0],%f0
+ ldd [%o0+8],%f2
+ fqtox %f0,%f4
+ std %f4,[%o1]
+ .end
diff --git a/usr/src/lib/libc/sparc/fp/__quad_mag.c b/usr/src/lib/libc/sparc/fp/__quad_mag.c
new file mode 100644
index 0000000000..45e4c9fa51
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/__quad_mag.c
@@ -0,0 +1,404 @@
+/*
+ * 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) 1994-1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file contains __quad_mag_add and __quad_mag_sub, the core
+ * of the quad precision add and subtract operations.
+ */
+
+#include "quad.h"
+
+/*
+ * __quad_mag_add(x, y, z, fsr)
+ *
+ * Sets *z = *x + *y, rounded according to the rounding mode in *fsr,
+ * and updates the current exceptions in *fsr. This routine assumes
+ * *x and *y are finite, with the same sign (i.e., an addition of
+ * magnitudes), |*x| >= |*y|, and *z already has its sign bit set.
+ */
+void
+__quad_mag_add(const union longdouble *x, const union longdouble *y,
+ union longdouble *z, unsigned int *fsr)
+{
+ unsigned int lx, ly, ex, ey, frac2, frac3, frac4;
+ unsigned int round, sticky, carry, rm;
+ int e, uflo;
+
+ /* get the leading significand words and exponents */
+ ex = (x->l.msw & 0x7fffffff) >> 16;
+ lx = x->l.msw & 0xffff;
+ if (ex == 0)
+ ex = 1;
+ else
+ lx |= 0x10000;
+
+ ey = (y->l.msw & 0x7fffffff) >> 16;
+ ly = y->l.msw & 0xffff;
+ if (ey == 0)
+ ey = 1;
+ else
+ ly |= 0x10000;
+
+ /* prenormalize y */
+ e = (int) ex - (int) ey;
+ round = sticky = 0;
+ if (e >= 114) {
+ frac2 = x->l.frac2;
+ frac3 = x->l.frac3;
+ frac4 = x->l.frac4;
+ sticky = ly | y->l.frac2 | y->l.frac3 | y->l.frac4;
+ } else {
+ frac2 = y->l.frac2;
+ frac3 = y->l.frac3;
+ frac4 = y->l.frac4;
+ if (e >= 96) {
+ sticky = frac4 | frac3 | (frac2 & 0x7fffffff);
+ round = frac2 & 0x80000000;
+ frac4 = ly;
+ frac3 = frac2 = ly = 0;
+ e -= 96;
+ } else if (e >= 64) {
+ sticky = frac4 | (frac3 & 0x7fffffff);
+ round = frac3 & 0x80000000;
+ frac4 = frac2;
+ frac3 = ly;
+ frac2 = ly = 0;
+ e -= 64;
+ } else if (e >= 32) {
+ sticky = frac4 & 0x7fffffff;
+ round = frac4 & 0x80000000;
+ frac4 = frac3;
+ frac3 = frac2;
+ frac2 = ly;
+ ly = 0;
+ e -= 32;
+ }
+ if (e) {
+ sticky |= round | (frac4 & ((1 << (e - 1)) - 1));
+ round = frac4 & (1 << (e - 1));
+ frac4 = (frac4 >> e) | (frac3 << (32 - e));
+ frac3 = (frac3 >> e) | (frac2 << (32 - e));
+ frac2 = (frac2 >> e) | (ly << (32 - e));
+ ly >>= e;
+ }
+
+ /* add, propagating carries */
+ frac4 += x->l.frac4;
+ carry = (frac4 < x->l.frac4);
+ frac3 += x->l.frac3;
+ if (carry) {
+ frac3++;
+ carry = (frac3 <= x->l.frac3);
+ } else {
+ carry = (frac3 < x->l.frac3);
+ }
+ frac2 += x->l.frac2;
+ if (carry) {
+ frac2++;
+ carry = (frac2 <= x->l.frac2);
+ } else {
+ carry = (frac2 < x->l.frac2);
+ }
+ lx += ly;
+ if (carry)
+ lx++;
+
+ /* postnormalize */
+ if (lx >= 0x20000) {
+ sticky |= round;
+ round = frac4 & 1;
+ frac4 = (frac4 >> 1) | (frac3 << 31);
+ frac3 = (frac3 >> 1) | (frac2 << 31);
+ frac2 = (frac2 >> 1) | (lx << 31);
+ lx >>= 1;
+ ex++;
+ }
+ }
+
+ /* keep track of whether the result before rounding is tiny */
+ uflo = (lx < 0x10000);
+
+ /* get the rounding mode, fudging directed rounding modes */
+ /* as though the result were positive */
+ rm = *fsr >> 30;
+ if (z->l.msw)
+ rm ^= (rm >> 1);
+
+ /* see if we need to round */
+ if (round | sticky) {
+ *fsr |= FSR_NXC;
+
+ /* round up if necessary */
+ if (rm == FSR_RP || (rm == FSR_RN && round &&
+ (sticky || (frac4 & 1)))) {
+ if (++frac4 == 0)
+ if (++frac3 == 0)
+ if (++frac2 == 0)
+ if (++lx >= 0x20000) {
+ lx >>= 1;
+ ex++;
+ }
+ }
+ }
+
+ /* check for overflow */
+ if (ex >= 0x7fff) {
+ /* store the default overflowed result */
+ *fsr |= FSR_OFC | FSR_NXC;
+ if (rm == FSR_RN || rm == FSR_RP) {
+ z->l.msw |= 0x7fff0000;
+ z->l.frac2 = z->l.frac3 = z->l.frac4 = 0;
+ } else {
+ z->l.msw |= 0x7ffeffff;
+ z->l.frac2 = z->l.frac3 = z->l.frac4 = 0xffffffff;
+ }
+ } else {
+ /* store the result */
+ if (lx >= 0x10000)
+ z->l.msw |= (ex << 16);
+ z->l.msw |= (lx & 0xffff);
+ z->l.frac2 = frac2;
+ z->l.frac3 = frac3;
+ z->l.frac4 = frac4;
+
+ /* if the pre-rounded result was tiny and underflow trapping */
+ /* is enabled, simulate underflow */
+ if (uflo && (*fsr & FSR_UFM))
+ *fsr |= FSR_UFC;
+ }
+}
+
+/*
+ * __quad_mag_sub(x, y, z, fsr)
+ *
+ * Sets *z = *x - *y, rounded according to the rounding mode in *fsr,
+ * and updates the current exceptions in *fsr. This routine assumes
+ * *x and *y are finite, with opposite signs (i.e., a subtraction of
+ * magnitudes), |*x| >= |*y|, and *z already has its sign bit set.
+ */
+void
+__quad_mag_sub(const union longdouble *x, const union longdouble *y,
+ union longdouble *z, unsigned int *fsr)
+{
+ unsigned int lx, ly, ex, ey, frac2, frac3, frac4;
+ unsigned int guard, round, sticky, borrow, rm;
+ int e;
+
+ /* get the leading significand words and exponents */
+ ex = (x->l.msw & 0x7fffffff) >> 16;
+ lx = x->l.msw & 0xffff;
+ if (ex == 0)
+ ex = 1;
+ else
+ lx |= 0x10000;
+
+ ey = (y->l.msw & 0x7fffffff) >> 16;
+ ly = y->l.msw & 0xffff;
+ if (ey == 0)
+ ey = 1;
+ else
+ ly |= 0x10000;
+
+ /* prenormalize y */
+ e = (int) ex - (int) ey;
+ guard = round = sticky = 0;
+ if (e > 114) {
+ sticky = ly | y->l.frac2 | y->l.frac3 | y->l.frac4;
+ ly = frac2 = frac3 = frac4 = 0;
+ } else {
+ frac2 = y->l.frac2;
+ frac3 = y->l.frac3;
+ frac4 = y->l.frac4;
+ if (e >= 96) {
+ sticky = frac4 | frac3 | (frac2 & 0x3fffffff);
+ round = frac2 & 0x40000000;
+ guard = frac2 & 0x80000000;
+ frac4 = ly;
+ frac3 = frac2 = ly = 0;
+ e -= 96;
+ } else if (e >= 64) {
+ sticky = frac4 | (frac3 & 0x3fffffff);
+ round = frac3 & 0x40000000;
+ guard = frac3 & 0x80000000;
+ frac4 = frac2;
+ frac3 = ly;
+ frac2 = ly = 0;
+ e -= 64;
+ } else if (e >= 32) {
+ sticky = frac4 & 0x3fffffff;
+ round = frac4 & 0x40000000;
+ guard = frac4 & 0x80000000;
+ frac4 = frac3;
+ frac3 = frac2;
+ frac2 = ly;
+ ly = 0;
+ e -= 32;
+ }
+ if (e > 1) {
+ sticky |= guard | round |
+ (frac4 & ((1 << (e - 2)) - 1));
+ round = frac4 & (1 << (e - 2));
+ guard = frac4 & (1 << (e - 1));
+ frac4 = (frac4 >> e) | (frac3 << (32 - e));
+ frac3 = (frac3 >> e) | (frac2 << (32 - e));
+ frac2 = (frac2 >> e) | (ly << (32 - e));
+ ly >>= e;
+ } else if (e == 1) {
+ sticky |= round;
+ round = guard;
+ guard = frac4 & 1;
+ frac4 = (frac4 >> 1) | (frac3 << 31);
+ frac3 = (frac3 >> 1) | (frac2 << 31);
+ frac2 = (frac2 >> 1) | (ly << 31);
+ ly >>= 1;
+ }
+ }
+
+ /* complement guard, round, and sticky as need be */
+ if (sticky) {
+ round = !round;
+ guard = !guard;
+ } else if (round) {
+ guard = !guard;
+ }
+ borrow = (guard | round | sticky);
+
+ /* subtract, propagating borrows */
+ frac4 = x->l.frac4 - frac4;
+ if (borrow) {
+ frac4--;
+ borrow = (frac4 >= x->l.frac4);
+ } else {
+ borrow = (frac4 > x->l.frac4);
+ }
+ frac3 = x->l.frac3 - frac3;
+ if (borrow) {
+ frac3--;
+ borrow = (frac3 >= x->l.frac3);
+ } else {
+ borrow = (frac3 > x->l.frac3);
+ }
+ frac2 = x->l.frac2 - frac2;
+ if (borrow) {
+ frac2--;
+ borrow = (frac2 >= x->l.frac2);
+ } else {
+ borrow = (frac2 > x->l.frac2);
+ }
+ lx -= ly;
+ if (borrow)
+ lx--;
+
+ /* get the rounding mode */
+ rm = *fsr >> 30;
+
+ /* handle zero result */
+ if (!(lx | frac2 | frac3 | frac4 | guard)) {
+ z->l.msw = ((rm == FSR_RM)? 0x80000000 : 0);
+ z->l.frac2 = z->l.frac3 = z->l.frac4 = 0;
+ return;
+ }
+
+ /* postnormalize */
+ if (lx < 0x10000) {
+ /* if cancellation occurred or the exponent is 1, */
+ /* the result is exact */
+ if (lx < 0x8000 || ex == 1) {
+ while ((lx | (frac2 & 0xfffe0000)) == 0 && ex > 32) {
+ lx = frac2;
+ frac2 = frac3;
+ frac3 = frac4;
+ frac4 = ((guard)? 0x80000000 : 0);
+ guard = 0;
+ ex -= 32;
+ }
+ while (lx < 0x10000 && ex > 1) {
+ lx = (lx << 1) | (frac2 >> 31);
+ frac2 = (frac2 << 1) | (frac3 >> 31);
+ frac3 = (frac3 << 1) | (frac4 >> 31);
+ frac4 <<= 1;
+ if (guard) {
+ frac4 |= 1;
+ guard = 0;
+ }
+ ex--;
+ }
+ if (lx >= 0x10000)
+ z->l.msw |= (ex << 16);
+ z->l.msw |= (lx & 0xffff);
+ z->l.frac2 = frac2;
+ z->l.frac3 = frac3;
+ z->l.frac4 = frac4;
+
+ /* if the result is tiny and underflow trapping is */
+ /* enabled, simulate underflow */
+ if (lx < 0x10000 && (*fsr & FSR_UFM))
+ *fsr |= FSR_UFC;
+ return;
+ }
+
+ /* otherwise we only borrowed one place */
+ lx = (lx << 1) | (frac2 >> 31);
+ frac2 = (frac2 << 1) | (frac3 >> 31);
+ frac3 = (frac3 << 1) | (frac4 >> 31);
+ frac4 <<= 1;
+ if (guard)
+ frac4 |= 1;
+ ex--;
+ } else {
+ sticky |= round;
+ round = guard;
+ }
+
+ /* fudge directed rounding modes as though the result were positive */
+ if (z->l.msw)
+ rm ^= (rm >> 1);
+
+ /* see if we need to round */
+ if (round | sticky) {
+ *fsr |= FSR_NXC;
+
+ /* round up if necessary */
+ if (rm == FSR_RP || (rm == FSR_RN && round &&
+ (sticky || (frac4 & 1)))) {
+ if (++frac4 == 0)
+ if (++frac3 == 0)
+ if (++frac2 == 0)
+ if (++lx >= 0x20000) {
+ lx >>= 1;
+ ex++;
+ }
+ }
+ }
+
+ /* store the result */
+ z->l.msw |= (ex << 16) | (lx & 0xffff);
+ z->l.frac2 = frac2;
+ z->l.frac3 = frac3;
+ z->l.frac4 = frac4;
+}
diff --git a/usr/src/lib/libc/sparc/fp/base.il b/usr/src/lib/libc/sparc/fp/base.il
new file mode 100644
index 0000000000..e13b3e6447
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/base.il
@@ -0,0 +1,71 @@
+! .ident "%Z%%M% %I% %E% SMI"
+!
+! Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+! Use is subject to license terms.
+!
+! 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
+!
+
+ .inline __mul_set,3
+ std %o0,[%sp+0x48] ! save x
+ ldd [%sp+0x48],%f0
+ std %o2,[%sp+0x50] ! save y
+ ldd [%sp+0x50],%f2
+ .volatile
+ fmuld %f0,%f2,%f0 ! compute result and leave it for return
+ st %fsr,[%sp+0x44]
+ .nonvolatile
+ ld [%sp+0x44],%o0
+ and %o0,1,%o0
+ st %o0,[%o4] ! store eround
+ .end
+
+ .inline __div_set,3
+ std %o0,[%sp+0x48] ! save x
+ ldd [%sp+0x48],%f0
+ std %o2,[%sp+0x50] ! save y
+ ldd [%sp+0x50],%f2
+ .volatile
+ fdivd %f0,%f2,%f0 ! compute result and leave it for return
+ st %fsr,[%sp+0x44]
+ .nonvolatile
+ ld [%sp+0x44],%o0
+ and %o0,1,%o0
+ st %o0,[%o4] ! store eround
+ .end
+
+ .inline __dabs,2
+ ld [%o0],%f0
+ ld [%o0+4],%f1
+ fabss %f0,%f0
+ .end
+
+ .inline __get_ieee_flags,1
+ .volatile
+ st %fsr,[%o0]
+ st %g0,[%sp+0x44]
+ ld [%sp+0x44],%fsr
+ .nonvolatile
+ .end
+
+ .inline __set_ieee_flags,1
+ ld [%o0],%fsr
+ .end
diff --git a/usr/src/lib/libc/sparc/fp/fpgetmask.s b/usr/src/lib/libc/sparc/fp/fpgetmask.s
new file mode 100644
index 0000000000..6a41d8db88
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/fpgetmask.s
@@ -0,0 +1,48 @@
+/*
+ * 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.11 */
+
+ .file "fpgetmask.s"
+
+#include <sys/asm_linkage.h>
+
+ ANSI_PRAGMA_WEAK(fpgetmask,function)
+
+#include "synonyms.h"
+
+ ENTRY(fpgetmask)
+ add %sp, -SA(MINFRAME), %sp ! get an additional word of storage
+ set 0x0f800000, %o4 ! mask of trap enable bits
+ st %fsr, [%sp+ARGPUSH] ! get fsr value
+ ld [%sp+ARGPUSH], %o0 ! load into register
+ and %o0, %o4, %o0 ! mask off bits of interest
+ srl %o0, 23, %o0 ! return trap enable value
+ retl
+ add %sp, SA(MINFRAME), %sp ! reclaim stack space
+
+ SET_SIZE(fpgetmask)
diff --git a/usr/src/lib/libc/sparc/fp/fpgetrnd.s b/usr/src/lib/libc/sparc/fp/fpgetrnd.s
new file mode 100644
index 0000000000..6293fa74c3
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/fpgetrnd.s
@@ -0,0 +1,46 @@
+/*
+ * 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.11 */
+
+ .file "fpgetrnd.s"
+
+#include <sys/asm_linkage.h>
+
+ ANSI_PRAGMA_WEAK(fpgetround,function)
+
+#include "synonyms.h"
+
+ ENTRY(fpgetround)
+ add %sp, -SA(MINFRAME), %sp ! get an additional word of storage
+ st %fsr, [%sp+ARGPUSH] ! get fsr value
+ ld [%sp+ARGPUSH], %o0 ! load into register
+ srl %o0, 30, %o0 ! return round control value
+ retl
+ add %sp, SA(MINFRAME), %sp ! reclaim stack space
+
+ SET_SIZE(fpgetround)
diff --git a/usr/src/lib/libc/sparc/fp/fpgetsticky.s b/usr/src/lib/libc/sparc/fp/fpgetsticky.s
new file mode 100644
index 0000000000..8f7890973b
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/fpgetsticky.s
@@ -0,0 +1,48 @@
+/*
+ * 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.11 */
+
+ .file "fpgetsticky.s"
+
+#include <sys/asm_linkage.h>
+
+ ANSI_PRAGMA_WEAK(fpgetsticky,function)
+
+#include "synonyms.h"
+
+ ENTRY(fpgetsticky)
+ add %sp, -SA(MINFRAME), %sp ! get an additional word of storage
+ set 0x000003e0, %o4 ! mask of accrued exception bits
+ st %fsr, [%sp+ARGPUSH] ! get fsr value
+ ld [%sp+ARGPUSH], %o0 ! load into register
+ and %o0, %o4, %o0 ! mask off bits of interest
+ srl %o0, 5, %o0 ! return accrued exception value
+ retl
+ add %sp, SA(MINFRAME), %sp ! reclaim stack space
+
+ SET_SIZE(fpgetsticky)
diff --git a/usr/src/lib/libc/sparc/fp/fpsetmask.s b/usr/src/lib/libc/sparc/fp/fpsetmask.s
new file mode 100644
index 0000000000..9732d6a85c
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/fpsetmask.s
@@ -0,0 +1,64 @@
+/*
+ * 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.4.1.9 */
+
+/*
+ * fp_except fpsetmask(mask)
+ * fp_except mask;
+ * set exception masks as defined by user and return
+ * previous setting
+ * any sticky bit set whose corresponding mask is dis-abled
+ * is cleared
+ */
+
+ .file "fpsetmask.s"
+
+#include <sys/asm_linkage.h>
+
+ ANSI_PRAGMA_WEAK(fpsetmask,function)
+
+#include "synonyms.h"
+
+ ENTRY(fpsetmask)
+ add %sp, -SA(MINFRAME), %sp ! get an additional word of storage
+ set 0x0f800000, %o4 ! mask of trap enable bits
+ sll %o0, 23, %o1 ! move input bits into position
+ st %fsr, [%sp+ARGPUSH] ! get fsr value
+ ld [%sp+ARGPUSH], %o0 ! load into register
+ and %o1, %o4, %o1 ! generate new fsr value
+ andn %o0, %o4, %o2
+ or %o1, %o2, %o1
+ st %o1, [%sp+ARGPUSH] ! move new fsr value to memory
+ ld [%sp+ARGPUSH], %fsr ! load fsr with new value
+ and %o0, %o4, %o0 ! mask off bits of interest in old fsr
+ srl %o0, 23, %o0 ! return old trap enable value
+ retl
+ add %sp, SA(MINFRAME), %sp ! reclaim stack space
+
+ SET_SIZE(fpsetmask)
diff --git a/usr/src/lib/libc/sparc/fp/fpsetrnd.s b/usr/src/lib/libc/sparc/fp/fpsetrnd.s
new file mode 100644
index 0000000000..6178aeb4f4
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/fpsetrnd.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.5.1.9 */
+
+ .file "fpsetrnd.s"
+
+#include <sys/asm_linkage.h>
+
+ ANSI_PRAGMA_WEAK(fpsetround,function)
+
+#include "synonyms.h"
+
+ ENTRY(fpsetround)
+ add %sp, -SA(MINFRAME), %sp ! get an additional word of storage
+ set 0xc0000000, %o4 ! mask of round control bits
+ sll %o0, 30, %o1 ! move input bits into position
+ st %fsr, [%sp+ARGPUSH] ! get fsr value
+ ld [%sp+ARGPUSH], %o0 ! load into register
+ and %o1, %o4, %o1 ! generate new fsr value
+ andn %o0, %o4, %o2
+ or %o1, %o2, %o1
+ st %o1, [%sp+ARGPUSH] ! move new fsr value to memory
+ ld [%sp+ARGPUSH], %fsr ! load fsr with new value
+ srl %o0, 30, %o0 ! return old round control value
+ retl
+ add %sp, SA(MINFRAME), %sp ! reclaim stack space
+
+ SET_SIZE(fpsetround)
diff --git a/usr/src/lib/libc/sparc/fp/fpsetsticky.s b/usr/src/lib/libc/sparc/fp/fpsetsticky.s
new file mode 100644
index 0000000000..1ce9b3c8a3
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/fpsetsticky.s
@@ -0,0 +1,55 @@
+/*
+ * 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.4.1.7 */
+
+ .file "fpsetsticky.s"
+
+#include <sys/asm_linkage.h>
+
+ ANSI_PRAGMA_WEAK(fpsetsticky,function)
+
+#include "synonyms.h"
+
+ ENTRY(fpsetsticky)
+ add %sp, -SA(MINFRAME), %sp ! get an additional word of storage
+ set 0x000003e0, %o4 ! mask of accrued exception bits
+ sll %o0, 5, %o1 ! move input bits into position
+ st %fsr, [%sp+ARGPUSH] ! get fsr value
+ ld [%sp+ARGPUSH], %o0 ! load into register
+ and %o1, %o4, %o1 ! generate new fsr value
+ andn %o0, %o4, %o2
+ or %o1, %o2, %o1
+ st %o1, [%sp+ARGPUSH] ! move new fsr value to memory
+ ld [%sp+ARGPUSH], %fsr ! load fsr with new value
+ and %o0, %o4, %o0 ! mask off bits of interest in old fsr
+ srl %o0, 5, %o0 ! return old accrued exception value
+ retl
+ add %sp, SA(MINFRAME), %sp ! reclaim stack space
+
+ SET_SIZE(fpsetsticky)
diff --git a/usr/src/lib/libc/sparc/fp/quad.h b/usr/src/lib/libc/sparc/fp/quad.h
new file mode 100644
index 0000000000..e703948c2b
--- /dev/null
+++ b/usr/src/lib/libc/sparc/fp/quad.h
@@ -0,0 +1,163 @@
+/*
+ * 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) 1994-1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#ifndef _QUAD_H
+#define _QUAD_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Common definitions for quadruple precision emulation routines
+ * (SPARC only)
+ */
+
+/* macros to simplify dealing with the diferences between V8 and V9 */
+#ifdef __sparcv9
+
+#define Z (*pz)
+#define QUAD_RETURN(x) return
+
+#else
+
+#define Z z
+#define QUAD_RETURN(x) return (x)
+
+#endif
+
+/* fsr definitions */
+
+/* current exception bits */
+#define FSR_NXC 0x1
+#define FSR_DZC 0x2
+#define FSR_UFC 0x4
+#define FSR_OFC 0x8
+#define FSR_NVC 0x10
+#define FSR_CEXC 0x1f /* mask for all cexc bits */
+
+/* accrued exception bits */
+#define FSR_NXA 0x20
+#define FSR_DZA 0x40
+#define FSR_UFA 0x80
+#define FSR_OFA 0x100
+#define FSR_NVA 0x200
+
+/* trap enable bits */
+#define FSR_NXM 0x00800000
+#define FSR_DZM 0x01000000
+#define FSR_UFM 0x02000000
+#define FSR_OFM 0x04000000
+#define FSR_NVM 0x08000000
+
+/* rounding directions (shifted) */
+#define FSR_RN 0
+#define FSR_RZ 1
+#define FSR_RP 2
+#define FSR_RM 3
+
+/*
+ * in struct longdouble, msw implicitly consists of
+ * unsigned short sign:1;
+ * unsigned short exponent:15;
+ * unsigned short frac1:16;
+ */
+
+/* structure used to access words within a quad */
+union longdouble {
+ struct {
+ unsigned int msw;
+ unsigned int frac2;
+ unsigned int frac3;
+ unsigned int frac4;
+ } l;
+ long double d; /* unused; just guarantees correct alignment */
+};
+
+/* macros used internally for readability */
+#define QUAD_ISNAN(x) \
+ (((x).l.msw & 0x7fff0000) == 0x7fff0000 && \
+ (((x).l.msw & 0xffff) | (x).l.frac2 | (x).l.frac3 | (x).l.frac4))
+
+#define QUAD_ISZERO(x) \
+ (!(((x).l.msw & 0x7fffffff) | (x).l.frac2 | (x).l.frac3 | (x).l.frac4))
+
+/* structure used to access words within a double */
+union xdouble {
+ struct {
+ unsigned int hi;
+ unsigned int lo;
+ } l;
+ double d;
+};
+
+/* relationships returned by _Q_cmp and _Q_cmpe */
+enum fcc_type {
+ fcc_equal = 0,
+ fcc_less = 1,
+ fcc_greater = 2,
+ fcc_unordered = 3
+};
+
+/* internal routines */
+extern void __quad_mag_add(const union longdouble *,
+ const union longdouble *, union longdouble *, unsigned int *);
+extern void __quad_mag_sub(const union longdouble *,
+ const union longdouble *, union longdouble *, unsigned int *);
+
+/* inline templates */
+extern void __quad_getfsrp(unsigned int *);
+extern void __quad_setfsrp(const unsigned int *);
+extern double __quad_dp_sqrt(double *);
+extern void __quad_faddq(const union longdouble *, const union longdouble *,
+ union longdouble *);
+extern void __quad_fsubq(const union longdouble *, const union longdouble *,
+ union longdouble *);
+extern void __quad_fmulq(const union longdouble *, const union longdouble *,
+ union longdouble *);
+extern void __quad_fdivq(const union longdouble *, const union longdouble *,
+ union longdouble *);
+extern void __quad_fsqrtq(const union longdouble *, union longdouble *);
+extern void __quad_fcmpq(const union longdouble *, const union longdouble *,
+ unsigned int *);
+extern void __quad_fcmpeq(const union longdouble *, const union longdouble *,
+ unsigned int *);
+extern void __quad_fstoq(const float *, union longdouble *);
+extern void __quad_fdtoq(const double *, union longdouble *);
+extern void __quad_fqtoi(const union longdouble *, int *);
+extern void __quad_fqtos(const union longdouble *, float *);
+extern void __quad_fqtod(const union longdouble *, double *);
+#ifdef __sparcv9
+extern void __quad_fqtox(const union longdouble *, long *);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _QUAD_H */
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[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
diff --git a/usr/src/lib/libc/sparc/genassym.c b/usr/src/lib/libc/sparc/genassym.c
new file mode 100644
index 0000000000..e85b97c676
--- /dev/null
+++ b/usr/src/lib/libc/sparc/genassym.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"
+
+#include <stdio.h>
+#include <stddef.h>
+#include <signal.h>
+#include <sys/synch.h>
+#include <sys/synch32.h>
+#include "thr_uberdata.h"
+
+/*
+ * This file generates two values used by _lwp_mutex_unlock.s:
+ * a) the byte offset (in lwp_mutex_t) of the word containing the lock byte
+ * b) a mask to extract the waiter field from the word containing it
+ * These offsets do not change between 32-bit and 64-bit.
+ * Mutexes can be shared between 32-bit and 64-bit programs.
+ */
+
+int
+main(void)
+{
+ (void) printf("#define\tMUTEX_LOCK_WORD\t0x%p\n",
+ offsetof(lwp_mutex_t, mutex_lockword));
+ (void) printf("#define\tWAITER_MASK\t0xff\n");
+
+ (void) printf("#define\tSIG_SETMASK\t0x%lx\n", SIG_SETMASK);
+ (void) printf("#define\tMASKSET0\t0x%lx\n", MASKSET0);
+ (void) printf("#define\tMASKSET1\t0x%lx\n", MASKSET1);
+ (void) printf("#define\tSIGSEGV\t0x%lx\n", SIGSEGV);
+
+ return (0);
+}
diff --git a/usr/src/lib/libc/sparc/inc/SYS.h b/usr/src/lib/libc/sparc/inc/SYS.h
new file mode 100644
index 0000000000..7a0f619a72
--- /dev/null
+++ b/usr/src/lib/libc/sparc/inc/SYS.h
@@ -0,0 +1,264 @@
+/*
+ * 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.
+ */
+
+#ifndef _LIBC_SPARC_INC_SYS_H
+#define _LIBC_SPARC_INC_SYS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file defines common code sequences for system calls. Note that
+ * it is assumed that __cerror is within the short branch distance from
+ * all the traps (so that a simple bcs can follow the trap, rather than
+ * a position independent code sequence.) Ditto for __cerror64.
+ */
+
+#include <sys/asm_linkage.h>
+#include <sys/syscall.h>
+#include <sys/errno.h>
+#include "synonyms.h"
+
+/*
+ * While it's tempting to imagine we could use 'rd %pc' here,
+ * in fact it's a rather slow operation that consumes many
+ * cycles, so we use the usual side-effect of 'call' instead.
+ */
+#define PIC_SETUP(r) \
+ mov %o7, %g1; \
+9: call 8f; \
+ sethi %hi(_GLOBAL_OFFSET_TABLE_ - (9b - .)), %r; \
+8: or %r, %lo(_GLOBAL_OFFSET_TABLE_ - (9b - .)), %r; \
+ add %r, %o7, %r; \
+ mov %g1, %o7
+
+/*
+ * Trap number for system calls
+ */
+#define SYSCALL_TRAPNUM 8
+#define FASTSCALL_TRAPNUM 9
+
+/*
+ * Define the external symbols __cerror and __cerror64 for all files.
+ */
+ .global __cerror
+ .global __cerror64
+
+/*
+ * __SYSTRAP provides the basic trap sequence. It assumes that an entry
+ * of the form SYS_name exists (probably from sys/syscall.h).
+ */
+#define __SYSTRAP(name) \
+ /* CSTYLED */ \
+ mov SYS_/**/name, %g1; \
+ ta SYSCALL_TRAPNUM
+
+#define SYSTRAP_RVAL1(name) __SYSTRAP(name)
+#define SYSTRAP_RVAL2(name) __SYSTRAP(name)
+#define SYSTRAP_2RVALS(name) __SYSTRAP(name)
+#define SYSTRAP_64RVAL(name) __SYSTRAP(name)
+
+/*
+ * SYSFASTTRAP provides the fast system call trap sequence. It assumes
+ * that an entry of the form ST_name exists (probably from sys/trap.h).
+ */
+#define SYSFASTTRAP(name) \
+ /* CSTYLED */ \
+ ta ST_/**/name
+
+/*
+ * SYSCERROR provides the sequence to branch to __cerror if an error is
+ * indicated by the carry-bit being set upon return from a trap.
+ */
+#define SYSCERROR \
+ bcs __cerror; \
+ nop
+
+/*
+ * SYSCERROR64 provides the sequence to branch to __cerror64 if an error is
+ * indicated by the carry-bit being set upon return from a trap.
+ */
+#define SYSCERROR64 \
+ bcs __cerror64; \
+ nop
+
+/*
+ * SYSLWPERR provides the sequence to return 0 on a successful trap
+ * and the error code if unsuccessful.
+ * Error is indicated by the carry-bit being set upon return from a trap.
+ */
+#define SYSLWPERR \
+ /* CSTYLED */ \
+ bcc,a,pt %icc, 1f; \
+ clr %o0; \
+ cmp %o0, ERESTART; \
+ move %icc, EINTR, %o0; \
+1:
+
+#define SAVE_OFFSET 68
+
+/*
+ * SYSREENTRY provides the entry sequence for restartable system calls.
+ */
+#define SYSREENTRY(name) \
+ ENTRY(name); \
+ stn %o0, [%sp + SAVE_OFFSET]; \
+/* CSTYLED */ \
+.restart_/**/name:
+
+/*
+ * SYSRESTART provides the error handling sequence for restartable
+ * system calls.
+ */
+#define SYSRESTART(name) \
+ /* CSTYLED */ \
+ bcc,pt %icc, 1f; \
+ cmp %o0, ERESTART; \
+ /* CSTYLED */ \
+ be,a,pn %icc, name; \
+ ldn [%sp + SAVE_OFFSET], %o0; \
+ /* CSTYLED */ \
+ ba,a __cerror; \
+1:
+
+/*
+ * SYSINTR_RESTART provides the error handling sequence for restartable
+ * system calls in case of EINTR or ERESTART.
+ */
+#define SYSINTR_RESTART(name) \
+ /* CSTYLED */ \
+ bcc,a,pt %icc, 1f; \
+ clr %o0; \
+ cmp %o0, ERESTART; \
+ /* CSTYLED */ \
+ be,a,pn %icc, name; \
+ ldn [%sp + SAVE_OFFSET], %o0; \
+ cmp %o0, EINTR; \
+ /* CSTYLED */ \
+ be,a,pn %icc, name; \
+ ldn [%sp + SAVE_OFFSET], %o0; \
+1:
+
+/*
+ * SYSCALL provides the standard (i.e.: most common) system call sequence.
+ */
+#define SYSCALL(name) \
+ ENTRY(name); \
+ SYSTRAP_2RVALS(name); \
+ SYSCERROR
+
+#define SYSCALL_RVAL1(name) \
+ ENTRY(name); \
+ SYSTRAP_RVAL1(name); \
+ SYSCERROR
+
+/*
+ * SYSCALL64 provides the standard (i.e.: most common) system call sequence
+ * for system calls that return 64-bit values.
+ */
+#define SYSCALL64(name) \
+ ENTRY(name); \
+ SYSTRAP_64RVAL(name); \
+ SYSCERROR64
+
+/*
+ * SYSCALL_RESTART provides the most common restartable system call sequence.
+ */
+#define SYSCALL_RESTART(name) \
+ SYSREENTRY(name); \
+ SYSTRAP_2RVALS(name); \
+ /* CSTYLED */ \
+ SYSRESTART(.restart_/**/name)
+
+#define SYSCALL_RESTART_RVAL1(name) \
+ SYSREENTRY(name); \
+ SYSTRAP_RVAL1(name); \
+ /* CSTYLED */ \
+ SYSRESTART(.restart_/**/name)
+
+/*
+ * SYSCALL2 provides a common system call sequence when the entry name
+ * is different than the trap name.
+ */
+#define SYSCALL2(entryname, trapname) \
+ ENTRY(entryname); \
+ SYSTRAP_2RVALS(trapname); \
+ SYSCERROR
+
+#define SYSCALL2_RVAL1(entryname, trapname) \
+ ENTRY(entryname); \
+ SYSTRAP_RVAL1(trapname); \
+ SYSCERROR
+
+/*
+ * SYSCALL2_RESTART provides a common restartable system call sequence when the
+ * entry name is different than the trap name.
+ */
+#define SYSCALL2_RESTART(entryname, trapname) \
+ SYSREENTRY(entryname); \
+ SYSTRAP_2RVALS(trapname); \
+ /* CSTYLED */ \
+ SYSRESTART(.restart_/**/entryname)
+
+#define SYSCALL2_RESTART_RVAL1(entryname, trapname) \
+ SYSREENTRY(entryname); \
+ SYSTRAP_RVAL1(trapname); \
+ /* CSTYLED */ \
+ SYSRESTART(.restart_/**/entryname)
+
+/*
+ * SYSCALL_NOERROR provides the most common system call sequence for those
+ * system calls which don't check the error return (carry bit).
+ */
+#define SYSCALL_NOERROR(name) \
+ ENTRY(name); \
+ SYSTRAP_2RVALS(name)
+
+#define SYSCALL_NOERROR_RVAL1(name) \
+ ENTRY(name); \
+ SYSTRAP_RVAL1(name)
+
+/*
+ * Standard syscall return sequence, return code equal to rval1.
+ */
+#define RET \
+ retl; \
+ nop
+
+/*
+ * Syscall return sequence, return code equal to rval2.
+ */
+#define RET2 \
+ retl; \
+ mov %o1, %o0
+
+/*
+ * Syscall return sequence with return code forced to zero.
+ */
+#define RETC \
+ retl; \
+ clr %o0
+
+#endif /* _LIBC_SPARC_INC_SYS_H */
diff --git a/usr/src/lib/libc/sparc/offsets.in b/usr/src/lib/libc/sparc/offsets.in
new file mode 100644
index 0000000000..dd625da012
--- /dev/null
+++ b/usr/src/lib/libc/sparc/offsets.in
@@ -0,0 +1,64 @@
+\
+\ Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+\ Use is subject to license terms.
+\
+\ 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
+\
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+\
+\ offsets.in: input file to produce assym.h using the ctfstabs program
+\
+
+#include "libc_int.h"
+#include "thr_uberdata.h"
+#include "sigjmp_struct.h"
+
+TLS_index
+ ti_moduleid
+ ti_tlsoffset
+
+tls_t SIZEOF_TLS_T
+ tls_data
+ tls_size
+
+\#define UL_TLSENT (UL_TLS + TLS_DATA)
+\#define UL_NTLSENT (UL_TLS + TLS_SIZE)
+
+ulwp_t
+ ul_tls
+ ul_ustack
+ ul_vfork
+ ul_schedctl
+ ul_schedctl_called
+ ul_sigmask
+ ul_unwind_ret
+
+sigjmp_struct_t
+ sjs_sp
+ sjs_pc
+ sjs_fp
+ sjs_i7
+
+stack_t
+ ss_sp
+ ss_size
diff --git a/usr/src/lib/libc/sparc/sys/__clock_gettime.s b/usr/src/lib/libc/sparc/sys/__clock_gettime.s
new file mode 100644
index 0000000000..a464864da2
--- /dev/null
+++ b/usr/src/lib/libc/sparc/sys/__clock_gettime.s
@@ -0,0 +1,55 @@
+/*
+ * 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/time_impl.h>
+#include "SYS.h"
+
+/*
+ * int
+ * __clock_gettime(clockid_t clock_id, timespec_t *tp)
+ */
+
+ ENTRY(__clock_gettime)
+ cmp %o0, __CLOCK_REALTIME0 ! if (clock_id)
+ beq 2f ! equal to __CLOCK_REALTIME0
+ cmp %o0, CLOCK_REALTIME ! or
+ bne 1f ! equal to CLOCK_REALTIME
+ .empty ! optimize for CLOCK_REALTIME
+2:
+ mov %o1, %o5
+ SYSFASTTRAP(GETHRESTIME)
+ stn %o0, [%o5]
+ stn %o1, [%o5 + CLONGSIZE]
+ RETC
+1:
+ SYSTRAP_RVAL1(clock_gettime)
+ SYSCERROR
+ RETC
+ SET_SIZE(__clock_gettime)
diff --git a/usr/src/lib/libc/sparc/sys/__getcontext.s b/usr/src/lib/libc/sparc/sys/__getcontext.s
new file mode 100644
index 0000000000..ce2cd69835
--- /dev/null
+++ b/usr/src/lib/libc/sparc/sys/__getcontext.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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+ .file "%M%"
+
+/*
+ * __getcontext() must be implemented in assembler, as opposed
+ * to the other members of the SYS_context family (see ucontext.c)
+ * because we must be careful to get the precise context of the caller.
+ */
+
+#include "SYS.h"
+
+ ANSI_PRAGMA_WEAK2(__getcontext_syscall,__getcontext,function)
+
+ ENTRY(__getcontext)
+ mov %o0, %o1
+ mov 0, %o0
+ SYSTRAP_RVAL1(context)
+ SYSCERROR
+ RET
+ SET_SIZE(__getcontext)
diff --git a/usr/src/lib/libc/sparc/sys/_lwp_mutex_unlock.s b/usr/src/lib/libc/sparc/sys/_lwp_mutex_unlock.s
new file mode 100644
index 0000000000..5cf848d7b7
--- /dev/null
+++ b/usr/src/lib/libc/sparc/sys/_lwp_mutex_unlock.s
@@ -0,0 +1,59 @@
+/*
+ * 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"
+
+ .file "%M%"
+
+#include <sys/asm_linkage.h>
+
+ ANSI_PRAGMA_WEAK(_lwp_mutex_unlock,function)
+
+#include "SYS.h"
+#include <sys/synch32.h>
+#include <../assym.h>
+
+ ANSI_PRAGMA_WEAK2(_private_lwp_mutex_unlock,_lwp_mutex_unlock,function)
+
+ ENTRY(_lwp_mutex_unlock)
+ membar #LoadStore|#StoreStore
+ add %o0, MUTEX_LOCK_WORD, %o1
+ ld [%o1], %o2
+1:
+ clr %o3 ! clear lock/get waiter field
+ cas [%o1], %o2, %o3 ! atomically
+ cmp %o2, %o3
+ bne,a,pn %icc, 1b
+ mov %o3, %o2
+ btst WAITER_MASK, %o3 ! check for waiters
+ beq,a,pt %icc,2f ! if no waiters
+ clr %o0 ! return 0
+ ! else (note that %o0 is still
+ ! &mutex)
+ SYSTRAP_RVAL1(lwp_mutex_wakeup) ! call kernel to wakeup waiter
+ SYSLWPERR
+2: RET
+ SET_SIZE(_lwp_mutex_unlock)
diff --git a/usr/src/lib/libc/sparc/sys/door.s b/usr/src/lib/libc/sparc/sys/door.s
new file mode 100644
index 0000000000..3b1abf187e
--- /dev/null
+++ b/usr/src/lib/libc/sparc/sys/door.s
@@ -0,0 +1,181 @@
+/*
+ * 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"
+
+ .file "%M%"
+
+#include <sys/asm_linkage.h>
+
+ /*
+ * weak aliases for public interfaces
+ */
+ ANSI_PRAGMA_WEAK(_door_bind,function)
+ ANSI_PRAGMA_WEAK(_door_call,function)
+ ANSI_PRAGMA_WEAK(_door_getparam,function)
+ ANSI_PRAGMA_WEAK(_door_info,function)
+ ANSI_PRAGMA_WEAK(_door_revoke,function)
+ ANSI_PRAGMA_WEAK(_door_setparam,function)
+ ANSI_PRAGMA_WEAK(_door_unbind,function)
+
+ ANSI_PRAGMA_WEAK(door_bind,function)
+ ANSI_PRAGMA_WEAK(door_call,function)
+ ANSI_PRAGMA_WEAK(door_getparam,function)
+ ANSI_PRAGMA_WEAK(door_info,function)
+ ANSI_PRAGMA_WEAK(door_revoke,function)
+ ANSI_PRAGMA_WEAK(door_setparam,function)
+ ANSI_PRAGMA_WEAK(door_unbind,function)
+
+#include <sys/door.h>
+#include "SYS.h"
+
+/*
+ * Offsets within struct door_results
+ */
+#define DOOR_COOKIE (SA(MINFRAME) + STACK_BIAS + 0*CLONGSIZE)
+#define DOOR_DATA_PTR (SA(MINFRAME) + STACK_BIAS + 1*CLONGSIZE)
+#define DOOR_DATA_SIZE (SA(MINFRAME) + STACK_BIAS + 2*CLONGSIZE)
+#define DOOR_DESC_PTR (SA(MINFRAME) + STACK_BIAS + 3*CLONGSIZE)
+#define DOOR_DESC_SIZE (SA(MINFRAME) + STACK_BIAS + 4*CLONGSIZE)
+#define DOOR_PC (SA(MINFRAME) + STACK_BIAS + 5*CLONGSIZE)
+#define DOOR_SERVERS (SA(MINFRAME) + STACK_BIAS + 6*CLONGSIZE)
+#define DOOR_INFO_PTR (SA(MINFRAME) + STACK_BIAS + 7*CLONGSIZE)
+
+/*
+ * All of the syscalls except door_return() follow the same pattern. The
+ * subcode goes in %o5, after all of the other arguments.
+ */
+#define DOOR_SYSCALL(name, code) \
+ ENTRY(name); \
+ mov code, %o5; /* subcode */ \
+ SYSTRAP_RVAL1(door); \
+ SYSCERROR; \
+ RET; \
+ SET_SIZE(name)
+
+ DOOR_SYSCALL(__door_bind, DOOR_BIND)
+ DOOR_SYSCALL(__door_call, DOOR_CALL)
+ DOOR_SYSCALL(__door_create, DOOR_CREATE)
+ DOOR_SYSCALL(__door_getparam, DOOR_GETPARAM)
+ DOOR_SYSCALL(__door_info, DOOR_INFO)
+ DOOR_SYSCALL(__door_revoke, DOOR_REVOKE)
+ DOOR_SYSCALL(__door_setparam, DOOR_SETPARAM)
+ DOOR_SYSCALL(__door_ucred, DOOR_UCRED)
+ DOOR_SYSCALL(__door_unbind, DOOR_UNBIND)
+ DOOR_SYSCALL(__door_unref, DOOR_UNREFSYS)
+
+/*
+ * int
+ * __door_return(
+ * void *data_ptr,
+ * size_t data_size, (in bytes)
+ * door_return_desc_t *door_ptr, (holds returned desc info)
+ * caddr_t stack_base,
+ * size_t stack_size)
+ */
+ ENTRY(__door_return)
+door_restart:
+ mov DOOR_RETURN, %o5 /* subcode */
+ SYSTRAP_RVAL1(door)
+ bcs,pn %icc, 2f /* errno is set */
+ ld [%sp + DOOR_SERVERS], %g1 /* (delay) load nservers */
+ /*
+ * On return, we're serving a door_call. Our stack looks like this:
+ *
+ * descriptors (if any)
+ * data (if any)
+ * struct door_results
+ * MINFRAME
+ * sp ->
+ */
+ tst %g1 /* test nservers */
+ bg 1f /* everything looks o.k. */
+ ldn [%sp + DOOR_COOKIE], %o0 /* (delay) load cookie */
+ /*
+ * this is the last server thread - call creation func for more
+ */
+ save %sp, -SA(MINFRAME), %sp
+ PIC_SETUP(g1)
+#ifdef __sparcv9
+ sethi %hi(door_server_func), %g5
+ or %g5, %lo(door_server_func), %g5
+ ldn [%g5 + %g1], %g1
+#else
+ ldn [%g1 + door_server_func], %g1
+#endif
+ ldn [%g1], %g1
+ jmpl %g1, %o7 /* call create function */
+ ldn [%fp + DOOR_INFO_PTR], %o0 /* (delay) load door_info ptr */
+ restore
+1:
+ /* Call the door server function now */
+ ldn [%sp + DOOR_DATA_PTR], %o1
+ ldn [%sp + DOOR_DATA_SIZE], %o2
+ ldn [%sp + DOOR_DESC_PTR], %o3
+ ldn [%sp + DOOR_PC], %g1
+ jmpl %g1, %o7
+ ldn [%sp + DOOR_DESC_SIZE], %o4
+
+ /* Exit the thread if we return here */
+ call _thr_terminate
+ mov %g0, %o0
+ /* NOTREACHED */
+2:
+ /*
+ * Error during door_return call. Repark the thread in the kernel if
+ * the error code is EINTR (or ERESTART) and this lwp is still part
+ * of the same process.
+ */
+ cmp %o0, ERESTART /* ERESTART is same as EINTR */
+ be,a 3f
+ mov EINTR, %o0
+3:
+ cmp %o0, EINTR /* interrupted while waiting? */
+ bne __cerror /* if not, return the error */
+ nop
+
+ save %sp, -SA(MINFRAME), %sp
+ call _private_getpid /* get current process id */
+ nop
+ PIC_SETUP(g1)
+#ifdef __sparcv9
+ sethi %hi(door_create_pid), %g5
+ or %g5, %lo(door_create_pid), %g5
+ ldn [%g1 + %g5], %g1
+#else
+ ldn [%g1 + door_create_pid], %g1
+#endif
+ ld [%g1], %g1
+ cmp %o0, %g1 /* same process? */
+ mov EINTR, %o0 /* if no, return EINTR (child of forkall) */
+ bne __cerror
+ restore
+
+ clr %o0 /* clear arguments and restart */
+ clr %o1
+ ba door_restart
+ clr %o2
+ SET_SIZE(__door_return)
diff --git a/usr/src/lib/libc/sparc/sys/fork1.s b/usr/src/lib/libc/sparc/sys/fork1.s
new file mode 100644
index 0000000000..1d011cbb37
--- /dev/null
+++ b/usr/src/lib/libc/sparc/sys/fork1.s
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+ .file "%M%"
+
+/*
+ * C library -- fork1
+ * pid_t fork1(void)
+ */
+
+/*
+ * From the syscall:
+ * %o1 == 0 in parent process, %o1 == 1 in child process.
+ * %o0 == pid of child in parent, %o0 == pid of parent in child.
+ *
+ * The child gets a zero return value.
+ * The parent gets the pid of the child.
+ */
+
+#include "SYS.h"
+
+ ENTRY(__fork1);
+ SYSTRAP_2RVALS(fork1);
+ SYSCERROR
+ movrnz %o1, 0, %o0
+ RET
+ SET_SIZE(__fork1)
diff --git a/usr/src/lib/libc/sparc/sys/forkall.s b/usr/src/lib/libc/sparc/sys/forkall.s
new file mode 100644
index 0000000000..43ef74e8bb
--- /dev/null
+++ b/usr/src/lib/libc/sparc/sys/forkall.s
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+ .file "%M%"
+
+/*
+ * C library -- forkall
+ * pid_t forkall(void)
+ */
+
+/*
+ * From the syscall:
+ * %o1 == 0 in parent process, %o1 == 1 in child process.
+ * %o0 == pid of child in parent, %o0 == pid of parent in child.
+ *
+ * The child gets a zero return value.
+ * The parent gets the pid of the child.
+ */
+
+#include "SYS.h"
+
+ ENTRY(__forkall)
+ SYSTRAP_2RVALS(forkall)
+ SYSCERROR
+ movrnz %o1, 0, %o0
+ RET
+ SET_SIZE(__forkall)
diff --git a/usr/src/lib/libc/sparc/sys/gettimeofday.s b/usr/src/lib/libc/sparc/sys/gettimeofday.s
new file mode 100644
index 0000000000..23984f57ee
--- /dev/null
+++ b/usr/src/lib/libc/sparc/sys/gettimeofday.s
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+ .file "%M%"
+
+/*
+ * C library -- gettimeofday
+ * int gettimeofday (struct timeval *tp);
+ */
+
+#include <sys/asm_linkage.h>
+
+ ANSI_PRAGMA_WEAK(gettimeofday,function)
+
+#include "SYS.h"
+
+/*
+ * The interface below calls the trap (0x27) to get the timestamp in
+ * secs and nsecs. It than converts the nsecs value into usecs before
+ * it returns.
+ *
+ * The algorithm used to perform the division by 1000 is based upon
+ * algorithms for division based upon multiplication by invariant
+ * integers. Relevant sources for these algorithms are:
+ *
+ * Granlund, T.; Montgomery, P.L.: "Division by Invariant Integers using
+ * Multiplication". SIGPLAN Notices, Vol. 29, June 1994, page 61.
+ *
+ * Magenheimer, D.J.; et al: "Integer Multiplication and Division on the HP
+ * Precision Architecture". IEEE Transactions on Computers, Vol 37, No. 8,
+ * August 1988, page 980.
+ *
+ * Steele G.; Warren H.: Hacker's Delight. 2002 Pearson Education, Ch 10
+ *
+ */
+
+ ENTRY(_gettimeofday)
+ brz,pn %o0, 1f
+ mov %o0, %o5
+ SYSFASTTRAP(GETHRESTIME)
+ stn %o0, [%o5]
+ sethi %hi(0x10624DD3), %o2
+ or %o2, %lo(0x10624DD3), %o2
+ mulx %o1, %o2, %o2
+ srlx %o2, 38, %o2
+ stn %o2, [%o5 + CLONGSIZE]
+1: RETC
+ SET_SIZE(_gettimeofday)
diff --git a/usr/src/lib/libc/sparc/sys/pipe.s b/usr/src/lib/libc/sparc/sys/pipe.s
new file mode 100644
index 0000000000..d9eadc070c
--- /dev/null
+++ b/usr/src/lib/libc/sparc/sys/pipe.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 (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"
+
+/* C library -- pipe */
+/* int pipe (int fildes[2]); */
+
+ .file "pipe.s"
+
+#include <sys/asm_linkage.h>
+
+ ANSI_PRAGMA_WEAK(pipe,function)
+
+#include "SYS.h"
+
+ ENTRY(pipe)
+ mov %o0, %o2 /* save ptr to array */
+ SYSTRAP_2RVALS(pipe)
+ SYSCERROR
+ st %o0, [%o2]
+ st %o1, [%o2 + 4]
+ RETC
+
+ SET_SIZE(pipe)
diff --git a/usr/src/lib/libc/sparc/sys/ptrace.c b/usr/src/lib/libc/sparc/sys/ptrace.c
new file mode 100644
index 0000000000..53f9a1964a
--- /dev/null
+++ b/usr/src/lib/libc/sparc/sys/ptrace.c
@@ -0,0 +1,748 @@
+/*
+ * 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
+ */
+/*
+ * ptrace(2) interface built on top of proc(4).
+ */
+
+/*
+ * Copyright 1990-2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#pragma weak ptrace = _ptrace
+
+#include "synonyms.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <memory.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <signal.h>
+#include <sys/siginfo.h>
+#include <sys/fault.h>
+#include <sys/syscall.h>
+#include <procfs.h>
+#include <sys/psw.h>
+#include <sys/user.h>
+/*
+ * mtlib.h must precede thread.h
+ */
+#include <mtlib.h>
+#include <thread.h>
+#include <synch.h>
+#include <unistd.h>
+
+static mutex_t pt_lock = DEFAULTMUTEX;
+
+#define TRUE 1
+#define FALSE 0
+
+/*
+ * All my children...
+ */
+typedef struct cstatus {
+ struct cstatus *next; /* linked list */
+ pid_t pid; /* process-id */
+ int asfd; /* /proc/<pid>/as */
+ int ctlfd; /* /proc/<pid>/ctl */
+ int statusfd; /* /proc/<pid>/status */
+ int flags; /* see below */
+ pstatus_t pstatus; /* from /proc/<pid>/status */
+ user_t user; /* manufactured u-block */
+} cstatus_t;
+
+/* flags */
+#define CS_SETREGS 0x01 /* set registers on run */
+#define CS_PSARGS 0x02 /* u_psargs[] has been fetched */
+#define CS_SIGNAL 0x04 /* u_signal[] has been fetched */
+
+#define NULLCP ((cstatus_t *)0)
+
+static cstatus_t *childp = NULLCP;
+
+/* fake u-block offsets */
+#define UP ((user_t *)NULL)
+#define U_REG ((int)(&UP->u_reg[0]))
+#define U_AR0 ((int)(&UP->u_ar0))
+#define U_PSARGS ((int)(&UP->u_psargs[0]))
+#define U_SIGNAL ((int)(&UP->u_signal[0]))
+#define U_CODE ((int)(&UP->u_code))
+#define U_ADDR ((int)(&UP->u_addr))
+#define U_END ((int)sizeof (user_t))
+#define REGADDR 0xffff0000 /* arbitrary kernel address for u_ar0 */
+
+/* external routines defined in this module */
+extern int ptrace(int, pid_t, int, int);
+/* static routines defined in this module */
+static cstatus_t *FindProc(pid_t);
+static void CheckAllProcs(void);
+static int Dupfd(int, int);
+static void MakeProcName(char *, pid_t);
+static int OpenProc(cstatus_t *);
+static void CloseProc(cstatus_t *);
+static cstatus_t *GrabProc(pid_t);
+static void ReleaseProc(cstatus_t *);
+static int ProcUpdate(cstatus_t *);
+static void MakeUser(cstatus_t *);
+static void GetPsargs(cstatus_t *);
+static void GetSignal(cstatus_t *);
+
+#if PTRACE_DEBUG
+/* for debugging */
+static char *
+map(int request)
+{
+ static char name[20];
+
+ switch (request) {
+ case 0: return ("PTRACE_TRACEME");
+ case 1: return ("PTRACE_PEEKTEXT");
+ case 2: return ("PTRACE_PEEKDATA");
+ case 3: return ("PTRACE_PEEKUSER");
+ case 4: return ("PTRACE_POKETEXT");
+ case 5: return ("PTRACE_POKEDATA");
+ case 6: return ("PTRACE_POKEUSER");
+ case 7: return ("PTRACE_CONT");
+ case 8: return ("PTRACE_KILL");
+ case 9: return ("PTRACE_SINGLESTEP");
+ }
+ (void) sprintf(name, "%d", request);
+ return (name);
+}
+#endif
+
+int
+ptrace(int request, pid_t pid, int addr, int data)
+{
+ pstatus_t *ps;
+ cstatus_t *cp;
+ unsigned xaddr;
+ struct {
+ long cmd;
+ union {
+ long flags;
+ sigset_t signals;
+ fltset_t faults;
+ sysset_t syscalls;
+ siginfo_t siginfo;
+ } arg;
+ } ctl;
+
+#if PTRACE_DEBUG
+ fprintf(stderr, " ptrace(%s, 0x%X, 0x%X, 0x%X)\n",
+ map(request), pid, addr, data);
+#endif
+
+ (void) _private_mutex_lock(&pt_lock);
+
+ if (request == 0) { /* PTRACE_TRACEME, executed by traced process */
+ /*
+ * Set stop-on-all-signals and nothing else.
+ * Turn off inherit-on-fork flag (grandchildren run away).
+ * Set ptrace-compatible flag.
+ */
+ char procname[64]; /* /proc/<pid>/ctl */
+ int fd;
+
+ MakeProcName(procname, getpid());
+ (void) strcat(procname, "/ctl");
+ if ((fd = open(procname, O_WRONLY, 0)) < 0)
+ exit(255);
+ ctl.cmd = PCSTRACE;
+ prfillset(&ctl.arg.signals);
+ if (write(fd, (char *)&ctl, sizeof (long)+sizeof (sigset_t))
+ != sizeof (long)+sizeof (sigset_t))
+ exit(255);
+ ctl.cmd = PCSFAULT;
+ premptyset(&ctl.arg.faults);
+ if (write(fd, (char *)&ctl, sizeof (long)+sizeof (fltset_t))
+ != sizeof (long)+sizeof (fltset_t))
+ exit(255);
+ ctl.cmd = PCSENTRY;
+ premptyset(&ctl.arg.syscalls);
+ if (write(fd, (char *)&ctl, sizeof (long)+sizeof (sysset_t))
+ != sizeof (long)+sizeof (sysset_t))
+ exit(255);
+ ctl.cmd = PCSEXIT;
+ premptyset(&ctl.arg.syscalls);
+ if (write(fd, (char *)&ctl, sizeof (long)+sizeof (sysset_t))
+ != sizeof (long)+sizeof (sysset_t))
+ exit(255);
+ ctl.cmd = PCUNSET;
+ ctl.arg.flags = PR_FORK;
+ if (write(fd, (char *)&ctl, sizeof (long)+sizeof (long))
+ != sizeof (long)+sizeof (long))
+ exit(255);
+ ctl.cmd = PCSET;
+ ctl.arg.flags = PR_PTRACE;
+ if (write(fd, (char *)&ctl, sizeof (long)+sizeof (long))
+ != sizeof (long)+sizeof (long))
+ exit(255);
+ if (close(fd) != 0)
+ exit(255);
+
+ (void) _private_mutex_unlock(&pt_lock);
+ return (0);
+ }
+
+again:
+ errno = 0;
+
+ /* find the cstatus structure corresponding to pid */
+ if ((cp = GrabProc(pid)) == NULLCP)
+ goto esrch;
+
+ ps = &cp->pstatus;
+ if (!(ps->pr_flags & PR_ISTOP)) {
+ if (ProcUpdate(cp) != 0) {
+ ReleaseProc(cp);
+ goto esrch;
+ }
+ if (!(ps->pr_flags & PR_ISTOP))
+ goto esrch;
+ }
+
+ /*
+ * Process the request.
+ */
+ errno = 0;
+ switch (request) {
+ case 1: /* PTRACE_PEEKTEXT */
+ case 2: /* PTRACE_PEEKDATA */
+ if (addr & 03)
+ goto eio;
+ if (pread(cp->asfd, (char *)&data, sizeof (data), (off_t)addr)
+ == sizeof (data)) {
+ (void) _private_mutex_unlock(&pt_lock);
+ return (data);
+ }
+ goto eio;
+
+ case 3: /* PTRACE_PEEKUSER */
+ if (addr & 03)
+ goto eio;
+ xaddr = addr;
+ if (xaddr >= REGADDR && xaddr < REGADDR+sizeof (gregset_t))
+ xaddr -= REGADDR-U_REG;
+ if (xaddr >= U_PSARGS && xaddr < U_PSARGS+sizeof (UP->u_psargs))
+ GetPsargs(cp);
+ if (xaddr >= U_SIGNAL && xaddr < U_SIGNAL+sizeof (UP->u_signal))
+ GetSignal(cp);
+ if ((int)xaddr >= 0 && xaddr < U_END) {
+ /* LINTED pointer alignment */
+ data = *((int *)((caddr_t)(&cp->user) + xaddr));
+ (void) _private_mutex_unlock(&pt_lock);
+ return (data);
+ }
+ goto eio;
+
+ case 4: /* PTRACE_POKETEXT */
+ case 5: /* PTRACE_POKEDATA */
+ if (addr & 03)
+ goto eio;
+ xaddr = addr;
+ if (xaddr >= (unsigned)cp->user.u_reg[REG_SP] &&
+ xaddr < (unsigned)cp->user.u_reg[REG_SP]+16*sizeof (int))
+ cp->flags |= CS_SETREGS;
+ if (pwrite(cp->asfd, (char *)&data, sizeof (data), (off_t)addr)
+ == sizeof (data)) {
+ (void) _private_mutex_unlock(&pt_lock);
+ return (data);
+ }
+ goto eio;
+
+ case 6: /* PTRACE_POKEUSER */
+ if (addr & 03)
+ goto eio;
+ xaddr = addr;
+ if (xaddr >= REGADDR && xaddr < REGADDR+sizeof (gregset_t))
+ xaddr -= REGADDR-U_REG;
+ if ((int)xaddr >= U_REG && xaddr < U_REG+sizeof (gregset_t)) {
+ int rx = (xaddr-U_REG)/sizeof (greg_t);
+ if (rx == REG_PS)
+ data = (cp->user.u_reg[REG_PS] &
+ ~PSL_USERMASK) | (data & PSL_USERMASK);
+ else if (rx == REG_SP || rx == REG_PC || rx == REG_nPC)
+ data &= ~03;
+ cp->user.u_reg[rx] = data;
+ cp->flags |= CS_SETREGS;
+ (void) _private_mutex_unlock(&pt_lock);
+ return (data);
+ }
+ goto eio;
+
+ case 7: /* PTRACE_CONT */
+ case 9: /* PTRACE_SINGLESTEP */
+ {
+ long runctl[3];
+
+ if (cp->flags & CS_SETREGS) {
+ long cmd;
+ iovec_t iov[2];
+
+ ps->pr_lwp.pr_reg[R_PSR] = cp->user.u_reg[REG_PSR];
+ ps->pr_lwp.pr_reg[R_PC] = cp->user.u_reg[REG_PC];
+ ps->pr_lwp.pr_reg[R_nPC] = cp->user.u_reg[REG_nPC];
+ ps->pr_lwp.pr_reg[R_Y] = cp->user.u_reg[REG_Y];
+ ps->pr_lwp.pr_reg[R_G1] = cp->user.u_reg[REG_G1];
+ ps->pr_lwp.pr_reg[R_G2] = cp->user.u_reg[REG_G2];
+ ps->pr_lwp.pr_reg[R_G3] = cp->user.u_reg[REG_G3];
+ ps->pr_lwp.pr_reg[R_G4] = cp->user.u_reg[REG_G4];
+ ps->pr_lwp.pr_reg[R_G5] = cp->user.u_reg[REG_G5];
+ ps->pr_lwp.pr_reg[R_G6] = cp->user.u_reg[REG_G6];
+ ps->pr_lwp.pr_reg[R_G7] = cp->user.u_reg[REG_G7];
+ ps->pr_lwp.pr_reg[R_O0] = cp->user.u_reg[REG_O0];
+ ps->pr_lwp.pr_reg[R_O1] = cp->user.u_reg[REG_O1];
+ ps->pr_lwp.pr_reg[R_O2] = cp->user.u_reg[REG_O2];
+ ps->pr_lwp.pr_reg[R_O3] = cp->user.u_reg[REG_O3];
+ ps->pr_lwp.pr_reg[R_O4] = cp->user.u_reg[REG_O4];
+ ps->pr_lwp.pr_reg[R_O5] = cp->user.u_reg[REG_O5];
+ ps->pr_lwp.pr_reg[R_O6] = cp->user.u_reg[REG_O6];
+ ps->pr_lwp.pr_reg[R_O7] = cp->user.u_reg[REG_O7];
+ (void) pread(cp->asfd, (char *)&ps->pr_lwp.pr_reg[R_L0],
+ 16*sizeof (int), (off_t)cp->user.u_reg[REG_SP]);
+ cmd = PCSREG;
+ iov[0].iov_base = (caddr_t)&cmd;
+ iov[0].iov_len = sizeof (long);
+ iov[1].iov_base = (caddr_t)&ps->pr_lwp.pr_reg[0];
+ iov[1].iov_len = sizeof (ps->pr_lwp.pr_reg);
+ if (writev(cp->ctlfd, iov, 2) < 0)
+ goto tryagain;
+ }
+ if (addr != 1 && /* new virtual address */
+ (addr & ~03) != cp->user.u_reg[REG_PC]) {
+ runctl[0] = PCSVADDR;
+ runctl[1] = (addr & ~03);
+ if (write(cp->ctlfd, (char *)runctl, 2*sizeof (long))
+ != 2*sizeof (long))
+ goto tryagain;
+ }
+ /* make data the current signal */
+ if (data != 0 && data != ps->pr_lwp.pr_cursig) {
+ (void) memset((char *)&ctl.arg.siginfo, 0,
+ sizeof (siginfo_t));
+ ctl.arg.siginfo.si_signo = data;
+ ctl.cmd = PCSSIG;
+ if (write(cp->ctlfd, (char *)&ctl,
+ sizeof (long)+sizeof (siginfo_t))
+ != sizeof (long)+sizeof (siginfo_t))
+ goto tryagain;
+ }
+ if (data == 0)
+ runctl[0] = PCCSIG;
+ else
+ runctl[0] = PCNULL;
+ runctl[1] = PCRUN;
+ runctl[2] = (request == 9)? PRSTEP : 0;
+ if (write(cp->ctlfd, (char *)runctl, 3*sizeof (long))
+ != 3*sizeof (long)) {
+ if (errno == ENOENT) {
+ /* current signal must have killed it */
+ ReleaseProc(cp);
+ (void) _private_mutex_unlock(&pt_lock);
+ return (data);
+ }
+ goto tryagain;
+ }
+ (void) memset((char *)ps, 0, sizeof (pstatus_t));
+ cp->flags = 0;
+ (void) _private_mutex_unlock(&pt_lock);
+ return (data);
+ }
+
+ case 8: /* PTRACE_KILL */
+ /* overkill? */
+ (void) memset((char *)&ctl.arg.siginfo, 0, sizeof (siginfo_t));
+ ctl.arg.siginfo.si_signo = SIGKILL;
+ ctl.cmd = PCSSIG;
+ (void) write(cp->ctlfd, (char *)&ctl,
+ sizeof (long)+sizeof (siginfo_t));
+ (void) kill(pid, SIGKILL);
+ ReleaseProc(cp);
+ (void) _private_mutex_unlock(&pt_lock);
+ return (0);
+
+ default:
+ goto eio;
+ }
+
+tryagain:
+ if (errno == EAGAIN) {
+ if (OpenProc(cp) == 0)
+ goto again;
+ ReleaseProc(cp);
+ }
+eio:
+ errno = EIO;
+ (void) _private_mutex_unlock(&pt_lock);
+ return (-1);
+esrch:
+ errno = ESRCH;
+ (void) _private_mutex_unlock(&pt_lock);
+ return (-1);
+}
+
+/*
+ * Find the cstatus structure corresponding to pid.
+ */
+static cstatus_t *
+FindProc(pid_t pid)
+{
+ cstatus_t *cp;
+
+ for (cp = childp; cp != NULLCP; cp = cp->next)
+ if (cp->pid == pid)
+ break;
+
+ return (cp);
+}
+
+/*
+ * Check every proc for existence, release those that are gone.
+ * Be careful about the linked list; ReleaseProc() changes it.
+ */
+static void
+CheckAllProcs()
+{
+ cstatus_t *cp = childp;
+
+ while (cp != NULLCP) {
+ cstatus_t *next = cp->next;
+
+ if (ProcUpdate(cp) != 0)
+ ReleaseProc(cp);
+ cp = next;
+ }
+}
+
+/*
+ * Utility for OpenProc().
+ */
+static int
+Dupfd(int fd, int dfd)
+{
+ /*
+ * Make sure fd not one of 0, 1, or 2 to avoid stdio interference.
+ * Also, if dfd is greater than 2, dup fd to be exactly dfd.
+ */
+ if (dfd > 2 || (0 <= fd && fd <= 2)) {
+ if (dfd > 2 && fd != dfd)
+ (void) close(dfd);
+ else
+ dfd = 3;
+ if (fd != dfd) {
+ dfd = fcntl(fd, F_DUPFD, (intptr_t)dfd);
+ (void) close(fd);
+ fd = dfd;
+ }
+ }
+ /*
+ * Mark filedescriptor close-on-exec.
+ * Should also be close-on-return-from-fork-in-child.
+ */
+ (void) fcntl(fd, F_SETFD, (intptr_t)1);
+ return (fd);
+}
+
+/*
+ * Construct the /proc directory name: "/proc/<pid>"
+ * The name buffer passed by the caller must be large enough.
+ */
+static void
+MakeProcName(char *procname, pid_t pid)
+{
+ (void) sprintf(procname, "/proc/%d", pid);
+}
+
+/*
+ * Open/reopen the /proc/<pid> files.
+ */
+static int
+OpenProc(cstatus_t *cp)
+{
+ char procname[64]; /* /proc/nnnnn/fname */
+ char *fname;
+ int fd;
+ int omode;
+
+ MakeProcName(procname, cp->pid);
+ fname = procname + strlen(procname);
+
+ /*
+ * Use exclusive-open only if this is the first open.
+ */
+ omode = (cp->asfd > 0)? O_RDWR : (O_RDWR|O_EXCL);
+ (void) strcpy(fname, "/as");
+ if ((fd = open(procname, omode, 0)) < 0 ||
+ (cp->asfd = Dupfd(fd, cp->asfd)) < 0)
+ goto err;
+
+ (void) strcpy(fname, "/ctl");
+ if ((fd = open(procname, O_WRONLY, 0)) < 0 ||
+ (cp->ctlfd = Dupfd(fd, cp->ctlfd)) < 0)
+ goto err;
+
+ (void) strcpy(fname, "/status");
+ if ((fd = open(procname, O_RDONLY, 0)) < 0 ||
+ (cp->statusfd = Dupfd(fd, cp->statusfd)) < 0)
+ goto err;
+
+ return (0);
+
+err:
+ CloseProc(cp);
+ return (-1);
+}
+
+/*
+ * Close the /proc/<pid> files.
+ */
+static void
+CloseProc(cstatus_t *cp)
+{
+ if (cp->asfd > 0)
+ (void) close(cp->asfd);
+ if (cp->ctlfd > 0)
+ (void) close(cp->ctlfd);
+ if (cp->statusfd > 0)
+ (void) close(cp->statusfd);
+ cp->asfd = 0;
+ cp->ctlfd = 0;
+ cp->statusfd = 0;
+}
+
+/*
+ * Take control of a child process.
+ */
+static cstatus_t *
+GrabProc(pid_t pid)
+{
+ cstatus_t *cp;
+ long ctl[2];
+ pid_t ppid;
+
+ if (pid <= 0)
+ return (NULLCP);
+
+ if ((cp = FindProc(pid)) != NULLCP) /* already grabbed */
+ return (cp);
+
+ CheckAllProcs(); /* clean up before grabbing new process */
+
+ cp = (cstatus_t *)malloc(sizeof (cstatus_t));
+ if (cp == NULLCP)
+ return (NULLCP);
+ (void) memset((char *)cp, 0, sizeof (cstatus_t));
+ cp->pid = pid;
+
+ ppid = getpid();
+ while (OpenProc(cp) == 0) {
+ ctl[0] = PCSET;
+ ctl[1] = PR_RLC;
+ errno = 0;
+
+ if (pread(cp->statusfd, (char *)&cp->pstatus,
+ sizeof (cp->pstatus), (off_t)0) == sizeof (cp->pstatus) &&
+ cp->pstatus.pr_ppid == ppid &&
+ (cp->pstatus.pr_flags & PR_PTRACE) &&
+ write(cp->ctlfd, (char *)ctl, 2*sizeof (long))
+ == 2*sizeof (long)) {
+ cp->next = childp;
+ childp = cp;
+ MakeUser(cp);
+ return (cp);
+ }
+
+ if (errno != EAGAIN)
+ break;
+ }
+
+ free((char *)cp);
+ return (NULLCP);
+}
+
+/*
+ * Close the /proc/<pid> file, if open.
+ * Deallocate the memory used by the cstatus_t structure.
+ */
+static void
+ReleaseProc(cstatus_t *cp)
+{
+ CloseProc(cp);
+
+ if (childp == cp)
+ childp = cp->next;
+ else {
+ cstatus_t *pcp;
+
+ for (pcp = childp; pcp != NULLCP; pcp = pcp->next) {
+ if (pcp->next == cp) {
+ pcp->next = cp->next;
+ break;
+ }
+ }
+ }
+
+ free((char *)cp);
+}
+
+/*
+ * Update process information from /proc.
+ * Return 0 on success, -1 on failure.
+ */
+static int
+ProcUpdate(cstatus_t *cp)
+{
+ pstatus_t *ps = &cp->pstatus;
+
+ if (cp->flags & CS_SETREGS) {
+ long cmd;
+ iovec_t iov[2];
+
+ ps->pr_lwp.pr_reg[R_PSR] = cp->user.u_reg[REG_PSR];
+ ps->pr_lwp.pr_reg[R_PC] = cp->user.u_reg[REG_PC];
+ ps->pr_lwp.pr_reg[R_nPC] = cp->user.u_reg[REG_nPC];
+ ps->pr_lwp.pr_reg[R_Y] = cp->user.u_reg[REG_Y];
+ ps->pr_lwp.pr_reg[R_G1] = cp->user.u_reg[REG_G1];
+ ps->pr_lwp.pr_reg[R_G2] = cp->user.u_reg[REG_G2];
+ ps->pr_lwp.pr_reg[R_G3] = cp->user.u_reg[REG_G3];
+ ps->pr_lwp.pr_reg[R_G4] = cp->user.u_reg[REG_G4];
+ ps->pr_lwp.pr_reg[R_G5] = cp->user.u_reg[REG_G5];
+ ps->pr_lwp.pr_reg[R_G6] = cp->user.u_reg[REG_G6];
+ ps->pr_lwp.pr_reg[R_G7] = cp->user.u_reg[REG_G7];
+ ps->pr_lwp.pr_reg[R_O0] = cp->user.u_reg[REG_O0];
+ ps->pr_lwp.pr_reg[R_O1] = cp->user.u_reg[REG_O1];
+ ps->pr_lwp.pr_reg[R_O2] = cp->user.u_reg[REG_O2];
+ ps->pr_lwp.pr_reg[R_O3] = cp->user.u_reg[REG_O3];
+ ps->pr_lwp.pr_reg[R_O4] = cp->user.u_reg[REG_O4];
+ ps->pr_lwp.pr_reg[R_O5] = cp->user.u_reg[REG_O5];
+ ps->pr_lwp.pr_reg[R_O6] = cp->user.u_reg[REG_O6];
+ ps->pr_lwp.pr_reg[R_O7] = cp->user.u_reg[REG_O7];
+ (void) pread(cp->asfd, (char *)&ps->pr_lwp.pr_reg[R_L0],
+ 16*sizeof (int), (off_t)cp->user.u_reg[REG_SP]);
+ cmd = PCSREG;
+ iov[0].iov_base = (caddr_t)&cmd;
+ iov[0].iov_len = sizeof (long);
+ iov[1].iov_base = (caddr_t)&ps->pr_lwp.pr_reg[0];
+ iov[1].iov_len = sizeof (ps->pr_lwp.pr_reg);
+ (void) writev(cp->ctlfd, iov, 2);
+ cp->flags &= ~CS_SETREGS;
+ }
+
+ while (pread(cp->statusfd, (char *)ps, sizeof (*ps), (off_t)0) < 0) {
+ /* attempt to regain control */
+ if (errno != EINTR &&
+ !(errno == EAGAIN && OpenProc(cp) == 0))
+ return (-1);
+ }
+
+ if (ps->pr_flags & PR_ISTOP)
+ MakeUser(cp);
+ else
+ (void) memset((char *)ps, 0, sizeof (pstatus_t));
+
+ return (0);
+}
+
+/*
+ * Manufacture the contents of the fake u-block.
+ */
+static void
+MakeUser(cstatus_t *cp)
+{
+ pstatus_t *ps = &cp->pstatus;
+
+ cp->user.u_reg[REG_PSR] = ps->pr_lwp.pr_reg[R_PSR];
+ cp->user.u_reg[REG_PC] = ps->pr_lwp.pr_reg[R_PC];
+ cp->user.u_reg[REG_nPC] = ps->pr_lwp.pr_reg[R_nPC];
+ cp->user.u_reg[REG_Y] = ps->pr_lwp.pr_reg[R_Y];
+ cp->user.u_reg[REG_G1] = ps->pr_lwp.pr_reg[R_G1];
+ cp->user.u_reg[REG_G2] = ps->pr_lwp.pr_reg[R_G2];
+ cp->user.u_reg[REG_G3] = ps->pr_lwp.pr_reg[R_G3];
+ cp->user.u_reg[REG_G4] = ps->pr_lwp.pr_reg[R_G4];
+ cp->user.u_reg[REG_G5] = ps->pr_lwp.pr_reg[R_G5];
+ cp->user.u_reg[REG_G6] = ps->pr_lwp.pr_reg[R_G6];
+ cp->user.u_reg[REG_G7] = ps->pr_lwp.pr_reg[R_G7];
+ cp->user.u_reg[REG_O0] = ps->pr_lwp.pr_reg[R_O0];
+ cp->user.u_reg[REG_O1] = ps->pr_lwp.pr_reg[R_O1];
+ cp->user.u_reg[REG_O2] = ps->pr_lwp.pr_reg[R_O2];
+ cp->user.u_reg[REG_O3] = ps->pr_lwp.pr_reg[R_O3];
+ cp->user.u_reg[REG_O4] = ps->pr_lwp.pr_reg[R_O4];
+ cp->user.u_reg[REG_O5] = ps->pr_lwp.pr_reg[R_O5];
+ cp->user.u_reg[REG_O6] = ps->pr_lwp.pr_reg[R_O6];
+ cp->user.u_reg[REG_O7] = ps->pr_lwp.pr_reg[R_O7];
+ cp->user.u_ar0 = (greg_t *)REGADDR;
+ cp->user.u_code = ps->pr_lwp.pr_info.si_code;
+ cp->user.u_addr = ps->pr_lwp.pr_info.si_addr;
+ cp->flags &= ~(CS_PSARGS|CS_SIGNAL);
+}
+
+/*
+ * Fetch the contents of u_psargs[].
+ */
+static void
+GetPsargs(cstatus_t *cp)
+{
+ char procname[64]; /* /proc/<pid>/psinfo */
+ int fd;
+
+ MakeProcName(procname, cp->pid);
+ (void) strcat(procname, "/psinfo");
+ if ((fd = open(procname, O_RDONLY, 0)) < 0) {
+ (void) memset(cp->user.u_psargs, 0, PSARGSZ);
+ return;
+ }
+ (void) pread(fd, cp->user.u_psargs, PSARGSZ,
+ (off_t)((psinfo_t *)0)->pr_psargs);
+ (void) close(fd);
+
+ cp->flags |= CS_PSARGS;
+}
+
+/*
+ * Fetch the contents of u_signal[].
+ */
+static void
+GetSignal(cstatus_t *cp)
+{
+ char procname[64]; /* /proc/<pid>/sigact */
+ int fd;
+ struct sigaction action[MAXSIG];
+ int i;
+
+ MakeProcName(procname, cp->pid);
+ (void) strcat(procname, "/sigact");
+ (void) memset((char *)action, 0, sizeof (action));
+ if ((fd = open(procname, O_RDONLY, 0)) >= 0) {
+ (void) read(fd, (char *)action, sizeof (action));
+ (void) close(fd);
+ }
+ for (i = 0; i < MAXSIG; i++)
+ cp->user.u_signal[i] = action[i].sa_handler;
+ cp->flags |= CS_SIGNAL;
+}
diff --git a/usr/src/lib/libc/sparc/sys/syscall.s b/usr/src/lib/libc/sparc/sys/syscall.s
new file mode 100644
index 0000000000..ab4fa8020f
--- /dev/null
+++ b/usr/src/lib/libc/sparc/sys/syscall.s
@@ -0,0 +1,157 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * C library -- int syscall(int sysnum, ...);
+ * C library -- int __systemcall(sysret_t *, int sysnum, ...);
+ *
+ * Interpret a given system call
+ *
+ * This version handles up to 8 'long' arguments to a system call.
+ *
+ * Even though indirect system call support exists in the SPARC
+ * 32-bit kernel, we want to eliminate it in a future release,
+ * so the real trap for the desired system call is issued right here.
+ *
+ * Even though %g5 can be used as a scratch register for sparcv9, we don't
+ * use it here because this code is shared between sparcv8 and sparcv9.
+ */
+
+ .file "%M%"
+
+#include <sys/asm_linkage.h>
+
+ ANSI_PRAGMA_WEAK(syscall,function)
+
+#include "SYS.h"
+
+#undef _syscall /* override "synonyms.h" */
+#undef __systemcall
+
+ ENTRY(_syscall)
+ save %sp, -SA(MINFRAME + 2*CLONGSIZE), %sp
+ ldn [%fp + STACK_BIAS + MINFRAME], %o5 ! arg 5
+ mov %i3, %o2 ! arg 2
+ ldn [%fp + STACK_BIAS + MINFRAME + CLONGSIZE], %g1
+ mov %i4, %o3 ! arg 3
+ stn %g1, [%sp + STACK_BIAS + MINFRAME] ! arg 6
+ mov %i5, %o4 ! arg 4
+ ldn [%fp + STACK_BIAS + MINFRAME + 2*CLONGSIZE], %g1
+ mov %i1, %o0 ! arg 0
+ stn %g1, [%sp + STACK_BIAS + MINFRAME + CLONGSIZE] ! arg 7
+ mov %i2, %o1 ! arg 1
+ mov %i0, %g1 ! sysnum
+ ta SYSCALL_TRAPNUM
+ bcc,a,pt %icc, 1f
+ sra %o0, 0, %i0 ! (int) cast
+ restore %o0, 0, %o0
+ ba __cerror
+ nop
+1:
+ ret
+ restore
+ SET_SIZE(_syscall)
+
+/*
+ * Same as _syscall(), but restricted to 6 syscall arguments
+ * so it doesn't need to incur the overhead of a register window.
+ * Implemented for use only within libc; symbol is not exported.
+ */
+ ENTRY(_syscall6)
+ mov %o0, %g1 /* sysnum */
+ mov %o1, %o0 /* syscall args */
+ mov %o2, %o1
+ mov %o3, %o2
+ mov %o4, %o3
+ mov %o5, %o4
+ ldn [%sp + STACK_BIAS + MINFRAME], %o5
+ ta SYSCALL_TRAPNUM
+ SYSCERROR
+ retl
+ sra %o0, 0, %o0 /* (int) cast */
+ SET_SIZE(_syscall6)
+
+ ENTRY(__systemcall)
+ save %sp, -SA(MINFRAME + 2*CLONGSIZE), %sp
+ ldn [%fp + STACK_BIAS + MINFRAME], %o4 ! arg 4
+ mov %i3, %o1 ! arg 1
+ ldn [%fp + STACK_BIAS + MINFRAME + CLONGSIZE], %o5 ! arg5
+ mov %i4, %o2 ! arg 2
+ ldn [%fp + STACK_BIAS + MINFRAME + 2*CLONGSIZE], %g1
+ mov %i5, %o3 ! arg 3
+ stn %g1, [%sp + STACK_BIAS + MINFRAME] ! arg 6
+ mov %i2, %o0 ! arg 0
+ ldn [%fp + STACK_BIAS + MINFRAME + 3*CLONGSIZE], %g1
+ stn %g1, [%sp + STACK_BIAS + MINFRAME + CLONGSIZE] ! arg7
+ mov %i1, %g1 ! sysnum
+ ta SYSCALL_TRAPNUM
+ bcc,pt %icc, 1f
+ mov -1, %g1
+ stn %g1, [%i0] /* error */
+ ba 2f
+ stn %g1, [%i0 + CLONGSIZE]
+1:
+ stn %o0, [%i0] /* no error */
+ clr %o0
+ stn %o1, [%i0 + CLONGSIZE]
+2:
+ ret
+ restore %o0, 0, %o0
+ SET_SIZE(__systemcall)
+
+/*
+ * Same as __systemcall(), but restricted to 6 syscall arguments
+ * so it doesn't need to incur the overhead of a register window.
+ * Implemented for use only within libc; symbol is not exported.
+ */
+ ENTRY(__systemcall6)
+ stn %o0, [%sp + SAVE_OFFSET] /* sysret address */
+ mov %o1, %g1 /* sysnum */
+ mov %o2, %o0 /* syscall args */
+ mov %o3, %o1
+ mov %o4, %o2
+ mov %o5, %o3
+ ldn [%sp + STACK_BIAS + MINFRAME], %o4
+ ldn [%sp + STACK_BIAS + MINFRAME + CLONGSIZE], %o5
+ ta SYSCALL_TRAPNUM
+ bcs,pn %icc, 1f
+ ldn [%sp + SAVE_OFFSET], %g1
+ stn %o0, [%g1] /* no error */
+ stn %o1, [%g1 + CLONGSIZE]
+ retl
+ clr %o0
+1:
+ mov -1, %o1 /* error */
+ stn %o1, [%g1]
+ retl
+ stn %o1, [%g1 + CLONGSIZE]
+ SET_SIZE(__systemcall6)
diff --git a/usr/src/lib/libc/sparc/sys/syssun.s b/usr/src/lib/libc/sparc/sys/syssun.s
new file mode 100644
index 0000000000..799a91d99a
--- /dev/null
+++ b/usr/src/lib/libc/sparc/sys/syssun.s
@@ -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 (c) 1988 AT&T */
+/* All Rights Reserved */
+
+
+/* Copyright (c) 1989 by Sun Microsystems, Inc. */
+
+.ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.3.1.5 */
+
+/* C library -- syssun (from sys3b2) */
+/* int syssun(cmd, ... ); */
+
+ .file "syssun.s"
+
+#include <sys/asm_linkage.h>
+
+ ANSI_PRAGMA_WEAK(syssun,function)
+
+#include "SYS.h"
+
+ SYSCALL(syssun)
+ RET
+
+ SET_SIZE(syssun)
diff --git a/usr/src/lib/libc/sparc/sys/uadmin.s b/usr/src/lib/libc/sparc/sys/uadmin.s
new file mode 100644
index 0000000000..772bcb6ce6
--- /dev/null
+++ b/usr/src/lib/libc/sparc/sys/uadmin.s
@@ -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 (c) 1988 AT&T */
+/* All Rights Reserved */
+
+
+/* Copyright (c) 1989 by Sun Microsystems, Inc. */
+
+.ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.6 */
+
+/* C library -- uadmin */
+/* int uadmin (int cmd, int fcn, int mdep); */
+
+ .file "uadmin.s"
+
+#include <sys/asm_linkage.h>
+
+ ANSI_PRAGMA_WEAK(uadmin,function)
+
+#include "SYS.h"
+
+ SYSCALL(uadmin)
+ RET
+
+ SET_SIZE(uadmin)
diff --git a/usr/src/lib/libc/sparc/sys/uname.s b/usr/src/lib/libc/sparc/sys/uname.s
new file mode 100644
index 0000000000..8488026115
--- /dev/null
+++ b/usr/src/lib/libc/sparc/sys/uname.s
@@ -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 (c) 1988 AT&T */
+/* All Rights Reserved */
+
+
+/* Copyright (c) 1989 by Sun Microsystems, Inc. */
+
+.ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.8 */
+
+/* C library -- uname */
+/* int uname (struct utsname *name); */
+
+ .file "uname.s"
+
+#include <sys/asm_linkage.h>
+
+ ANSI_PRAGMA_WEAK(uname,function)
+
+#include "SYS.h"
+
+ SYSCALL(uname)
+ RET
+
+ SET_SIZE(uname)
diff --git a/usr/src/lib/libc/sparc/sys/vfork.s b/usr/src/lib/libc/sparc/sys/vfork.s
new file mode 100644
index 0000000000..45153a1374
--- /dev/null
+++ b/usr/src/lib/libc/sparc/sys/vfork.s
@@ -0,0 +1,115 @@
+/*
+ * 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"
+
+/*
+ * C library -- vfork
+ * pid_t vfork(void);
+ */
+
+/*
+ * From the syscall:
+ * %o1 == 0 in parent process, %o1 == 1 in child process.
+ * %o0 == pid of child in parent, %o0 == pid of parent in child.
+ *
+ * The child process gets a zero return value from vfork; the parent
+ * gets the pid of the child.
+ *
+ * We block all blockable signals while performing the vfork() system call
+ * trap. This enables us to set curthread->ul_vfork safely, so that we
+ * don't end up in a signal handler with curthread->ul_vfork set wrong.
+ *
+ * Note that since the SPARC architecture maintains stack maintence
+ * information (return pc, sp, fp) in the register windows, both parent
+ * and child can execute in a common address space without conflict.
+ */
+
+ .file "%M%"
+
+#include <sys/asm_linkage.h>
+
+ ANSI_PRAGMA_WEAK(vfork,function)
+
+#include "SYS.h"
+#include <../assym.h>
+
+ ENTRY(vfork)
+ mov SIG_SETMASK, %o0 ! block signals
+ set MASKSET0, %o1
+ set MASKSET1, %o2
+ SYSTRAP_2RVALS(lwp_sigmask)
+
+ SYSTRAP_2RVALS(vfork)
+ bcc,a,pt %icc, 1f
+ tst %o1
+ mov %o0, %o3 ! save the vfork() error number
+
+ mov SIG_SETMASK, %o0 ! reinstate signals
+ ld [%g7 + UL_SIGMASK], %o1
+ ld [%g7 + UL_SIGMASK + 4], %o2
+ SYSTRAP_2RVALS(lwp_sigmask)
+
+ mov %o3, %o0 ! restore the vfork() error number
+ ba,a __cerror
+1:
+ /*
+ * To determine if we are (still) a child of vfork(), the child
+ * increments curthread->ul_vfork by one and the parent decrements
+ * it by one. If the result is zero, then we are not a child of
+ * vfork(), else we are. We do this to deal with the case of
+ * a vfork() child calling vfork().
+ */
+ bnz,pt %icc, 2f
+ ld [%g7 + UL_VFORK], %g1
+ brnz,a,pt %g1, 3f ! don't let it go negative
+ sub %g1, 1, %g1 ! curthread->ul_vfork--;
+ ba,a 3f
+2:
+ clr %o0 ! child, return (0)
+ add %g1, 1, %g1 ! curthread->ul_vfork++;
+3:
+ st %g1, [%g7 + UL_VFORK]
+ /*
+ * Clear the schedctl interface in both parent and child.
+ * (The child might have modified the parent.)
+ */
+ stn %g0, [%g7 + UL_SCHEDCTL]
+ stn %g0, [%g7 + UL_SCHEDCTL_CALLED]
+ mov %o0, %o3 ! save the vfork() return value
+
+ mov SIG_SETMASK, %o0 ! reinstate signals
+ ld [%g7 + UL_SIGMASK], %o1
+ ld [%g7 + UL_SIGMASK + 4], %o2
+ SYSTRAP_2RVALS(lwp_sigmask)
+
+ retl
+ mov %o3, %o0 ! restore the vfork() return value
+ SET_SIZE(vfork)
diff --git a/usr/src/lib/libc/sparc/threads/asm_subr.s b/usr/src/lib/libc/sparc/threads/asm_subr.s
new file mode 100644
index 0000000000..22245d6155
--- /dev/null
+++ b/usr/src/lib/libc/sparc/threads/asm_subr.s
@@ -0,0 +1,173 @@
+/*
+ * 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"
+
+ .file "asm_subr.s"
+
+#include <sys/asm_linkage.h>
+#include <sys/trap.h>
+#include <../assym.h>
+#include "SYS.h"
+
+ ! This is where execution resumes when a thread created with
+ ! thr_create() or pthread_create() returns (see setup_context()).
+ ! We pass the (void *) return value to _thr_terminate().
+ ENTRY(_lwp_start)
+ nop ! this is the location from which the func() was "called"
+ nop
+ call _thr_terminate ! %o0 contains the return value
+ nop
+ SET_SIZE(_lwp_start)
+
+ ENTRY(_lwp_terminate)
+ ! Flush the register windows so the stack can be reused.
+ ta ST_FLUSH_WINDOWS
+ ! All we need to do now is (carefully) call lwp_exit().
+ mov SYS_lwp_exit, %g1
+ ta SYSCALL_TRAPNUM
+ RET ! if we return, it is very bad
+ SET_SIZE(_lwp_terminate)
+
+ ENTRY(set_curthread)
+ retl
+ mov %o0, %g7
+ SET_SIZE(set_curthread)
+
+#ifdef __sparcv9
+#define GREGSIZE 8
+#else
+#define GREGSIZE 4
+#endif
+ ! void _fetch_globals(greg_t *);
+ ! (called from siglongjmp())
+ ENTRY(_fetch_globals)
+ stn %g1, [%o0 + 0*GREGSIZE]
+ stn %g2, [%o0 + 1*GREGSIZE]
+ stn %g3, [%o0 + 2*GREGSIZE]
+ stn %g4, [%o0 + 3*GREGSIZE]
+ stn %g5, [%o0 + 4*GREGSIZE]
+ stn %g6, [%o0 + 5*GREGSIZE]
+ retl
+ stn %g7, [%o0 + 6*GREGSIZE]
+ SET_SIZE(_fetch_globals)
+
+#ifdef __sparcv9
+ ENTRY(_getfprs)
+ retl
+ mov %fprs, %o0
+ SET_SIZE(_getfprs)
+#else
+ ENTRY(_getpsr)
+ retl
+ ta ST_GETPSR
+ SET_SIZE(_getpsr)
+#endif
+
+ ENTRY(_getfsr)
+ retl
+ stn %fsr, [%o0]
+ SET_SIZE(_getfsr)
+
+ ENTRY(_setfsr)
+ retl
+ ldn [%o0], %fsr
+ SET_SIZE(_setfsr)
+
+ ENTRY(_flush_windows)
+ retl
+ ta ST_FLUSH_WINDOWS
+ SET_SIZE(_flush_windows)
+
+ ENTRY(__lwp_park)
+ mov %o1, %o2
+ mov %o0, %o1
+ mov 0, %o0
+ SYSTRAP_RVAL1(lwp_park)
+ SYSLWPERR
+ RET
+ SET_SIZE(__lwp_park)
+
+ ENTRY(__lwp_unpark)
+ mov %o0, %o1
+ mov 1, %o0
+ SYSTRAP_RVAL1(lwp_park)
+ SYSLWPERR
+ RET
+ SET_SIZE(__lwp_unpark)
+
+ ENTRY(__lwp_unpark_all)
+ mov %o1, %o2
+ mov %o0, %o1
+ mov 2, %o0
+ SYSTRAP_RVAL1(lwp_park)
+ SYSLWPERR
+ RET
+ SET_SIZE(__lwp_unpark_all)
+
+ ENTRY(lwp_yield)
+ SYSTRAP_RVAL1(yield)
+ RET
+ SET_SIZE(lwp_yield)
+
+/*
+ * __sighndlr(int sig, siginfo_t *si, ucontex_t *uc, void (*hndlr)())
+ *
+ * This is called from sigacthandler() for the entire purpose of
+ * communicating the ucontext to java's stack tracing functions.
+ */
+ ENTRY(__sighndlr)
+ .globl __sighndlrend
+ save %sp, -SA(MINFRAME), %sp
+ mov %i0, %o0
+ mov %i1, %o1
+ jmpl %i3, %o7
+ mov %i2, %o2
+ ret
+ restore
+__sighndlrend:
+ SET_SIZE(__sighndlr)
+
+/*
+ * int _sigsetjmp(sigjmp_buf env, int savemask)
+ *
+ * This version is faster than the old non-threaded version because we
+ * don't normally have to call __getcontext() to get the signal mask.
+ * (We have a copy of it in the ulwp_t structure.)
+ */
+
+#undef sigsetjmp
+
+ ENTRY2(sigsetjmp,_sigsetjmp)
+ stn %sp, [%o0 + SJS_SP] ! save caller's sp into env->sjs_sp
+ add %o7, 8, %o2 ! calculate caller's return pc
+ stn %o2, [%o0 + SJS_PC] ! save caller's pc into env->sjs_pc
+ stn %fp, [%o0 + SJS_FP] ! save caller's return linkage
+ stn %i7, [%o0 + SJS_I7]
+ call __csigsetjmp
+ sub %o2, 8, %o7 ! __csigsetjmp returns to caller
+ SET_SIZE(sigsetjmp)
+ SET_SIZE(_sigsetjmp)
diff --git a/usr/src/lib/libc/sparc/threads/machdep.c b/usr/src/lib/libc/sparc/threads/machdep.c
new file mode 100644
index 0000000000..5ebb6b324c
--- /dev/null
+++ b/usr/src/lib/libc/sparc/threads/machdep.c
@@ -0,0 +1,179 @@
+/*
+ * 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"
+
+#include "lint.h"
+#include "thr_uberdata.h"
+#include <procfs.h>
+#include <setjmp.h>
+#include <sys/fsr.h>
+#include "sigjmp_struct.h"
+
+extern int getlwpstatus(thread_t, lwpstatus_t *);
+extern int putlwpregs(thread_t, prgregset_t);
+
+int
+setup_context(ucontext_t *ucp, void *(*func)(ulwp_t *),
+ ulwp_t *ulwp, caddr_t stk, size_t stksize)
+{
+ /*
+ * Top-of-stack must be rounded down to STACK_ALIGN and
+ * there must be a minimum frame for the register window.
+ */
+ uintptr_t stack = (((uintptr_t)stk + stksize) & ~(STACK_ALIGN - 1)) -
+ SA(MINFRAME);
+
+ /* clear the context and the top stack frame */
+ (void) _memset(ucp, 0, sizeof (*ucp));
+ (void) _memset((void *)stack, 0, SA(MINFRAME));
+
+ /* fill in registers of interest */
+ ucp->uc_flags |= UC_CPU;
+ ucp->uc_mcontext.gregs[REG_PC] = (greg_t)func;
+ ucp->uc_mcontext.gregs[REG_nPC] = (greg_t)func + 4;
+ ucp->uc_mcontext.gregs[REG_O0] = (greg_t)ulwp;
+ ucp->uc_mcontext.gregs[REG_SP] = (greg_t)(stack - STACK_BIAS);
+ ucp->uc_mcontext.gregs[REG_O7] = (greg_t)_lwp_start;
+ ucp->uc_mcontext.gregs[REG_G7] = (greg_t)ulwp;
+
+ return (0);
+}
+
+/*
+ * Machine-dependent startup code for a newly-created thread.
+ */
+void *
+_thr_setup(ulwp_t *self)
+{
+ extern void _setfsr(greg_t *);
+
+ if (self->ul_fpuenv.fpu_en)
+ _setfsr(&self->ul_fpuenv.fsr);
+
+ self->ul_ustack.ss_sp = (void *)(self->ul_stktop - self->ul_stksiz);
+ self->ul_ustack.ss_size = self->ul_stksiz;
+ self->ul_ustack.ss_flags = 0;
+ (void) _private_setustack(&self->ul_ustack);
+ tls_setup();
+
+ /* signals have been deferred until now */
+ sigon(self);
+
+ return (self->ul_startpc(self->ul_startarg));
+}
+
+void
+_fpinherit(ulwp_t *ulwp)
+{
+ extern void _getfsr(greg_t *);
+ int fpu_enabled;
+
+#ifdef __sparcv9
+ extern greg_t _getfprs();
+ fpu_enabled = _getfprs() & FPRS_FEF;
+#else
+ extern psw_t _getpsr();
+ fpu_enabled = _getpsr() & PSR_EF;
+#endif /* __sparcv9 */
+
+ if (fpu_enabled) {
+ _getfsr(&ulwp->ul_fpuenv.fsr);
+ ulwp->ul_fpuenv.fpu_en = 1;
+ } else {
+ ulwp->ul_fpuenv.fpu_en = 0;
+ }
+}
+
+void
+getgregs(ulwp_t *ulwp, gregset_t rs)
+{
+ lwpstatus_t status;
+
+ if (getlwpstatus(ulwp->ul_lwpid, &status) == 0) {
+ rs[REG_PC] = status.pr_reg[R_PC];
+ rs[REG_O6] = status.pr_reg[R_O6];
+ rs[REG_O7] = status.pr_reg[R_O7];
+ rs[REG_G1] = status.pr_reg[R_G1];
+ rs[REG_G2] = status.pr_reg[R_G2];
+ rs[REG_G3] = status.pr_reg[R_G3];
+ rs[REG_G4] = status.pr_reg[R_G4];
+ } else {
+ rs[REG_PC] = 0;
+ rs[REG_O6] = 0;
+ rs[REG_O7] = 0;
+ rs[REG_G1] = 0;
+ rs[REG_G2] = 0;
+ rs[REG_G3] = 0;
+ rs[REG_G4] = 0;
+ }
+}
+
+void
+setgregs(ulwp_t *ulwp, gregset_t rs)
+{
+ lwpstatus_t status;
+
+ if (getlwpstatus(ulwp->ul_lwpid, &status) == 0) {
+ status.pr_reg[R_PC] = rs[REG_PC];
+ status.pr_reg[R_O6] = rs[REG_O6];
+ status.pr_reg[R_O7] = rs[REG_O7];
+ status.pr_reg[R_G1] = rs[REG_G1];
+ status.pr_reg[R_G2] = rs[REG_G2];
+ status.pr_reg[R_G3] = rs[REG_G3];
+ status.pr_reg[R_G4] = rs[REG_G4];
+ (void) putlwpregs(ulwp->ul_lwpid, status.pr_reg);
+ }
+}
+
+int
+__csigsetjmp(sigjmp_buf env, int savemask)
+{
+ sigjmp_struct_t *bp = (sigjmp_struct_t *)env;
+ ulwp_t *self = curthread;
+
+ /*
+ * bp->sjs_sp, bp->sjs_pc, bp->sjs_fp and bp->sjs_i7 are already set.
+ */
+ bp->sjs_flags = JB_FRAMEPTR;
+ bp->sjs_uclink = self->ul_siglink;
+ if (self->ul_ustack.ss_flags & SS_ONSTACK)
+ bp->sjs_stack = self->ul_ustack;
+ else {
+ bp->sjs_stack.ss_sp =
+ (void *)(self->ul_stktop - self->ul_stksiz);
+ bp->sjs_stack.ss_size = self->ul_stksiz;
+ bp->sjs_stack.ss_flags = 0;
+ }
+ if (savemask) {
+ bp->sjs_flags |= JB_SAVEMASK;
+ enter_critical(self);
+ bp->sjs_sigmask = self->ul_sigmask;
+ exit_critical(self);
+ }
+
+ return (0);
+}
diff --git a/usr/src/lib/libc/sparc/threads/sparc.il b/usr/src/lib/libc/sparc/threads/sparc.il
new file mode 100644
index 0000000000..ba0ff4a938
--- /dev/null
+++ b/usr/src/lib/libc/sparc/threads/sparc.il
@@ -0,0 +1,105 @@
+/*
+ * 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"
+
+ .inline _curthread, 0
+ .register %g7, #scratch
+ mov %g7, %o0
+ .end
+
+ .inline __curthread, 0
+ .register %g7, #scratch
+ tst %g7
+ be,a 1f
+ mov %g0, %o0
+ ld [%g7 + 80], %o0 ! ul_self
+1:
+ .end
+
+ .inline stkptr, 0
+ mov %sp, %o0
+ .end
+
+ .inline gethrtime, 0
+ ta 0x24
+ .end
+
+ .inline set_lock_byte, 0
+ ldstub [%o0], %o0
+ .end
+
+ /*
+ * When compiling with -xarch=v8, the compiler refuses to
+ * accept the 'cas' instruction, so we encode it in hex below.
+ * We can't compile the 32-bit libc with -xarch=v8plus because
+ * then %g5 would become a scratch register and we would break
+ * 32-bit applications that use %g5 as an invariant register.
+ */
+
+ .inline cas32, 0
+ .word 0xd5e21009 ! cas [%o0], %o1, %o2
+ mov %o2, %o0
+ .end
+
+ .inline swap32, 0
+ ld [%o0], %o2
+1:
+ mov %o1, %o3
+ .word 0xd7e2100a ! cas [%o0], %o2, %o3
+ cmp %o2, %o3
+ bne,a 1b
+ mov %o3, %o2
+ mov %o3, %o0
+ .end
+
+ .inline incr32, 0
+ ld [%o0], %o2
+1:
+ add %o2, 1, %o3
+ .word 0xd7e2100a ! cas [%o0], %o2, %o3
+ cmp %o2, %o3
+ bne,a 1b
+ mov %o3, %o2
+ .end
+
+ .inline decr32, 0
+ ld [%o0], %o2
+1:
+ sub %o2, 1, %o3
+ .word 0xd7e2100a ! cas [%o0], %o2, %o3
+ cmp %o2, %o3
+ bne,a 1b
+ mov %o3, %o2
+ .end
+
+ .inline caller, 0
+ mov %i7, %o0
+ .end
+
+ .inline getfp, 0
+ mov %fp, %o0
+ .end
diff --git a/usr/src/lib/libc/sparc/threads/tls_get_addr.s b/usr/src/lib/libc/sparc/threads/tls_get_addr.s
new file mode 100644
index 0000000000..9e88bde010
--- /dev/null
+++ b/usr/src/lib/libc/sparc/threads/tls_get_addr.s
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+ .file "%M%"
+
+#include <sys/asm_linkage.h>
+#include <sys/trap.h>
+#include <../assym.h>
+#include "SYS.h"
+
+/*
+ * To make thread-local storage accesses as fast as possible, we
+ * hand-craft the __tls_get_addr() function below, from this C code:
+ * void *
+ * __tls_get_addr(TLS_index *tls_index)
+ * {
+ * ulwp_t *self = curthread;
+ * tls_t *tlsent = self->ul_tlsent;
+ * ulong_t moduleid;
+ * caddr_t base;
+ *
+ * if ((moduleid = tls_index->ti_moduleid) < self->ul_ntlsent &&
+ * (base = tlsent[moduleid].tls_data) != NULL)
+ * return (base + tls_index->ti_tlsoffset);
+ *
+ * return (slow_tls_get_addr(tls_index));
+ * }
+ */
+
+/*
+ * We assume that the tls_t structure contains two pointer-sized elements.
+ * Cause a build failure if this becomes not true.
+ */
+#if SIZEOF_TLS_T == 8 && !defined(__sparcv9)
+#define SHIFT 3
+#elif SIZEOF_TLS_T == 16 && defined(__sparcv9)
+#define SHIFT 4
+#else
+#error "Assumption violated: SIZEOF_TLS_T is not 2 * sizeof (uintptr_t)"
+#endif
+
+#if defined(__sparcv9)
+#define PN ,pn %xcc,
+#else
+#define PN
+#endif
+
+ ENTRY(__tls_get_addr)
+ ldn [%o0 + TI_MODULEID], %o1
+ ldn [%g7 + UL_TLSENT], %o2
+ ldn [%g7 + UL_NTLSENT], %o3
+ cmp %o1, %o3
+ bgeu PN 1f
+ slln %o1, SHIFT, %o1
+#if TLS_DATA != 0
+ add %o1, TLS_DATA, %o1
+#endif
+ ldn [%o1 + %o2], %o2
+ cmp %o2, 0
+ be PN 1f
+ ldn [%o0 + TI_TLSOFFSET], %o1
+ retl
+ add %o1, %o2, %o0
+1:
+ mov %o7, %g1
+ call slow_tls_get_addr
+ mov %g1, %o7
+ SET_SIZE(__tls_get_addr)
diff --git a/usr/src/lib/libc/sparc/unwind/unwind_frame.s b/usr/src/lib/libc/sparc/unwind/unwind_frame.s
new file mode 100644
index 0000000000..022e4ac781
--- /dev/null
+++ b/usr/src/lib/libc/sparc/unwind/unwind_frame.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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+ .file "%M%"
+
+#include "SYS.h"
+#include <../assym.h>
+
+/* Cancellation/thr_exit() stuff */
+
+/*
+ * _ex_unwind_local(void)
+ *
+ * Called only from _t_cancel().
+ * Unwind two frames and invoke _t_cancel(fp) again.
+ *
+ * Before this the call stack is: f4 f3 f2 f1 _t_cancel
+ * After this the call stack is: f4 f3 f2 _t_cancel
+ * (as if "call f1" is replaced by "call _t_cancel(fp)" in f2)
+ */
+ ENTRY(_ex_unwind_local)
+ restore
+ restore
+ ba _t_cancel ! tailcall _t_cancel(fp)
+ mov %fp, %o0 ! passing the frame pointer
+ SET_SIZE(_ex_unwind_local)
+
+/*
+ * _ex_clnup_handler(void *arg, void (*clnup)(void *))
+ *
+ * Called only from _t_cancel().
+ * Unwind one frame, call the cleanup handler with argument arg from the
+ * restored frame, then jump to _t_cancel(fp) again from the restored frame.
+ */
+ ENTRY(_ex_clnup_handler)
+ mov %o1, %i1 ! handler address -> %o1 after restore
+ restore %o0, %g0, %o0 ! handler arg -> %o0 after restore
+ stn %o7, [%g7 + UL_UNWIND_RET] ! save caller's return address
+ jmpl %o1, %o7 ! invoke func with arg
+ nop ! and return here
+ ldn [%g7 + UL_UNWIND_RET], %o7 ! restore return address
+ ba _t_cancel ! tailcall _t_cancel(fp)
+ mov %fp, %o0 ! passing the frame pointer
+ SET_SIZE(_ex_clnup_handler)
+
+/*
+ * _thrp_unwind(void *arg)
+ *
+ * Ignore the argument; jump to _t_cancel(fp) with caller's fp
+ */
+ ENTRY(_thrp_unwind)
+ ba _t_cancel ! tailcall _t_cancel(fp)
+ mov %fp, %o0 ! passing the frame pointer
+ SET_SIZE(_thrp_unwind)