LWG 3075 basic_string needs deduction guides from basic_string_view
[official-gcc.git] / libffi / src / metag / sysv.S
blobb4b2a3b26bbfbdcdc9cf5ffb6c69d4388598feab
1 /* -----------------------------------------------------------------------
2    sysv.S - Copyright (c) 2013 Imagination Technologies Ltd.
4    Meta Foreign Function Interface
6    Permission is hereby granted, free of charge, to any person obtaining
7    a copy of this software and associated documentation files (the
8    ``Software''), to deal in the Software without restriction, including
9    without limitation the rights to use, copy, modify, merge, publish,
10    distribute, sublicense, and/or sell copies of the Software, and to
11    permit persons to whom the Software is furnished to do so, subject to
12    the following conditions:
14    The above copyright notice and this permission notice shall be included
15    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    ----------------------------------------------------------------------- */
28 #define LIBFFI_ASM
29 #include <fficonfig.h>
30 #include <ffi.h>
31 #ifdef HAVE_MACHINE_ASM_H
32 #include <machine/asm.h>
33 #else
34 #ifdef __USER_LABEL_PREFIX__
35 #define CONCAT1(a, b) CONCAT2(a, b)
36 #define CONCAT2(a, b) a ## b
38 /* Use the right prefix for global labels. */
39 #define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
40 #else
41 #define CNAME(x) x
42 #endif
43 #define ENTRY(x) .globl CNAME(x); .type CNAME(x), %function; CNAME(x):
44 #endif
46 #ifdef __ELF__
47 #define LSYM(x) .x
48 #else
49 #define LSYM(x) x
50 #endif
52 .macro call_reg x=
53         .text
54         .balign 4
55         mov D1RtP, \x
56         swap D1RtP, PC
57 .endm
59 ! Save register arguments
60 .macro SAVE_ARGS
61         .text
62         .balign 4
63         setl    [A0StP++], D0Ar6, D1Ar5
64         setl    [A0StP++], D0Ar4, D1Ar3
65         setl    [A0StP++], D0Ar2, D1Ar1
66 .endm
68 ! Save retrun, frame pointer and other regs
69 .macro SAVE_REGS regs=
70         .text
71         .balign 4
72         setl    [A0StP++], D0FrT, D1RtP
73         ! Needs to be a pair of regs
74         .ifnc "\regs",""
75         setl    [A0StP++], \regs
76         .endif
77 .endm
79 ! Declare a global function
80 .macro METAG_FUNC_START name
81         .text
82         .balign 4
83         ENTRY(\name)
84 .endm
86 ! Return registers from the stack. Reverse SAVE_REGS operation
87 .macro RET_REGS regs=, cond=
88         .ifnc "\regs", ""
89         getl    \regs, [--A0StP]
90         .endif
91         getl    D0FrT, D1RtP, [--A0StP]
92 .endm
94 ! Return arguments
95 .macro RET_ARGS
96         getl    D0Ar2, D1Ar1, [--A0StP]
97         getl    D0Ar4, D1Ar3, [--A0StP]
98         getl    D0Ar6, D1Ar5, [--A0StP]
99 .endm
102         ! D1Ar1:        fn
103         ! D0Ar2:        &ecif
104         ! D1Ar3:        cif->bytes
105         ! D0Ar4:        fig->flags
106         ! D1Ar5:        ecif.rvalue
108         ! This assumes we are using GNU as
109 METAG_FUNC_START ffi_call_SYSV
110         ! Save argument registers
112         SAVE_ARGS
114         ! new frame
115         mov     D0FrT, A0FrP
116         add     A0FrP, A0StP, #0
118         ! Preserve the old frame pointer
119         SAVE_REGS "D1.5, D0.5"
121         ! Make room for new args. cifs->bytes is the total space for input
122         ! and return arguments
124         add     A0StP, A0StP, D1Ar3
126         ! Preserve cifs->bytes & fn
127         mov     D0.5, D1Ar3
128         mov     D1.5, D1Ar1
130         ! Place all of the ffi_prep_args in position
131         mov     D1Ar1, A0StP
133         ! Call ffi_prep_args(stack, &ecif)
134 #ifdef __PIC__
135         callr  D1RtP, CNAME(ffi_prep_args@PLT)
136 #else
137         callr  D1RtP, CNAME(ffi_prep_args)
138 #endif
140         ! Restore fn pointer
142         ! The foreign stack should look like this
143         ! XXXXX XXXXXX <--- stack pointer
144         ! FnArgN rvalue
145         ! FnArgN+2 FnArgN+1
146         ! FnArgN+4 FnArgN+3
147         ! ....
148         !
150         ! A0StP now points to the first (or return) argument + 4
152         ! Preserve cif->bytes
153         getl    D0Ar2, D1Ar1, [--A0StP]
154         getl    D0Ar4, D1Ar3, [--A0StP]
155         getl    D0Ar6, D1Ar5, [--A0StP]
157         ! Place A0StP to the first argument again
158         add     A0StP, A0StP, #24 ! That's because we loaded 6 regs x 4 byte each
160         ! A0FrP points to the initial stack without the reserved space for the
161         ! cifs->bytes, whilst A0StP points to the stack after the space allocation
163         ! fn was the first argument of ffi_call_SYSV.
164         ! The stack at this point looks like this:
165         !
166         ! A0StP(on entry to _SYSV) ->   Arg6    Arg5     | low
167         !                               Arg4    Arg3     |
168         !                               Arg2    Arg1     |
169         ! A0FrP ---->                   D0FrtP  D1RtP    |
170         !                               D1.5    D0.5     |
171         ! A0StP(bf prep_args) ->        FnArgn  FnArgn-1 |
172         !                               FnArgn-2FnArgn-3 |
173         !                               ................ | <= cifs->bytes
174         !                               FnArg4  FnArg3   |
175         ! A0StP (prv_A0StP+cifs->bytes) FnArg2  FnArg1   | high
176         !
177         ! fn was in Arg1 so it's located in in A0FrP+#-0xC
178         !
180         ! D0Re0 contains the size of arguments stored in registers
181         sub     A0StP, A0StP, D0Re0
183         ! Arg1 is the function pointer for the foreign call. This has been
184         ! preserved in D1.5
186         ! Time to call (fn). Arguments should be like this:
187         ! Arg1-Arg6 are loaded to regs
188         ! The rest of the arguments are stored in stack pointed by A0StP
190         call_reg D1.5
192         ! Reset stack.
194         mov     A0StP, A0FrP
196         ! Load Arg1 with the pointer to storage for the return type
197         ! This was stored in Arg5
199         getd    D1Ar1, [A0FrP+#-20]
201         ! Load D0Ar2 with the return type code. This was stored in Arg4 (flags)
203         getd    D0Ar2, [A0FrP+#-16]
205         ! We are ready to start processing the return value
206         ! D0Re0 (and D1Re0) hold the return value
208         ! If the return value is NULL, assume no return value
209         cmp     D1Ar1, #0
210         beq     LSYM(Lepilogue)
212         ! return INT
213         cmp             D0Ar2, #FFI_TYPE_INT
214         ! Sadly, there is no setd{cc} instruction so we need to workaround that
215         bne     .INT64
216         setd    [D1Ar1], D0Re0
217         b       LSYM(Lepilogue)
219         ! return INT64
220 .INT64:
221         cmp     D0Ar2, #FFI_TYPE_SINT64
222         setleq  [D1Ar1], D0Re0, D1Re0
224         ! return DOUBLE
225         cmp     D0Ar2, #FFI_TYPE_DOUBLE
226         setl    [D1AR1++], D0Re0, D1Re0
228 LSYM(Lepilogue):
229         ! At this point, the stack pointer points right after the argument
230         ! saved area. We need to restore 4 regs, therefore we need to move
231         ! 16 bytes ahead.
232         add     A0StP, A0StP, #16
233         RET_REGS "D1.5, D0.5"
234         RET_ARGS
235         getd    D0Re0, [A0StP]
236         mov     A0FrP, D0FrT
237         swap    D1RtP, PC
239 .ffi_call_SYSV_end:
240        .size   CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
244         (called by ffi_metag_trampoline)
245         void ffi_closure_SYSV (ffi_closure*)
247         (called by ffi_closure_SYSV)
248         unsigned int FFI_HIDDEN
249         ffi_closure_SYSV_inner (closure,respp, args)
250                 ffi_closure *closure;
251                 void **respp;
252                 void *args;
255 METAG_FUNC_START ffi_closure_SYSV
256         ! We assume that D1Ar1 holds the address of the
257         ! ffi_closure struct. We will use that to fetch the
258         ! arguments. The stack pointer points to an empty space
259         ! and it is ready to store more data.
261         ! D1Ar1 is ready
262         ! Allocate stack space for return value
263         add A0StP, A0StP, #8
264         ! Store it to D0Ar2
265         sub D0Ar2, A0StP, #8
267         sub D1Ar3, A0FrP, #4
269         ! D1Ar3 contains the address of the original D1Ar1 argument
270         ! We need to subtract #4 later on
272         ! Preverve D0Ar2
273         mov D0.5, D0Ar2
275 #ifdef __PIC__
276         callr D1RtP, CNAME(ffi_closure_SYSV_inner@PLT)
277 #else
278         callr D1RtP, CNAME(ffi_closure_SYSV_inner)
279 #endif
281         ! Check the return value and store it to D0.5
282         cmp D0Re0, #FFI_TYPE_INT
283         beq .Lretint
284         cmp D0Re0, #FFI_TYPE_DOUBLE
285         beq .Lretdouble
286 .Lclosure_epilogue:
287         sub A0StP, A0StP, #8
288         RET_REGS "D1.5, D0.5"
289         RET_ARGS
290         swap    D1RtP, PC
292 .Lretint:
293         setd [D0.5], D0Re0
294         b .Lclosure_epilogue
295 .Lretdouble:
296         setl [D0.5++], D0Re0, D1Re0
297         b .Lclosure_epilogue
298 .ffi_closure_SYSV_end:
299 .size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV)
302 ENTRY(ffi_metag_trampoline)
303         SAVE_ARGS
304         ! New frame
305         mov A0FrP, A0StP
306         SAVE_REGS "D1.5, D0.5"
307         mov D0.5, PC
308         ! Load D1Ar1 the value of ffi_metag_trampoline
309         getd D1Ar1, [D0.5 + #8]
310         ! Jump to ffi_closure_SYSV
311         getd PC, [D0.5 + #12]