2017-02-16 Vladimir Makarov <vmakarov@redhat.com>
[official-gcc.git] / libffi / src / powerpc / linux64_closure.S
blob6487d2a2970a11a6d71d8b2759a0b490d194ba87
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         .text
37         .cfi_startproc
38 # if _CALL_ELF == 2
39 ffi_closure_LINUX64:
40         addis   %r2, %r12, .TOC.-ffi_closure_LINUX64@ha
41         addi    %r2, %r2, .TOC.-ffi_closure_LINUX64@l
42         .localentry ffi_closure_LINUX64, . - ffi_closure_LINUX64
43 # else
44         .section        ".opd","aw"
45         .align  3
46 ffi_closure_LINUX64:
47 #  ifdef _CALL_LINUX
48         .quad   .L.ffi_closure_LINUX64,.TOC.@tocbase,0
49         .type   ffi_closure_LINUX64,@function
50         .text
51 .L.ffi_closure_LINUX64:
52 #  else
53         FFI_HIDDEN (.ffi_closure_LINUX64)
54         .globl  .ffi_closure_LINUX64
55         .quad   .ffi_closure_LINUX64,.TOC.@tocbase,0
56         .size   ffi_closure_LINUX64,24
57         .type   .ffi_closure_LINUX64,@function
58         .text
59 .ffi_closure_LINUX64:
60 #  endif
61 # endif
63 # if _CALL_ELF == 2
64 #  32 byte special reg save area + 64 byte parm save area
65 #  + 64 byte retval area + 13*8 fpr save area + round to 16
66 #  define STACKFRAME 272
67 #  define PARMSAVE 32
68 #  define RETVAL PARMSAVE+64
69 # else
70 #  48 bytes special reg save area + 64 bytes parm save area
71 #  + 16 bytes retval area + 13*8 bytes fpr save area + round to 16
72 #  define STACKFRAME 240
73 #  define PARMSAVE 48
74 #  define RETVAL PARMSAVE+64
75 # endif
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, 0f
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
89         # Save general regs into parm save area
90         std     %r3, 0(%r12)
91         std     %r4, 8(%r12)
92         std     %r5, 16(%r12)
93         std     %r6, 24(%r12)
94         std     %r7, 32(%r12)
95         std     %r8, 40(%r12)
96         std     %r9, 48(%r12)
97         std     %r10, 56(%r12)
99         # load up the pointer to the parm save area
100         mr      %r7, %r12
101 # else
102         # copy r2 to r11 and load TOC into r2
103         mr      %r11, %r2
104         ld      %r2, 16(%r2)
106         mflr    %r0
107         # Save general regs into parm save area
108         # This is the parameter save area set up by our caller.
109         std     %r3, PARMSAVE+0(%r1)
110         std     %r4, PARMSAVE+8(%r1)
111         std     %r5, PARMSAVE+16(%r1)
112         std     %r6, PARMSAVE+24(%r1)
113         std     %r7, PARMSAVE+32(%r1)
114         std     %r8, PARMSAVE+40(%r1)
115         std     %r9, PARMSAVE+48(%r1)
116         std     %r10, PARMSAVE+56(%r1)
118         # load up the pointer to the parm save area
119         addi    %r7, %r1, PARMSAVE
120 # endif
121         std     %r0, 16(%r1)
123         # closure->cif
124         ld      %r3, FFI_TRAMPOLINE_SIZE(%r11)
125         # closure->fun
126         ld      %r4, FFI_TRAMPOLINE_SIZE+8(%r11)
127         # closure->user_data
128         ld      %r5, FFI_TRAMPOLINE_SIZE+16(%r11)
130 .Ldoclosure:
131         # next save fpr 1 to fpr 13
132         stfd    %f1, -104+(0*8)(%r1)
133         stfd    %f2, -104+(1*8)(%r1)
134         stfd    %f3, -104+(2*8)(%r1)
135         stfd    %f4, -104+(3*8)(%r1)
136         stfd    %f5, -104+(4*8)(%r1)
137         stfd    %f6, -104+(5*8)(%r1)
138         stfd    %f7, -104+(6*8)(%r1)
139         stfd    %f8, -104+(7*8)(%r1)
140         stfd    %f9, -104+(8*8)(%r1)
141         stfd    %f10, -104+(9*8)(%r1)
142         stfd    %f11, -104+(10*8)(%r1)
143         stfd    %f12, -104+(11*8)(%r1)
144         stfd    %f13, -104+(12*8)(%r1)
146         # load up the pointer to the saved fpr registers */
147         addi    %r8, %r1, -104
149         # load up the pointer to the result storage
150         addi    %r6, %r1, -STACKFRAME+RETVAL
152         stdu    %r1, -STACKFRAME(%r1)
153         .cfi_def_cfa_offset STACKFRAME
154         .cfi_offset 65, 16
156         # make the call
157 # if defined _CALL_LINUX || _CALL_ELF == 2
158         bl ffi_closure_helper_LINUX64
159 # else
160         bl .ffi_closure_helper_LINUX64
161 # endif
162 .Lret:
164         # now r3 contains the return type
165         # so use it to look up in a table
166         # so we know how to deal with each type
168         # look up the proper starting point in table
169         # by using return type as offset
170         ld %r0, STACKFRAME+16(%r1)
171         cmpldi %r3, FFI_V2_TYPE_SMALL_STRUCT
172         bge .Lsmall
173         mflr %r4                # move address of .Lret to r4
174         sldi %r3, %r3, 4        # now multiply return type by 16
175         addi %r4, %r4, .Lret_type0 - .Lret
176         add %r3, %r3, %r4       # add contents of table to table address
177         mtctr %r3
178         bctr                    # jump to it
180 # Each of the ret_typeX code fragments has to be exactly 16 bytes long
181 # (4 instructions). For cache effectiveness we align to a 16 byte boundary
182 # first.
183         .align 4
185 .Lret_type0:
186 # case FFI_TYPE_VOID
187         mtlr %r0
188         addi %r1, %r1, STACKFRAME
189         .cfi_def_cfa_offset 0
190         blr
191         .cfi_def_cfa_offset STACKFRAME
192         nop
193 # case FFI_TYPE_INT
194 # ifdef __LITTLE_ENDIAN__
195         lwa %r3, RETVAL+0(%r1)
196 # else
197         lwa %r3, RETVAL+4(%r1)
198 # endif
199         mtlr %r0
200         addi %r1, %r1, STACKFRAME
201         .cfi_def_cfa_offset 0
202         blr
203         .cfi_def_cfa_offset STACKFRAME
204 # case FFI_TYPE_FLOAT
205         lfs %f1, RETVAL+0(%r1)
206         mtlr %r0
207         addi %r1, %r1, STACKFRAME
208         .cfi_def_cfa_offset 0
209         blr
210         .cfi_def_cfa_offset STACKFRAME
211 # case FFI_TYPE_DOUBLE
212         lfd %f1, RETVAL+0(%r1)
213         mtlr %r0
214         addi %r1, %r1, STACKFRAME
215         .cfi_def_cfa_offset 0
216         blr
217         .cfi_def_cfa_offset STACKFRAME
218 # case FFI_TYPE_LONGDOUBLE
219         lfd %f1, RETVAL+0(%r1)
220         mtlr %r0
221         lfd %f2, RETVAL+8(%r1)
222         b .Lfinish
223 # case FFI_TYPE_UINT8
224 # ifdef __LITTLE_ENDIAN__
225         lbz %r3, RETVAL+0(%r1)
226 # else
227         lbz %r3, RETVAL+7(%r1)
228 # endif
229         mtlr %r0
230         addi %r1, %r1, STACKFRAME
231         .cfi_def_cfa_offset 0
232         blr
233         .cfi_def_cfa_offset STACKFRAME
234 # case FFI_TYPE_SINT8
235 # ifdef __LITTLE_ENDIAN__
236         lbz %r3, RETVAL+0(%r1)
237 # else
238         lbz %r3, RETVAL+7(%r1)
239 # endif
240         extsb %r3,%r3
241         mtlr %r0
242         b .Lfinish
243 # case FFI_TYPE_UINT16
244 # ifdef __LITTLE_ENDIAN__
245         lhz %r3, RETVAL+0(%r1)
246 # else
247         lhz %r3, RETVAL+6(%r1)
248 # endif
249         mtlr %r0
250 .Lfinish:
251         addi %r1, %r1, STACKFRAME
252         .cfi_def_cfa_offset 0
253         blr
254         .cfi_def_cfa_offset STACKFRAME
255 # case FFI_TYPE_SINT16
256 # ifdef __LITTLE_ENDIAN__
257         lha %r3, RETVAL+0(%r1)
258 # else
259         lha %r3, RETVAL+6(%r1)
260 # endif
261         mtlr %r0
262         addi %r1, %r1, STACKFRAME
263         .cfi_def_cfa_offset 0
264         blr
265         .cfi_def_cfa_offset STACKFRAME
266 # case FFI_TYPE_UINT32
267 # ifdef __LITTLE_ENDIAN__
268         lwz %r3, RETVAL+0(%r1)
269 # else
270         lwz %r3, RETVAL+4(%r1)
271 # endif
272         mtlr %r0
273         addi %r1, %r1, STACKFRAME
274         .cfi_def_cfa_offset 0
275         blr
276         .cfi_def_cfa_offset STACKFRAME
277 # case FFI_TYPE_SINT32
278 # ifdef __LITTLE_ENDIAN__
279         lwa %r3, RETVAL+0(%r1)
280 # else
281         lwa %r3, RETVAL+4(%r1)
282 # endif
283         mtlr %r0
284         addi %r1, %r1, STACKFRAME
285         .cfi_def_cfa_offset 0
286         blr
287         .cfi_def_cfa_offset STACKFRAME
288 # case FFI_TYPE_UINT64
289         ld %r3, RETVAL+0(%r1)
290         mtlr %r0
291         addi %r1, %r1, STACKFRAME
292         .cfi_def_cfa_offset 0
293         blr
294         .cfi_def_cfa_offset STACKFRAME
295 # case FFI_TYPE_SINT64
296         ld %r3, RETVAL+0(%r1)
297         mtlr %r0
298         addi %r1, %r1, STACKFRAME
299         .cfi_def_cfa_offset 0
300         blr
301         .cfi_def_cfa_offset STACKFRAME
302 # case FFI_TYPE_STRUCT
303         mtlr %r0
304         addi %r1, %r1, STACKFRAME
305         .cfi_def_cfa_offset 0
306         blr
307         .cfi_def_cfa_offset STACKFRAME
308         nop
309 # case FFI_TYPE_POINTER
310         ld %r3, RETVAL+0(%r1)
311         mtlr %r0
312         addi %r1, %r1, STACKFRAME
313         .cfi_def_cfa_offset 0
314         blr
315         .cfi_def_cfa_offset STACKFRAME
316 # case FFI_V2_TYPE_FLOAT_HOMOG
317         lfs %f1, RETVAL+0(%r1)
318         lfs %f2, RETVAL+4(%r1)
319         lfs %f3, RETVAL+8(%r1)
320         b .Lmorefloat
321 # case FFI_V2_TYPE_DOUBLE_HOMOG
322         lfd %f1, RETVAL+0(%r1)
323         lfd %f2, RETVAL+8(%r1)
324         lfd %f3, RETVAL+16(%r1)
325         lfd %f4, RETVAL+24(%r1)
326         mtlr %r0
327         lfd %f5, RETVAL+32(%r1)
328         lfd %f6, RETVAL+40(%r1)
329         lfd %f7, RETVAL+48(%r1)
330         lfd %f8, RETVAL+56(%r1)
331         addi %r1, %r1, STACKFRAME
332         .cfi_def_cfa_offset 0
333         blr
334         .cfi_def_cfa_offset STACKFRAME
335 .Lmorefloat:
336         lfs %f4, RETVAL+12(%r1)
337         mtlr %r0
338         lfs %f5, RETVAL+16(%r1)
339         lfs %f6, RETVAL+20(%r1)
340         lfs %f7, RETVAL+24(%r1)
341         lfs %f8, RETVAL+28(%r1)
342         addi %r1, %r1, STACKFRAME
343         .cfi_def_cfa_offset 0
344         blr
345         .cfi_def_cfa_offset STACKFRAME
346 .Lsmall:
347 # ifdef __LITTLE_ENDIAN__
348         ld %r3,RETVAL+0(%r1)
349         mtlr %r0
350         ld %r4,RETVAL+8(%r1)
351         addi %r1, %r1, STACKFRAME
352         .cfi_def_cfa_offset 0
353         blr
354 # else
355         # A struct smaller than a dword is returned in the low bits of r3
356         # ie. right justified.  Larger structs are passed left justified
357         # in r3 and r4.  The return value area on the stack will have
358         # the structs as they are usually stored in memory.
359         cmpldi %r3, FFI_V2_TYPE_SMALL_STRUCT + 7 # size 8 bytes?
360         neg %r5, %r3
361         ld %r3,RETVAL+0(%r1)
362         blt .Lsmalldown
363         mtlr %r0
364         ld %r4,RETVAL+8(%r1)
365         addi %r1, %r1, STACKFRAME
366         .cfi_def_cfa_offset 0
367         blr
368         .cfi_def_cfa_offset STACKFRAME
369 .Lsmalldown:
370         addi %r5, %r5, FFI_V2_TYPE_SMALL_STRUCT + 7
371         mtlr %r0
372         sldi %r5, %r5, 3
373         addi %r1, %r1, STACKFRAME
374         .cfi_def_cfa_offset 0
375         srd %r3, %r3, %r5
376         blr
377 # endif
379         .cfi_endproc
380 # if _CALL_ELF == 2
381         .size   ffi_closure_LINUX64,.-ffi_closure_LINUX64
382 # else
383 #  ifdef _CALL_LINUX
384         .size   ffi_closure_LINUX64,.-.L.ffi_closure_LINUX64
385 #  else
386         .long   0
387         .byte   0,12,0,1,128,0,0,0
388         .size   .ffi_closure_LINUX64,.-.ffi_closure_LINUX64
389 #  endif
390 # endif
393         FFI_HIDDEN (ffi_go_closure_linux64)
394         .globl  ffi_go_closure_linux64
395         .text
396         .cfi_startproc
397 # if _CALL_ELF == 2
398 ffi_go_closure_linux64:
399         addis   %r2, %r12, .TOC.-ffi_go_closure_linux64@ha
400         addi    %r2, %r2, .TOC.-ffi_go_closure_linux64@l
401         .localentry ffi_go_closure_linux64, . - ffi_go_closure_linux64
402 # else
403         .section        ".opd","aw"
404         .align  3
405 ffi_go_closure_linux64:
406 #  ifdef _CALL_LINUX
407         .quad   .L.ffi_go_closure_linux64,.TOC.@tocbase,0
408         .type   ffi_go_closure_linux64,@function
409         .text
410 .L.ffi_go_closure_linux64:
411 #  else
412         FFI_HIDDEN (.ffi_go_closure_linux64)
413         .globl  .ffi_go_closure_linux64
414         .quad   .ffi_go_closure_linux64,.TOC.@tocbase,0
415         .size   ffi_go_closure_linux64,24
416         .type   .ffi_go_closure_linux64,@function
417         .text
418 .ffi_go_closure_linux64:
419 #  endif
420 # endif
422 # if _CALL_ELF == 2
423         ld      %r12, 8(%r11)                           # closure->cif
424         mflr    %r0
425         lwz     %r12, 28(%r12)                          # cif->flags
426         mtcrf   0x40, %r12
427         addi    %r12, %r1, PARMSAVE
428         bt      7, 0f
429         # Our caller has not allocated a parameter save area.
430         # We need to allocate one here and use it to pass gprs to
431         # ffi_closure_helper_LINUX64.
432         addi    %r12, %r1, -STACKFRAME+PARMSAVE
434         # Save general regs into parm save area
435         std     %r3, 0(%r12)
436         std     %r4, 8(%r12)
437         std     %r5, 16(%r12)
438         std     %r6, 24(%r12)
439         std     %r7, 32(%r12)
440         std     %r8, 40(%r12)
441         std     %r9, 48(%r12)
442         std     %r10, 56(%r12)
444         # load up the pointer to the parm save area
445         mr      %r7, %r12
446 # else
447         mflr    %r0
448         # Save general regs into parm save area
449         # This is the parameter save area set up by our caller.
450         std     %r3, PARMSAVE+0(%r1)
451         std     %r4, PARMSAVE+8(%r1)
452         std     %r5, PARMSAVE+16(%r1)
453         std     %r6, PARMSAVE+24(%r1)
454         std     %r7, PARMSAVE+32(%r1)
455         std     %r8, PARMSAVE+40(%r1)
456         std     %r9, PARMSAVE+48(%r1)
457         std     %r10, PARMSAVE+56(%r1)
459         # load up the pointer to the parm save area
460         addi    %r7, %r1, PARMSAVE
461 # endif
462         std     %r0, 16(%r1)
464         # closure->cif
465         ld      %r3, 8(%r11)
466         # closure->fun
467         ld      %r4, 16(%r11)
468         # user_data
469         mr      %r5, %r11
470         b       .Ldoclosure
472         .cfi_endproc
473 # if _CALL_ELF == 2
474         .size   ffi_go_closure_linux64,.-ffi_go_closure_linux64
475 # else
476 #  ifdef _CALL_LINUX
477         .size   ffi_go_closure_linux64,.-.L.ffi_go_closure_linux64
478 #  else
479         .long   0
480         .byte   0,12,0,1,128,0,0,0
481         .size   .ffi_go_closure_linux64,.-.ffi_go_closure_linux64
482 #  endif
483 # endif
484 #endif
486 #if (defined __ELF__ && defined __linux__) || _CALL_ELF == 2
487         .section        .note.GNU-stack,"",@progbits
488 #endif