/Modules/_ctypes/libffi/src/mips/n32.S

http://unladen-swallow.googlecode.com/ · Assembly · 534 lines · 412 code · 67 blank · 55 comment · 1 complexity · 8fdee765a24e902062f1680fd7e1eeef MD5 · raw file

  1. /* -----------------------------------------------------------------------
  2. n32.S - Copyright (c) 1996, 1998, 2005 Red Hat, Inc.
  3. MIPS Foreign Function Interface
  4. Permission is hereby granted, free of charge, to any person obtaining
  5. a copy of this software and associated documentation files (the
  6. ``Software''), to deal in the Software without restriction, including
  7. without limitation the rights to use, copy, modify, merge, publish,
  8. distribute, sublicense, and/or sell copies of the Software, and to
  9. permit persons to whom the Software is furnished to do so, subject to
  10. the following conditions:
  11. The above copyright notice and this permission notice shall be included
  12. in all copies or substantial portions of the Software.
  13. THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
  14. OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  15. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  16. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
  17. ANY CLAIM, DAMAGES OR
  18. OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19. ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20. OTHER DEALINGS IN THE SOFTWARE.
  21. ----------------------------------------------------------------------- */
  22. #define LIBFFI_ASM
  23. #include <fficonfig.h>
  24. #include <ffi.h>
  25. /* Only build this code if we are compiling for n32 */
  26. #if defined(FFI_MIPS_N32)
  27. #define callback a0
  28. #define bytes a2
  29. #define flags a3
  30. #define raddr a4
  31. #define fn a5
  32. #define SIZEOF_FRAME ( 8 * FFI_SIZEOF_ARG )
  33. .abicalls
  34. .text
  35. .align 2
  36. .globl ffi_call_N32
  37. .ent ffi_call_N32
  38. ffi_call_N32:
  39. .LFB3:
  40. .frame $fp, SIZEOF_FRAME, ra
  41. .mask 0xc0000000,-FFI_SIZEOF_ARG
  42. .fmask 0x00000000,0
  43. # Prologue
  44. SUBU $sp, SIZEOF_FRAME # Frame size
  45. .LCFI0:
  46. REG_S $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Save frame pointer
  47. REG_S ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Save return address
  48. .LCFI1:
  49. move $fp, $sp
  50. .LCFI3:
  51. move t9, callback # callback function pointer
  52. REG_S bytes, 2*FFI_SIZEOF_ARG($fp) # bytes
  53. REG_S flags, 3*FFI_SIZEOF_ARG($fp) # flags
  54. REG_S raddr, 4*FFI_SIZEOF_ARG($fp) # raddr
  55. REG_S fn, 5*FFI_SIZEOF_ARG($fp) # fn
  56. # Allocate at least 4 words in the argstack
  57. move v0, bytes
  58. bge bytes, 4 * FFI_SIZEOF_ARG, bigger
  59. LI v0, 4 * FFI_SIZEOF_ARG
  60. b sixteen
  61. bigger:
  62. ADDU t4, v0, 2 * FFI_SIZEOF_ARG -1 # make sure it is aligned
  63. and v0, t4, -2 * FFI_SIZEOF_ARG # to a proper boundry.
  64. sixteen:
  65. SUBU $sp, $sp, v0 # move the stack pointer to reflect the
  66. # arg space
  67. move a0, $sp # 4 * FFI_SIZEOF_ARG
  68. ADDU a3, $fp, 3 * FFI_SIZEOF_ARG
  69. # Call ffi_prep_args
  70. jal t9
  71. # Copy the stack pointer to t9
  72. move t9, $sp
  73. # Fix the stack if there are more than 8 64bit slots worth
  74. # of arguments.
  75. # Load the number of bytes
  76. REG_L t6, 2*FFI_SIZEOF_ARG($fp)
  77. # Is it bigger than 8 * FFI_SIZEOF_ARG?
  78. daddiu t8, t6, -(8 * FFI_SIZEOF_ARG)
  79. bltz t8, loadregs
  80. ADDU t9, t9, t8
  81. loadregs:
  82. REG_L t6, 3*FFI_SIZEOF_ARG($fp) # load the flags word into t6.
  83. and t4, t6, ((1<<FFI_FLAG_BITS)-1)
  84. bnez t4, arg1_floatp
  85. REG_L a0, 0*FFI_SIZEOF_ARG(t9)
  86. b arg1_next
  87. arg1_floatp:
  88. bne t4, FFI_TYPE_FLOAT, arg1_doublep
  89. l.s $f12, 0*FFI_SIZEOF_ARG(t9)
  90. b arg1_next
  91. arg1_doublep:
  92. l.d $f12, 0*FFI_SIZEOF_ARG(t9)
  93. arg1_next:
  94. SRL t4, t6, 1*FFI_FLAG_BITS
  95. and t4, ((1<<FFI_FLAG_BITS)-1)
  96. bnez t4, arg2_floatp
  97. REG_L a1, 1*FFI_SIZEOF_ARG(t9)
  98. b arg2_next
  99. arg2_floatp:
  100. bne t4, FFI_TYPE_FLOAT, arg2_doublep
  101. l.s $f13, 1*FFI_SIZEOF_ARG(t9)
  102. b arg2_next
  103. arg2_doublep:
  104. l.d $f13, 1*FFI_SIZEOF_ARG(t9)
  105. arg2_next:
  106. SRL t4, t6, 2*FFI_FLAG_BITS
  107. and t4, ((1<<FFI_FLAG_BITS)-1)
  108. bnez t4, arg3_floatp
  109. REG_L a2, 2*FFI_SIZEOF_ARG(t9)
  110. b arg3_next
  111. arg3_floatp:
  112. bne t4, FFI_TYPE_FLOAT, arg3_doublep
  113. l.s $f14, 2*FFI_SIZEOF_ARG(t9)
  114. b arg3_next
  115. arg3_doublep:
  116. l.d $f14, 2*FFI_SIZEOF_ARG(t9)
  117. arg3_next:
  118. SRL t4, t6, 3*FFI_FLAG_BITS
  119. and t4, ((1<<FFI_FLAG_BITS)-1)
  120. bnez t4, arg4_floatp
  121. REG_L a3, 3*FFI_SIZEOF_ARG(t9)
  122. b arg4_next
  123. arg4_floatp:
  124. bne t4, FFI_TYPE_FLOAT, arg4_doublep
  125. l.s $f15, 3*FFI_SIZEOF_ARG(t9)
  126. b arg4_next
  127. arg4_doublep:
  128. l.d $f15, 3*FFI_SIZEOF_ARG(t9)
  129. arg4_next:
  130. SRL t4, t6, 4*FFI_FLAG_BITS
  131. and t4, ((1<<FFI_FLAG_BITS)-1)
  132. bnez t4, arg5_floatp
  133. REG_L a4, 4*FFI_SIZEOF_ARG(t9)
  134. b arg5_next
  135. arg5_floatp:
  136. bne t4, FFI_TYPE_FLOAT, arg5_doublep
  137. l.s $f16, 4*FFI_SIZEOF_ARG(t9)
  138. b arg5_next
  139. arg5_doublep:
  140. l.d $f16, 4*FFI_SIZEOF_ARG(t9)
  141. arg5_next:
  142. SRL t4, t6, 5*FFI_FLAG_BITS
  143. and t4, ((1<<FFI_FLAG_BITS)-1)
  144. bnez t4, arg6_floatp
  145. REG_L a5, 5*FFI_SIZEOF_ARG(t9)
  146. b arg6_next
  147. arg6_floatp:
  148. bne t4, FFI_TYPE_FLOAT, arg6_doublep
  149. l.s $f17, 5*FFI_SIZEOF_ARG(t9)
  150. b arg6_next
  151. arg6_doublep:
  152. l.d $f17, 5*FFI_SIZEOF_ARG(t9)
  153. arg6_next:
  154. SRL t4, t6, 6*FFI_FLAG_BITS
  155. and t4, ((1<<FFI_FLAG_BITS)-1)
  156. bnez t4, arg7_floatp
  157. REG_L a6, 6*FFI_SIZEOF_ARG(t9)
  158. b arg7_next
  159. arg7_floatp:
  160. bne t4, FFI_TYPE_FLOAT, arg7_doublep
  161. l.s $f18, 6*FFI_SIZEOF_ARG(t9)
  162. b arg7_next
  163. arg7_doublep:
  164. l.d $f18, 6*FFI_SIZEOF_ARG(t9)
  165. arg7_next:
  166. SRL t4, t6, 7*FFI_FLAG_BITS
  167. and t4, ((1<<FFI_FLAG_BITS)-1)
  168. bnez t4, arg8_floatp
  169. REG_L a7, 7*FFI_SIZEOF_ARG(t9)
  170. b arg8_next
  171. arg8_floatp:
  172. bne t4, FFI_TYPE_FLOAT, arg8_doublep
  173. l.s $f19, 7*FFI_SIZEOF_ARG(t9)
  174. b arg8_next
  175. arg8_doublep:
  176. l.d $f19, 7*FFI_SIZEOF_ARG(t9)
  177. arg8_next:
  178. callit:
  179. # Load the function pointer
  180. REG_L t9, 5*FFI_SIZEOF_ARG($fp)
  181. # If the return value pointer is NULL, assume no return value.
  182. REG_L t5, 4*FFI_SIZEOF_ARG($fp)
  183. beqz t5, noretval
  184. # Shift the return type flag over
  185. SRL t6, 8*FFI_FLAG_BITS
  186. bne t6, FFI_TYPE_INT, retfloat
  187. jal t9
  188. REG_L t4, 4*FFI_SIZEOF_ARG($fp)
  189. REG_S v0, 0(t4)
  190. b epilogue
  191. retfloat:
  192. bne t6, FFI_TYPE_FLOAT, retdouble
  193. jal t9
  194. REG_L t4, 4*FFI_SIZEOF_ARG($fp)
  195. s.s $f0, 0(t4)
  196. b epilogue
  197. retdouble:
  198. bne t6, FFI_TYPE_DOUBLE, retstruct_d
  199. jal t9
  200. REG_L t4, 4*FFI_SIZEOF_ARG($fp)
  201. s.d $f0, 0(t4)
  202. b epilogue
  203. retstruct_d:
  204. bne t6, FFI_TYPE_STRUCT_D, retstruct_f
  205. jal t9
  206. REG_L t4, 4*FFI_SIZEOF_ARG($fp)
  207. s.d $f0, 0(t4)
  208. b epilogue
  209. retstruct_f:
  210. bne t6, FFI_TYPE_STRUCT_F, retstruct_d_d
  211. jal t9
  212. REG_L t4, 4*FFI_SIZEOF_ARG($fp)
  213. s.s $f0, 0(t4)
  214. b epilogue
  215. retstruct_d_d:
  216. bne t6, FFI_TYPE_STRUCT_DD, retstruct_f_f
  217. jal t9
  218. REG_L t4, 4*FFI_SIZEOF_ARG($fp)
  219. s.d $f0, 0(t4)
  220. s.d $f2, 8(t4)
  221. b epilogue
  222. retstruct_f_f:
  223. bne t6, FFI_TYPE_STRUCT_FF, retstruct_d_f
  224. jal t9
  225. REG_L t4, 4*FFI_SIZEOF_ARG($fp)
  226. s.s $f0, 0(t4)
  227. s.s $f2, 4(t4)
  228. b epilogue
  229. retstruct_d_f:
  230. bne t6, FFI_TYPE_STRUCT_DF, retstruct_f_d
  231. jal t9
  232. REG_L t4, 4*FFI_SIZEOF_ARG($fp)
  233. s.d $f0, 0(t4)
  234. s.s $f2, 8(t4)
  235. b epilogue
  236. retstruct_f_d:
  237. bne t6, FFI_TYPE_STRUCT_FD, retstruct_small
  238. jal t9
  239. REG_L t4, 4*FFI_SIZEOF_ARG($fp)
  240. s.s $f0, 0(t4)
  241. s.d $f2, 8(t4)
  242. b epilogue
  243. retstruct_small:
  244. bne t6, FFI_TYPE_STRUCT_SMALL, retstruct_small2
  245. jal t9
  246. REG_L t4, 4*FFI_SIZEOF_ARG($fp)
  247. REG_S v0, 0(t4)
  248. b epilogue
  249. retstruct_small2:
  250. bne t6, FFI_TYPE_STRUCT_SMALL2, retstruct
  251. jal t9
  252. REG_L t4, 4*FFI_SIZEOF_ARG($fp)
  253. REG_S v0, 0(t4)
  254. REG_S v1, 8(t4)
  255. b epilogue
  256. retstruct:
  257. noretval:
  258. jal t9
  259. # Epilogue
  260. epilogue:
  261. move $sp, $fp
  262. REG_L $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Restore frame pointer
  263. REG_L ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Restore return address
  264. ADDU $sp, SIZEOF_FRAME # Fix stack pointer
  265. j ra
  266. .LFE3:
  267. .end ffi_call_N32
  268. /* ffi_closure_N32. Expects address of the passed-in ffi_closure in t0
  269. ($12). Stores any arguments passed in registers onto the stack,
  270. then calls ffi_closure_mips_inner_N32, which then decodes
  271. them.
  272. Stack layout:
  273. 20 - Start of parameters, original sp
  274. 19 - Called function a7 save
  275. 18 - Called function a6 save
  276. 17 - Called function a5 save
  277. 16 - Called function a4 save
  278. 15 - Called function a3 save
  279. 14 - Called function a2 save
  280. 13 - Called function a1 save
  281. 12 - Called function a0 save
  282. 11 - Called function f19
  283. 10 - Called function f18
  284. 9 - Called function f17
  285. 8 - Called function f16
  286. 7 - Called function f15
  287. 6 - Called function f14
  288. 5 - Called function f13
  289. 4 - Called function f12
  290. 3 - return value high (v1 or $f2)
  291. 2 - return value low (v0 or $f0)
  292. 1 - ra save
  293. 0 - gp save our sp points here
  294. */
  295. #define SIZEOF_FRAME2 (20 * FFI_SIZEOF_ARG)
  296. #define A7_OFF2 (19 * FFI_SIZEOF_ARG)
  297. #define A6_OFF2 (18 * FFI_SIZEOF_ARG)
  298. #define A5_OFF2 (17 * FFI_SIZEOF_ARG)
  299. #define A4_OFF2 (16 * FFI_SIZEOF_ARG)
  300. #define A3_OFF2 (15 * FFI_SIZEOF_ARG)
  301. #define A2_OFF2 (14 * FFI_SIZEOF_ARG)
  302. #define A1_OFF2 (13 * FFI_SIZEOF_ARG)
  303. #define A0_OFF2 (12 * FFI_SIZEOF_ARG)
  304. #define F19_OFF2 (11 * FFI_SIZEOF_ARG)
  305. #define F18_OFF2 (10 * FFI_SIZEOF_ARG)
  306. #define F17_OFF2 (9 * FFI_SIZEOF_ARG)
  307. #define F16_OFF2 (8 * FFI_SIZEOF_ARG)
  308. #define F15_OFF2 (7 * FFI_SIZEOF_ARG)
  309. #define F14_OFF2 (6 * FFI_SIZEOF_ARG)
  310. #define F13_OFF2 (5 * FFI_SIZEOF_ARG)
  311. #define F12_OFF2 (4 * FFI_SIZEOF_ARG)
  312. #define V1_OFF2 (3 * FFI_SIZEOF_ARG)
  313. #define V0_OFF2 (2 * FFI_SIZEOF_ARG)
  314. #define RA_OFF2 (1 * FFI_SIZEOF_ARG)
  315. #define GP_OFF2 (0 * FFI_SIZEOF_ARG)
  316. .align 2
  317. .globl ffi_closure_N32
  318. .ent ffi_closure_N32
  319. ffi_closure_N32:
  320. .LFB2:
  321. .frame $sp, SIZEOF_FRAME2, ra
  322. .mask 0x90000000,-(SIZEOF_FRAME2 - RA_OFF2)
  323. .fmask 0x00000000,0
  324. SUBU $sp, SIZEOF_FRAME2
  325. .LCFI5:
  326. .cpsetup t9, GP_OFF2, ffi_closure_N32
  327. REG_S ra, RA_OFF2($sp) # Save return address
  328. .LCFI6:
  329. # Store all possible argument registers. If there are more than
  330. # fit in registers, then they were stored on the stack.
  331. REG_S a0, A0_OFF2($sp)
  332. REG_S a1, A1_OFF2($sp)
  333. REG_S a2, A2_OFF2($sp)
  334. REG_S a3, A3_OFF2($sp)
  335. REG_S a4, A4_OFF2($sp)
  336. REG_S a5, A5_OFF2($sp)
  337. REG_S a6, A6_OFF2($sp)
  338. REG_S a7, A7_OFF2($sp)
  339. # Store all possible float/double registers.
  340. s.d $f12, F12_OFF2($sp)
  341. s.d $f13, F13_OFF2($sp)
  342. s.d $f14, F14_OFF2($sp)
  343. s.d $f15, F15_OFF2($sp)
  344. s.d $f16, F16_OFF2($sp)
  345. s.d $f17, F17_OFF2($sp)
  346. s.d $f18, F18_OFF2($sp)
  347. s.d $f19, F19_OFF2($sp)
  348. # Call ffi_closure_mips_inner_N32 to do the real work.
  349. LA t9, ffi_closure_mips_inner_N32
  350. move a0, $12 # Pointer to the ffi_closure
  351. ADDU a1, $sp, V0_OFF2
  352. ADDU a2, $sp, A0_OFF2
  353. ADDU a3, $sp, F12_OFF2
  354. jalr t9
  355. # Return flags are in v0
  356. bne v0, FFI_TYPE_INT, cls_retfloat
  357. REG_L v0, V0_OFF2($sp)
  358. b cls_epilogue
  359. cls_retfloat:
  360. bne v0, FFI_TYPE_FLOAT, cls_retdouble
  361. l.s $f0, V0_OFF2($sp)
  362. b cls_epilogue
  363. cls_retdouble:
  364. bne v0, FFI_TYPE_DOUBLE, cls_retstruct_d
  365. l.d $f0, V0_OFF2($sp)
  366. b cls_epilogue
  367. cls_retstruct_d:
  368. bne v0, FFI_TYPE_STRUCT_D, cls_retstruct_f
  369. l.d $f0, V0_OFF2($sp)
  370. b cls_epilogue
  371. cls_retstruct_f:
  372. bne v0, FFI_TYPE_STRUCT_F, cls_retstruct_d_d
  373. l.s $f0, V0_OFF2($sp)
  374. b cls_epilogue
  375. cls_retstruct_d_d:
  376. bne v0, FFI_TYPE_STRUCT_DD, cls_retstruct_f_f
  377. l.d $f0, V0_OFF2($sp)
  378. l.d $f2, V1_OFF2($sp)
  379. b cls_epilogue
  380. cls_retstruct_f_f:
  381. bne v0, FFI_TYPE_STRUCT_FF, cls_retstruct_d_f
  382. l.s $f0, V0_OFF2($sp)
  383. l.s $f2, V1_OFF2($sp)
  384. b cls_epilogue
  385. cls_retstruct_d_f:
  386. bne v0, FFI_TYPE_STRUCT_DF, cls_retstruct_f_d
  387. l.d $f0, V0_OFF2($sp)
  388. l.s $f2, V1_OFF2($sp)
  389. b cls_epilogue
  390. cls_retstruct_f_d:
  391. bne v0, FFI_TYPE_STRUCT_FD, cls_retstruct_small2
  392. l.s $f0, V0_OFF2($sp)
  393. l.d $f2, V1_OFF2($sp)
  394. b cls_epilogue
  395. cls_retstruct_small2:
  396. REG_L v0, V0_OFF2($sp)
  397. REG_L v1, V1_OFF2($sp)
  398. # Epilogue
  399. cls_epilogue:
  400. REG_L ra, RA_OFF2($sp) # Restore return address
  401. .cpreturn
  402. ADDU $sp, SIZEOF_FRAME2
  403. j ra
  404. .LFE2:
  405. .end ffi_closure_N32
  406. .section .eh_frame,"aw",@progbits
  407. .Lframe1:
  408. .4byte .LECIE1-.LSCIE1 # length
  409. .LSCIE1:
  410. .4byte 0x0 # CIE
  411. .byte 0x1 # Version 1
  412. .ascii "\000" # Augmentation
  413. .uleb128 0x1 # Code alignment 1
  414. .sleb128 -4 # Data alignment -4
  415. .byte 0x1f # Return Address $31
  416. .byte 0xc # DW_CFA_def_cfa
  417. .uleb128 0x1d # in $sp
  418. .uleb128 0x0 # offset 0
  419. .align EH_FRAME_ALIGN
  420. .LECIE1:
  421. .LSFDE1:
  422. .4byte .LEFDE1-.LASFDE1 # length.
  423. .LASFDE1:
  424. .4byte .LASFDE1-.Lframe1 # CIE_pointer.
  425. FDE_ADDR_BYTES .LFB3 # initial_location.
  426. FDE_ADDR_BYTES .LFE3-.LFB3 # address_range.
  427. .byte 0x4 # DW_CFA_advance_loc4
  428. .4byte .LCFI0-.LFB3 # to .LCFI0
  429. .byte 0xe # DW_CFA_def_cfa_offset
  430. .uleb128 SIZEOF_FRAME # adjust stack.by SIZEOF_FRAME
  431. .byte 0x4 # DW_CFA_advance_loc4
  432. .4byte .LCFI1-.LCFI0 # to .LCFI1
  433. .byte 0x9e # DW_CFA_offset of $fp
  434. .uleb128 2*FFI_SIZEOF_ARG/4 #
  435. .byte 0x9f # DW_CFA_offset of ra
  436. .uleb128 1*FFI_SIZEOF_ARG/4 #
  437. .byte 0x4 # DW_CFA_advance_loc4
  438. .4byte .LCFI3-.LCFI1 # to .LCFI3
  439. .byte 0xd # DW_CFA_def_cfa_register
  440. .uleb128 0x1e # in $fp
  441. .align EH_FRAME_ALIGN
  442. .LEFDE1:
  443. .LSFDE3:
  444. .4byte .LEFDE3-.LASFDE3 # length
  445. .LASFDE3:
  446. .4byte .LASFDE3-.Lframe1 # CIE_pointer.
  447. FDE_ADDR_BYTES .LFB2 # initial_location.
  448. FDE_ADDR_BYTES .LFE2-.LFB2 # address_range.
  449. .byte 0x4 # DW_CFA_advance_loc4
  450. .4byte .LCFI5-.LFB2 # to .LCFI5
  451. .byte 0xe # DW_CFA_def_cfa_offset
  452. .uleb128 SIZEOF_FRAME2 # adjust stack.by SIZEOF_FRAME
  453. .byte 0x4 # DW_CFA_advance_loc4
  454. .4byte .LCFI6-.LCFI5 # to .LCFI6
  455. .byte 0x9c # DW_CFA_offset of $gp ($28)
  456. .uleb128 (SIZEOF_FRAME2 - GP_OFF2)/4
  457. .byte 0x9f # DW_CFA_offset of ra ($31)
  458. .uleb128 (SIZEOF_FRAME2 - RA_OFF2)/4
  459. .align EH_FRAME_ALIGN
  460. .LEFDE3:
  461. #endif