mips16.S 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783
  1. /* mips16 floating point support code
  2. Copyright (C) 1996-2022 Free Software Foundation, Inc.
  3. Contributed by Cygnus Support
  4. This file is free software; you can redistribute it and/or modify it
  5. under the terms of the GNU General Public License as published by the
  6. Free Software Foundation; either version 3, or (at your option) any
  7. later version.
  8. This file is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. Under Section 7 of GPL version 3, you are granted additional
  13. permissions described in the GCC Runtime Library Exception, version
  14. 3.1, as published by the Free Software Foundation.
  15. You should have received a copy of the GNU General Public License and
  16. a copy of the GCC Runtime Library Exception along with this program;
  17. see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
  18. <http://www.gnu.org/licenses/>. */
  19. /* An executable stack is *not* required for these functions. */
  20. #include "gnustack.h"
  21. #include "auto-host.h"
  22. #if defined(__mips_micromips) || defined(__mips_soft_float) \
  23. || __mips_isa_rev >= 6
  24. /* Do nothing because this code is only needed when linking
  25. against mips16 hard-float objects. Neither micromips code
  26. nor soft-float nor MIPS R6 code can be linked against mips16
  27. hard-float objects so we do not need these routines when
  28. building libgcc for those cases. */
  29. #else
  30. #if defined(HAVE_AS_MODULE)
  31. #if __mips_fpr == 32
  32. .module fp=32
  33. #elif __mips_fpr == 0
  34. .module fp=xx
  35. #elif __mips_fpr == 64
  36. .module fp=64
  37. #endif
  38. #endif
  39. /* This file contains mips16 floating point support functions. These
  40. functions are called by mips16 code to handle floating point when
  41. -msoft-float is not used. They accept the arguments and return
  42. values using the soft-float calling convention, but do the actual
  43. operation using the hard floating point instructions. */
  44. #if defined _MIPS_SIM && (_MIPS_SIM == _ABIO32 || _MIPS_SIM == _ABIO64)
  45. /* This file contains 32-bit assembly code. */
  46. .set nomips16
  47. /* Start a function. */
  48. #define STARTFN(NAME) .globl NAME; .ent NAME; NAME:
  49. /* Finish a function. */
  50. #define ENDFN(NAME) .end NAME
  51. /* ARG1
  52. The FPR that holds the first floating-point argument.
  53. ARG2
  54. The FPR that holds the second floating-point argument.
  55. RET
  56. The FPR that holds a floating-point return value. */
  57. #define RET $f0
  58. #define ARG1 $f12
  59. #ifdef __mips64
  60. #define ARG2 $f13
  61. #else
  62. #define ARG2 $f14
  63. #endif
  64. /* Set 64-bit register GPR so that its high 32 bits contain HIGH_FPR
  65. and so that its low 32 bits contain LOW_FPR. */
  66. #define MERGE_GPRf(GPR, HIGH_FPR, LOW_FPR) \
  67. .set noat; \
  68. mfc1 $1, LOW_FPR; \
  69. mfc1 GPR, HIGH_FPR; \
  70. dsll $1, $1, 32; \
  71. dsll GPR, GPR, 32; \
  72. dsrl $1, $1, 32; \
  73. or GPR, GPR, $1; \
  74. .set at
  75. /* Move the high 32 bits of GPR to HIGH_FPR and the low 32 bits of
  76. GPR to LOW_FPR. */
  77. #define MERGE_GPRt(GPR, HIGH_FPR, LOW_FPR) \
  78. .set noat; \
  79. dsrl $1, GPR, 32; \
  80. mtc1 GPR, LOW_FPR; \
  81. mtc1 $1, HIGH_FPR; \
  82. .set at
  83. /* Jump to T, and use "OPCODE, OP2" to implement a delayed move. */
  84. #define DELAYt(T, OPCODE, OP2) \
  85. .set noreorder; \
  86. jr T; \
  87. OPCODE, OP2; \
  88. .set reorder
  89. #if __mips >= 4
  90. /* Coprocessor moves are interlocked from the MIPS IV ISA up. */
  91. #define DELAYf(T, OPCODE, OP2) DELAYt (T, OPCODE, OP2)
  92. #else
  93. /* Use "OPCODE. OP2" and jump to T. */
  94. #define DELAYf(T, OPCODE, OP2) OPCODE, OP2; jr T
  95. #endif
  96. /* MOVE_SF_BYTE0(D)
  97. Move the first single-precision floating-point argument between
  98. GPRs and FPRs.
  99. MOVE_SI_BYTE0(D)
  100. Likewise the first single-precision integer argument.
  101. MOVE_SF_BYTE4(D)
  102. Move the second single-precision floating-point argument between
  103. GPRs and FPRs, given that the first argument occupies 4 bytes.
  104. MOVE_SF_BYTE8(D)
  105. Move the second single-precision floating-point argument between
  106. GPRs and FPRs, given that the first argument occupies 8 bytes.
  107. MOVE_DF_BYTE0(D)
  108. Move the first double-precision floating-point argument between
  109. GPRs and FPRs.
  110. MOVE_DF_BYTE8(D)
  111. Likewise the second double-precision floating-point argument.
  112. MOVE_SF_RET(D, T)
  113. Likewise a single-precision floating-point return value,
  114. then jump to T.
  115. MOVE_SC_RET(D, T)
  116. Likewise a complex single-precision floating-point return value.
  117. MOVE_DF_RET(D, T)
  118. Likewise a double-precision floating-point return value.
  119. MOVE_DC_RET(D, T)
  120. Likewise a complex double-precision floating-point return value.
  121. MOVE_SI_RET(D, T)
  122. Likewise a single-precision integer return value.
  123. The D argument is "t" to move to FPRs and "f" to move from FPRs.
  124. The return macros may assume that the target of the jump does not
  125. use a floating-point register. */
  126. #define MOVE_SF_RET(D, T) DELAY##D (T, m##D##c1 $2,$f0)
  127. #define MOVE_SI_RET(D, T) DELAY##D (T, m##D##c1 $2,$f0)
  128. #if defined(__mips64) && defined(__MIPSEB__)
  129. #define MOVE_SC_RET(D, T) MERGE_GPR##D ($2, $f0, $f1); jr T
  130. #elif defined(__mips64)
  131. /* The high 32 bits of $2 correspond to the second word in memory;
  132. i.e. the imaginary part. */
  133. #define MOVE_SC_RET(D, T) MERGE_GPR##D ($2, $f1, $f0); jr T
  134. #else
  135. #define MOVE_SC_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f2)
  136. #endif
  137. #if defined(__mips64)
  138. #define MOVE_SF_BYTE0(D) m##D##c1 $4,$f12
  139. #define MOVE_SF_BYTE4(D) m##D##c1 $5,$f13
  140. #define MOVE_SF_BYTE8(D) m##D##c1 $5,$f13
  141. #else
  142. #define MOVE_SF_BYTE0(D) m##D##c1 $4,$f12
  143. #define MOVE_SF_BYTE4(D) m##D##c1 $5,$f14
  144. #define MOVE_SF_BYTE8(D) m##D##c1 $6,$f14
  145. #endif
  146. #define MOVE_SI_BYTE0(D) MOVE_SF_BYTE0(D)
  147. #if defined(__mips64)
  148. #define MOVE_DF_BYTE0(D) dm##D##c1 $4,$f12
  149. #define MOVE_DF_BYTE8(D) dm##D##c1 $5,$f13
  150. #define MOVE_DF_RET(D, T) DELAY##D (T, dm##D##c1 $2,$f0)
  151. #define MOVE_DC_RET(D, T) dm##D##c1 $3,$f1; MOVE_DF_RET (D, T)
  152. #elif __mips_fpr != 32 && __mips_isa_rev >= 2 && defined(__MIPSEB__)
  153. #define MOVE_DF_BYTE0(D) m##D##c1 $5,$f12; m##D##hc1 $4,$f12
  154. #define MOVE_DF_BYTE8(D) m##D##c1 $7,$f14; m##D##hc1 $6,$f14
  155. #define MOVE_DF_RET(D, T) m##D##c1 $3,$f0; DELAY##D (T, m##D##hc1 $2,$f0)
  156. #define MOVE_DC_RET(D, T) m##D##c1 $5,$f2; m##D##hc1 $4,$f2; MOVE_DF_RET (D, T)
  157. #elif __mips_fpr != 32 && __mips_isa_rev >= 2
  158. #define MOVE_DF_BYTE0(D) m##D##c1 $4,$f12; m##D##hc1 $5,$f12
  159. #define MOVE_DF_BYTE8(D) m##D##c1 $6,$f14; m##D##hc1 $7,$f14
  160. #define MOVE_DF_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##hc1 $3,$f0)
  161. #define MOVE_DC_RET(D, T) m##D##c1 $4,$f2; m##D##hc1 $5,$f2; MOVE_DF_RET (D, T)
  162. #elif __mips_fpr == 0
  163. #define MOVE_DF_BYTE0t sw $4, 0($29); sw $5, 4($29); ldc1 $f12, 0($29)
  164. #define MOVE_DF_BYTE0f sdc1 $f12, 0($29); lw $4, 0($29); lw $5, 4($29)
  165. #define MOVE_DF_BYTE0(D) MOVE_DF_BYTE0##D
  166. #define MOVE_DF_BYTE8t sw $6, 8($29); sw $7, 12($29); ldc1 $f14, 8($29)
  167. #define MOVE_DF_BYTE8f sdc1 $f14, 8($29); lw $6, 8($29); lw $7, 12($29)
  168. #define MOVE_DF_BYTE8(D) MOVE_DF_BYTE8##D
  169. #define MOVE_DF_RETt(T) sw $2, 0($29); sw $3, 4($29); DELAYt (T, ldc1 $f0, 0($29))
  170. #define MOVE_DF_RETf(T) sdc1 $f0, 0($29); lw $2, 0($29); DELAYf (T, lw $3, 4($29))
  171. #define MOVE_DF_RET(D, T) MOVE_DF_RET##D(T)
  172. #define MOVE_DC_RETt(T) sw $4, 8($29); sw $5, 12($29); ldc1 $f2, 8($29); MOVE_DF_RETt(T)
  173. #define MOVE_DC_RETf(T) sdc1 $f2, 8($29); lw $4, 8($29); lw $5, 12($29); MOVE_DF_RETf(T)
  174. #define MOVE_DC_RET(D, T) MOVE_DF_RET##D(T)
  175. #elif defined(__MIPSEB__)
  176. /* FPRs are little-endian. */
  177. #define MOVE_DF_BYTE0(D) m##D##c1 $4,$f13; m##D##c1 $5,$f12
  178. #define MOVE_DF_BYTE8(D) m##D##c1 $6,$f15; m##D##c1 $7,$f14
  179. #define MOVE_DF_RET(D, T) m##D##c1 $2,$f1; DELAY##D (T, m##D##c1 $3,$f0)
  180. #define MOVE_DC_RET(D, T) m##D##c1 $4,$f3; m##D##c1 $5,$f2; MOVE_DF_RET (D, T)
  181. #else
  182. #define MOVE_DF_BYTE0(D) m##D##c1 $4,$f12; m##D##c1 $5,$f13
  183. #define MOVE_DF_BYTE8(D) m##D##c1 $6,$f14; m##D##c1 $7,$f15
  184. #define MOVE_DF_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f1)
  185. #define MOVE_DC_RET(D, T) m##D##c1 $4,$f2; m##D##c1 $5,$f3; MOVE_DF_RET (D, T)
  186. #endif
  187. /* Single-precision math. */
  188. /* Define a function NAME that loads two single-precision values,
  189. performs FPU operation OPCODE on them, and returns the single-
  190. precision result. */
  191. #define OPSF3(NAME, OPCODE) \
  192. STARTFN (NAME); \
  193. MOVE_SF_BYTE0 (t); \
  194. MOVE_SF_BYTE4 (t); \
  195. OPCODE RET,ARG1,ARG2; \
  196. MOVE_SF_RET (f, $31); \
  197. ENDFN (NAME)
  198. #ifdef L_m16addsf3
  199. OPSF3 (__mips16_addsf3, add.s)
  200. #endif
  201. #ifdef L_m16subsf3
  202. OPSF3 (__mips16_subsf3, sub.s)
  203. #endif
  204. #ifdef L_m16mulsf3
  205. OPSF3 (__mips16_mulsf3, mul.s)
  206. #endif
  207. #ifdef L_m16divsf3
  208. OPSF3 (__mips16_divsf3, div.s)
  209. #endif
  210. /* Define a function NAME that loads a single-precision value,
  211. performs FPU operation OPCODE on it, and returns the single-
  212. precision result. */
  213. #define OPSF2(NAME, OPCODE) \
  214. STARTFN (NAME); \
  215. MOVE_SF_BYTE0 (t); \
  216. OPCODE RET,ARG1; \
  217. MOVE_SF_RET (f, $31); \
  218. ENDFN (NAME)
  219. #ifdef L_m16negsf2
  220. OPSF2 (__mips16_negsf2, neg.s)
  221. #endif
  222. #ifdef L_m16abssf2
  223. OPSF2 (__mips16_abssf2, abs.s)
  224. #endif
  225. /* Single-precision comparisons. */
  226. /* Define a function NAME that loads two single-precision values,
  227. performs floating point comparison OPCODE, and returns TRUE or
  228. FALSE depending on the result. */
  229. #define CMPSF(NAME, OPCODE, TRUE, FALSE) \
  230. STARTFN (NAME); \
  231. MOVE_SF_BYTE0 (t); \
  232. MOVE_SF_BYTE4 (t); \
  233. OPCODE ARG1,ARG2; \
  234. li $2,TRUE; \
  235. bc1t 1f; \
  236. li $2,FALSE; \
  237. 1:; \
  238. j $31; \
  239. ENDFN (NAME)
  240. /* Like CMPSF, but reverse the comparison operands. */
  241. #define REVCMPSF(NAME, OPCODE, TRUE, FALSE) \
  242. STARTFN (NAME); \
  243. MOVE_SF_BYTE0 (t); \
  244. MOVE_SF_BYTE4 (t); \
  245. OPCODE ARG2,ARG1; \
  246. li $2,TRUE; \
  247. bc1t 1f; \
  248. li $2,FALSE; \
  249. 1:; \
  250. j $31; \
  251. ENDFN (NAME)
  252. #ifdef L_m16eqsf2
  253. CMPSF (__mips16_eqsf2, c.eq.s, 0, 1)
  254. #endif
  255. #ifdef L_m16nesf2
  256. CMPSF (__mips16_nesf2, c.eq.s, 0, 1)
  257. #endif
  258. #ifdef L_m16gtsf2
  259. REVCMPSF (__mips16_gtsf2, c.lt.s, 1, 0)
  260. #endif
  261. #ifdef L_m16gesf2
  262. REVCMPSF (__mips16_gesf2, c.le.s, 0, -1)
  263. #endif
  264. #ifdef L_m16lesf2
  265. CMPSF (__mips16_lesf2, c.le.s, 0, 1)
  266. #endif
  267. #ifdef L_m16ltsf2
  268. CMPSF (__mips16_ltsf2, c.lt.s, -1, 0)
  269. #endif
  270. #ifdef L_m16unordsf2
  271. CMPSF(__mips16_unordsf2, c.un.s, 1, 0)
  272. #endif
  273. /* Single-precision conversions. */
  274. #ifdef L_m16fltsisf
  275. STARTFN (__mips16_floatsisf)
  276. MOVE_SF_BYTE0 (t)
  277. cvt.s.w RET,ARG1
  278. MOVE_SF_RET (f, $31)
  279. ENDFN (__mips16_floatsisf)
  280. #endif
  281. #ifdef L_m16fltunsisf
  282. STARTFN (__mips16_floatunsisf)
  283. .set noreorder
  284. bltz $4,1f
  285. MOVE_SF_BYTE0 (t)
  286. .set reorder
  287. cvt.s.w RET,ARG1
  288. MOVE_SF_RET (f, $31)
  289. 1:
  290. and $2,$4,1
  291. srl $3,$4,1
  292. or $2,$2,$3
  293. mtc1 $2,RET
  294. cvt.s.w RET,RET
  295. add.s RET,RET,RET
  296. MOVE_SF_RET (f, $31)
  297. ENDFN (__mips16_floatunsisf)
  298. #endif
  299. #ifdef L_m16fix_truncsfsi
  300. STARTFN (__mips16_fix_truncsfsi)
  301. MOVE_SF_BYTE0 (t)
  302. trunc.w.s RET,ARG1,$4
  303. MOVE_SI_RET (f, $31)
  304. ENDFN (__mips16_fix_truncsfsi)
  305. #endif
  306. #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
  307. /* Double-precision math. */
  308. /* Define a function NAME that loads two double-precision values,
  309. performs FPU operation OPCODE on them, and returns the double-
  310. precision result. */
  311. #define OPDF3(NAME, OPCODE) \
  312. STARTFN (NAME); \
  313. MOVE_DF_BYTE0 (t); \
  314. MOVE_DF_BYTE8 (t); \
  315. OPCODE RET,ARG1,ARG2; \
  316. MOVE_DF_RET (f, $31); \
  317. ENDFN (NAME)
  318. #ifdef L_m16adddf3
  319. OPDF3 (__mips16_adddf3, add.d)
  320. #endif
  321. #ifdef L_m16subdf3
  322. OPDF3 (__mips16_subdf3, sub.d)
  323. #endif
  324. #ifdef L_m16muldf3
  325. OPDF3 (__mips16_muldf3, mul.d)
  326. #endif
  327. #ifdef L_m16divdf3
  328. OPDF3 (__mips16_divdf3, div.d)
  329. #endif
  330. /* Define a function NAME that loads a double-precision value,
  331. performs FPU operation OPCODE on it, and returns the double-
  332. precision result. */
  333. #define OPDF2(NAME, OPCODE) \
  334. STARTFN (NAME); \
  335. MOVE_DF_BYTE0 (t); \
  336. OPCODE RET,ARG1; \
  337. MOVE_DF_RET (f, $31); \
  338. ENDFN (NAME)
  339. #ifdef L_m16negdf2
  340. OPDF2 (__mips16_negdf2, neg.d)
  341. #endif
  342. #ifdef L_m16absdf2
  343. OPDF2 (__mips16_absdf2, abs.d)
  344. #endif
  345. /* Conversions between single and double precision. */
  346. #ifdef L_m16extsfdf2
  347. STARTFN (__mips16_extendsfdf2)
  348. MOVE_SF_BYTE0 (t)
  349. cvt.d.s RET,ARG1
  350. MOVE_DF_RET (f, $31)
  351. ENDFN (__mips16_extendsfdf2)
  352. #endif
  353. #ifdef L_m16trdfsf2
  354. STARTFN (__mips16_truncdfsf2)
  355. MOVE_DF_BYTE0 (t)
  356. cvt.s.d RET,ARG1
  357. MOVE_SF_RET (f, $31)
  358. ENDFN (__mips16_truncdfsf2)
  359. #endif
  360. /* Double-precision comparisons. */
  361. /* Define a function NAME that loads two double-precision values,
  362. performs floating point comparison OPCODE, and returns TRUE or
  363. FALSE depending on the result. */
  364. #define CMPDF(NAME, OPCODE, TRUE, FALSE) \
  365. STARTFN (NAME); \
  366. MOVE_DF_BYTE0 (t); \
  367. MOVE_DF_BYTE8 (t); \
  368. OPCODE ARG1,ARG2; \
  369. li $2,TRUE; \
  370. bc1t 1f; \
  371. li $2,FALSE; \
  372. 1:; \
  373. j $31; \
  374. ENDFN (NAME)
  375. /* Like CMPDF, but reverse the comparison operands. */
  376. #define REVCMPDF(NAME, OPCODE, TRUE, FALSE) \
  377. STARTFN (NAME); \
  378. MOVE_DF_BYTE0 (t); \
  379. MOVE_DF_BYTE8 (t); \
  380. OPCODE ARG2,ARG1; \
  381. li $2,TRUE; \
  382. bc1t 1f; \
  383. li $2,FALSE; \
  384. 1:; \
  385. j $31; \
  386. ENDFN (NAME)
  387. #ifdef L_m16eqdf2
  388. CMPDF (__mips16_eqdf2, c.eq.d, 0, 1)
  389. #endif
  390. #ifdef L_m16nedf2
  391. CMPDF (__mips16_nedf2, c.eq.d, 0, 1)
  392. #endif
  393. #ifdef L_m16gtdf2
  394. REVCMPDF (__mips16_gtdf2, c.lt.d, 1, 0)
  395. #endif
  396. #ifdef L_m16gedf2
  397. REVCMPDF (__mips16_gedf2, c.le.d, 0, -1)
  398. #endif
  399. #ifdef L_m16ledf2
  400. CMPDF (__mips16_ledf2, c.le.d, 0, 1)
  401. #endif
  402. #ifdef L_m16ltdf2
  403. CMPDF (__mips16_ltdf2, c.lt.d, -1, 0)
  404. #endif
  405. #ifdef L_m16unorddf2
  406. CMPDF(__mips16_unorddf2, c.un.d, 1, 0)
  407. #endif
  408. /* Double-precision conversions. */
  409. #ifdef L_m16fltsidf
  410. STARTFN (__mips16_floatsidf)
  411. MOVE_SI_BYTE0 (t)
  412. cvt.d.w RET,ARG1
  413. MOVE_DF_RET (f, $31)
  414. ENDFN (__mips16_floatsidf)
  415. #endif
  416. #ifdef L_m16fltunsidf
  417. STARTFN (__mips16_floatunsidf)
  418. MOVE_SI_BYTE0 (t)
  419. cvt.d.w RET,ARG1
  420. bgez $4,1f
  421. li.d ARG1, 4.294967296e+9
  422. add.d RET, RET, ARG1
  423. 1: MOVE_DF_RET (f, $31)
  424. ENDFN (__mips16_floatunsidf)
  425. #endif
  426. #ifdef L_m16fix_truncdfsi
  427. STARTFN (__mips16_fix_truncdfsi)
  428. MOVE_DF_BYTE0 (t)
  429. trunc.w.d RET,ARG1,$4
  430. MOVE_SI_RET (f, $31)
  431. ENDFN (__mips16_fix_truncdfsi)
  432. #endif
  433. #endif /* !__mips_single_float */
  434. /* We don't export stubs from libgcc_s.so and always require static
  435. versions to be pulled from libgcc.a as needed because they use $2
  436. and possibly $3 as arguments, diverging from the standard SysV ABI,
  437. and as such would require severe pessimisation of MIPS16 PLT entries
  438. just for this single special case.
  439. For compatibility with old binaries that used safe standard MIPS PLT
  440. entries and referred to these functions we still export them at
  441. version GCC_4.4.0 for run-time loading only. */
  442. #ifdef SHARED
  443. #define CE_STARTFN(NAME) \
  444. STARTFN (NAME##_compat); \
  445. .symver NAME##_compat, NAME@GCC_4.4.0
  446. #define CE_ENDFN(NAME) ENDFN (NAME##_compat)
  447. #else
  448. #define CE_STARTFN(NAME) \
  449. STARTFN (NAME); \
  450. .hidden NAME
  451. #define CE_ENDFN(NAME) ENDFN (NAME)
  452. #endif
  453. /* Define a function NAME that moves a return value of mode MODE from
  454. FPRs to GPRs. */
  455. #define RET_FUNCTION(NAME, MODE) \
  456. CE_STARTFN (NAME); \
  457. MOVE_##MODE##_RET (t, $31); \
  458. CE_ENDFN (NAME)
  459. #ifdef L_m16retsf
  460. RET_FUNCTION (__mips16_ret_sf, SF)
  461. #endif
  462. #ifdef L_m16retsc
  463. RET_FUNCTION (__mips16_ret_sc, SC)
  464. #endif
  465. #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
  466. #ifdef L_m16retdf
  467. RET_FUNCTION (__mips16_ret_df, DF)
  468. #endif
  469. #ifdef L_m16retdc
  470. RET_FUNCTION (__mips16_ret_dc, DC)
  471. #endif
  472. #endif /* !__mips_single_float */
  473. /* STUB_ARGS_X copies the arguments from GPRs to FPRs for argument
  474. code X. X is calculated as ARG1 + ARG2 * 4, where ARG1 and ARG2
  475. classify the first and second arguments as follows:
  476. 1: a single-precision argument
  477. 2: a double-precision argument
  478. 0: no argument, or not one of the above. */
  479. #define STUB_ARGS_0 /* () */
  480. #define STUB_ARGS_1 MOVE_SF_BYTE0 (t) /* (sf) */
  481. #define STUB_ARGS_5 MOVE_SF_BYTE0 (t); MOVE_SF_BYTE4 (t) /* (sf, sf) */
  482. #define STUB_ARGS_9 MOVE_SF_BYTE0 (t); MOVE_DF_BYTE8 (t) /* (sf, df) */
  483. #define STUB_ARGS_2 MOVE_DF_BYTE0 (t) /* (df) */
  484. #define STUB_ARGS_6 MOVE_DF_BYTE0 (t); MOVE_SF_BYTE8 (t) /* (df, sf) */
  485. #define STUB_ARGS_10 MOVE_DF_BYTE0 (t); MOVE_DF_BYTE8 (t) /* (df, df) */
  486. /* These functions are used by 16-bit code when calling via a function
  487. pointer. They must copy the floating point arguments from the GPRs
  488. to FPRs and then call function $2. */
  489. #define CALL_STUB_NO_RET(NAME, CODE) \
  490. CE_STARTFN (NAME); \
  491. STUB_ARGS_##CODE; \
  492. .set noreorder; \
  493. jr $2; \
  494. move $25,$2; \
  495. .set reorder; \
  496. CE_ENDFN (NAME)
  497. #ifdef L_m16stub1
  498. CALL_STUB_NO_RET (__mips16_call_stub_1, 1)
  499. #endif
  500. #ifdef L_m16stub5
  501. CALL_STUB_NO_RET (__mips16_call_stub_5, 5)
  502. #endif
  503. #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
  504. #ifdef L_m16stub2
  505. CALL_STUB_NO_RET (__mips16_call_stub_2, 2)
  506. #endif
  507. #ifdef L_m16stub6
  508. CALL_STUB_NO_RET (__mips16_call_stub_6, 6)
  509. #endif
  510. #ifdef L_m16stub9
  511. CALL_STUB_NO_RET (__mips16_call_stub_9, 9)
  512. #endif
  513. #ifdef L_m16stub10
  514. CALL_STUB_NO_RET (__mips16_call_stub_10, 10)
  515. #endif
  516. #endif /* !__mips_single_float */
  517. /* Now we have the same set of functions, except that this time the
  518. function being called returns an SFmode, SCmode, DFmode or DCmode
  519. value; we need to instantiate a set for each case. The calling
  520. function will arrange to preserve $18, so these functions are free
  521. to use it to hold the return address.
  522. Note that we do not know whether the function we are calling is 16
  523. bit or 32 bit. However, it does not matter, because 16-bit
  524. functions always return floating point values in both the gp and
  525. the fp regs. It would be possible to check whether the function
  526. being called is 16 bits, in which case the copy is unnecessary;
  527. however, it's faster to always do the copy. */
  528. #define CALL_STUB_RET(NAME, CODE, MODE) \
  529. CE_STARTFN (NAME); \
  530. .cfi_startproc; \
  531. /* Create a fake CFA 4 bytes below the stack pointer. */ \
  532. .cfi_def_cfa 29,-4; \
  533. /* "Save" $sp in itself so we don't use the fake CFA. \
  534. This is: DW_CFA_val_expression r29, { DW_OP_reg29 }. */ \
  535. .cfi_escape 0x16,29,1,0x6d; \
  536. move $18,$31; \
  537. .cfi_register 31,18; \
  538. STUB_ARGS_##CODE; \
  539. .set noreorder; \
  540. jalr $2; \
  541. move $25,$2; \
  542. .set reorder; \
  543. MOVE_##MODE##_RET (f, $18); \
  544. .cfi_endproc; \
  545. CE_ENDFN (NAME)
  546. /* First, instantiate the single-float set. */
  547. #ifdef L_m16stubsf0
  548. CALL_STUB_RET (__mips16_call_stub_sf_0, 0, SF)
  549. #endif
  550. #ifdef L_m16stubsf1
  551. CALL_STUB_RET (__mips16_call_stub_sf_1, 1, SF)
  552. #endif
  553. #ifdef L_m16stubsf5
  554. CALL_STUB_RET (__mips16_call_stub_sf_5, 5, SF)
  555. #endif
  556. #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
  557. #ifdef L_m16stubsf2
  558. CALL_STUB_RET (__mips16_call_stub_sf_2, 2, SF)
  559. #endif
  560. #ifdef L_m16stubsf6
  561. CALL_STUB_RET (__mips16_call_stub_sf_6, 6, SF)
  562. #endif
  563. #ifdef L_m16stubsf9
  564. CALL_STUB_RET (__mips16_call_stub_sf_9, 9, SF)
  565. #endif
  566. #ifdef L_m16stubsf10
  567. CALL_STUB_RET (__mips16_call_stub_sf_10, 10, SF)
  568. #endif
  569. #endif /* !__mips_single_float */
  570. /* Now we have the same set of functions again, except that this time
  571. the function being called returns an DFmode value. */
  572. #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
  573. #ifdef L_m16stubdf0
  574. CALL_STUB_RET (__mips16_call_stub_df_0, 0, DF)
  575. #endif
  576. #ifdef L_m16stubdf1
  577. CALL_STUB_RET (__mips16_call_stub_df_1, 1, DF)
  578. #endif
  579. #ifdef L_m16stubdf5
  580. CALL_STUB_RET (__mips16_call_stub_df_5, 5, DF)
  581. #endif
  582. #ifdef L_m16stubdf2
  583. CALL_STUB_RET (__mips16_call_stub_df_2, 2, DF)
  584. #endif
  585. #ifdef L_m16stubdf6
  586. CALL_STUB_RET (__mips16_call_stub_df_6, 6, DF)
  587. #endif
  588. #ifdef L_m16stubdf9
  589. CALL_STUB_RET (__mips16_call_stub_df_9, 9, DF)
  590. #endif
  591. #ifdef L_m16stubdf10
  592. CALL_STUB_RET (__mips16_call_stub_df_10, 10, DF)
  593. #endif
  594. #endif /* !__mips_single_float */
  595. /* Ho hum. Here we have the same set of functions again, this time
  596. for when the function being called returns an SCmode value. */
  597. #ifdef L_m16stubsc0
  598. CALL_STUB_RET (__mips16_call_stub_sc_0, 0, SC)
  599. #endif
  600. #ifdef L_m16stubsc1
  601. CALL_STUB_RET (__mips16_call_stub_sc_1, 1, SC)
  602. #endif
  603. #ifdef L_m16stubsc5
  604. CALL_STUB_RET (__mips16_call_stub_sc_5, 5, SC)
  605. #endif
  606. #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
  607. #ifdef L_m16stubsc2
  608. CALL_STUB_RET (__mips16_call_stub_sc_2, 2, SC)
  609. #endif
  610. #ifdef L_m16stubsc6
  611. CALL_STUB_RET (__mips16_call_stub_sc_6, 6, SC)
  612. #endif
  613. #ifdef L_m16stubsc9
  614. CALL_STUB_RET (__mips16_call_stub_sc_9, 9, SC)
  615. #endif
  616. #ifdef L_m16stubsc10
  617. CALL_STUB_RET (__mips16_call_stub_sc_10, 10, SC)
  618. #endif
  619. #endif /* !__mips_single_float */
  620. /* Finally, another set of functions for DCmode. */
  621. #if !defined(__mips_single_float) && !defined(__SINGLE_FLOAT)
  622. #ifdef L_m16stubdc0
  623. CALL_STUB_RET (__mips16_call_stub_dc_0, 0, DC)
  624. #endif
  625. #ifdef L_m16stubdc1
  626. CALL_STUB_RET (__mips16_call_stub_dc_1, 1, DC)
  627. #endif
  628. #ifdef L_m16stubdc5
  629. CALL_STUB_RET (__mips16_call_stub_dc_5, 5, DC)
  630. #endif
  631. #ifdef L_m16stubdc2
  632. CALL_STUB_RET (__mips16_call_stub_dc_2, 2, DC)
  633. #endif
  634. #ifdef L_m16stubdc6
  635. CALL_STUB_RET (__mips16_call_stub_dc_6, 6, DC)
  636. #endif
  637. #ifdef L_m16stubdc9
  638. CALL_STUB_RET (__mips16_call_stub_dc_9, 9, DC)
  639. #endif
  640. #ifdef L_m16stubdc10
  641. CALL_STUB_RET (__mips16_call_stub_dc_10, 10, DC)
  642. #endif
  643. #endif /* !__mips_single_float */
  644. #endif
  645. #endif /* defined(__mips_micromips) || defined(__mips_soft_float) */