~ubuntu-branches/debian/squeeze/ffcall/squeeze

« back to all changes in this revision

Viewing changes to avcall/avcall-sparc.c

  • Committer: Bazaar Package Importer
  • Author(s): Christoph Egger
  • Date: 2010-06-26 15:29:30 UTC
  • mfrom: (5.1.1 experimental)
  • Revision ID: james.westby@ubuntu.com-20100626152930-c09y01gk3szcnykn
Tags: 1.10+cvs20100619-2
Ship to unstable

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#ifndef _avcall_sparc_c                         /*-*- C -*-*/
 
2
#define _avcall_sparc_c
 
3
/**
 
4
  Copyright 1993 Bill Triggs, <Bill.Triggs@inrialpes.fr>
 
5
  Copyright 1995-1999, 2005 Bruno Haible, <bruno@clisp.org>
 
6
 
 
7
  This is free software distributed under the GNU General Public
 
8
  Licence described in the file COPYING. Contact the author if
 
9
  you don't have this or can't live with it. There is ABSOLUTELY
 
10
  NO WARRANTY, explicit or implied, on this software.
 
11
**/
 
12
/*----------------------------------------------------------------------
 
13
  !!! THIS ROUTINE MUST BE COMPILED gcc -O !!!
 
14
 
 
15
  Foreign function interface for a Sun4 Sparc with gcc/sun-cc.
 
16
 
 
17
  This calls a C function with an argument list built up using macros
 
18
  defined in av_call.h.
 
19
 
 
20
  Sparc Argument Passing Conventions
 
21
 
 
22
  The first 6 words of arguments are passed in integer registers o0-o5
 
23
  regardless of type or alignment.  (Registers are windowed: o0-o5 become
 
24
  i0-i5 if the called function executes a `save' instruction.)  Remaining
 
25
  arguments are pushed onto the stack starting at a fixed offset
 
26
  ("argframe"). Space is left on the stack frame for temporary storage of
 
27
  the register arguments as well.
 
28
 
 
29
  Doubles may be cut in half and misaligned.  Shorter integers are
 
30
  always promoted to word-length.  Functions with K&R-style declarations
 
31
  and float args pass them as doubles and truncate them on function entry.
 
32
  Structures are passed as pointers to a local copy of the structure made
 
33
  by the caller.
 
34
 
 
35
  Integers and pointers are returned in o0, floats in f0, doubles in
 
36
  f0/f1.  If the function returns a structure a pointer to space
 
37
  allocated by the caller is pushed onto the stack immediately
 
38
  before the function arguments. Gcc without -fpcc-struct-return returns
 
39
  <= 4 byte structures as integers.
 
40
 
 
41
  Sun cc allocates temporary space for a returned structure just below
 
42
  the current frame pointer $fp (the $sp of the caller), and the caller
 
43
  must copy them from there. It also returns the temp address in $o0, but
 
44
  that gets nuked in the return in the code below so we can't use it.
 
45
  **The Sun cc struct return stuff below is a kludge**, but seems to work
 
46
  on the test cases...
 
47
 
 
48
  Compile this routine with gcc for the __asm__ extensions and with
 
49
  optimisation on (-O or -O2 or -g -O) so that argframe is set to the
 
50
  correct offset. (%sp is used differently in non-optimized code).
 
51
  For Sun cc, use the pre-compiled assembler version of this routine.
 
52
  ----------------------------------------------------------------------*/
 
53
#include "avcall.h.in"
 
54
 
 
55
#define RETURN(TYPE,VAL)        (*(TYPE*)l->raddr = (TYPE)(VAL))
 
56
 
 
57
register void* callee   __asm__("%g2");  /* any global or local register */
 
58
register __avword o0    __asm__("%o0");
 
59
register __avword o1    __asm__("%o1");
 
60
register __avword o2    __asm__("%o2");
 
61
register __avword o3    __asm__("%o3");
 
62
register __avword o4    __asm__("%o4");
 
63
register __avword o5    __asm__("%o5");
 
64
 
 
65
int
 
66
__builtin_avcall(av_alist* l)
 
