Return-Path: mikpe@ida.liu.se Received: by jove.pa.dec.com; id AA02257; Tue, 30 Mar 93 07:55:11 -0800 Received: by inet-gw-1.pa.dec.com; id AA15718; Tue, 30 Mar 93 07:55:04 -0800 Received: from senilix by ida.liu.se (5.65b/ida.minimaster-V1.0b6d5)id AA01376; Tue, 30 Mar 93 17:55:00 +0200 From: Mikael Pettersson Received: from sen9 by senilix (5.65b/ida.slave-V1.0b3)id AA04559; Tue, 30 Mar 93 17:54:58 +0200 Received: by sen9 (5.65b/ida.slave-V1.0b3)id AA07859; Tue, 30 Mar 93 17:54:55 +0200 Date: Tue, 30 Mar 93 17:54:55 +0200 Message-Id: <9303301554.AA07859@sen9> To: bartlett Subject: S->C SUN4 revised patch kit [I managed to goof up when creating the `diffs' file; the first patch was off by 32 lines, and this caused serious problems for some people. Please replace the existing MPE01-15mar93.patches with this file. Sorry about the inconvenience. /Mike] This is a set of patches and new files for porting the `15mar93' release of Scheme->C to Sun's SPARC-based machines. Unpacking the shar script below in the Scheme->C root directory creates a build script, `build-sun4', and a SUN4 directory containing auxiliary files and a patch file. Executing `build-sun4' copies the generic source tree to SUN4, adds some new files, and patches some others. Then cd to SUN4 and `make port' to actually build the system. On my machine (Sun SPARCstation, SunOS 4.1.3, using Sun's bundled C compiler), this port passes all tests without any errors. It has also recompiled itself several times without any problems. (I have not tried the server version though.) Acknowledgements: * Roger Critchlow (rec@arris.com ?) ported the 01nov91 release to the SPARC. I used his `sparc.s' and `sparc-pragma.h'. * I defined the `options.h' file (using Roger's definition of sc_jmp_buf), added the assembly code and macros for dealing with unaligned double floating-point values, and some necessary declarations and fixes. Some of the fixes are conditionalized on `SUNOS' instead of `SPARC': they should be applicable also for Sun3 machines. /Mikael Pettersson (mpe@ida.liu.se), March 24 1993. #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh build-sun4 <<'END_OF_build-sun4' X#!/bin/sh XCPU=SUN4 X# X# mimic the forANY target of the root makefile X# Xecho "Building the initial source tree under ${CPU}..." Xln -s ../ports/makefile ${CPU} Xmkdir ${CPU}/scsc Xcat ${CPU}/makefile-head scsc/makefile >${CPU}/scsc/makefile Xcd ${CPU}/scsc; make srclinks; cd ../.. Xmkdir ${CPU}/scrt Xcat ${CPU}/makefile-head scrt/makefile >${CPU}/scrt/makefile Xcd ${CPU}/scrt; make srclinks; cd ../.. Xmkdir ${CPU}/server Xcat ${CPU}/makefile-head scrt/makefile >${CPU}/server/makefile Xcd ${CPU}/server; make srclinks; cd ../.. Xmkdir ${CPU}/test Xcat ${CPU}/makefile-head test/makefile >${CPU}/test/makefile Xcd ${CPU}/test; make srclinks; cd ../.. Xmkdir ${CPU}/cdecl Xcat ${CPU}/makefile-head cdecl/makefile >${CPU}/cdecl/makefile Xcd ${CPU}/cdecl; make srclinks; cd ../.. Xmkdir ${CPU}/xlib Xcat ${CPU}/makefile-head xlib/makefile >${CPU}/xlib/makefile Xcd ${CPU}/xlib; make srclinks; cd ../.. X# X# mimic the rest of a for${CPU} makefile target X# Xecho "Installing ${CPU}-specific files..." Xcd ${CPU} Xln -s ../sparc.s scrt/sparc.s Xln -s ../sparc-pragma.h scrt/sparc-pragma.h Xln -s ../options.h scrt/options.h Xln -s ../sparc.s server/sparc.s Xln -s ../sparc-pragma.h server/sparc-pragma.h Xln -s ../options-server.h server/options.h Xcd .. X# X# make copies of files we will change X# Xecho "Copying files that will be patched..." Xcd ${CPU}/scsc Xcp makefile temp; mv -f temp makefile; chmod u+w makefile Xcd ../scrt Xcp callcc.c temp; mv -f temp callcc.c; chmod u+w callcc.c Xcp cio.c temp; mv -f temp cio.c; chmod u+w cio.c Xcp heap.c temp; mv -f temp heap.c; chmod u+w heap.c Xcp objects.c temp; mv -f temp objects.c; chmod u+w objects.c Xcp objects.h temp; mv -f temp objects.h; chmod u+w objects.h Xcp scinit.c temp; mv -f temp scinit.c; chmod u+w scinit.c Xcd ../.. X# X# now apply patches X# Xecho "Applying patches..." Xcd ${CPU} Xpatch < diffs X# X# all done X# Xecho "Build succeeded." Xecho "Now cd to the ${CPU} directory and type \`make port'." END_OF_build-sun4 if test 1915 -ne `wc -c SUN4/diffs <<'END_OF_SUN4/diffs' X*** scsc/makefile.~1~ Sat Jan 30 00:17:02 1993 X--- scsc/makefile Tue Mar 16 17:44:45 1993 X*************** X*** 68,74 **** X .SUFFIXES: .o .sc .c X X .sc.c: X! ${SCC} -C $*.sc X X .c.o: X ${CC} -c ${CFLAGS} -I${RTDIR} $*.c X--- 68,74 ---- X .SUFFIXES: .o .sc .c X X .sc.c: X! ${SCC} -C ${SCCFLAGS} $*.sc X X .c.o: X ${CC} -c ${CFLAGS} -I${RTDIR} $*.c X*** scrt/callcc.c.~1~ Wed Feb 24 00:25:41 1993 X--- scrt/callcc.c Mon Mar 15 21:09:10 1993 X*************** X*** 91,96 **** X--- 91,107 ---- X #define SETJMP( x ) sc_setjmp( x ) X #endif X X+ #ifdef SUN4 X+ extern sc_setjmp(); X+ /* The Sun4 compilers need a special #pragma for setjmp-like functions, but X+ * some compilers generate error messages upon seeing such a directive. X+ * Hence this kludge. X+ */ X+ #include "sparc-pragma.h" X+ #define LONGJMP( x, y ) sc_longjmp( x, y ) X+ #define SETJMP( x ) sc_setjmp( x ) X+ #endif X+ X TSCP sc_clink; /* Pointer to inner most continuation on stack. */ X X /* Static declarations for data structures internal to the module. These X*** scrt/cio.c.~1~ Wed Feb 24 00:26:58 1993 X--- scrt/cio.c Tue Mar 16 15:41:04 1993 X*************** X*** 93,99 **** X--- 93,102 ---- X } X #else X #include X+ #ifdef SUNOS X+ extern double strtod( XAL2( char*, char** ) ); X #endif X+ #endif X X #ifdef MAC X #include X*************** X*** 143,148 **** X--- 146,155 ---- X #define HAVE_RUSAGE X #endif X X+ #ifdef SUNOS X+ #define HAVE_RUSAGE X+ #endif X+ X #ifdef SYSV X #define HAVE_TIMES X #else X*************** X*** 159,165 **** X #endif X #endif X X! #ifdef VAX X extern int sys_nerr; X X extern char *sys_errlist[]; X--- 166,172 ---- X #endif X #endif X X! #if defined(VAX) || defined(SUNOS) X extern int sys_nerr; X X extern char *sys_errlist[]; X*** scrt/heap.c.~1~ Mon Feb 22 17:11:33 1993 X--- scrt/heap.c Mon Mar 15 23:12:33 1993 X*************** X*** 373,378 **** X--- 373,393 ---- X } X #endif X X+ #ifdef SUN4 X+ /* All processor registers which might contain pointers are traced by the X+ following procedure. X+ */ X+ X+ static trace_stack_and_registers() X+ { X+ S2CINT *pp; X+ sc_jmp_buf tmp; X+ X+ STACKPTR( pp ); X+ while (pp != sc_stackbase) move_continuation_ptr( ((SCP)*pp++) ); X+ } X+ #endif X+ X #ifdef WIN16 X /* The following code is used to read the stack pointer. The register X number is passed in to force an argument to be on the stack, which in X*************** X*** 1962,1967 **** X--- 1977,1989 ---- X the Scheme object with that value. X */ X X+ #ifdef SUN4 X+ extern void sc_set_double( XAL2( int* , double ) ); X+ #define SET_FLOAT_VALUE( scp, val ) sc_set_double(&(scp)->doublefloat.value[0], (val) ) X+ #else X+ #define SET_FLOAT_VALUE( scp, val ) (scp)->doublefloat.value = (val) X+ #endif X+ X #ifdef OLD_FASHIONED_C X TSCP sc_makedoublefloat( value ) X double value; X*************** X*** 1982,1988 **** X } X else X pp = sc_allocateheap( DOUBLEFLOATSIZE, DOUBLEFLOATTAG, 0 ); X! pp->doublefloat.value = value; X MUTEXOFF; X return( U_T( pp, EXTENDEDTAG ) ); X } X--- 2004,2010 ---- X } X else X pp = sc_allocateheap( DOUBLEFLOATSIZE, DOUBLEFLOATTAG, 0 ); X! SET_FLOAT_VALUE( pp, value ); X MUTEXOFF; X return( U_T( pp, EXTENDEDTAG ) ); X } X*** scrt/objects.c.~1~ Mon Feb 22 17:12:04 1993 X--- scrt/objects.c Mon Mar 15 23:06:42 1993 X*************** X*** 555,561 **** X break; X case EXTENDEDTAG: X if (TX_U( p )->extendedobj.tag == DOUBLEFLOATTAG) X! return( (S2CINT)( TX_U( p )->doublefloat.value ) ); X break; X } X sc_error( "TSCP_S2CINT", "Argument cannot be converted to C int", X--- 555,561 ---- X break; X case EXTENDEDTAG: X if (TX_U( p )->extendedobj.tag == DOUBLEFLOATTAG) X! return( (S2CINT) FLOAT_VALUE( p ) ); X break; X } X sc_error( "TSCP_S2CINT", "Argument cannot be converted to C int", X*************** X*** 578,584 **** X break; X case EXTENDEDTAG: X if (TX_U( p )->extendedobj.tag == DOUBLEFLOATTAG) { X! v = TX_U( p )->doublefloat.value; X if (v <= MAXS2CINTF) X return( (S2CUINT)( v ) ); X else X--- 578,584 ---- X break; X case EXTENDEDTAG: X if (TX_U( p )->extendedobj.tag == DOUBLEFLOATTAG) { X! v = FLOAT_VALUE( p ); X if (v <= MAXS2CINTF) X return( (S2CUINT)( v ) ); X else X*************** X*** 614,620 **** X return( (void*)sc_procedureaddress( p ) ); X break; X case DOUBLEFLOATTAG: X! v = TX_U( p )->doublefloat.value; X if (v <= MAXS2CINTF) X return( (void*)((S2CUINT)( v )) ); X else X--- 614,620 ---- X return( (void*)sc_procedureaddress( p ) ); X break; X case DOUBLEFLOATTAG: X! v = FLOAT_VALUE( p ); X if (v <= MAXS2CINTF) X return( (void*)((S2CUINT)( v )) ); X else X*************** X*** 639,645 **** X break; X case EXTENDEDTAG: X if (TX_U( p )->extendedobj.tag == DOUBLEFLOATTAG) X! return( TX_U( p )->doublefloat.value ); X break; X } X sc_error( "TSCP_DOUBLE", "Argument cannot be converted to C double", X--- 639,645 ---- X break; X case EXTENDEDTAG: X if (TX_U( p )->extendedobj.tag == DOUBLEFLOATTAG) X! return( FLOAT_VALUE( p ) ); X break; X } X sc_error( "TSCP_DOUBLE", "Argument cannot be converted to C double", X*** scrt/objects.h.~1~ Wed Feb 24 00:29:09 1993 X--- scrt/objects.h Mon Mar 15 23:54:09 1993 X*************** X*** 157,163 **** X--- 157,167 ---- X } record; X struct { /* DOUBLEFLOAT */ X S2CUINT_FIELDS2( tag:8, rest:S2CINTBITS-8 ); X+ #ifdef SUN4 X+ int value[2]; X+ #else X double value; X+ #endif X } doublefloat; X struct { /* FORWARD */ X S2CUINT_FIELDS2( tag:8, length:S2CINTBITS-8 ); X*************** X*** 896,902 **** X--- 900,911 ---- X (*((PATSCP)(((char*)( tscp ))+((sizeof(S2CINT)*2)-1)+((S2CINT)n)*2))) X #endif X X+ #ifdef SUN4 X+ extern double sc_get_double( XAL1( int* ) ); X+ #define FLOAT_VALUE( tscp ) sc_get_double(&(TX_U( tscp )->doublefloat.value[0])) X+ #else X #define FLOAT_VALUE( tscp ) (TX_U( tscp )->doublefloat.value) X+ #endif X X #define PAIR_CAR( tscp ) (TP_U( tscp )->pair.car) X #define PAIR_CDR( tscp ) (TP_U( tscp )->pair.cdr) X*** scrt/scinit.c.~1~ Mon Mar 1 20:32:10 1993 X--- scrt/scinit.c Mon Mar 15 20:50:39 1993 X*************** X*** 314,330 **** X { X S2CINT bytes; X char* addr; X X! if ( (*pagegen = sc_gettable( (last-first+2)*sizeof( unsigned char ), X! ~module_initialized )) != NULL && X! (*type = sc_gettable( (last-first+2)*sizeof( unsigned char ), X! ~module_initialized )) != NULL && X! (*lock = sc_gettable( (last-first+2)*sizeof( unsigned char ), X! ~module_initialized )) != NULL && X! (*link = (PAGELINK*)sc_gettable( (last-first+2) X! *sizeof( PAGELINK ), X! ~module_initialized )) X! != NULL ) { X return; X } X expandfailed = 1; X--- 314,329 ---- X { X S2CINT bytes; X char* addr; X+ typedef unsigned char uchar; X X! if ( (*pagegen = (uchar*)sc_gettable( (last-first+2)*sizeof( unsigned char ), X! ~module_initialized )) != NULL && X! (*type = (uchar*)sc_gettable( (last-first+2)*sizeof( unsigned char ), X! ~module_initialized )) != NULL && X! (*lock = (uchar*)sc_gettable( (last-first+2)*sizeof( unsigned char ), X! ~module_initialized )) != NULL && X! (*link = (PAGELINK*)sc_gettable( (last-first+2)*sizeof( PAGELINK ), X! ~module_initialized )) != NULL ) { X return; X } X expandfailed = 1; X*************** X*** 337,342 **** X--- 336,344 ---- X } X X /* The following function is called to initialize the heap from scratch. */ X+ #ifdef SUNOS X+ #include /* get definition of stderr */ X+ #endif X X sc_newheap() X { X*************** X*** 344,349 **** X--- 346,354 ---- X TSCP unknown; X SCP ep; X X+ #ifdef SUNOS X+ setbuf(stderr, (char*)0); X+ #endif X sc_limit = sclimit; X sc_heappages = 0; X sc_maxheappages = scmaxheap*(ONEMB/PAGEBYTES); END_OF_SUN4/diffs if test 8043 -ne `wc -c SUN4/makefile-head <<'END_OF_SUN4/makefile-head' X# X# This is the header file for constructing make files for Sun4. X# X X# Default flags to use when invoking the C compiler. X XCFLAGS = -O XCC = cc X X# Assembly language object files. X XAruntime = sparc.o X X# need to override the default ".s.o" rule in the generic makefile X Xsparc.o: sparc.s X as -o sparc.o -P sparc.s X X# Profiled library X XPlib = libsc_p.a X X# Installation tools X XRANLIB = ranlib X X# X library X XXLIB = -lX11 XXLIBCFLAGS = X X# End of Sun4 header. END_OF_SUN4/makefile-head if test 451 -ne `wc -c SUN4/options-server.h <<'END_OF_SUN4/options-server.h' X/* SCHEME->C */ X X#define SUN4 X X/****************/ X/* SUN4 */ X/****************/ X X#ifdef SUN4 X#define IMPLEMENTATION_MACHINE "Sun4" X#define IMPLEMENTATION_CPU "SPARC" X#define IMPLEMENTATION_OS "SunOS 4.x" X#undef IMPLEMENTATION_FS X#define SUNOS X X#define BIGENDIAN 1 X#define OLD_FASHIONED_C 1 X#define DOUBLE_ALIGN 0 X#undef NEED_MACROS_ARGS X#define CHECKSTACK 1 X#define TIMESLICE 1 X#define COMPACTPUSHTRACE 0 X#define COMPACTPOPTRACE 0 X#define S2CSIGNALS 0 X#define MATHTRAPS 0 X#undef STACK_GROWS_POSITIVE X Xtypedef int S2CINT; /* Signed pointer size integer */ Xtypedef unsigned S2CUINT; /* Unsigned pointer size interger */ X Xtypedef int PAGELINK; /* 32-bit sc_pagelink values */ X#define MAXS2CINT 0x7fffffff /* Maximum value of an S2CINT */ X#define MSBS2CUINT 0x80000000 /* S2CUINT with 1 in the MSB */ X Xtypedef int sc_jmp_buf[2+7+8+8+1+1]; X/* The buffer contains the following items: X * %o6-%o7, %g1-%g7, %l0-%l7, %i0-%i7, %y, X */ X X#define STACKPTR(x) ((x) = (sc_processor_register(0))) X X#endif /*SUN4*/ END_OF_SUN4/options-server.h if test 1032 -ne `wc -c SUN4/options.h <<'END_OF_SUN4/options.h' X/* SCHEME->C */ X X#define SUN4 X X/****************/ X/* SUN4 */ X/****************/ X X#ifdef SUN4 X#define IMPLEMENTATION_MACHINE "Sun4" X#define IMPLEMENTATION_CPU "SPARC" X#define IMPLEMENTATION_OS "SunOS 4.x" X#undef IMPLEMENTATION_FS X#define SUNOS X X#define BIGENDIAN 1 X#define OLD_FASHIONED_C 1 X#define DOUBLE_ALIGN 0 X#undef NEED_MACROS_ARGS X#define CHECKSTACK 0 X#define TIMESLICE 0 X#define COMPACTPUSHTRACE 0 X#define COMPACTPOPTRACE 0 X#define S2CSIGNALS 1 X#define MATHTRAPS 0 X#undef STACK_GROWS_POSITIVE X Xtypedef int S2CINT; /* Signed pointer size integer */ Xtypedef unsigned S2CUINT; /* Unsigned pointer size interger */ X Xtypedef int PAGELINK; /* 32-bit sc_pagelink values */ X#define MAXS2CINT 0x7fffffff /* Maximum value of an S2CINT */ X#define MSBS2CUINT 0x80000000 /* S2CUINT with 1 in the MSB */ X Xtypedef int sc_jmp_buf[2+7+8+8+1+1]; X/* The buffer contains the following items: X * %o6-%o7, %g1-%g7, %l0-%l7, %i0-%i7, %y, X */ X X#define STACKPTR(x) ((x) = (sc_processor_register(0))) X X#endif /*SUN4*/ END_OF_SUN4/options.h if test 1032 -ne `wc -c SUN4/sparc-pragma.h <<'END_OF_SUN4/sparc-pragma.h' X/* This is the pragma declaration that is necessary to tell the SPARC */ X/* compiler about the new setjmp routine. */ X#pragma unknown_control_flow(sc_setjmp) END_OF_SUN4/sparc-pragma.h if test 158 -ne `wc -c SUN4/sparc.s <<'END_OF_SUN4/sparc.s' X! X! SCHEME->C X! X! SPARC assembly code. X! X! Rules for building continuations on the SPARC: X! X! 1 - register windows must be flushed to memory before X! the stack is copied to the heap. X! X! 2 - setjmp must save the caller's local and input register X! frames when saving context, because longjmp will not X! have access to the saved stack to fetch the registers X! from their normal resting place. X! X! 3 - longjmp must flush register windows so the correct register X! values will be reloaded from memory when execution continues X! on the restored stack. X! X! 4 - longjmp must restore the caller's local and input register X! frames because the stack hasn't been restored when longjmp X! is called. X! X#include X X! X! This misnamed function is responsible for providing the X! top of stack address, via macro STACKPTR, to the continuation X! builder and the heap manager. Because both of these functions X! immediately begin examining the memory on the stack, the register X! windows are flushed to memory so their values will be saved in X! heap allocated continuations and seen by the garbage collector. X! X .global _sc_processor_register X_sc_processor_register: X ta 3 ! flush register windows X jmp %o7+8 ! return X add %sp, 0, %o0 ! return stack pointer X X! X! On the SPARC, doubles are normally aligned on eight-byte boundaries. X! Sun's bundled C compiler will, upon seeing a double-typed field in a struct, X! make sure the byte offset from the beginning of that struct to the field X! is a multiple of 8. The compiler will therefore insert a 4-byte padding X! between the header and the f.p. value in struct doublefloat (objects.h). X! This means that the object really extends 4 bytes past its allocated memory, X! causing garbage to be read when the object is accessed (the last half of X! the f.p. value will often be read from the next node's header!). Sun's C X! compiler can be tricked into doing this correctly by declaring the field X! as "int value[2]" and accessing it as "*(double*)&(.. ->doublefloat.value[0])". X! Unfortunately, GCC _insists_ on using the ldd/std instructions when accessing X! any "double*". My solution (can you say "kludge"?) is to use the fake X! declaration hack, and two assembly-coded routines for safe accesses. X! As a consequence, DOUBLE_ALIGN need not be defined for the SPARC. X! The two routines below expect the address of the "double" itself, rather X! than the base address of the node. X! X X! extern double sc_get_double(int*) X X .global _sc_get_double X_sc_get_double: X ld [%o0+0],%f0 X retl X ld [%o0+4],%f1 X X! extern void sc_set_double(int*, double) X X .global _sc_set_double X_sc_set_double: X st %o1,[%o0+0] X retl X st %o2,[%o0+4] X X! X! Save the current environment in a heap allocated continuation. X! X .global _sc_setjmp X_sc_setjmp: X st %o6, [%o0 + 0] ! save stack pointer X st %o7, [%o0 + 4] ! save continuation pointer X st %g1, [%o0 + 8] ! save global registers X st %g2, [%o0 + 12] ! these may be allocated for X st %g3, [%o0 + 16] ! caller saves registers or X st %g4, [%o0 + 20] ! for global values. X st %g5, [%o0 + 24] X st %g6, [%o0 + 28] X st %g7, [%o0 + 32] X st %l0, [%o0 + 36] ! save local registers X st %l1, [%o0 + 40] ! the sunos setjmp uses X st %l2, [%o0 + 44] ! the register windows to X st %l3, [%o0 + 48] ! save these, we can't. X st %l4, [%o0 + 52] X st %l5, [%o0 + 56] X st %l6, [%o0 + 60] X st %l7, [%o0 + 64] X st %i0, [%o0 + 68] X st %i1, [%o0 + 72] X st %i2, [%o0 + 76] X st %i3, [%o0 + 80] X st %i4, [%o0 + 84] X st %i5, [%o0 + 88] X st %i6, [%o0 + 92] X st %i7, [%o0 + 96] X mov %y, %o2 ! fetch %y, whatever it is X st %o2, [%o0 + 100] ! and save it X X add %o0, %g0, %i0 ! save o0 in i0 X clr %o0 X mov SYS_sigblock,%g1 X t 0 X st %o0, [%i0 + 104] ! save signal mask X X jmp %o7+8 ! return X add %g0, %g0, %o0 ! return 0 X X! X! Restore an environment from a heap allocated continuation. X! X .global _sc_longjmp X_sc_longjmp: X add %o0, %g0, %i0 ! save o0 in i0 X add %o1, %g0, %i1 ! save o1 in i1 X ld [%o0 + 104], %o0 X mov SYS_sigsetmask, %g1 X t 0 ! sigsetmask(oldmask) X add %i0, %g0, %o0 ! restore o0 X add %i1, %g0, %o1 ! restore o1 X X ta 3 ! flush register windows X ld [%o0 + 0], %o6 ! restore stack pointer X ld [%o0 + 4], %o7 ! load continuation pointer X ld [%o0 + 8], %g1 ! restore global registers X ld [%o0 + 12], %g2 X ld [%o0 + 16], %g3 X ld [%o0 + 20], %g4 X ld [%o0 + 24], %g5 X ld [%o0 + 28], %g6 X ld [%o0 + 32], %g7 X ld [%o0 + 36], %l0 ! restore local frame from stack X ld [%o0 + 40], %l1 X ld [%o0 + 44], %l2 X ld [%o0 + 48], %l3 X ld [%o0 + 52], %l4 X ld [%o0 + 56], %l5 X ld [%o0 + 60], %l6 X ld [%o0 + 64], %l7 X ld [%o0 + 68], %i0 X ld [%o0 + 72], %i1 X ld [%o0 + 76], %i2 X ld [%o0 + 80], %i3 X ld [%o0 + 84], %i4 X ld [%o0 + 88], %i5 X ld [%o0 + 92], %i6 X ld [%o0 + 96], %i7 X ld [%o0 + 100], %o2 ! restore %y, whatever it is X mov %o2, %y X jmp %o7+8 ! return X add %o1, %g0, %o0 ! return arg END_OF_SUN4/sparc.s if test 4857 -ne `wc -c