int64.inc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by the Free Pascal development team
  4. This file contains some helper routines for int64 and qword
  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. {$Q- no overflow checking }
  12. {$R- no range checking }
  13. type
  14. {$ifdef ENDIAN_LITTLE}
  15. tqwordrec = packed record
  16. low : dword;
  17. high : dword;
  18. end;
  19. {$endif ENDIAN_LITTLE}
  20. {$ifdef ENDIAN_BIG}
  21. tqwordrec = packed record
  22. high : dword;
  23. low : dword;
  24. end;
  25. {$endif ENDIAN_BIG}
  26. {$ifdef FPC_INCLUDE_SOFTWARE_SHIFT_INT64}
  27. {$ifndef FPC_SYSTEM_HAS_SHL_QWORD}
  28. function fpc_shl_qword(value : qword;shift : sizeint) : qword; [public,alias: 'FPC_SHL_QWORD']; compilerproc;
  29. begin
  30. shift:=shift and 63;
  31. if shift=0 then
  32. result:=value
  33. else if shift>31 then
  34. begin
  35. tqwordrec(result).low:=0;
  36. tqwordrec(result).high:=tqwordrec(value).low shl (shift-32);
  37. end
  38. else
  39. begin
  40. tqwordrec(result).low:=tqwordrec(value).low shl shift;
  41. tqwordrec(result).high:=(tqwordrec(value).high shl shift) or (tqwordrec(value).low shr (32-shift));
  42. end;
  43. end;
  44. {$endif FPC_SYSTEM_HAS_SHL_QWORD}
  45. {$ifndef FPC_SYSTEM_HAS_SHR_QWORD}
  46. function fpc_shr_qword(value : qword;shift : sizeint) : qword; [public,alias: 'FPC_SHR_QWORD']; compilerproc;
  47. begin
  48. shift:=shift and 63;
  49. if shift=0 then
  50. result:=value
  51. else if shift>31 then
  52. begin
  53. tqwordrec(result).high:=0;
  54. tqwordrec(result).low:=tqwordrec(value).high shr (shift-32);
  55. end
  56. else
  57. begin
  58. tqwordrec(result).high:=tqwordrec(value).high shr shift;
  59. tqwordrec(result).low:=(tqwordrec(value).low shr shift) or (tqwordrec(value).high shl (32-shift));
  60. end;
  61. end;
  62. {$endif FPC_SYSTEM_HAS_SHR_QWORD}
  63. {$ifndef FPC_SYSTEM_HAS_SHL_INT64}
  64. function fpc_shl_int64(value : int64;shift : sizeint) : int64; [public,alias: 'FPC_SHL_INT64']; compilerproc;
  65. begin
  66. shift:=shift and 63;
  67. if shift=0 then
  68. result:=value
  69. else if shift>31 then
  70. begin
  71. tqwordrec(result).low:=0;
  72. tqwordrec(result).high:=tqwordrec(value).low shl (shift-32);
  73. end
  74. else
  75. begin
  76. tqwordrec(result).low:=tqwordrec(value).low shl shift;
  77. tqwordrec(result).high:=(tqwordrec(value).high shl shift) or (tqwordrec(value).low shr (32-shift));
  78. end;
  79. end;
  80. {$endif FPC_SYSTEM_HAS_SHL_INT64}
  81. {$ifndef FPC_SYSTEM_HAS_SHR_INT64}
  82. function fpc_shr_int64(value : int64;shift : sizeint) : int64; [public,alias: 'FPC_SHR_INT64']; compilerproc;
  83. begin
  84. shift:=shift and 63;
  85. if shift=0 then
  86. result:=value
  87. else if shift>31 then
  88. begin
  89. tqwordrec(result).high:=0;
  90. tqwordrec(result).low:=tqwordrec(value).high shr (shift-32);
  91. end
  92. else
  93. begin
  94. tqwordrec(result).high:=tqwordrec(value).high shr shift;
  95. tqwordrec(result).low:=(tqwordrec(value).low shr shift) or (tqwordrec(value).high shl (32-shift));
  96. end;
  97. end;
  98. {$endif FPC_SYSTEM_HAS_SHR_INT64}
  99. {$endif FPC_INCLUDE_SOFTWARE_SHIFT_INT64}
  100. {$ifndef FPC_SYSTEM_HAS_DIV_QWORD}
  101. function fpc_div_qword(n,z : qword) : qword;[public,alias: 'FPC_DIV_QWORD']; compilerproc;
  102. var
  103. shift,lzz,lzn : longint;
  104. begin
  105. { Use the usually faster 32-bit division if possible }
  106. if (hi(z) = 0) and (hi(n) = 0) then
  107. begin
  108. fpc_div_qword := Dword(z) div Dword(n);
  109. exit;
  110. end;
  111. fpc_div_qword:=0;
  112. if n=0 then
  113. HandleErrorAddrFrameInd(200,get_pc_addr,get_frame);
  114. if z=0 then
  115. exit;
  116. lzz:=BsrQWord(z);
  117. lzn:=BsrQWord(n);
  118. { if the denominator contains less zeros }
  119. { than the numerator }
  120. { then d is greater than the n }
  121. if lzn>lzz then
  122. exit;
  123. shift:=lzz-lzn;
  124. n:=n shl shift;
  125. for shift:=shift downto 0 do
  126. begin
  127. if z>=n then
  128. begin
  129. z:=z-n;
  130. fpc_div_qword:=fpc_div_qword+(qword(1) shl shift);
  131. end;
  132. n:=n shr 1;
  133. end;
  134. end;
  135. {$endif FPC_SYSTEM_HAS_DIV_QWORD}
  136. {$ifndef FPC_SYSTEM_HAS_MOD_QWORD}
  137. function fpc_mod_qword(n,z : qword) : qword;[public,alias: 'FPC_MOD_QWORD']; compilerproc;
  138. var
  139. shift,lzz,lzn : longint;
  140. begin
  141. { Use the usually faster 32-bit mod if possible }
  142. if (hi(z) = 0) and (hi(n) = 0) then
  143. begin
  144. fpc_mod_qword := Dword(z) mod Dword(n);
  145. exit;
  146. end;
  147. fpc_mod_qword:=0;
  148. if n=0 then
  149. HandleErrorAddrFrameInd(200,get_pc_addr,get_frame);
  150. if z=0 then
  151. exit;
  152. lzz:=BsrQword(z);
  153. lzn:=BsrQword(n);
  154. { if the denominator contains less zeros }
  155. { then the numerator }
  156. { the d is greater than the n }
  157. if lzn>lzz then
  158. begin
  159. fpc_mod_qword:=z;
  160. exit;
  161. end;
  162. shift:=lzz-lzn;
  163. n:=n shl shift;
  164. for shift:=shift downto 0 do
  165. begin
  166. if z>=n then
  167. z:=z-n;
  168. n:=n shr 1;
  169. end;
  170. fpc_mod_qword:=z;
  171. end;
  172. {$endif FPC_SYSTEM_HAS_MOD_QWORD}
  173. {$ifndef FPC_SYSTEM_HAS_DIV_INT64}
  174. function fpc_div_int64(n,z : int64) : int64;[public,alias: 'FPC_DIV_INT64']; compilerproc;
  175. var
  176. sign : boolean;
  177. q1,q2 : qword;
  178. begin
  179. if n=0 then
  180. HandleErrorAddrFrameInd(200,get_pc_addr,get_frame);
  181. { can the fpu do the work? }
  182. begin
  183. sign:=false;
  184. if z<0 then
  185. begin
  186. sign:=not(sign);
  187. q1:=qword(-z);
  188. end
  189. else
  190. q1:=z;
  191. if n<0 then
  192. begin
  193. sign:=not(sign);
  194. q2:=qword(-n);
  195. end
  196. else
  197. q2:=n;
  198. { the div is coded by the compiler as call to divqword }
  199. if sign then
  200. fpc_div_int64:=-(q1 div q2)
  201. else
  202. fpc_div_int64:=q1 div q2;
  203. end;
  204. end;
  205. {$endif FPC_SYSTEM_HAS_DIV_INT64}
  206. {$ifndef FPC_SYSTEM_HAS_MOD_INT64}
  207. function fpc_mod_int64(n,z : int64) : int64;[public,alias: 'FPC_MOD_INT64']; compilerproc;
  208. var
  209. signed : boolean;
  210. r,nq,zq : qword;
  211. begin
  212. if n=0 then
  213. HandleErrorAddrFrameInd(200,get_pc_addr,get_frame);
  214. if n<0 then
  215. nq:=-n
  216. else
  217. nq:=n;
  218. if z<0 then
  219. begin
  220. signed:=true;
  221. zq:=qword(-z)
  222. end
  223. else
  224. begin
  225. signed:=false;
  226. zq:=z;
  227. end;
  228. r:=zq mod nq;
  229. if signed then
  230. fpc_mod_int64:=-int64(r)
  231. else
  232. fpc_mod_int64:=r;
  233. end;
  234. {$endif FPC_SYSTEM_HAS_MOD_INT64}
  235. {$ifndef FPC_SYSTEM_HAS_MUL_QWORD}
  236. { multiplies two qwords
  237. the longbool for checkoverflow avoids a misaligned stack
  238. }
  239. function fpc_mul_qword(f1,f2 : qword;checkoverflow : longbool) : qword;[public,alias: 'FPC_MUL_QWORD']; compilerproc;
  240. var
  241. _f1,bitpos : qword;
  242. l : longint;
  243. f1overflowed : boolean;
  244. begin
  245. fpc_mul_qword:=0;
  246. bitpos:=1;
  247. f1overflowed:=false;
  248. for l:=0 to 63 do
  249. begin
  250. if (f2 and bitpos)<>0 then
  251. begin
  252. _f1:=fpc_mul_qword;
  253. fpc_mul_qword:=fpc_mul_qword+f1;
  254. { if one of the operands is greater than the result an
  255. overflow occurs }
  256. if checkoverflow and (f1overflowed or ((_f1<>0) and (f1<>0) and
  257. ((_f1>fpc_mul_qword) or (f1>fpc_mul_qword)))) then
  258. HandleErrorAddrFrameInd(215,get_pc_addr,get_frame);
  259. end;
  260. { when bootstrapping, we forget about overflow checking for qword :) }
  261. f1overflowed:=f1overflowed or ((f1 and (qword(1) shl 63))<>0);
  262. f1:=f1 shl 1;
  263. bitpos:=bitpos shl 1;
  264. end;
  265. end;
  266. {$endif FPC_SYSTEM_HAS_MUL_QWORD}
  267. {$ifndef FPC_SYSTEM_HAS_MUL_DWORD_TO_QWORD}
  268. function fpc_mul_qword_compilerproc(f1,f2 : qword;checkoverflow : longbool) : qword; external name 'FPC_MUL_QWORD';
  269. function fpc_mul_dword_to_qword(f1,f2 : dword) : qword;[public,alias: 'FPC_MUL_DWORD_TO_QWORD']; compilerproc;
  270. begin
  271. fpc_mul_dword_to_qword:=fpc_mul_qword_compilerproc(f1,f2,false);
  272. end;
  273. {$endif FPC_SYSTEM_HAS_MUL_DWORD_TO_QWORD}
  274. {$ifndef FPC_SYSTEM_HAS_MUL_INT64}
  275. function fpc_mul_int64(f1,f2 : int64;checkoverflow : longbool) : int64;[public,alias: 'FPC_MUL_INT64']; compilerproc;
  276. var
  277. sign : boolean;
  278. q1,q2,q3 : qword;
  279. begin
  280. {$ifdef EXCLUDE_COMPLEX_PROCS}
  281. runerror(219);
  282. {$else EXCLUDE_COMPLEX_PROCS}
  283. { there's no difference between signed and unsigned multiplication,
  284. when the destination size is equal to the source size and overflow
  285. checking is off }
  286. if not checkoverflow then
  287. { qword(f1)*qword(f2) is coded as a call to mulqword }
  288. fpc_mul_int64:=int64(qword(f1)*qword(f2))
  289. else
  290. begin
  291. sign:=false;
  292. if f1<0 then
  293. begin
  294. sign:=not(sign);
  295. q1:=qword(-f1);
  296. end
  297. else
  298. q1:=f1;
  299. if f2<0 then
  300. begin
  301. sign:=not(sign);
  302. q2:=qword(-f2);
  303. end
  304. else
  305. q2:=f2;
  306. { the q1*q2 is coded as call to mulqword }
  307. q3:=q1*q2;
  308. if (q1 <> 0) and (q2 <>0) and
  309. ((q1>q3) or (q2>q3) or
  310. { the bit 63 can be only set if we have $80000000 00000000 }
  311. { and sign is true }
  312. (q3 shr 63<>0) and
  313. ((q3<>qword(qword(1) shl 63)) or not(sign))
  314. ) then
  315. HandleErrorAddrFrameInd(215,get_pc_addr,get_frame);
  316. if sign then
  317. fpc_mul_int64:=-q3
  318. else
  319. fpc_mul_int64:=q3;
  320. end;
  321. {$endif EXCLUDE_COMPLEX_PROCS}
  322. end;
  323. {$endif FPC_SYSTEM_HAS_MUL_INT64}
  324. {$ifndef FPC_SYSTEM_HAS_MUL_LONGINT_TO_INT64}
  325. function fpc_mul_int64_compilerproc(f1,f2 : int64;checkoverflow : longbool) : int64; external name 'FPC_MUL_INT64';
  326. function fpc_mul_longint_to_int64(f1,f2 : longint) : int64;[public,alias: 'FPC_MUL_LONGINT_TO_INT64']; compilerproc;
  327. {$ifdef EXCLUDE_COMPLEX_PROCS}
  328. begin
  329. runerror(217);
  330. end;
  331. {$else EXCLUDE_COMPLEX_PROCS}
  332. begin
  333. fpc_mul_longint_to_int64:=fpc_mul_int64_compilerproc(f1,f2,false);
  334. end;
  335. {$endif EXCLUDE_COMPLEX_PROCS}
  336. {$endif FPC_SYSTEM_HAS_MUL_LONGINT_TO_INT64}