int64.inc 12 KB

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