Merge branches/gcc-4_8-branch rev 216856
[official-gcc.git] / gcc-4_8-branch / libffi / src / powerpc / linux64_closure.S
blob1d80a39490b581db3a126f6b53c24ed257d8077b
1 /* -----------------------------------------------------------------------
2    sysv.h - Copyright (c) 2003 Jakub Jelinek <jakub@redhat.com>
3             Copyright (c) 2008 Red Hat, Inc.
5    PowerPC64 Assembly glue.
7    Permission is hereby granted, free of charge, to any person obtaining
8    a copy of this software and associated documentation files (the
9    ``Software''), to deal in the Software without restriction, including
10    without limitation the rights to use, copy, modify, merge, publish,
11    distribute, sublicense, and/or sell copies of the Software, and to
12    permit persons to whom the Software is furnished to do so, subject to
13    the following conditions:
15    The above copyright notice and this permission notice shall be included
16    in all copies or substantial portions of the Software.
18    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
19    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21    NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25    DEALINGS IN THE SOFTWARE.
26    ----------------------------------------------------------------------- */
27 #define LIBFFI_ASM
28 #include <fficonfig.h>
29 #include <ffi.h>
31         .file   "linux64_closure.S"
33 #ifdef POWERPC64
34         FFI_HIDDEN (ffi_closure_LINUX64)
35         .globl  ffi_closure_LINUX64
36 # if _CALL_ELF == 2
37         .text
38 ffi_closure_LINUX64:
39         addis   %r2, %r12, .TOC.-ffi_closure_LINUX64@ha
40         addi    %r2, %r2, .TOC.-ffi_closure_LINUX64@l
41         .localentry ffi_closure_LINUX64, . - ffi_closure_LINUX64
42 # else
43         .section        ".opd","aw"
44         .align  3
45 ffi_closure_LINUX64:
46 #  ifdef _CALL_LINUX
47         .quad   .L.ffi_closure_LINUX64,.TOC.@tocbase,0
48         .type   ffi_closure_LINUX64,@function
49         .text
50 .L.ffi_closure_LINUX64:
51 #  else
52         FFI_HIDDEN (.ffi_closure_LINUX64)
53         .globl  .ffi_closure_LINUX64
54         .quad   .ffi_closure_LINUX64,.TOC.@tocbase,0
55         .size   ffi_closure_LINUX64,24
56         .type   .ffi_closure_LINUX64,@function
57         .text
58 .ffi_closure_LINUX64:
59 #  endif
60 # endif
62 # if _CALL_ELF == 2
63 #  32 byte special reg save area + 64 byte parm save area
64 #  + 64 byte retval area + 13*8 fpr save area + round to 16
65 #  define STACKFRAME 272
66 #  define PARMSAVE 32
67 #  define RETVAL PARMSAVE+64
68 # else
69 #  48 bytes special reg save area + 64 bytes parm save area
70 #  + 16 bytes retval area + 13*8 bytes fpr save area + round to 16
71 #  define STACKFRAME 240
72 #  define PARMSAVE 48
73 #  define RETVAL PARMSAVE+64
74 # endif
76 .LFB1:
77 # if _CALL_ELF == 2
78         ld      %r12, FFI_TRAMPOLINE_SIZE(%r11)         # closure->cif
79         mflr    %r0
80         lwz     %r12, 28(%r12)                          # cif->flags
81         mtcrf   0x40, %r12
82         addi    %r12, %r1, PARMSAVE
83         bt      7, .Lparmsave
84         # Our caller has not allocated a parameter save area.
85         # We need to allocate one here and use it to pass gprs to
86         # ffi_closure_helper_LINUX64.
87         addi    %r12, %r1, -STACKFRAME+PARMSAVE
88 .Lparmsave:
89         std     %r0, 16(%r1)
90         # Save general regs into parm save area
91         std     %r3, 0(%r12)
92         std     %r4, 8(%r12)
93         std     %r5, 16(%r12)
94         std     %r6, 24(%r12)
95         std     %r7, 32(%r12)
96         std     %r8, 40(%r12)
97         std     %r9, 48(%r12)
98         std     %r10, 56(%r12)
100         # load up the pointer to the parm save area
101         mr      %r5, %r12
102 # else
103         mflr    %r0
104         # Save general regs into parm save area
105         # This is the parameter save area set up by our caller.
106         std     %r3, PARMSAVE+0(%r1)
107         std     %r4, PARMSAVE+8(%r1)
108         std     %r5, PARMSAVE+16(%r1)
109         std     %r6, PARMSAVE+24(%r1)
110         std     %r7, PARMSAVE+32(%r1)
111         std     %r8, PARMSAVE+40(%r1)
112         std     %r9, PARMSAVE+48(%r1)
113         std     %r10, PARMSAVE+56(%r1)
115         std     %r0, 16(%r1)
117         # load up the pointer to the parm save area
118         addi    %r5, %r1, PARMSAVE
119 # endif
121         # next save fpr 1 to fpr 13
122         stfd    %f1, -104+(0*8)(%r1)
123         stfd    %f2, -104+(1*8)(%r1)
124         stfd    %f3, -104+(2*8)(%r1)
125         stfd    %f4, -104+(3*8)(%r1)
126         stfd    %f5, -104+(4*8)(%r1)
127         stfd    %f6, -104+(5*8)(%r1)
128         stfd    %f7, -104+(6*8)(%r1)
129         stfd    %f8, -104+(7*8)(%r1)
130         stfd    %f9, -104+(8*8)(%r1)
131         stfd    %f10, -104+(9*8)(%r1)
132         stfd    %f11, -104+(10*8)(%r1)
133         stfd    %f12, -104+(11*8)(%r1)
134         stfd    %f13, -104+(12*8)(%r1)
136         # load up the pointer to the saved fpr registers */
137         addi    %r6, %r1, -104
139         # load up the pointer to the result storage
140         addi    %r4, %r1, -STACKFRAME+RETVAL
142         stdu    %r1, -STACKFRAME(%r1)
143 .LCFI0:
145         # get the context pointer from the trampoline
146         mr      %r3, %r11
148         # make the call
149 # if defined _CALL_LINUX || _CALL_ELF == 2
150         bl ffi_closure_helper_LINUX64
151 # else
152         bl .ffi_closure_helper_LINUX64
153 # endif
154 .Lret:
156         # now r3 contains the return type
157         # so use it to look up in a table
158         # so we know how to deal with each type
160         # look up the proper starting point in table
161         # by using return type as offset
162         ld %r0, STACKFRAME+16(%r1)
163         cmpldi %r3, FFI_V2_TYPE_SMALL_STRUCT
164         bge .Lsmall
165         mflr %r4                # move address of .Lret to r4
166         sldi %r3, %r3, 4        # now multiply return type by 16
167         addi %r4, %r4, .Lret_type0 - .Lret
168         add %r3, %r3, %r4       # add contents of table to table address
169         mtctr %r3
170         bctr                    # jump to it
172 # Each of the ret_typeX code fragments has to be exactly 16 bytes long
173 # (4 instructions). For cache effectiveness we align to a 16 byte boundary
174 # first.
175         .align 4
177 .Lret_type0:
178 # case FFI_TYPE_VOID
179         mtlr %r0
180         addi %r1, %r1, STACKFRAME
181         blr
182         nop
183 # case FFI_TYPE_INT
184 # ifdef __LITTLE_ENDIAN__
185         lwa %r3, RETVAL+0(%r1)
186 # else
187         lwa %r3, RETVAL+4(%r1)
188 # endif
189         mtlr %r0
190         addi %r1, %r1, STACKFRAME
191         blr
192 # case FFI_TYPE_FLOAT
193         lfs %f1, RETVAL+0(%r1)
194         mtlr %r0
195         addi %r1, %r1, STACKFRAME
196         blr
197 # case FFI_TYPE_DOUBLE
198         lfd %f1, RETVAL+0(%r1)
199         mtlr %r0
200         addi %r1, %r1, STACKFRAME
201         blr
202 # case FFI_TYPE_LONGDOUBLE
203         lfd %f1, RETVAL+0(%r1)
204         mtlr %r0
205         lfd %f2, RETVAL+8(%r1)
206         b .Lfinish
207 # case FFI_TYPE_UINT8
208 # ifdef __LITTLE_ENDIAN__
209         lbz %r3, RETVAL+0(%r1)
210 # else
211         lbz %r3, RETVAL+7(%r1)
212 # endif
213         mtlr %r0
214         addi %r1, %r1, STACKFRAME
215         blr
216 # case FFI_TYPE_SINT8
217 # ifdef __LITTLE_ENDIAN__
218         lbz %r3, RETVAL+0(%r1)
219 # else
220         lbz %r3, RETVAL+7(%r1)
221 # endif
222         extsb %r3,%r3
223         mtlr %r0
224         b .Lfinish
225 # case FFI_TYPE_UINT16
226 # ifdef __LITTLE_ENDIAN__
227         lhz %r3, RETVAL+0(%r1)
228 # else
229         lhz %r3, RETVAL+6(%r1)
230 # endif
231         mtlr %r0
232 .Lfinish:
233         addi %r1, %r1, STACKFRAME
234         blr
235 # case FFI_TYPE_SINT16
236 # ifdef __LITTLE_ENDIAN__
237         lha %r3, RETVAL+0(%r1)
238 # else
239         lha %r3, RETVAL+6(%r1)
240 # endif
241         mtlr %r0
242         addi %r1, %r1, STACKFRAME
243         blr
244 # case FFI_TYPE_UINT32
245 # ifdef __LITTLE_ENDIAN__
246         lwz %r3, RETVAL+0(%r1)
247 # else
248         lwz %r3, RETVAL+4(%r1)
249 # endif
250         mtlr %r0
251         addi %r1, %r1, STACKFRAME
252         blr
253 # case FFI_TYPE_SINT32
254 # ifdef __LITTLE_ENDIAN__
255         lwa %r3, RETVAL+0(%r1)
256 # else
257         lwa %r3, RETVAL+4(%r1)
258 # endif
259         mtlr %r0
260         addi %r1, %r1, STACKFRAME
261         blr
262 # case FFI_TYPE_UINT64
263         ld %r3, RETVAL+0(%r1)
264         mtlr %r0
265         addi %r1, %r1, STACKFRAME
266         blr
267 # case FFI_TYPE_SINT64
268         ld %r3, RETVAL+0(%r1)
269         mtlr %r0
270         addi %r1, %r1, STACKFRAME
271         blr
272 # case FFI_TYPE_STRUCT
273         mtlr %r0
274         addi %r1, %r1, STACKFRAME
275         blr
276         nop
277 # case FFI_TYPE_POINTER
278         ld %r3, RETVAL+0(%r1)
279         mtlr %r0
280         addi %r1, %r1, STACKFRAME
281         blr
282 # case FFI_V2_TYPE_FLOAT_HOMOG
283         lfs %f1, RETVAL+0(%r1)
284         lfs %f2, RETVAL+4(%r1)
285         lfs %f3, RETVAL+8(%r1)
286         b .Lmorefloat
287 # case FFI_V2_TYPE_DOUBLE_HOMOG
288         lfd %f1, RETVAL+0(%r1)
289         lfd %f2, RETVAL+8(%r1)
290         lfd %f3, RETVAL+16(%r1)
291         lfd %f4, RETVAL+24(%r1)
292         mtlr %r0
293         lfd %f5, RETVAL+32(%r1)
294         lfd %f6, RETVAL+40(%r1)
295         lfd %f7, RETVAL+48(%r1)
296         lfd %f8, RETVAL+56(%r1)
297         addi %r1, %r1, STACKFRAME
298         blr
299 .Lmorefloat:
300         lfs %f4, RETVAL+12(%r1)
301         mtlr %r0
302         lfs %f5, RETVAL+16(%r1)
303         lfs %f6, RETVAL+20(%r1)
304         lfs %f7, RETVAL+24(%r1)
305         lfs %f8, RETVAL+28(%r1)
306         addi %r1, %r1, STACKFRAME
307         blr
308 .Lsmall:
309 # ifdef __LITTLE_ENDIAN__
310         ld %r3,RETVAL+0(%r1)
311         mtlr %r0
312         ld %r4,RETVAL+8(%r1)
313         addi %r1, %r1, STACKFRAME
314         blr
315 # else
316         # A struct smaller than a dword is returned in the low bits of r3
317         # ie. right justified.  Larger structs are passed left justified
318         # in r3 and r4.  The return value area on the stack will have
319         # the structs as they are usually stored in memory.
320         cmpldi %r3, FFI_V2_TYPE_SMALL_STRUCT + 7 # size 8 bytes?
321         neg %r5, %r3
322         ld %r3,RETVAL+0(%r1)
323         blt .Lsmalldown
324         mtlr %r0
325         ld %r4,RETVAL+8(%r1)
326         addi %r1, %r1, STACKFRAME
327         blr
328 .Lsmalldown:
329         addi %r5, %r5, FFI_V2_TYPE_SMALL_STRUCT + 7
330         mtlr %r0
331         sldi %r5, %r5, 3
332         addi %r1, %r1, STACKFRAME
333         srd %r3, %r3, %r5
334         blr
335 # endif
337 .LFE1:
338         .long   0
339         .byte   0,12,0,1,128,0,0,0
340 # if _CALL_ELF == 2
341         .size   ffi_closure_LINUX64,.-ffi_closure_LINUX64
342 # else
343 #  ifdef _CALL_LINUX
344         .size   ffi_closure_LINUX64,.-.L.ffi_closure_LINUX64
345 #  else
346         .size   .ffi_closure_LINUX64,.-.ffi_closure_LINUX64
347 #  endif
348 # endif
350         .section        .eh_frame,EH_FRAME_FLAGS,@progbits
351 .Lframe1:
352         .4byte  .LECIE1-.LSCIE1  # Length of Common Information Entry
353 .LSCIE1:
354         .4byte  0x0      # CIE Identifier Tag
355         .byte   0x1      # CIE Version
356         .ascii "zR\0"    # CIE Augmentation
357         .uleb128 0x1     # CIE Code Alignment Factor
358         .sleb128 -8      # CIE Data Alignment Factor
359         .byte   0x41     # CIE RA Column
360         .uleb128 0x1     # Augmentation size
361         .byte   0x14     # FDE Encoding (pcrel udata8)
362         .byte   0xc      # DW_CFA_def_cfa
363         .uleb128 0x1
364         .uleb128 0x0
365         .align 3
366 .LECIE1:
367 .LSFDE1:
368         .4byte  .LEFDE1-.LASFDE1         # FDE Length
369 .LASFDE1:
370         .4byte  .LASFDE1-.Lframe1        # FDE CIE offset
371         .8byte  .LFB1-.  # FDE initial location
372         .8byte  .LFE1-.LFB1      # FDE address range
373         .uleb128 0x0     # Augmentation size
374         .byte   0x2      # DW_CFA_advance_loc1
375         .byte   .LCFI0-.LFB1
376         .byte   0xe      # DW_CFA_def_cfa_offset
377         .uleb128 STACKFRAME
378         .byte   0x11     # DW_CFA_offset_extended_sf
379         .uleb128 0x41
380         .sleb128 -2
381         .align 3
382 .LEFDE1:
384 #endif
386 #if (defined __ELF__ && defined __linux__) || _CALL_ELF == 2
387         .section        .note.GNU-stack,"",@progbits
388 #endif