1 /* -----------------------------------------------------------------------
2 unix.S - Copyright (c) 1998 Red Hat, Inc.
3 Copyright (c) 2000 Hewlett Packard Company
5 IA64/unix Foreign Function Interface
7 Primary author: Hans Boehm, HP Labs
9 Loosely modeled on Cygnus code for other platforms.
11 Permission is hereby granted, free of charge, to any person obtaining
12 a copy of this software and associated documentation files (the
13 ``Software''), to deal in the Software without restriction, including
14 without limitation the rights to use, copy, modify, merge, publish,
15 distribute, sublicense, and/or sell copies of the Software, and to
16 permit persons to whom the Software is furnished to do so, subject to
17 the following conditions:
19 The above copyright notice and this permission notice shall be included
20 in all copies or substantial portions of the Software.
22 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25 IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
26 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
27 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 OTHER DEALINGS IN THE SOFTWARE.
29 ----------------------------------------------------------------------- */
32 #include <fficonfig.h>
34 #include "ia64_flags.h"
44 #define FLOAT_SZ 8 /* in-memory size of fp operands */
46 /* Allocate an ia64_args structure on the stack; call ffi_prep_args */
47 /* to fill it in with argument values; copy those to the real */
48 /* registers, leaving overflow arguments on the stack. Then call fn */
49 /* and move the result from registers into *raddr. */
50 .pred.safe_across_calls p1-p5,p16-p63
57 .save ar.pfs,r38 /* loc0 */
58 alloc loc0=ar.pfs,6,6,8,0
65 mov loc4=r1 /* Save gp */
66 ld8 r8=[callback],8 /* code address of callback */
71 ld8 r1=[callback] /* Set up gp for callback. Unnecessary? */
74 br.call.sptk.many b0 = b6 /* call ffi_prep_args */
75 cmp.eq p6,p0=0,r8 /* r8 nonzero ==> need fp regs */
77 (p6) add loc2=32+8*FLOAT_SZ,sp
78 (p6) br.cond.dptk.many fp_done
79 ;; /* Quiets warning; needed? */
81 add loc3=32+FLOAT_SZ,sp
83 ldfd f8=[loc2],2*FLOAT_SZ
84 ldfd f9=[loc3],2*FLOAT_SZ
86 ldfd f10=[loc2],2*FLOAT_SZ
87 ldfd f11=[loc3],2*FLOAT_SZ
89 ldfd f12=[loc2],2*FLOAT_SZ
90 ldfd f13=[loc3],2*FLOAT_SZ
92 ldfd f14=[loc2],2*FLOAT_SZ
96 add r9=16,sp /* Pointer to r8_contents */
97 /* loc2 points at first integer register value. */
100 ld8 r8=[r9] /* Just in case we return large struct */
112 /* Set sp to 16 bytes below the first stack parameter. This */
113 /* is the value currently in loc2. */
118 ld8 r1=[fn] /* Set up gp */
120 br.call.sptk.many b0 = b6 /* call fn */
122 /* Handle return value. */
124 cmp.eq p7,p0=FFI_TYPE_INT,flags
125 cmp.eq p10,p0=FFI_IS_SMALL_STRUCT2,flags
126 cmp.eq p11,p0=FFI_IS_SMALL_STRUCT3,flags
127 cmp.eq p12,p0=FFI_IS_SMALL_STRUCT4,flags
129 (p6) br.cond.dpnt.few done /* Dont copy ret values if raddr = 0 */
130 (p7) br.cond.dptk.few copy1
131 (p10) br.cond.dpnt.few copy2
132 (p11) br.cond.dpnt.few copy3
133 (p12) br.cond.dpnt.few copy4
134 cmp.eq p8,p0=FFI_TYPE_FLOAT,flags
135 cmp.eq p9,p0=FFI_TYPE_DOUBLE,flags
136 tbit.nz p6,p0=flags,FLOAT_FP_AGGREGATE_BIT
137 tbit.nz p7,p0=flags,DOUBLE_FP_AGGREGATE_BIT
143 (p6) br.cond.dpnt.few handle_float_hfa
144 (p7) br.cond.dpnt.few handle_double_hfa
161 /* In the big struct case, raddr was passed as an argument. */
162 /* In the void case there was nothing to do. */
165 mov r1=loc4 /* Restore gp */
175 /* Homogeneous floating point array of doubles is returned in */
176 /* registers f8-f15. Save one at a time to return area. */
177 and flags=0xf,flags /* Retrieve size */
183 cmp.eq p10,p0=6,flags
184 cmp.eq p11,p0=7,flags
185 cmp.eq p12,p0=8,flags
187 (p6) br.cond.dptk.few dhfa2
188 (p7) br.cond.dptk.few dhfa3
189 (p8) br.cond.dptk.few dhfa4
190 (p9) br.cond.dptk.few dhfa5
191 (p10) br.cond.dptk.few dhfa6
192 (p11) br.cond.dptk.few dhfa7
193 dhfa8: add loc3=7*8,raddr
196 dhfa7: add loc3=6*8,raddr
199 dhfa6: add loc3=5*8,raddr
202 dhfa5: add loc3=4*8,raddr
205 dhfa4: add loc3=3*8,raddr
208 dhfa3: add loc3=2*8,raddr
211 dhfa2: add loc3=1*8,raddr
218 /* Homogeneous floating point array of floats is returned in */
219 /* registers f8-f15. Save one at a time to return area. */
220 and flags=0xf,flags /* Retrieve size */
226 cmp.eq p10,p0=6,flags
227 cmp.eq p11,p0=7,flags
228 cmp.eq p12,p0=8,flags
230 (p6) br.cond.dptk.few shfa2
231 (p7) br.cond.dptk.few shfa3
232 (p8) br.cond.dptk.few shfa4
233 (p9) br.cond.dptk.few shfa5
234 (p10) br.cond.dptk.few shfa6
235 (p11) br.cond.dptk.few shfa7
236 shfa8: add loc3=7*4,raddr
239 shfa7: add loc3=6*4,raddr
242 shfa6: add loc3=5*4,raddr
245 shfa5: add loc3=4*4,raddr
248 shfa4: add loc3=3*4,raddr
251 shfa3: add loc3=2*4,raddr
254 shfa2: add loc3=1*4,raddr
263 .pred.safe_across_calls p1-p5,p16-p63
266 .global ffi_closure_UNIX
267 .proc ffi_closure_UNIX
270 .save ar.pfs,r40 /* loc0 */
271 alloc loc0=ar.pfs,8,3,2,0
276 /* Retrieve closure pointer and real gp. */
281 /* Reserve a structia64_args on the stack such that arguments */
282 /* past the first 8 are automatically placed in the right */
283 /* slot. Note that when we start the sp points at 2 8-byte */
284 /* scratch words, followed by the extra arguments. */
285 # define BASIC_ARGS_SZ (8*FLOAT_SZ+8*8+2*8)
286 # define FIRST_FP_OFFSET (4*8)
287 add r14=-(BASIC_ARGS_SZ-FIRST_FP_OFFSET),sp
288 add r15=-(BASIC_ARGS_SZ-FIRST_FP_OFFSET-FLOAT_SZ),sp
289 add sp=-BASIC_ARGS_SZ,sp
290 /* r14 points to fp_regs[0], r15 points to fp_regs[1] */
292 stfd [r14]=f8,2*FLOAT_SZ
293 stfd [r15]=f9,2*FLOAT_SZ
295 stfd [r14]=f10,2*FLOAT_SZ
296 stfd [r15]=f11,2*FLOAT_SZ
298 stfd [r14]=f12,2*FLOAT_SZ
299 stfd [r15]=f13,2*FLOAT_SZ
301 stfd [r14]=f14,2*FLOAT_SZ
302 stfd [r15]=f15,FLOAT_SZ+8
304 /* r14 points to first parameter register area, r15 to second. */
316 /* Call ffi_closure_UNIX_inner */
318 br.call.sptk.many b0=ffi_closure_UNIX_inner
325 .endp ffi_closure_UNIX