int64.inc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by the Free Pascal development team
  5. This file contains some helper routines for int64 and qword
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {$Q- no overflow checking }
  13. {$R- no range checking }
  14. type
  15. {$ifdef ENDIAN_LITTLE}
  16. tqwordrec = packed record
  17. low : dword;
  18. high : dword;
  19. end;
  20. {$endif ENDIAN_LITTLE}
  21. {$ifdef ENDIAN_BIG}
  22. tqwordrec = packed record
  23. high : dword;
  24. low : dword;
  25. end;
  26. {$endif ENDIAN_BIG}
  27. {$ifdef FPC_INCLUDE_SOFTWARE_SHIFT_INT64}
  28. {$ifndef FPC_SYSTEM_HAS_SHL_QWORD}
  29. function fpc_shl_qword(value,shift : qword) : qword; [public,alias: 'FPC_SHL_QWORD']; {$ifdef hascompilerproc} compilerproc; {$endif}
  30. begin
  31. if shift=0 then
  32. result:=value
  33. else if shift>63 then
  34. result:=0
  35. else if shift>31 then
  36. begin
  37. tqwordrec(result).low:=0;
  38. tqwordrec(result).high:=tqwordrec(value).low shl (shift-32);
  39. end
  40. else
  41. begin
  42. tqwordrec(result).low:=tqwordrec(value).low shl shift;
  43. tqwordrec(result).high:=(tqwordrec(value).high shl shift) or (tqwordrec(value).low shr (32-shift));
  44. end;
  45. end;
  46. {$endif FPC_SYSTEM_HAS_SHL_QWORD}
  47. {$ifndef FPC_SYSTEM_HAS_SHR_QWORD}
  48. function fpc_shr_qword(value,shift : qword) : qword; [public,alias: 'FPC_SHR_QWORD']; {$ifdef hascompilerproc} compilerproc; {$endif}
  49. begin
  50. if shift=0 then
  51. result:=value
  52. else if shift>63 then
  53. result:=0
  54. else if shift>31 then
  55. begin
  56. tqwordrec(result).high:=0;
  57. tqwordrec(result).low:=tqwordrec(value).high shr (shift-32);
  58. end
  59. else
  60. begin
  61. tqwordrec(result).high:=tqwordrec(value).high shr shift;
  62. tqwordrec(result).low:=(tqwordrec(value).low shr shift) or (tqwordrec(value).high shl (32-shift));
  63. end;
  64. end;
  65. {$endif FPC_SYSTEM_HAS_SHR_QWORD}
  66. {$ifndef FPC_SYSTEM_HAS_SHL_INT64}
  67. function fpc_shl_int64(value,shift : int64) : int64; [public,alias: 'FPC_SHL_INT64']; {$ifdef hascompilerproc} compilerproc; {$endif}
  68. begin
  69. if shift=0 then
  70. result:=value
  71. else if shift>63 then
  72. result:=0
  73. else if shift>31 then
  74. begin
  75. tqwordrec(result).low:=0;
  76. tqwordrec(result).high:=tqwordrec(value).low shl (shift-32);
  77. end
  78. else
  79. begin
  80. tqwordrec(result).low:=tqwordrec(value).low shl shift;
  81. tqwordrec(result).high:=(tqwordrec(value).high shl shift) or (tqwordrec(value).low shr (32-shift));
  82. end;
  83. end;
  84. {$endif FPC_SYSTEM_HAS_SHL_INT64}
  85. {$ifndef FPC_SYSTEM_HAS_SHR_INT64}
  86. function fpc_shr_int64(value,shift : int64) : int64; [public,alias: 'FPC_SHR_INT64']; {$ifdef hascompilerproc} compilerproc; {$endif}
  87. begin
  88. if shift=0 then
  89. result:=value
  90. else if shift>63 then
  91. result:=0
  92. else if shift>31 then
  93. begin
  94. tqwordrec(result).high:=0;
  95. tqwordrec(result).low:=tqwordrec(value).high shr (shift-32);
  96. end
  97. else
  98. begin
  99. tqwordrec(result).high:=tqwordrec(value).high shr shift;
  100. tqwordrec(result).low:=(tqwordrec(value).low shr shift) or (tqwordrec(value).high shl (32-shift));
  101. end;
  102. end;
  103. {$endif FPC_SYSTEM_HAS_SHR_INT64}
  104. {$endif FPC_INCLUDE_SOFTWARE_SHIFT_INT64}
  105. function count_leading_zeros(q : qword) : longint;
  106. var
  107. r,i : longint;
  108. begin
  109. r:=0;
  110. for i:=0 to 31 do
  111. begin
  112. if (tqwordrec(q).high and (dword($80000000) shr i))<>0 then
  113. begin
  114. count_leading_zeros:=r;
  115. exit;
  116. end;
  117. inc(r);
  118. end;
  119. for i:=0 to 31 do
  120. begin
  121. if (tqwordrec(q).low and (dword($80000000) shr i))<>0 then
  122. begin
  123. count_leading_zeros:=r;
  124. exit;
  125. end;
  126. inc(r);
  127. end;
  128. count_leading_zeros:=r;
  129. end;
  130. {$ifndef FPC_SYSTEM_HAS_DIV_QWORD}
  131. function fpc_div_qword(n,z : qword) : qword;[public,alias: 'FPC_DIV_QWORD']; {$ifdef hascompilerproc} compilerproc; {$endif}
  132. var
  133. shift,lzz,lzn : longint;
  134. begin
  135. fpc_div_qword:=0;
  136. if n=0 then
  137. HandleErrorFrame(200,get_frame);
  138. lzz:=count_leading_zeros(z);
  139. lzn:=count_leading_zeros(n);
  140. { if the denominator contains less zeros }
  141. { then the numerator }
  142. { the d is greater than the n }
  143. if lzn<lzz then
  144. exit;
  145. shift:=lzn-lzz;
  146. n:=n shl shift;
  147. repeat
  148. if z>=n then
  149. begin
  150. z:=z-n;
  151. fpc_div_qword:=fpc_div_qword+(qword(1) shl shift);
  152. end;
  153. dec(shift);
  154. n:=n shr 1;
  155. until shift<0;
  156. end;
  157. {$endif FPC_SYSTEM_HAS_DIV_QWORD}
  158. {$ifndef FPC_SYSTEM_HAS_MOD_QWORD}
  159. function fpc_mod_qword(n,z : qword) : qword;[public,alias: 'FPC_MOD_QWORD']; {$ifdef hascompilerproc} compilerproc; {$endif}
  160. var
  161. shift,lzz,lzn : longint;
  162. begin
  163. fpc_mod_qword:=0;
  164. if n=0 then
  165. HandleErrorFrame(200,get_frame);
  166. lzz:=count_leading_zeros(z);
  167. lzn:=count_leading_zeros(n);
  168. { if the denominator contains less zeros }
  169. { then the numerator }
  170. { the d is greater than the n }
  171. if lzn<lzz then
  172. begin
  173. fpc_mod_qword:=z;
  174. exit;
  175. end;
  176. shift:=lzn-lzz;
  177. n:=n shl shift;
  178. repeat
  179. if z>=n then
  180. z:=z-n;
  181. dec(shift);
  182. n:=n shr 1;
  183. until shift<0;
  184. fpc_mod_qword:=z;
  185. end;
  186. {$endif FPC_SYSTEM_HAS_MOD_QWORD}
  187. {$ifndef FPC_SYSTEM_HAS_DIV_INT64}
  188. function fpc_div_int64(n,z : int64) : int64;[public,alias: 'FPC_DIV_INT64']; {$ifdef hascompilerproc} compilerproc; {$endif}
  189. var
  190. sign : boolean;
  191. q1,q2 : qword;
  192. begin
  193. if n=0 then
  194. HandleErrorFrame(200,get_frame);
  195. { can the fpu do the work? }
  196. begin
  197. sign:=false;
  198. if z<0 then
  199. begin
  200. sign:=not(sign);
  201. q1:=qword(-z);
  202. end
  203. else
  204. q1:=z;
  205. if n<0 then
  206. begin
  207. sign:=not(sign);
  208. q2:=qword(-n);
  209. end
  210. else
  211. q2:=n;
  212. { the div is coded by the compiler as call to divqword }
  213. if sign then
  214. fpc_div_int64:=-(q1 div q2)
  215. else
  216. fpc_div_int64:=q1 div q2;
  217. end;
  218. end;
  219. {$endif FPC_SYSTEM_HAS_DIV_INT64}
  220. {$ifndef FPC_SYSTEM_HAS_MOD_INT64}
  221. function fpc_mod_int64(n,z : int64) : int64;[public,alias: 'FPC_MOD_INT64']; {$ifdef hascompilerproc} compilerproc; {$endif}
  222. var
  223. signed : boolean;
  224. r,nq,zq : qword;
  225. begin
  226. if n=0 then
  227. HandleErrorFrame(200,get_frame);
  228. if n<0 then
  229. nq:=-n
  230. else
  231. nq:=n;
  232. if z<0 then
  233. begin
  234. signed:=true;
  235. zq:=qword(-z)
  236. end
  237. else
  238. begin
  239. signed:=false;
  240. zq:=z;
  241. end;
  242. r:=zq mod nq;
  243. if signed then
  244. fpc_mod_int64:=-int64(r)
  245. else
  246. fpc_mod_int64:=r;
  247. end;
  248. {$endif FPC_SYSTEM_HAS_MOD_INT64}
  249. {$ifndef FPC_SYSTEM_HAS_MUL_QWORD}
  250. { multiplies two qwords
  251. the longbool for checkoverflow avoids a misaligned stack
  252. }
  253. function fpc_mul_qword(f1,f2 : qword;checkoverflow : longbool) : qword;[public,alias: 'FPC_MUL_QWORD']; {$ifdef hascompilerproc} compilerproc; {$endif}
  254. var
  255. _f1,bitpos : qword;
  256. l : longint;
  257. begin
  258. fpc_mul_qword:=0;
  259. bitpos:=1;
  260. // store f1 for overflow checking
  261. _f1:=f1;
  262. for l:=0 to 63 do
  263. begin
  264. if (f2 and bitpos)<>0 then
  265. fpc_mul_qword:=fpc_mul_qword+f1;
  266. f1:=f1 shl 1;
  267. bitpos:=bitpos shl 1;
  268. end;
  269. { if one of the operands is greater than the result an }
  270. { overflow occurs }
  271. if checkoverflow and (_f1 <> 0) and (f2 <>0) and
  272. ((_f1>fpc_mul_qword) or (f2>fpc_mul_qword)) then
  273. HandleErrorFrame(215,get_frame);
  274. end;
  275. {$endif FPC_SYSTEM_HAS_MUL_QWORD}
  276. {$ifndef FPC_SYSTEM_HAS_MUL_INT64}
  277. function fpc_mul_int64(f1,f2 : int64;checkoverflow : longbool) : int64;[public,alias: 'FPC_MUL_INT64']; {$ifdef hascompilerproc} compilerproc; {$endif}
  278. var
  279. sign : boolean;
  280. q1,q2,q3 : qword;
  281. begin
  282. begin
  283. sign:=false;
  284. if f1<0 then
  285. begin
  286. sign:=not(sign);
  287. q1:=qword(-f1);
  288. end
  289. else
  290. q1:=f1;
  291. if f2<0 then
  292. begin
  293. sign:=not(sign);
  294. q2:=qword(-f2);
  295. end
  296. else
  297. q2:=f2;
  298. { the q1*q2 is coded as call to mulqword }
  299. q3:=q1*q2;
  300. if checkoverflow and (q1 <> 0) and (q2 <>0) and
  301. ((q1>q3) or (q2>q3) or
  302. { the bit 63 can be only set if we have $80000000 00000000 }
  303. { and sign is true }
  304. ((tqwordrec(q3).high and dword($80000000))<>0) and
  305. ((q3<>(qword(1) shl 63)) or not(sign))
  306. ) then
  307. HandleErrorFrame(215,get_frame);
  308. if sign then
  309. fpc_mul_int64:=-q3
  310. else
  311. fpc_mul_int64:=q3;
  312. end;
  313. end;
  314. {$endif FPC_SYSTEM_HAS_MUL_INT64}
  315. {
  316. $Log$
  317. Revision 1.25 2004-04-29 18:59:43 peter
  318. * str() helpers now also use valint/valuint
  319. * int64/qword helpers disabled for cpu64
  320. Revision 1.24 2004/04/24 17:14:09 florian
  321. * prt0.as exit code handling fixed
  322. * int64 mod int64 for negative numbers fixed
  323. Revision 1.23 2004/01/23 15:14:04 florian
  324. + implemented software shl/shr for 64 bit ints
  325. Revision 1.22 2003/09/14 11:34:13 peter
  326. * moved int64 asm code to int64p.inc
  327. * save ebx,esi
  328. Revision 1.21 2003/09/03 14:09:37 florian
  329. * arm fixes to the common rtl code
  330. * some generic math code fixed
  331. * ...
  332. Revision 1.20 2003/05/12 11:17:55 florian
  333. * fixed my commit, strange, it didn't give any conflicts with Jonas patch
  334. Revision 1.19 2003/05/12 11:16:21 florian
  335. * qword division fixed (MSB/LSB problem)
  336. Revision 1.18 2003/05/12 07:19:04 jonas
  337. * fixed for big endian systems (since Florian doesn't seem to want to
  338. commit this fix :)
  339. Revision 1.17 2002/09/07 21:21:42 carl
  340. - remove FPUInt64 variable
  341. Revision 1.16 2002/09/07 15:07:45 peter
  342. * old logs removed and tabs fixed
  343. Revision 1.15 2002/09/01 14:44:01 peter
  344. * renamed conditional to insert optimized mod_qword for i386. The
  345. code is broken
  346. Revision 1.14 2002/07/01 16:29:05 peter
  347. * sLineBreak changed to normal constant like Kylix
  348. }