diff options
author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
---|---|---|
committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/libc/sparc | |
download | illumos-gate-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz |
OpenSolaris Launch
Diffstat (limited to 'usr/src/lib/libc/sparc')
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_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) |