re PR middle-end/32176 (ICE tree-type mismatch: expected integer_cst, have plus_expr...
[gcc.git] / libffi / src / mips / o32.S
1 /* -----------------------------------------------------------------------
2 o32.S - Copyright (c) 1996, 1998, 2005 Red Hat, Inc.
3
4 MIPS Foreign Function Interface
5
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:
13
14 The above copyright notice and this permission notice shall be included
15 in all copies or substantial portions of the Software.
16
17 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 OTHER DEALINGS IN THE SOFTWARE.
24 ----------------------------------------------------------------------- */
25
26 #define LIBFFI_ASM
27 #include <fficonfig.h>
28 #include <ffi.h>
29
30 /* Only build this code if we are compiling for o32 */
31
32 #if defined(FFI_MIPS_O32)
33
34 #define callback a0
35 #define bytes a2
36 #define flags a3
37
38 #define SIZEOF_FRAME (4 * FFI_SIZEOF_ARG + 2 * FFI_SIZEOF_ARG)
39 #define A3_OFF (SIZEOF_FRAME + 3 * FFI_SIZEOF_ARG)
40 #define FP_OFF (SIZEOF_FRAME - 2 * FFI_SIZEOF_ARG)
41 #define RA_OFF (SIZEOF_FRAME - 1 * FFI_SIZEOF_ARG)
42
43 .abicalls
44 .text
45 .align 2
46 .globl ffi_call_O32
47 .ent ffi_call_O32
48 ffi_call_O32:
49 $LFB0:
50 # Prologue
51 SUBU $sp, SIZEOF_FRAME # Frame size
52 $LCFI0:
53 REG_S $fp, FP_OFF($sp) # Save frame pointer
54 $LCFI1:
55 REG_S ra, RA_OFF($sp) # Save return address
56 $LCFI2:
57 move $fp, $sp
58
59 $LCFI3:
60 move t9, callback # callback function pointer
61 REG_S flags, A3_OFF($fp) # flags
62
63 # Allocate at least 4 words in the argstack
64 LI v0, 4 * FFI_SIZEOF_ARG
65 blt bytes, v0, sixteen
66
67 ADDU v0, bytes, 7 # make sure it is aligned
68 and v0, -8 # to an 8 byte boundry
69
70 sixteen:
71 SUBU $sp, v0 # move the stack pointer to reflect the
72 # arg space
73
74 ADDU a0, $sp, 4 * FFI_SIZEOF_ARG
75
76 jalr t9
77
78 REG_L t0, A3_OFF($fp) # load the flags word
79 SRL t2, t0, 4 # shift our arg info
80 and t0, ((1<<4)-1) # mask out the return type
81
82 ADDU $sp, 4 * FFI_SIZEOF_ARG # adjust $sp to new args
83
84 bnez t0, pass_d # make it quick for int
85 REG_L a0, 0*FFI_SIZEOF_ARG($sp) # just go ahead and load the
86 REG_L a1, 1*FFI_SIZEOF_ARG($sp) # four regs.
87 REG_L a2, 2*FFI_SIZEOF_ARG($sp)
88 REG_L a3, 3*FFI_SIZEOF_ARG($sp)
89 b call_it
90
91 pass_d:
92 bne t0, FFI_ARGS_D, pass_f
93 l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
94 REG_L a2, 2*FFI_SIZEOF_ARG($sp) # passing a double
95 REG_L a3, 3*FFI_SIZEOF_ARG($sp)
96 b call_it
97
98 pass_f:
99 bne t0, FFI_ARGS_F, pass_d_d
100 l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
101 REG_L a1, 1*FFI_SIZEOF_ARG($sp) # passing a float
102 REG_L a2, 2*FFI_SIZEOF_ARG($sp)
103 REG_L a3, 3*FFI_SIZEOF_ARG($sp)
104 b call_it
105
106 pass_d_d:
107 bne t0, FFI_ARGS_DD, pass_f_f
108 l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
109 l.d $f14, 2*FFI_SIZEOF_ARG($sp) # passing two doubles
110 b call_it
111
112 pass_f_f:
113 bne t0, FFI_ARGS_FF, pass_d_f
114 l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
115 l.s $f14, 1*FFI_SIZEOF_ARG($sp) # passing two floats
116 REG_L a2, 2*FFI_SIZEOF_ARG($sp)
117 REG_L a3, 3*FFI_SIZEOF_ARG($sp)
118 b call_it
119
120 pass_d_f:
121 bne t0, FFI_ARGS_DF, pass_f_d
122 l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
123 l.s $f14, 2*FFI_SIZEOF_ARG($sp) # passing double and float
124 REG_L a3, 3*FFI_SIZEOF_ARG($sp)
125 b call_it
126
127 pass_f_d:
128 # assume that the only other combination must be float then double
129 # bne t0, FFI_ARGS_F_D, call_it
130 l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
131 l.d $f14, 2*FFI_SIZEOF_ARG($sp) # passing double and float
132
133 call_it:
134 # Load the function pointer
135 REG_L t9, SIZEOF_FRAME + 5*FFI_SIZEOF_ARG($fp)
136
137 # If the return value pointer is NULL, assume no return value.
138 REG_L t1, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
139 beqz t1, noretval
140
141 bne t2, FFI_TYPE_INT, retlonglong
142 jalr t9
143 REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
144 REG_S v0, 0(t0)
145 b epilogue
146
147 retlonglong:
148 # Really any 64-bit int, signed or not.
149 bne t2, FFI_TYPE_UINT64, retfloat
150 jalr t9
151 REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
152 REG_S v1, 4(t0)
153 REG_S v0, 0(t0)
154 b epilogue
155
156 retfloat:
157 bne t2, FFI_TYPE_FLOAT, retdouble
158 jalr t9
159 REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
160 s.s $f0, 0(t0)
161 b epilogue
162
163 retdouble:
164 bne t2, FFI_TYPE_DOUBLE, noretval
165 jalr t9
166 REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
167 s.d $f0, 0(t0)
168 b epilogue
169
170 noretval:
171 jalr t9
172
173 # Epilogue
174 epilogue:
175 move $sp, $fp
176 REG_L $fp, FP_OFF($sp) # Restore frame pointer
177 REG_L ra, RA_OFF($sp) # Restore return address
178 ADDU $sp, SIZEOF_FRAME # Fix stack pointer
179 j ra
180
181 $LFE0:
182 .end ffi_call_O32
183
184
185 /* ffi_closure_O32. Expects address of the passed-in ffi_closure
186 in t0. Stores any arguments passed in registers onto the
187 stack, then calls ffi_closure_mips_inner_O32, which
188 then decodes them.
189
190 Stack layout:
191
192 14 - Start of parameters, original sp
193 13 - ra save
194 12 - fp save
195 11 - $16 (s0) save
196 10 - cprestore
197 9 - return value high (v1)
198 8 - return value low (v0)
199 7 - f14 (le high, be low)
200 6 - f14 (le low, be high)
201 5 - f12 (le high, be low)
202 4 - f12 (le low, be high)
203 3 - Called function a3 save
204 2 - Called function a2 save
205 1 - Called function a1 save
206 0 - Called function a0 save our sp, fp point here
207 */
208
209 #define SIZEOF_FRAME2 (14 * FFI_SIZEOF_ARG)
210 #define A3_OFF2 (SIZEOF_FRAME2 + 3 * FFI_SIZEOF_ARG)
211 #define A2_OFF2 (SIZEOF_FRAME2 + 2 * FFI_SIZEOF_ARG)
212 #define A1_OFF2 (SIZEOF_FRAME2 + 1 * FFI_SIZEOF_ARG)
213 #define A0_OFF2 (SIZEOF_FRAME2 + 0 * FFI_SIZEOF_ARG)
214 #define RA_OFF2 (SIZEOF_FRAME2 - 1 * FFI_SIZEOF_ARG)
215 #define FP_OFF2 (SIZEOF_FRAME2 - 2 * FFI_SIZEOF_ARG)
216 #define S0_OFF2 (SIZEOF_FRAME2 - 3 * FFI_SIZEOF_ARG)
217 #define GP_OFF2 (SIZEOF_FRAME2 - 4 * FFI_SIZEOF_ARG)
218 #define V1_OFF2 (SIZEOF_FRAME2 - 5 * FFI_SIZEOF_ARG)
219 #define V0_OFF2 (SIZEOF_FRAME2 - 6 * FFI_SIZEOF_ARG)
220 #define FA_1_1_OFF2 (SIZEOF_FRAME2 - 7 * FFI_SIZEOF_ARG)
221 #define FA_1_0_OFF2 (SIZEOF_FRAME2 - 8 * FFI_SIZEOF_ARG)
222 #define FA_0_1_OFF2 (SIZEOF_FRAME2 - 9 * FFI_SIZEOF_ARG)
223 #define FA_0_0_OFF2 (SIZEOF_FRAME2 - 10 * FFI_SIZEOF_ARG)
224
225 .text
226 .align 2
227 .globl ffi_closure_O32
228 .ent ffi_closure_O32
229 ffi_closure_O32:
230 $LFB1:
231 # Prologue
232 .frame $fp, SIZEOF_FRAME2, ra
233 .set noreorder
234 .cpload t9
235 .set reorder
236 SUBU $sp, SIZEOF_FRAME2
237 .cprestore GP_OFF2
238 $LCFI4:
239 REG_S $16, S0_OFF2($sp) # Save s0
240 REG_S $fp, FP_OFF2($sp) # Save frame pointer
241 REG_S ra, RA_OFF2($sp) # Save return address
242 $LCFI6:
243 move $fp, $sp
244
245 $LCFI7:
246 # Store all possible argument registers. If there are more than
247 # four arguments, then they are stored above where we put a3.
248 REG_S a0, A0_OFF2($fp)
249 REG_S a1, A1_OFF2($fp)
250 REG_S a2, A2_OFF2($fp)
251 REG_S a3, A3_OFF2($fp)
252
253 # Load ABI enum to s0
254 REG_L $16, 20($8) # cif pointer follows tramp.
255 REG_L $16, 0($16) # abi is first member.
256
257 li $13, 1 # FFI_O32
258 bne $16, $13, 1f # Skip fp save if FFI_O32_SOFT_FLOAT
259
260 # Store all possible float/double registers.
261 s.d $f12, FA_0_0_OFF2($fp)
262 s.d $f14, FA_1_0_OFF2($fp)
263 1:
264 # Call ffi_closure_mips_inner_O32 to do the work.
265 la t9, ffi_closure_mips_inner_O32
266 move a0, $8 # Pointer to the ffi_closure
267 addu a1, $fp, V0_OFF2
268 addu a2, $fp, A0_OFF2
269 addu a3, $fp, FA_0_0_OFF2
270 jalr t9
271
272 # Load the return value into the appropriate register.
273 move $8, $2
274 li $9, FFI_TYPE_VOID
275 beq $8, $9, closure_done
276
277 li $13, 1 # FFI_O32
278 bne $16, $13, 1f # Skip fp restore if FFI_O32_SOFT_FLOAT
279
280 li $9, FFI_TYPE_FLOAT
281 l.s $f0, V0_OFF2($fp)
282 beq $8, $9, closure_done
283
284 li $9, FFI_TYPE_DOUBLE
285 l.d $f0, V0_OFF2($fp)
286 beq $8, $9, closure_done
287 1:
288 REG_L $3, V1_OFF2($fp)
289 REG_L $2, V0_OFF2($fp)
290
291 closure_done:
292 # Epilogue
293 move $sp, $fp
294 REG_L $16, S0_OFF2($sp) # Restore s0
295 REG_L $fp, FP_OFF2($sp) # Restore frame pointer
296 REG_L ra, RA_OFF2($sp) # Restore return address
297 ADDU $sp, SIZEOF_FRAME2
298 j ra
299 $LFE1:
300 .end ffi_closure_O32
301
302 /* DWARF-2 unwind info. */
303
304 .section .eh_frame,"a",@progbits
305 $Lframe0:
306 .4byte $LECIE0-$LSCIE0 # Length of Common Information Entry
307 $LSCIE0:
308 .4byte 0x0 # CIE Identifier Tag
309 .byte 0x1 # CIE Version
310 .ascii "zR\0" # CIE Augmentation
311 .uleb128 0x1 # CIE Code Alignment Factor
312 .sleb128 4 # CIE Data Alignment Factor
313 .byte 0x1f # CIE RA Column
314 .uleb128 0x1 # Augmentation size
315 .byte 0x00 # FDE Encoding (absptr)
316 .byte 0xc # DW_CFA_def_cfa
317 .uleb128 0x1d
318 .uleb128 0x0
319 .align 2
320 $LECIE0:
321 $LSFDE0:
322 .4byte $LEFDE0-$LASFDE0 # FDE Length
323 $LASFDE0:
324 .4byte $LASFDE0-$Lframe0 # FDE CIE offset
325 .4byte $LFB0 # FDE initial location
326 .4byte $LFE0-$LFB0 # FDE address range
327 .uleb128 0x0 # Augmentation size
328 .byte 0x4 # DW_CFA_advance_loc4
329 .4byte $LCFI0-$LFB0
330 .byte 0xe # DW_CFA_def_cfa_offset
331 .uleb128 0x18
332 .byte 0x4 # DW_CFA_advance_loc4
333 .4byte $LCFI2-$LCFI0
334 .byte 0x11 # DW_CFA_offset_extended_sf
335 .uleb128 0x1e # $fp
336 .sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)
337 .byte 0x11 # DW_CFA_offset_extended_sf
338 .uleb128 0x1f # $ra
339 .sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
340 .byte 0x4 # DW_CFA_advance_loc4
341 .4byte $LCFI3-$LCFI2
342 .byte 0xc # DW_CFA_def_cfa
343 .uleb128 0x1e
344 .uleb128 0x18
345 .align 2
346 $LEFDE0:
347 $LSFDE1:
348 .4byte $LEFDE1-$LASFDE1 # FDE Length
349 $LASFDE1:
350 .4byte $LASFDE1-$Lframe0 # FDE CIE offset
351 .4byte $LFB1 # FDE initial location
352 .4byte $LFE1-$LFB1 # FDE address range
353 .uleb128 0x0 # Augmentation size
354 .byte 0x4 # DW_CFA_advance_loc4
355 .4byte $LCFI4-$LFB1
356 .byte 0xe # DW_CFA_def_cfa_offset
357 .uleb128 0x38
358 .byte 0x4 # DW_CFA_advance_loc4
359 .4byte $LCFI6-$LCFI4
360 .byte 0x11 # DW_CFA_offset_extended_sf
361 .uleb128 0x10 # $16
362 .sleb128 -3 # SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($sp)
363 .byte 0x11 # DW_CFA_offset_extended_sf
364 .uleb128 0x1e # $fp
365 .sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)
366 .byte 0x11 # DW_CFA_offset_extended_sf
367 .uleb128 0x1f # $ra
368 .sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
369 .byte 0x4 # DW_CFA_advance_loc4
370 .4byte $LCFI7-$LCFI6
371 .byte 0xc # DW_CFA_def_cfa
372 .uleb128 0x1e
373 .uleb128 0x38
374 .align 2
375 $LEFDE1:
376
377 #endif