math.inc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. {
  2. Implementation of mathematical routines for x86_64
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2005 by the Free Pascal development team
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {-------------------------------------------------------------------------
  12. Using functions from AMath/DAMath libraries, which are covered by the
  13. following license:
  14. (C) Copyright 2009-2013 Wolfgang Ehrhardt
  15. This software is provided 'as-is', without any express or implied warranty.
  16. In no event will the authors be held liable for any damages arising from
  17. the use of this software.
  18. Permission is granted to anyone to use this software for any purpose,
  19. including commercial applications, and to alter it and redistribute it
  20. freely, subject to the following restrictions:
  21. 1. The origin of this software must not be misrepresented; you must not
  22. claim that you wrote the original software. If you use this software in
  23. a product, an acknowledgment in the product documentation would be
  24. appreciated but is not required.
  25. 2. Altered source versions must be plainly marked as such, and must not be
  26. misrepresented as being the original software.
  27. 3. This notice may not be removed or altered from any source distribution.
  28. ----------------------------------------------------------------------------}
  29. {$push}
  30. {$codealign constmin=16}
  31. const
  32. FPC_ABSMASK_SINGLE: array[0..1] of qword=($7fffffff7fffffff,$7fffffff7fffffff); cvar; public;
  33. FPC_ABSMASK_DOUBLE: array[0..1] of qword=($7fffffffffffffff,$7fffffffffffffff); cvar; public;
  34. {$pop}
  35. {****************************************************************************
  36. FPU Control word
  37. ****************************************************************************}
  38. procedure Set8087CW(cw:word);
  39. begin
  40. default8087cw:=cw;
  41. asm
  42. fnclex
  43. fldcw cw
  44. end;
  45. end;
  46. function Get8087CW:word;assembler;
  47. var
  48. tmp: word;
  49. asm
  50. fnstcw tmp
  51. movw tmp,%ax
  52. andl $0xffff,%eax { clears bits 32-63 }
  53. end;
  54. procedure SetMXCSR(w : dword);
  55. begin
  56. defaultmxcsr:=w;
  57. asm
  58. {$ifdef FPUX86_HAS_AVXUNIT}
  59. vldmxcsr w
  60. {$else FPUX86_HAS_AVXUNIT}
  61. ldmxcsr w
  62. {$endif FPUX86_HAS_AVXUNIT}
  63. end;
  64. end;
  65. function GetMXCSR : dword;assembler;
  66. var
  67. _w : dword;
  68. asm
  69. {$ifdef FPUX86_HAS_AVXUNIT}
  70. vstmxcsr _w
  71. {$else FPUX86_HAS_AVXUNIT}
  72. stmxcsr _w
  73. {$endif FPUX86_HAS_AVXUNIT}
  74. movl _w,%eax
  75. end;
  76. function GetNativeFPUControlWord: TNativeFPUControlWord; {$if defined(SYSTEMINLINE)}inline;{$endif}
  77. begin
  78. result.cw8087:=Get8087CW;
  79. result.MXCSR:=GetMXCSR
  80. end;
  81. procedure SetNativeFPUControlWord(const cw: TNativeFPUControlWord); {$if defined(SYSTEMINLINE)}inline;{$endif}
  82. begin
  83. Set8087CW(cw.cw8087);
  84. SetMXCSR(cw.MXCSR);
  85. end;
  86. procedure SetSSECSR(w : dword);
  87. begin
  88. SetMXCSR(w);
  89. end;
  90. function GetSSECSR: dword;
  91. begin
  92. result:=GetMXCSR;
  93. end;
  94. {****************************************************************************
  95. EXTENDED data type routines
  96. ****************************************************************************}
  97. {$ifndef FPC_SYSTEM_HAS_ABS}
  98. {$define FPC_SYSTEM_HAS_ABS}
  99. function fpc_abs_real(d : ValReal) : ValReal;compilerproc;
  100. {$ifndef cpullvm}
  101. begin
  102. { Function is handled internal in the compiler }
  103. runerror(207);
  104. result:=0;
  105. {$else not cpullvm}
  106. assembler;
  107. asm
  108. fldt d
  109. fabs
  110. {$endif not cpullvm}
  111. end;
  112. {$endif FPC_SYSTEM_HAS_ABS}
  113. {$ifndef FPC_SYSTEM_HAS_SQR}
  114. {$define FPC_SYSTEM_HAS_SQR}
  115. function fpc_sqr_real(d : ValReal) : ValReal;compilerproc;
  116. {$ifndef cpullvm}
  117. begin
  118. { Function is handled internal in the compiler }
  119. runerror(207);
  120. result:=0;
  121. {$else not cpullvm}
  122. begin
  123. fpc_sqr_real:=d*d;
  124. {$endif not cpullvm}
  125. end;
  126. {$endif FPC_SYSTEM_HAS_SQR}
  127. {$ifndef FPC_SYSTEM_HAS_SQRT}
  128. {$define FPC_SYSTEM_HAS_SQRT}
  129. function fpc_sqrt_real(d : ValReal) : ValReal;compilerproc;
  130. {$ifndef cpullvm}
  131. begin
  132. { Function is handled internal in the compiler }
  133. runerror(207);
  134. result:=0;
  135. {$else not cpullvm}
  136. assembler;
  137. asm
  138. fldt d
  139. fsqrt
  140. {$endif not cpullvm}
  141. end;
  142. {$endif FPC_SYSTEM_HAS_SQRT}
  143. {$ifdef FPC_HAS_TYPE_EXTENDED}
  144. {$ifndef FPC_SYSTEM_HAS_ARCTAN}
  145. {$define FPC_SYSTEM_HAS_ARCTAN}
  146. function fpc_arctan_real(d : ValReal) : ValReal;compilerproc;
  147. {$ifndef cpullvm}
  148. begin
  149. { Function is handled internal in the compiler }
  150. runerror(207);
  151. result:=0;
  152. {$else not cpullvm}
  153. assembler;
  154. asm
  155. fldt d
  156. fld1
  157. fpatan
  158. {$endif not cpullvm}
  159. end;
  160. {$endif FPC_SYSTEM_HAS_ARCTAN}
  161. {$ifndef FPC_SYSTEM_HAS_LN}
  162. {$define FPC_SYSTEM_HAS_LN}
  163. function fpc_ln_real(d : ValReal) : ValReal;compilerproc;
  164. {$ifndef cpullvm}
  165. begin
  166. { Function is handled internal in the compiler }
  167. runerror(207);
  168. result:=0;
  169. {$else not cpullvm}
  170. assembler;
  171. asm
  172. fldln2
  173. fldt d
  174. fyl2x
  175. {$endif not cpullvm}
  176. end;
  177. {$endif FPC_SYSTEM_HAS_LN}
  178. {$ifndef FPC_SYSTEM_HAS_SIN}
  179. {$define FPC_SYSTEM_HAS_SIN}
  180. function fpc_sin_real(d : ValReal) : ValReal;compilerproc;
  181. {$ifndef cpullvm}
  182. begin
  183. { Function is handled internal in the compiler }
  184. runerror(207);
  185. result:=0;
  186. {$else not cpullvm}
  187. assembler;
  188. asm
  189. fldt d
  190. fsin
  191. {$endif not cpullvm}
  192. end;
  193. {$endif FPC_SYSTEM_HAS_SIN}
  194. {$ifndef FPC_SYSTEM_HAS_COS}
  195. {$define FPC_SYSTEM_HAS_COS}
  196. function fpc_cos_real(d : ValReal) : ValReal;compilerproc;
  197. {$ifndef cpullvm}
  198. begin
  199. { Function is handled internal in the compiler }
  200. runerror(207);
  201. result:=0;
  202. {$else not cpullvm}
  203. assembler;
  204. asm
  205. fldt d
  206. fcos
  207. {$endif not cpullvm}
  208. end;
  209. {$endif FPC_SYSTEM_HAS_COS}
  210. {$ifndef FPC_SYSTEM_HAS_EXP}
  211. {$define FPC_SYSTEM_HAS_EXP}
  212. { exp function adapted from AMath library (C) Copyright 2009-2013 Wolfgang Ehrhardt
  213. * translated into AT&T syntax
  214. + PIC support
  215. * return +Inf/0 for +Inf/-Inf input, instead of NaN }
  216. function fpc_exp_real(d : ValReal) : ValReal;assembler;compilerproc;
  217. const
  218. ln2hi: double=6.9314718036912382E-001;
  219. ln2lo: double=1.9082149292705877E-010;
  220. large: single=24576.0;
  221. two: single=2.0;
  222. half: single=0.5;
  223. asm
  224. fldt d
  225. fldl2e
  226. fmul %st(1),%st { z = d * log2(e) }
  227. frndint
  228. { Calculate frac(z) using modular arithmetic to avoid precision loss }
  229. fldl ln2hi(%rip)
  230. fmul %st(1),%st
  231. fsubrp %st,%st(2)
  232. fldl ln2lo(%rip)
  233. fmul %st(1),%st
  234. fsubrp %st,%st(2)
  235. fxch %st(1) { (d-int(z)*ln2_hi)-int(z)*ln2_lo }
  236. fldl2e
  237. fmulp %st,%st(1) { frac(z) }
  238. { Above calculation can yield |frac(z)|>1, particularly when rounding mode
  239. is not "round to nearest". f2xm1 is undefined in that case, so it's
  240. necessary to check }
  241. fld %st
  242. fabs
  243. fld1
  244. fcomip %st(1),%st(0)
  245. fstp %st
  246. jp .L3 { NaN }
  247. jae .L1 { |frac(z)| <= 1, good }
  248. fld %st(1)
  249. fabs
  250. flds large(%rip)
  251. fcomip %st(1),%st(0)
  252. fstp %st
  253. jb .L3 { int(z) >= 24576 }
  254. .L0:
  255. { Calculate 2**frac(z)-1 as N*(N+2), where N=2**(frac(z)/2)-1 }
  256. fmuls half(%rip)
  257. f2xm1
  258. fld %st
  259. fadds two(%rip)
  260. fmulp %st,%st(1)
  261. jmp .L2
  262. .L3:
  263. fstp %st { pop frac(z) and load 0 }
  264. fldz
  265. .L1:
  266. f2xm1
  267. .L2:
  268. fld1
  269. faddp %st,%st(1)
  270. fscale
  271. fstp %st(1)
  272. end;
  273. {$endif FPC_SYSTEM_HAS_EXP}
  274. {$ifndef FPC_SYSTEM_HAS_FRAC}
  275. {$define FPC_SYSTEM_HAS_FRAC}
  276. function fpc_frac_real(d : ValReal) : ValReal;assembler;compilerproc;
  277. var
  278. oldcw,newcw: word;
  279. asm
  280. fnstcw oldcw
  281. fldt d
  282. movw oldcw,%cx
  283. orw $0x0c00,%cx
  284. movw %cx,newcw
  285. fldcw newcw
  286. fld %st
  287. frndint
  288. fsubrp %st,%st(1)
  289. fwait
  290. fldcw oldcw
  291. end;
  292. {$endif FPC_SYSTEM_HAS_FRAC}
  293. {$ifndef FPC_SYSTEM_HAS_INT}
  294. {$define FPC_SYSTEM_HAS_INT}
  295. function fpc_int_real(d : ValReal) : ValReal;assembler;compilerproc;
  296. var
  297. oldcw,newcw: word;
  298. asm
  299. fnstcw oldcw
  300. movw oldcw,%cx
  301. orw $0x0c00,%cx
  302. movw %cx,newcw
  303. fldcw newcw
  304. fldt d
  305. frndint
  306. fwait
  307. fldcw oldcw
  308. end;
  309. {$endif FPC_SYSTEM_HAS_INT}
  310. {$ifndef FPC_SYSTEM_HAS_TRUNC}
  311. {$define FPC_SYSTEM_HAS_TRUNC}
  312. function fpc_trunc_real(d : ValReal) : int64;assembler;compilerproc;
  313. var
  314. oldcw,
  315. newcw : word;
  316. res : int64;
  317. asm
  318. fnstcw oldcw
  319. movw oldcw,%cx
  320. orw $0x0c00,%cx
  321. movw %cx,newcw
  322. fldcw newcw
  323. fldt d
  324. fistpq res
  325. fwait
  326. movq res,%rax
  327. fldcw oldcw
  328. end;
  329. {$endif FPC_SYSTEM_HAS_TRUNC}
  330. {$ifndef FPC_SYSTEM_HAS_ROUND}
  331. {$define FPC_SYSTEM_HAS_ROUND}
  332. function fpc_round_real(d : ValReal) : int64;assembler;compilerproc;
  333. var
  334. res : int64;
  335. asm
  336. fldt d
  337. fistpq res
  338. fwait
  339. movq res,%rax
  340. end;
  341. {$endif FPC_SYSTEM_HAS_ROUND}
  342. {$else FPC_HAS_TYPE_EXTENDED}
  343. {$ifndef FPC_SYSTEM_HAS_INT}
  344. {$define FPC_SYSTEM_HAS_INT}
  345. function fpc_int_real(d : ValReal) : ValReal;compilerproc; assembler; nostackframe;
  346. asm
  347. movq %xmm0, %rax
  348. shr $48, %rax
  349. and $0x7ff0,%ax
  350. cmp $0x4330,%ax
  351. jge .L0
  352. cvttsd2si %xmm0, %rax
  353. cvtsi2sd %rax, %xmm0
  354. .L0:
  355. end;
  356. {$endif FPC_SYSTEM_HAS_INT}
  357. {$ifndef FPC_SYSTEM_HAS_TRUNC}
  358. {$define FPC_SYSTEM_HAS_TRUNC}
  359. function fpc_trunc_real(d : ValReal) : int64;compilerproc; assembler; nostackframe;
  360. asm
  361. cvttsd2si %xmm0,%rax;
  362. end;
  363. {$endif FPC_SYSTEM_HAS_TRUNC}
  364. {$ifndef FPC_SYSTEM_HAS_ROUND}
  365. {$define FPC_SYSTEM_HAS_ROUND}
  366. function fpc_round_real(d : ValReal) : int64;compilerproc; assembler; nostackframe;
  367. asm
  368. cvtsd2si %xmm0,%rax;
  369. end;
  370. {$endif FPC_SYSTEM_HAS_ROUND}
  371. {$ifndef FPC_SYSTEM_HAS_FRAC}
  372. {$define FPC_SYSTEM_HAS_FRAC}
  373. function fpc_frac_real(d: ValReal) : ValReal;compilerproc; assembler; nostackframe;
  374. asm
  375. { Windows defines %xmm4 and %xmm5 as first non-parameter volatile registers;
  376. on SYSV systems all are considered as such, so use %xmm4 }
  377. movq %xmm0, %rax
  378. movapd %xmm0, %xmm4
  379. shr $48, %rax
  380. and $0x7ff0,%ax
  381. cmp $0x4330,%ax
  382. jge .L0
  383. cvttsd2si %xmm0, %rax
  384. cvtsi2sd %rax, %xmm4
  385. .L0:
  386. subsd %xmm4, %xmm0
  387. end;
  388. {$endif FPC_SYSTEM_HAS_FRAC}
  389. {$endif FPC_HAS_TYPE_EXTENDED}