From a46395ecf932ea4e91ad047e92d1c70395e15673 Mon Sep 17 00:00:00 2001 From: rsc Date: Wed, 1 Oct 2003 02:53:00 +0000 Subject: More Darwin. --- src/lib9/ffork-Darwin.c | 26 ++++ src/lib9/lib9.h | 246 ------------------------------ src/lib9/rendez-Darwin.c | 2 + src/lib9/rendez-FreeBSD.c | 1 + src/lib9/rendez-Linux.c | 1 + src/lib9/rendez-pthread.c | 168 ++++++++++++++++++++ src/lib9/rendez-signal.c | 180 ++++++++++++++++++++++ src/lib9/rendez.c | 180 ---------------------- src/libthread/Darwin.c | 5 + src/libthread/PowerMacintosh.c | 28 ++++ src/libthread/asm-Darwin-PowerMacintosh.s | 80 ++++++++++ 11 files changed, 491 insertions(+), 426 deletions(-) create mode 100644 src/lib9/ffork-Darwin.c delete mode 100644 src/lib9/lib9.h create mode 100644 src/lib9/rendez-Darwin.c create mode 100644 src/lib9/rendez-FreeBSD.c create mode 100644 src/lib9/rendez-Linux.c create mode 100644 src/lib9/rendez-pthread.c create mode 100644 src/lib9/rendez-signal.c delete mode 100644 src/lib9/rendez.c create mode 100644 src/libthread/Darwin.c create mode 100644 src/libthread/PowerMacintosh.c create mode 100644 src/libthread/asm-Darwin-PowerMacintosh.s diff --git a/src/lib9/ffork-Darwin.c b/src/lib9/ffork-Darwin.c new file mode 100644 index 00000000..189ac94f --- /dev/null +++ b/src/lib9/ffork-Darwin.c @@ -0,0 +1,26 @@ +#include +#include + +extern int __isthreaded; +int +ffork(int flags, void(*fn)(void*), void *arg) +{ + void *p; + pthread_t tid; + + if(flags != (RFMEM|RFNOWAIT)){ + werrstr("ffork unsupported"); + return -1; + } + + if(pthread_create(&tid, NULL, (void*(*)(void*))fn, arg) < 0) + return -1; + return (int)tid; +} + +int +getfforkid(void) +{ + return (int)pthread_self(); +} + diff --git a/src/lib9/lib9.h b/src/lib9/lib9.h deleted file mode 100644 index bb7e5404..00000000 --- a/src/lib9/lib9.h +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Lib9 is miscellany from the Plan 9 C library that doesn't - * fit into libutf or into libfmt, but is still missing from traditional - * Unix C libraries. - */ -#ifndef _LIB9H_ -#define _LIB9H_ 1 - -#if defined(__cplusplus) -extern "C" { -#endif - - -#include -#include -#include -#include -#include -#include - -#ifndef _FMTH_ -# include -#endif - -#define nil ((void*)0) -#define nelem(x) (sizeof(x)/sizeof((x)[0])) - -#define _NEEDUCHAR 1 -#define _NEEDUSHORT 1 -#define _NEEDUINT 1 -#define _NEEDULONG 1 - -#if defined(__linux__) -# include -# if defined(__USE_MISC) -# undef _NEEDUSHORT -# undef _NEEDUINT -# undef _NEEDULONG -# endif -#endif -#if defined(__FreeBSD__) -# include -# if !defined(_POSIX_SOURCE) -# undef _NEEDUSHORT -# undef _NEEDUINT -# endif -#endif - -typedef signed char schar; -typedef unsigned int u32int; -#ifdef _NEEDUCHAR - typedef unsigned char uchar; -#endif -#ifdef _NEEDUSHORT - typedef unsigned short ushort; -#endif -#ifdef _NEEDUINT - typedef unsigned int uint; -#endif -#ifdef _NEEDULONG - typedef unsigned long ulong; -#endif -typedef unsigned long long uvlong; -typedef long long vlong; - -/* rfork to create new process running fn(arg) */ - -#if defined(__FreeBSD__) -#undef RFFDG -#undef RFNOTEG -#undef RFPROC -#undef RFMEM -#undef RFNOWAIT -#undef RFCFDG -#endif - -enum -{ -/* RFNAMEG = (1<<0), */ -/* RFENVG = (1<<1), */ - RFFDG = (1<<2), - RFNOTEG = (1<<3), - RFPROC = (1<<4), - RFMEM = (1<<5), - RFNOWAIT = (1<<6), -/* RFCNAMEG = (1<<10), */ -/* RFCENVG = (1<<11), */ - RFCFDG = (1<<12), -/* RFREND = (1<<13), */ -/* RFNOMNT = (1<<14) */ -}; -extern int ffork(int, void(*)(void*), void*); - -/* wait for processes */ -#define wait _p9wait -typedef struct Waitmsg Waitmsg; -struct Waitmsg -{ - int pid; /* of loved one */ - ulong time[3]; /* of loved one & descendants */ - char *msg; -}; -extern int await(char*, int); -extern Waitmsg* wait(void); - -/* synchronization */ -typedef struct Lock Lock; -struct Lock -{ - int val; -}; - -extern int _tas(void*); -extern void lock(Lock*); -extern void unlock(Lock*); -extern int canlock(Lock*); - -typedef struct QLp QLp; -struct QLp -{ - int inuse; - QLp *next; - int state; -}; - -typedef struct QLock QLock; -struct QLock -{ - Lock lock; - int locked; - QLp *head; - QLp *tail; -}; - -extern void qlock(QLock*); -extern void qunlock(QLock*); -extern int canqlock(QLock*); -extern void _qlockinit(ulong (*)(ulong, ulong)); - -typedef struct RWLock RWLock; -struct RWLock -{ - Lock lock; - int readers; - int writer; - QLp *head; - QLp *tail; -}; - -extern void rlock(RWLock*); -extern void runlock(RWLock*); -extern int canrlock(RWLock*); -extern void wlock(RWLock*); -extern void wunlock(RWLock*); -extern int canwlock(RWLock*); - -typedef struct Rendez Rendez; -struct Rendez -{ - QLock *l; - QLp *head; - QLp *tail; -}; - -extern void rsleep(Rendez*); -extern int rwakeup(Rendez*); -extern int rwakeupall(Rendez*); - -extern ulong rendezvous(ulong, ulong); - -/* one of a kind */ -extern void sysfatal(char*, ...); -extern int nrand(int); -extern void setmalloctag(void*, ulong); -extern void setrealloctag(void*, ulong); -extern void *mallocz(ulong, int); -extern long readn(int, void*, long); -extern void exits(char*); -extern void _exits(char*); -extern ulong getcallerpc(void*); - -/* string routines */ -extern char* strecpy(char*, char*, char*); -extern int tokenize(char*, char**, int); -extern int cistrncmp(char*, char*, int); -extern int cistrcmp(char*, char*); -extern char* cistrstr(char*, char*); -extern int getfields(char*, char**, int, int, char*); -extern int gettokens(char *, char **, int, char *); - -/* formatting helpers */ -extern int dec64(uchar*, int, char*, int); -extern int enc64(char*, int, uchar*, int); -extern int dec32(uchar*, int, char*, int); -extern int enc32(char*, int, uchar*, int); -extern int dec16(uchar*, int, char*, int); -extern int enc16(char*, int, uchar*, int); -extern int encodefmt(Fmt*); - -/* error string */ -enum -{ - ERRMAX = 128 -}; -extern void rerrstr(char*, uint); -extern void werrstr(char*, ...); -extern int errstr(char*, uint); - -/* compiler directives on plan 9 */ -#define USED(x) if(x){}else{} -#define SET(x) ((x)=0) - -/* command line */ -extern char *argv0; -#define ARGBEGIN for((argv0||(argv0=*argv)),argv++,argc--;\ - argv[0] && argv[0][0]=='-' && argv[0][1];\ - argc--, argv++) {\ - char *_args, *_argt;\ - Rune _argc;\ - _args = &argv[0][1];\ - if(_args[0]=='-' && _args[1]==0){\ - argc--; argv++; break;\ - }\ - _argc = 0;\ - while(*_args && (_args += chartorune(&_argc, _args)))\ - switch(_argc) -#define ARGEND SET(_argt);USED(_argt);USED(_argc);USED(_args);}USED(argv);USED(argc); -#define ARGF() (_argt=_args, _args="",\ - (*_argt? _argt: argv[1]? (argc--, *++argv): 0)) -#define EARGF(x) (_argt=_args, _args="",\ - (*_argt? _argt: argv[1]? (argc--, *++argv): ((x), abort(), (char*)0))) - -#define ARGC() _argc - -#define OREAD O_RDONLY -#define OWRITE O_WRONLY -#define AEXIST 0 -#define AREAD 4 -#define AWRITE 2 -#define AEXEC 1 - -#if defined(__cplusplus) -} -#endif - -#endif /* _LIB9H_ */ diff --git a/src/lib9/rendez-Darwin.c b/src/lib9/rendez-Darwin.c new file mode 100644 index 00000000..2f099fc4 --- /dev/null +++ b/src/lib9/rendez-Darwin.c @@ -0,0 +1,2 @@ +#include "rendez-pthread.c" + diff --git a/src/lib9/rendez-FreeBSD.c b/src/lib9/rendez-FreeBSD.c new file mode 100644 index 00000000..05c52ae7 --- /dev/null +++ b/src/lib9/rendez-FreeBSD.c @@ -0,0 +1 @@ +#include "rendez-signal.c" diff --git a/src/lib9/rendez-Linux.c b/src/lib9/rendez-Linux.c new file mode 100644 index 00000000..05c52ae7 --- /dev/null +++ b/src/lib9/rendez-Linux.c @@ -0,0 +1 @@ +#include "rendez-signal.c" diff --git a/src/lib9/rendez-pthread.c b/src/lib9/rendez-pthread.c new file mode 100644 index 00000000..9b5d4342 --- /dev/null +++ b/src/lib9/rendez-pthread.c @@ -0,0 +1,168 @@ +/* + NAME + rendezvous - user level process synchronization + + SYNOPSIS + ulong rendezvous(ulong tag, ulong value) + + DESCRIPTION + The rendezvous system call allows two processes to synchro- + nize and exchange a value. In conjunction with the shared + memory system calls (see segattach(2) and fork(2)), it + enables parallel programs to control their scheduling. + + Two processes wishing to synchronize call rendezvous with a + common tag, typically an address in memory they share. One + process will arrive at the rendezvous first; it suspends + execution until a second arrives. When a second process + meets the rendezvous the value arguments are exchanged + between the processes and returned as the result of the + respective rendezvous system calls. Both processes are + awakened when the rendezvous succeeds. + + The set of tag values which two processes may use to + rendezvous-their tag space-is inherited when a process + forks, unless RFREND is set in the argument to rfork; see + fork(2). + + If a rendezvous is interrupted the return value is ~0, so + that value should not be used in normal communication. + + * This assumes we're using pthreads and simulates rendezvous using + * shared memory and mutexes. + */ + +#include +#include + +enum +{ + VOUSHASH = 257, +}; + +typedef struct Vous Vous; +struct Vous +{ + Vous *link; + Lock lk; + ulong val; + ulong tag; + pthread_mutex_t mutex; +}; + +static void +ign(int x) +{ + USED(x); +} + +void /*__attribute__((constructor))*/ +ignusr1(void) +{ + signal(SIGUSR1, ign); +} + +static Vous vouspool[2048]; +static int nvousused; +static Vous *vousfree; +static Vous *voushash[VOUSHASH]; +static Lock vouslock; + +static Vous* +getvous(void) +{ + Vous *v; + + if(vousfree){ + v = vousfree; + vousfree = v->link; + }else if(nvousused < nelem(vouspool)){ + v = &vouspool[nvousused++]; + pthread_mutex_init(&v->mutex, NULL); + }else + abort(); + return v; +} + +static void +putvous(Vous *v) +{ + lock(&vouslock); + v->link = vousfree; + vousfree = v; + unlock(&vouslock); +} + +static Vous* +findvous(ulong tag, ulong val, int *found) +{ + int h; + Vous *v, **l; + + lock(&vouslock); + h = tag%VOUSHASH; + for(l=&voushash[h], v=*l; v; l=&(*l)->link, v=*l){ + if(v->tag == tag){ + *l = v->link; + *found = 1; + unlock(&vouslock); + return v; + } + } + v = getvous(); + v->link = voushash[h]; + v->val = val; + v->tag = tag; + lock(&v->lk); + voushash[h] = v; + unlock(&vouslock); + *found = 0; + return v; +} + +#define DBG 0 +ulong +rendezvous(ulong tag, ulong val) +{ + int found; + ulong rval; + Vous *v; + + v = findvous(tag, val, &found); + if(!found){ + if(DBG)fprint(2, "tag %lux, sleeping on %p\n", tag, v); + /* + * No rendezvous partner was found; the next guy + * through will find v and wake us, so we must go + * to sleep. Do this by locking the mutex (it is + * unlocked) and then locking it again (our waker will + * unlock it for us). + */ + if(pthread_mutex_lock(&v->mutex) != 0) + abort(); + unlock(&v->lk); + if(pthread_mutex_lock(&v->mutex) != 0) + abort(); + rval = v->val; + pthread_mutex_unlock(&v->mutex); + if(DBG)fprint(2, " awake on %p\n", v); + unlock(&v->lk); + putvous(v); + }else{ + /* + * Found someone to meet. Wake him: + * + * A. lock v->lk (waits for him to lock the mutex once. + * B. unlock the mutex (wakes him up) + */ + if(DBG)fprint(2, "found tag %lux on %p, waking\n", tag, v); + lock(&v->lk); + rval = v->val; + v->val = val; + if(pthread_mutex_unlock(&v->mutex) != 0) + abort(); + /* lock passes to him */ + } + return rval; +} + diff --git a/src/lib9/rendez-signal.c b/src/lib9/rendez-signal.c new file mode 100644 index 00000000..320bd11a --- /dev/null +++ b/src/lib9/rendez-signal.c @@ -0,0 +1,180 @@ +/* + NAME + rendezvous - user level process synchronization + + SYNOPSIS + ulong rendezvous(ulong tag, ulong value) + + DESCRIPTION + The rendezvous system call allows two processes to synchro- + nize and exchange a value. In conjunction with the shared + memory system calls (see segattach(2) and fork(2)), it + enables parallel programs to control their scheduling. + + Two processes wishing to synchronize call rendezvous with a + common tag, typically an address in memory they share. One + process will arrive at the rendezvous first; it suspends + execution until a second arrives. When a second process + meets the rendezvous the value arguments are exchanged + between the processes and returned as the result of the + respective rendezvous system calls. Both processes are + awakened when the rendezvous succeeds. + + The set of tag values which two processes may use to + rendezvous-their tag space-is inherited when a process + forks, unless RFREND is set in the argument to rfork; see + fork(2). + + If a rendezvous is interrupted the return value is ~0, so + that value should not be used in normal communication. + + * This simulates rendezvous with shared memory, pause, and SIGUSR1. + */ + +#include +#include + +enum +{ + VOUSHASH = 257, +}; + +typedef struct Vous Vous; +struct Vous +{ + Vous *link; + Lock lk; + int pid; + ulong val; + ulong tag; +}; + +static void +ign(int x) +{ + USED(x); +} + +void /*__attribute__((constructor))*/ +ignusr1(void) +{ + signal(SIGUSR1, ign); +} + +static Vous vouspool[2048]; +static int nvousused; +static Vous *vousfree; +static Vous *voushash[VOUSHASH]; +static Lock vouslock; + +static Vous* +getvous(void) +{ + Vous *v; + + if(vousfree){ + v = vousfree; + vousfree = v->link; + }else if(nvousused < nelem(vouspool)) + v = &vouspool[nvousused++]; + else + abort(); + return v; +} + +static void +putvous(Vous *v) +{ + lock(&vouslock); + v->link = vousfree; + vousfree = v; + unlock(&vouslock); +} + +static Vous* +findvous(ulong tag, ulong val, int pid) +{ + int h; + Vous *v, **l; + + lock(&vouslock); + h = tag%VOUSHASH; + for(l=&voushash[h], v=*l; v; l=&(*l)->link, v=*l){ + if(v->tag == tag){ + *l = v->link; + unlock(&vouslock); + return v; + } + } + v = getvous(); + v->pid = pid; + v->link = voushash[h]; + v->val = val; + v->tag = tag; + lock(&v->lk); + voushash[h] = v; + unlock(&vouslock); + return v; +} + +#define DBG 0 +ulong +rendezvous(ulong tag, ulong val) +{ + int me, vpid; + ulong rval; + Vous *v; + sigset_t mask; + + me = getpid(); + v = findvous(tag, val, me); + if(v->pid == me){ + if(DBG)fprint(2, "pid is %d tag %lux, sleeping\n", me, tag); + /* + * No rendezvous partner was found; the next guy + * through will find v and wake us, so we must go + * to sleep. + * + * To go to sleep: + * 1. disable USR1 signals. + * 2. unlock v->lk (tells waker okay to signal us). + * 3. atomically suspend and enable USR1 signals. + * + * The call to ignusr1() could be done once at + * process creation instead of every time through rendezvous. + */ + v->val = val; + ignusr1(); + sigprocmask(SIG_SETMASK, NULL, &mask); + sigaddset(&mask, SIGUSR1); + sigprocmask(SIG_SETMASK, &mask, NULL); + sigdelset(&mask, SIGUSR1); + unlock(&v->lk); + sigsuspend(&mask); + rval = v->val; + if(DBG)fprint(2, "pid is %d, awake\n", me); + putvous(v); + }else{ + /* + * Found someone to meet. Wake him: + * + * A. lock v->lk (waits for him to get to his step 2) + * B. send a USR1 + * + * He won't get the USR1 until he suspends, which + * means it must wake him up (it can't get delivered + * before he sleeps). + */ + vpid = v->pid; + lock(&v->lk); + rval = v->val; + v->val = val; + unlock(&v->lk); + if(kill(vpid, SIGUSR1) < 0){ + if(DBG)fprint(2, "pid is %d, kill %d failed: %r\n", me, vpid); + abort(); + } + } + return rval; +} + diff --git a/src/lib9/rendez.c b/src/lib9/rendez.c deleted file mode 100644 index 320bd11a..00000000 --- a/src/lib9/rendez.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - NAME - rendezvous - user level process synchronization - - SYNOPSIS - ulong rendezvous(ulong tag, ulong value) - - DESCRIPTION - The rendezvous system call allows two processes to synchro- - nize and exchange a value. In conjunction with the shared - memory system calls (see segattach(2) and fork(2)), it - enables parallel programs to control their scheduling. - - Two processes wishing to synchronize call rendezvous with a - common tag, typically an address in memory they share. One - process will arrive at the rendezvous first; it suspends - execution until a second arrives. When a second process - meets the rendezvous the value arguments are exchanged - between the processes and returned as the result of the - respective rendezvous system calls. Both processes are - awakened when the rendezvous succeeds. - - The set of tag values which two processes may use to - rendezvous-their tag space-is inherited when a process - forks, unless RFREND is set in the argument to rfork; see - fork(2). - - If a rendezvous is interrupted the return value is ~0, so - that value should not be used in normal communication. - - * This simulates rendezvous with shared memory, pause, and SIGUSR1. - */ - -#include -#include - -enum -{ - VOUSHASH = 257, -}; - -typedef struct Vous Vous; -struct Vous -{ - Vous *link; - Lock lk; - int pid; - ulong val; - ulong tag; -}; - -static void -ign(int x) -{ - USED(x); -} - -void /*__attribute__((constructor))*/ -ignusr1(void) -{ - signal(SIGUSR1, ign); -} - -static Vous vouspool[2048]; -static int nvousused; -static Vous *vousfree; -static Vous *voushash[VOUSHASH]; -static Lock vouslock; - -static Vous* -getvous(void) -{ - Vous *v; - - if(vousfree){ - v = vousfree; - vousfree = v->link; - }else if(nvousused < nelem(vouspool)) - v = &vouspool[nvousused++]; - else - abort(); - return v; -} - -static void -putvous(Vous *v) -{ - lock(&vouslock); - v->link = vousfree; - vousfree = v; - unlock(&vouslock); -} - -static Vous* -findvous(ulong tag, ulong val, int pid) -{ - int h; - Vous *v, **l; - - lock(&vouslock); - h = tag%VOUSHASH; - for(l=&voushash[h], v=*l; v; l=&(*l)->link, v=*l){ - if(v->tag == tag){ - *l = v->link; - unlock(&vouslock); - return v; - } - } - v = getvous(); - v->pid = pid; - v->link = voushash[h]; - v->val = val; - v->tag = tag; - lock(&v->lk); - voushash[h] = v; - unlock(&vouslock); - return v; -} - -#define DBG 0 -ulong -rendezvous(ulong tag, ulong val) -{ - int me, vpid; - ulong rval; - Vous *v; - sigset_t mask; - - me = getpid(); - v = findvous(tag, val, me); - if(v->pid == me){ - if(DBG)fprint(2, "pid is %d tag %lux, sleeping\n", me, tag); - /* - * No rendezvous partner was found; the next guy - * through will find v and wake us, so we must go - * to sleep. - * - * To go to sleep: - * 1. disable USR1 signals. - * 2. unlock v->lk (tells waker okay to signal us). - * 3. atomically suspend and enable USR1 signals. - * - * The call to ignusr1() could be done once at - * process creation instead of every time through rendezvous. - */ - v->val = val; - ignusr1(); - sigprocmask(SIG_SETMASK, NULL, &mask); - sigaddset(&mask, SIGUSR1); - sigprocmask(SIG_SETMASK, &mask, NULL); - sigdelset(&mask, SIGUSR1); - unlock(&v->lk); - sigsuspend(&mask); - rval = v->val; - if(DBG)fprint(2, "pid is %d, awake\n", me); - putvous(v); - }else{ - /* - * Found someone to meet. Wake him: - * - * A. lock v->lk (waits for him to get to his step 2) - * B. send a USR1 - * - * He won't get the USR1 until he suspends, which - * means it must wake him up (it can't get delivered - * before he sleeps). - */ - vpid = v->pid; - lock(&v->lk); - rval = v->val; - v->val = val; - unlock(&v->lk); - if(kill(vpid, SIGUSR1) < 0){ - if(DBG)fprint(2, "pid is %d, kill %d failed: %r\n", me, vpid); - abort(); - } - } - return rval; -} - diff --git a/src/libthread/Darwin.c b/src/libthread/Darwin.c new file mode 100644 index 00000000..fd260957 --- /dev/null +++ b/src/libthread/Darwin.c @@ -0,0 +1,5 @@ +int +_schedfork(Proc *p) +{ + return ffork(RFMEM|RFNOWAIT, _schedinit, p); +} diff --git a/src/libthread/PowerMacintosh.c b/src/libthread/PowerMacintosh.c new file mode 100644 index 00000000..ddacea37 --- /dev/null +++ b/src/libthread/PowerMacintosh.c @@ -0,0 +1,28 @@ +#include "threadimpl.h" + +static void +launcherpower(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, + void (*f)(void *arg), void *arg) +{ + (*f)(arg); + threadexits(nil); +} + +void +_threadinitstack(Thread *t, void (*f)(void*), void *arg) +{ + ulong *tos, *stk; + int n; + + tos = (ulong*)&t->stk[t->stksize&~7]; + stk = tos; + --stk; + --stk; + --stk; + --stk; + *--stk = (ulong)arg; + *--stk = (ulong)f; + t->sched.pc = (ulong)launcherpower+LABELDPC; + t->sched.sp = (ulong)tos-80; +} + diff --git a/src/libthread/asm-Darwin-PowerMacintosh.s b/src/libthread/asm-Darwin-PowerMacintosh.s new file mode 100644 index 00000000..c503e1d6 --- /dev/null +++ b/src/libthread/asm-Darwin-PowerMacintosh.s @@ -0,0 +1,80 @@ +/* get FPR and VR use flags with sc 0x7FF3 */ +/* get vsave with mfspr reg, 256 */ + +.text +.align 2 + +.globl __setlabel + +__setlabel: /* xxx: instruction scheduling */ + mflr r0 + mfcr r5 + mfctr r6 + mfxer r7 + stw r0, 0*4(r3) + stw r5, 1*4(r3) + stw r6, 2*4(r3) + stw r7, 3*4(r3) + + stw r1, 4*4(r3) + stw r2, 5*4(r3) + + stw r13, (0+6)*4(r3) /* callee-save GPRs */ + stw r14, (1+6)*4(r3) /* xxx: block move */ + stw r15, (2+6)*4(r3) + stw r16, (3+6)*4(r3) + stw r17, (4+6)*4(r3) + stw r18, (5+6)*4(r3) + stw r19, (6+6)*4(r3) + stw r20, (7+6)*4(r3) + stw r21, (8+6)*4(r3) + stw r22, (9+6)*4(r3) + stw r23, (10+6)*4(r3) + stw r24, (11+6)*4(r3) + stw r25, (12+6)*4(r3) + stw r26, (13+6)*4(r3) + stw r27, (14+6)*4(r3) + stw r28, (15+6)*4(r3) + stw r29, (16+6)*4(r3) + stw r30, (17+6)*4(r3) + stw r31, (18+6)*4(r3) + + li r3, 0 /* return */ + blr + +.globl __gotolabel + +__gotolabel: + lwz r13, (0+6)*4(r3) /* callee-save GPRs */ + lwz r14, (1+6)*4(r3) /* xxx: block move */ + lwz r15, (2+6)*4(r3) + lwz r16, (3+6)*4(r3) + lwz r17, (4+6)*4(r3) + lwz r18, (5+6)*4(r3) + lwz r19, (6+6)*4(r3) + lwz r20, (7+6)*4(r3) + lwz r21, (8+6)*4(r3) + lwz r22, (9+6)*4(r3) + lwz r23, (10+6)*4(r3) + lwz r24, (11+6)*4(r3) + lwz r25, (12+6)*4(r3) + lwz r26, (13+6)*4(r3) + lwz r27, (14+6)*4(r3) + lwz r28, (15+6)*4(r3) + lwz r29, (16+6)*4(r3) + lwz r30, (17+6)*4(r3) + lwz r31, (18+6)*4(r3) + + lwz r1, 4*4(r3) + lwz r2, 5*4(r3) + + lwz r0, 0*4(r3) + mtlr r0 + lwz r0, 1*4(r3) + mtcr r0 /* mtcrf 0xFF, r0 */ + lwz r0, 2*4(r3) + mtctr r0 + lwz r0, 3*4(r3) + mtxer r0 + li r3, 1 + blr -- cgit v1.2.3