67
{
 
68
  /*?? We probably need to make space for Sun cc
 
69
    struct return somewhere here. */
 
70
  register __avword* sp __asm__("%sp");  /* C names for registers */
 
71
  register float fret   __asm__("%f0");  /* %f0 */
 
72
  register double dret  __asm__("%f0");  /* %f0,%f1 */
 
73
 
 
74
  __avword trampoline[6];               /* room for a trampoline */
 
75
  __avword space[__AV_ALIST_WORDS];     /* space for callee's stack frame */
 
76
  __avword *argframe = sp + 17;         /* stack offset for argument list */
 
77
  int arglen = l->aptr - l->args;
 
78
  __avword i;
 
79
 
 
80
  if (l->rtype == __AVstruct)
 
81
    argframe[-1] = (__avword)l->raddr;  /* push struct return address */
 
82
 
 
83
  {
 
84
    int i;
 
85
    for (i = 6; i < arglen; i++)        /* push excess function args */
 
86
      argframe[i] = l->args[i];
 
87
  }
 
88
 
 
89
  if ((l->rtype == __AVstruct) && (l->flags & __AV_SUNPROCC_STRUCT_RETURN))
 
90
    /* SUNWspro cc compiled functions don't copy the structure to the area
 
91
     * pointed to by argframe[-1] unless the caller has a proper "unimp n"
 
92
     * instruction. We generate the calling instructions on the stack. */
 
93
    {
 
94
      trampoline[0] = 0x9FC08000;       /* call %g2     */
 
95
      trampoline[1] = 0x01000000;       /* nop          */
 
96
      trampoline[2] = l->rsize & 0xFFF; /* unimp n      */
 
97
      trampoline[3] = 0xB0102000;       /* mov 0,%i0    */
 
98
      trampoline[4] = 0x81C7E008;       /* ret          */
 
99
      trampoline[5] = 0x81E80000;       /* restore      */
 
100
      __asm__ __volatile__ ("iflush %0" : : "r" (&trampoline[0]));
 
101
      __asm__ __volatile__ ("iflush %0" : : "r" (&trampoline[2]));
 
102
      __asm__ __volatile__ ("iflush %0" : : "r" (&trampoline[4]));
 
103
      __asm__ __volatile__ ("iflush %0" : : "r" (&trampoline[5]));
 
104
      o0 = l->args[0]; o1 = l->args[1]; o2 = l->args[2];
 
105
      o3 = l->args[3]; o4 = l->args[4]; o5 = l->args[5];
 
106
      callee = l->func;
 
107
      goto *(void*)trampoline;
 
108
    }
 
109
 
 
110
                                        /* call function with 1st 6 args */
 
111
  i = ({ register __avword iret __asm__("%o0");
 
112
         iret = (*l->func)(l->args[0], l->args[1], l->args[2],
 
113
                           l->args[3], l->args[4], l->args[5]);
 
114
         asm ("nop");   /* struct returning functions skip this instruction */
 
115
         iret;
 
116
       });
 
117
 
 
118
  /* save return value */
 
119
  if (l->rtype == __AVvoid) {
 
120
  } else
 
121
  if (l->rtype == __AVword) {
 
122
    RETURN(__avword, i);
 
123
  } else
 
124
  if (l->rtype == __AVchar) {
 
125
    RETURN(char, i);
 
126
  } else
 
127
  if (l->rtype == __AVschar) {
 
128
    RETURN(signed char, i);
 
129
  } else
 
130
  if (l->rtype == __AVuchar) {
 
131
    RETURN(unsigned char, i);
 
132
  } else
 
133
  if (l->rtype == __AVshort) {
 
134
    RETURN(short, i);
 
135
  } else
 
136
  if (l->rtype == __AVushort) {
 
137
    RETURN(unsigned short, i);
 
138
  } else
 
139
  if (l->rtype == __AVint) {
 
140
    RETURN(int, i);
 
141
  } else
 
142
  if (l->rtype == __AVuint) {
 
143
    RETURN(unsigned int, i);
 
144
  } else
 
145
  if (l->rtype == __AVlong) {
 
146
    RETURN(long, i);
 
147
  } else
 
148
  if (l->rtype == __AVulong) {
 
149
    RETURN(unsigned long, i);
 
150
  } else
 
151
  if (l->rtype == __AVlonglong || l->rtype == __AVulonglong) {
 
152
    ((__avword*)l->raddr)[0] = i;
 
153
    ((__avword*)l->raddr)[1] = o1;
 
154
  } else
 
155
  if (l->rtype == __AVfloat) {
 
156
    /* old Sun cc returns floats as doubles */
 
157
    if (l->flags & __AV_SUNCC_FLOAT_RETURN) {
 
158
      RETURN(float, (float)dret);
 
159
    } else {
 
160
      RETURN(float, fret);
 
161
    }
 
162
  } else
 
163
  if (l->rtype == __AVdouble) {
 
164
    RETURN(double, dret);
 
165
  } else
 
166
  if (l->rtype == __AVvoidp) {
 
167
    RETURN(void*, i);
 
168
  } else
 
169
  if (l->rtype == __AVstruct) {
 
170
    if (l->flags & __AV_PCC_STRUCT_RETURN) {
 
171
      /* pcc struct return convention: need a  *(TYPE*)l->raddr = *(TYPE*)i;  */
 
172
      if (l->rsize == sizeof(char)) {
 
173
        RETURN(char, *(char*)i);
 
174
      } else
 
175
      if (l->rsize == sizeof(short)) {
 
176
        RETURN(short, *(short*)i);
 
177
      } else
 
178
      if (l->rsize == sizeof(int)) {
 
179
        RETURN(int, *(int*)i);
 
180
      } else
 
181
      if (l->rsize == sizeof(double)) {
 
182
        ((int*)l->raddr)[0] = ((int*)i)[0];
 
183
        ((int*)l->raddr)[1] = ((int*)i)[1];
 
184
      } else {
 
185
        int n = (l->rsize + sizeof(__avword)-1)/sizeof(__avword);
 
186
        while (--n >= 0)
 
187
          ((__avword*)l->raddr)[n] = ((__avword*)i)[n];
 
188
      }
 
189
    } else {
 
190
      /* normal struct return convention */
 
191
      if (l->flags & __AV_SMALL_STRUCT_RETURN) {
 
192
        if (l->rsize == sizeof(char)) {
 
193
          RETURN(char, i);
 
194
        } else
 
195
        if (l->rsize == sizeof(short)) {
 
196
          RETURN(short, i);
 
197
        } else
 
198
        if (l->rsize == sizeof(int)) {
 
199
          RETURN(int, i);
 
200
        }
 
201
      }
 
202
    }
 
203
  }
 
204
  return 0;
 
205
}
 
206
 
 
207
#endif /*_avcall_sparc_c */