avcall-sparc.c
上传用户:shenzhenrh
上传日期:2013-05-12
资源大小:2904k
文件大小:8k
- #ifndef _avcall_sparc_c /*-*- C -*-*/
- #define _avcall_sparc_c
- /**
- Copyright 1993 Bill Triggs, <Bill.Triggs@inrialpes.fr>
- Copyright 1995-1999 Bruno Haible, <haible@clisp.cons.org>
- This is free software distributed under the GNU General Public
- Licence described in the file COPYING. Contact the author if
- you don't have this or can't live with it. There is ABSOLUTELY
- NO WARRANTY, explicit or implied, on this software.
- **/
- /*----------------------------------------------------------------------
- !!! THIS ROUTINE MUST BE COMPILED gcc -O !!!
- Foreign function interface for a Sun4 Sparc with gcc/sun-cc.
- This calls a C function with an argument list built up using macros
- defined in av_call.h.
- Sparc Argument Passing Conventions
- The first 6 words of arguments are passed in integer registers o0-o5
- regardless of type or alignment. (Registers are windowed: o0-o5 become
- i0-i5 if the called function executes a `save' instruction.) Remaining
- arguments are pushed onto the stack starting at a fixed offset
- ("argframe"). Space is left on the stack frame for temporary storage of
- the register arguments as well.
- Doubles may be cut in half and misaligned. Shorter integers are
- always promoted to word-length. Functions with K&R-style declarations
- and float args pass them as doubles and truncate them on function entry.
- Structures are passed as pointers to a local copy of the structure made
- by the caller.
- Integers and pointers are returned in o0, floats in f0, doubles in
- f0/f1. If the function returns a structure a pointer to space
- allocated by the caller is pushed onto the stack immediately
- before the function arguments. Gcc without -fpcc-struct-return returns
- <= 4 byte structures as integers.
- Sun cc allocates temporary space for a returned structure just below
- the current frame pointer $fp (the $sp of the caller), and the caller
- must copy them from there. It also returns the temp address in $o0, but
- that gets nuked in the return in the code below so we can't use it.
- **The Sun cc struct return stuff below is a kludge**, but seems to work
- on the test cases...
- Compile this routine with gcc for the __asm__ extensions and with
- optimisation on (-O or -O2 or -g -O) so that argframe is set to the
- correct offset. (%sp is used differently in non-optimized code).
- For Sun cc, use the pre-compiled assembler version of this routine.
- ----------------------------------------------------------------------*/
- #include "avcall.h.in"
- #define RETURN(TYPE,VAL) (*(TYPE*)l->raddr = (TYPE)(VAL))
- register void* callee __asm__("%g2"); /* any global or local register */
- register __avword o0 __asm__("%o0");
- register __avword o1 __asm__("%o1");
- register __avword o2 __asm__("%o2");
- register __avword o3 __asm__("%o3");
- register __avword o4 __asm__("%o4");
- register __avword o5 __asm__("%o5");
- int
- __builtin_avcall(av_alist* l)
- {
- /*?? We probably need to make space for Sun cc
- struct return somewhere here. */
- register __avword* sp __asm__("%sp"); /* C names for registers */
- register float fret __asm__("%f0"); /* %f0 */
- register double dret __asm__("%f0"); /* %f0,%f1 */
- __avword trampoline[6]; /* room for a trampoline */
- __avword space[__AV_ALIST_WORDS]; /* space for callee's stack frame */
- __avword *argframe = sp + 17; /* stack offset for argument list */
- int arglen = l->aptr - l->args;
- __avword i;
- if ((l->rtype == __AVstruct) && !(l->flags & __AV_SUNCC_STRUCT_RETURN))
- argframe[-1] = (__avword)l->raddr; /* push struct return address */
- {
- int i;
- for (i = 6; i < arglen; i++) /* push excess function args */
- argframe[i] = l->args[i];
- }
- if ((l->rtype == __AVstruct) && (l->flags & __AV_SUNPROCC_STRUCT_RETURN))
- /* SUNWspro cc compiled functions don't copy the structure to the area
- * pointed to by argframe[-1] unless the caller has a proper "unimp n"
- * instruction. We generate the calling instructions on the stack. */
- {
- trampoline[0] = 0x9FC08000; /* call %g2 */
- trampoline[1] = 0x01000000; /* nop */
- trampoline[2] = l->rsize & 0xFFF; /* unimp n */
- trampoline[3] = 0xB0102000; /* mov 0,%i0 */
- trampoline[4] = 0x81C7E008; /* ret */
- trampoline[5] = 0x81E80000; /* restore */
- __asm__ __volatile__ ("iflush %0" : : "r" (&trampoline[0]));
- __asm__ __volatile__ ("iflush %0" : : "r" (&trampoline[2]));
- __asm__ __volatile__ ("iflush %0" : : "r" (&trampoline[4]));
- __asm__ __volatile__ ("iflush %0" : : "r" (&trampoline[5]));
- o0 = l->args[0]; o1 = l->args[1]; o2 = l->args[2];
- o3 = l->args[3]; o4 = l->args[4]; o5 = l->args[5];
- callee = l->func;
- goto *(void*)trampoline;
- }
- /* call function with 1st 6 args */
- i = ({ __avword iret; /* %o0 */
- iret = (*l->func)(l->args[0], l->args[1], l->args[2],
- l->args[3], l->args[4], l->args[5]);
- asm ("nop"); /* struct returning functions skip this instruction */
- iret;
- });
- /* save return value */
- if (l->rtype == __AVvoid) {
- } else
- if (l->rtype == __AVword) {
- RETURN(__avword, i);
- } else
- if (l->rtype == __AVchar) {
- RETURN(char, i);
- } else
- if (l->rtype == __AVschar) {
- RETURN(signed char, i);
- } else
- if (l->rtype == __AVuchar) {
- RETURN(unsigned char, i);
- } else
- if (l->rtype == __AVshort) {
- RETURN(short, i);
- } else
- if (l->rtype == __AVushort) {
- RETURN(unsigned short, i);
- } else
- if (l->rtype == __AVint) {
- RETURN(int, i);
- } else
- if (l->rtype == __AVuint) {
- RETURN(unsigned int, i);
- } else
- if (l->rtype == __AVlong) {
- RETURN(long, i);
- } else
- if (l->rtype == __AVulong) {
- RETURN(unsigned long, i);
- } else
- if (l->rtype == __AVlonglong || l->rtype == __AVulonglong) {
- ((__avword*)l->raddr)[0] = i;
- ((__avword*)l->raddr)[1] = o1;
- } else
- if (l->rtype == __AVfloat) {
- /* old Sun cc returns floats as doubles */
- if (l->flags & __AV_SUNCC_FLOAT_RETURN) {
- RETURN(float, (float)dret);
- } else {
- RETURN(float, fret);
- }
- } else
- if (l->rtype == __AVdouble) {
- RETURN(double, dret);
- } else
- if (l->rtype == __AVvoidp) {
- RETURN(void*, i);
- } else
- if (l->rtype == __AVstruct) {
- /* This is a kludge for old Sun cc and is probably fragile. */
- if (l->flags & __AV_SUNCC_STRUCT_RETURN) {
- /* Sun cc struct return convention */
- if (l->rsize == sizeof(char)) {
- RETURN(char, ((char*)sp)[-1]);
- } else
- if (l->rsize == sizeof(short)) {
- RETURN(short, ((short*)sp)[-1]);
- } else
- if (l->rsize == sizeof(int)) {
- RETURN(int, ((int*)sp)[-1]);
- } else
- if (l->rsize == sizeof(double)) {
- ((int*)l->raddr)[0] = ((int*)sp)[-2];
- ((int*)l->raddr)[1] = ((int*)sp)[-1];
- } else
- if (l->rsize % 4) {
- char* dstaddr = (char*)l->raddr;
- char* srcaddr = (char*)((long)sp - l->rsize);
- unsigned int count = l->rsize;
- if (count > 4)
- srcaddr = (char*)((long)srcaddr & -4);
- while (count > 0) {
- *dstaddr++ = *srcaddr++;
- count--;
- }
- } else {
- __avword* dstaddr = (__avword*)l->raddr;
- __avword* srcaddr = (__avword*)((long)sp - l->rsize);
- while (srcaddr < sp)
- *dstaddr++ = *srcaddr++;
- }
- } else {
- if (l->flags & __AV_PCC_STRUCT_RETURN) {
- /* pcc struct return convention: need a *(TYPE*)l->raddr = *(TYPE*)i; */
- if (l->rsize == sizeof(char)) {
- RETURN(char, *(char*)i);
- } else
- if (l->rsize == sizeof(short)) {
- RETURN(short, *(short*)i);
- } else
- if (l->rsize == sizeof(int)) {
- RETURN(int, *(int*)i);
- } else
- if (l->rsize == sizeof(double)) {
- ((int*)l->raddr)[0] = ((int*)i)[0];
- ((int*)l->raddr)[1] = ((int*)i)[1];
- } else {
- int n = (l->rsize + sizeof(__avword)-1)/sizeof(__avword);
- while (--n >= 0)
- ((__avword*)l->raddr)[n] = ((__avword*)i)[n];
- }
- } else {
- /* normal struct return convention */
- if (l->flags & __AV_SMALL_STRUCT_RETURN) {
- if (l->rsize == sizeof(char)) {
- RETURN(char, i);
- } else
- if (l->rsize == sizeof(short)) {
- RETURN(short, i);
- } else
- if (l->rsize == sizeof(int)) {
- RETURN(int, i);
- }
- }
- }
- }
- }
- return 0;
- }
- #endif /*_avcall_sparc_c */