int64.inc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601
  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_SHL_ASSIGN_QWORD}
  46. procedure fpc_shl_assign_qword(var value : qword;shift : sizeint); [public,alias: 'FPC_SHL_ASSIGN_QWORD']; compilerproc;
  47. begin
  48. shift:=shift and 63;
  49. if shift<>0 then
  50. begin
  51. if shift>31 then
  52. begin
  53. tqwordrec(value).high:=tqwordrec(value).low shl (shift-32);
  54. tqwordrec(value).low:=0;
  55. end
  56. else
  57. begin
  58. tqwordrec(value).high:=(tqwordrec(value).high shl shift) or (tqwordrec(value).low shr (32-shift));
  59. tqwordrec(value).low:=tqwordrec(value).low shl shift;
  60. end;
  61. end;
  62. end;
  63. {$endif FPC_SYSTEM_HAS_SHL_ASSIGN_QWORD}
  64. {$ifndef FPC_SYSTEM_HAS_SHR_QWORD}
  65. function fpc_shr_qword(value : qword;shift : sizeint) : qword; [public,alias: 'FPC_SHR_QWORD']; compilerproc;
  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).high:=0;
  73. tqwordrec(result).low:=tqwordrec(value).high shr (shift-32);
  74. end
  75. else
  76. begin
  77. tqwordrec(result).high:=tqwordrec(value).high shr shift;
  78. tqwordrec(result).low:=(tqwordrec(value).low shr shift) or (tqwordrec(value).high shl (32-shift));
  79. end;
  80. end;
  81. {$endif FPC_SYSTEM_HAS_SHR_QWORD}
  82. {$ifndef FPC_SYSTEM_HAS_SHR_ASSIGN_QWORD}
  83. procedure fpc_shr_assign_qword(var value : qword;shift : sizeint); [public,alias: 'FPC_SHR_ASSIGN_QWORD']; compilerproc;
  84. begin
  85. shift:=shift and 63;
  86. if shift<>0 then
  87. begin
  88. if shift>31 then
  89. begin
  90. tqwordrec(value).low:=tqwordrec(value).high shr (shift-32);
  91. tqwordrec(value).high:=0;
  92. end
  93. else
  94. begin
  95. tqwordrec(value).low:=(tqwordrec(value).low shr shift) or (tqwordrec(value).high shl (32-shift));
  96. tqwordrec(value).high:=tqwordrec(value).high shr shift;
  97. end;
  98. end;
  99. end;
  100. {$endif FPC_SYSTEM_HAS_SHR_ASSIGN_QWORD}
  101. {$ifndef FPC_SYSTEM_HAS_SHL_INT64}
  102. function fpc_shl_int64(value : int64;shift : sizeint) : int64; [public,alias: 'FPC_SHL_INT64']; compilerproc;
  103. begin
  104. shift:=shift and 63;
  105. if shift=0 then
  106. result:=value
  107. else if shift>31 then
  108. begin
  109. tqwordrec(result).low:=0;
  110. tqwordrec(result).high:=tqwordrec(value).low shl (shift-32);
  111. end
  112. else
  113. begin
  114. tqwordrec(result).low:=tqwordrec(value).low shl shift;
  115. tqwordrec(result).high:=(tqwordrec(value).high shl shift) or (tqwordrec(value).low shr (32-shift));
  116. end;
  117. end;
  118. {$endif FPC_SYSTEM_HAS_SHL_INT64}
  119. {$ifndef FPC_SYSTEM_HAS_SHL_ASSIGN_INT64}
  120. procedure fpc_shl_assign_int64(var value : int64;shift : sizeint); [public,alias: 'FPC_SHL_ASSIGN_INT64']; compilerproc;
  121. begin
  122. shift:=shift and 63;
  123. if shift<>0 then
  124. begin
  125. if shift>31 then
  126. begin
  127. tqwordrec(value).high:=tqwordrec(value).low shl (shift-32);
  128. tqwordrec(value).low:=0;
  129. end
  130. else
  131. begin
  132. tqwordrec(value).high:=(tqwordrec(value).high shl shift) or (tqwordrec(value).low shr (32-shift));
  133. tqwordrec(value).low:=tqwordrec(value).low shl shift;
  134. end;
  135. end;
  136. end;
  137. {$endif FPC_SYSTEM_HAS_SHL_ASSIGN_INT64}
  138. {$ifndef FPC_SYSTEM_HAS_SHR_INT64}
  139. function fpc_shr_int64(value : int64;shift : sizeint) : int64; [public,alias: 'FPC_SHR_INT64']; compilerproc;
  140. begin
  141. shift:=shift and 63;
  142. if shift=0 then
  143. result:=value
  144. else if shift>31 then
  145. begin
  146. tqwordrec(result).high:=0;
  147. tqwordrec(result).low:=tqwordrec(value).high shr (shift-32);
  148. end
  149. else
  150. begin
  151. tqwordrec(result).high:=tqwordrec(value).high shr shift;
  152. tqwordrec(result).low:=(tqwordrec(value).low shr shift) or (tqwordrec(value).high shl (32-shift));
  153. end;
  154. end;
  155. {$endif FPC_SYSTEM_HAS_SHR_INT64}
  156. {$ifndef FPC_SYSTEM_HAS_SHR_ASSIGN_INT64}
  157. procedure fpc_shr_assign_int64(var value : int64;shift : sizeint); [public,alias: 'FPC_SHR_ASSIGN_INT64']; compilerproc;
  158. begin
  159. shift:=shift and 63;
  160. if shift<>0 then
  161. begin
  162. if shift>31 then
  163. begin
  164. tqwordrec(value).low:=tqwordrec(value).high shr (shift-32);
  165. tqwordrec(value).high:=0;
  166. end
  167. else
  168. begin
  169. tqwordrec(value).low:=(tqwordrec(value).low shr shift) or (tqwordrec(value).high shl (32-shift));
  170. tqwordrec(value).high:=tqwordrec(value).high shr shift;
  171. end;
  172. end;
  173. end;
  174. {$endif FPC_SYSTEM_HAS_SHR_ASSIGN_INT64}
  175. {$endif FPC_INCLUDE_SOFTWARE_SHIFT_INT64}
  176. {$ifndef FPC_SYSTEM_HAS_DIV_QWORD}
  177. function fpc_div_qword(n,z : qword) : qword;[public,alias: 'FPC_DIV_QWORD']; compilerproc;
  178. var
  179. shift,lzz,lzn : longint;
  180. begin
  181. { Use the usually faster 32-bit division if possible }
  182. if (hi(z) = 0) and (hi(n) = 0) then
  183. begin
  184. fpc_div_qword := Dword(z) div Dword(n);
  185. exit;
  186. end;
  187. fpc_div_qword:=0;
  188. if n=0 then
  189. HandleErrorAddrFrameInd(200,get_pc_addr,get_frame);
  190. if z=0 then
  191. exit;
  192. lzz:=BsrQWord(z);
  193. lzn:=BsrQWord(n);
  194. { if the denominator contains less zeros }
  195. { than the numerator }
  196. { then d is greater than the n }
  197. if lzn>lzz then
  198. exit;
  199. shift:=lzz-lzn;
  200. n:=n shl shift;
  201. for shift:=shift downto 0 do
  202. begin
  203. if z>=n then
  204. begin
  205. z:=z-n;
  206. fpc_div_qword:=fpc_div_qword+(qword(1) shl shift);
  207. end;
  208. n:=n shr 1;
  209. end;
  210. end;
  211. {$endif FPC_SYSTEM_HAS_DIV_QWORD}
  212. {$ifndef FPC_SYSTEM_HAS_MOD_QWORD}
  213. function fpc_mod_qword(n,z : qword) : qword;[public,alias: 'FPC_MOD_QWORD']; compilerproc;
  214. var
  215. shift,lzz,lzn : longint;
  216. begin
  217. { Use the usually faster 32-bit mod if possible }
  218. if (hi(z) = 0) and (hi(n) = 0) then
  219. begin
  220. fpc_mod_qword := Dword(z) mod Dword(n);
  221. exit;
  222. end;
  223. fpc_mod_qword:=0;
  224. if n=0 then
  225. HandleErrorAddrFrameInd(200,get_pc_addr,get_frame);
  226. if z=0 then
  227. exit;
  228. lzz:=BsrQword(z);
  229. lzn:=BsrQword(n);
  230. { if the denominator contains less zeros }
  231. { then the numerator }
  232. { the d is greater than the n }
  233. if lzn>lzz then
  234. begin
  235. fpc_mod_qword:=z;
  236. exit;
  237. end;
  238. shift:=lzz-lzn;
  239. n:=n shl shift;
  240. for shift:=shift downto 0 do
  241. begin
  242. if z>=n then
  243. z:=z-n;
  244. n:=n shr 1;
  245. end;
  246. fpc_mod_qword:=z;
  247. end;
  248. {$endif FPC_SYSTEM_HAS_MOD_QWORD}
  249. {$ifndef FPC_SYSTEM_HAS_DIV_INT64}
  250. function fpc_div_int64(n,z : int64) : int64;[public,alias: 'FPC_DIV_INT64']; compilerproc;
  251. var
  252. sign : boolean;
  253. q1,q2 : qword;
  254. begin
  255. if n=0 then
  256. HandleErrorAddrFrameInd(200,get_pc_addr,get_frame);
  257. { can the fpu do the work? }
  258. begin
  259. sign:=false;
  260. if z<0 then
  261. begin
  262. sign:=not(sign);
  263. q1:=qword(-z);
  264. end
  265. else
  266. q1:=z;
  267. if n<0 then
  268. begin
  269. sign:=not(sign);
  270. q2:=qword(-n);
  271. end
  272. else
  273. q2:=n;
  274. { the div is coded by the compiler as call to divqword }
  275. if sign then
  276. fpc_div_int64:=-(q1 div q2)
  277. else
  278. fpc_div_int64:=q1 div q2;
  279. end;
  280. end;
  281. {$endif FPC_SYSTEM_HAS_DIV_INT64}
  282. {$ifndef FPC_SYSTEM_HAS_MOD_INT64}
  283. function fpc_mod_int64(n,z : int64) : int64;[public,alias: 'FPC_MOD_INT64']; compilerproc;
  284. var
  285. signed : boolean;
  286. r,nq,zq : qword;
  287. begin
  288. if n=0 then
  289. HandleErrorAddrFrameInd(200,get_pc_addr,get_frame);
  290. if n<0 then
  291. nq:=-n
  292. else
  293. nq:=n;
  294. if z<0 then
  295. begin
  296. signed:=true;
  297. zq:=qword(-z)
  298. end
  299. else
  300. begin
  301. signed:=false;
  302. zq:=z;
  303. end;
  304. r:=zq mod nq;
  305. if signed then
  306. fpc_mod_int64:=-int64(r)
  307. else
  308. fpc_mod_int64:=r;
  309. end;
  310. {$endif FPC_SYSTEM_HAS_MOD_INT64}
  311. {$ifdef VER3_0}
  312. {$ifndef FPC_SYSTEM_HAS_MUL_QWORD}
  313. { multiplies two qwords
  314. the longbool for checkoverflow avoids a misaligned stack
  315. }
  316. function fpc_mul_qword(f1,f2 : qword;checkoverflow : longbool) : qword;[public,alias: 'FPC_MUL_QWORD']; compilerproc;
  317. var
  318. _f1,bitpos : qword;
  319. l : longint;
  320. f1overflowed : boolean;
  321. begin
  322. fpc_mul_qword:=0;
  323. bitpos:=1;
  324. f1overflowed:=false;
  325. for l:=0 to 63 do
  326. begin
  327. if (f2 and bitpos)<>0 then
  328. begin
  329. _f1:=fpc_mul_qword;
  330. fpc_mul_qword:=fpc_mul_qword+f1;
  331. { if one of the operands is greater than the result an
  332. overflow occurs }
  333. if checkoverflow and (f1overflowed or ((_f1<>0) and (f1<>0) and
  334. ((_f1>fpc_mul_qword) or (f1>fpc_mul_qword)))) then
  335. HandleErrorAddrFrameInd(215,get_pc_addr,get_frame);
  336. end;
  337. { when bootstrapping, we forget about overflow checking for qword :) }
  338. f1overflowed:=f1overflowed or ((f1 and (qword(1) shl 63))<>0);
  339. f1:=f1 shl 1;
  340. bitpos:=bitpos shl 1;
  341. end;
  342. end;
  343. {$endif FPC_SYSTEM_HAS_MUL_QWORD}
  344. {$else VER3_0}
  345. {$ifndef FPC_SYSTEM_HAS_MUL_QWORD}
  346. function fpc_mul_qword(f1,f2 : qword) : qword;[public,alias: 'FPC_MUL_QWORD']; compilerproc;
  347. var
  348. bitpos : qword;
  349. l : longint;
  350. begin
  351. result:=0;
  352. bitpos:=1;
  353. for l:=0 to 63 do
  354. begin
  355. if (f2 and bitpos)<>0 then
  356. result:=result+f1;
  357. f1:=f1 shl 1;
  358. bitpos:=bitpos shl 1;
  359. end;
  360. end;
  361. function fpc_mul_qword_checkoverflow(f1,f2 : qword) : qword;[public,alias: 'FPC_MUL_QWORD_CHECKOVERFLOW']; compilerproc;
  362. var
  363. _f1,bitpos : qword;
  364. l : longint;
  365. f1overflowed : boolean;
  366. begin
  367. result:=0;
  368. bitpos:=1;
  369. f1overflowed:=false;
  370. for l:=0 to 63 do
  371. begin
  372. if (f2 and bitpos)<>0 then
  373. begin
  374. _f1:=result;
  375. result:=result+f1;
  376. { if one of the operands is greater than the result an
  377. overflow occurs }
  378. if (f1overflowed or ((_f1<>0) and (f1<>0) and
  379. ((_f1>result) or (f1>result)))) then
  380. HandleErrorAddrFrameInd(215,get_pc_addr,get_frame);
  381. end;
  382. { when bootstrapping, we forget about overflow checking for qword :) }
  383. f1overflowed:=f1overflowed or ((f1 and (qword(1) shl 63))<>0);
  384. f1:=f1 shl 1;
  385. bitpos:=bitpos shl 1;
  386. end;
  387. end;
  388. {$endif FPC_SYSTEM_HAS_MUL_QWORD}
  389. {$endif VER3_0}
  390. {$ifndef FPC_SYSTEM_HAS_MUL_DWORD_TO_QWORD}
  391. function fpc_mul_qword_compilerproc(f1,f2 : qword) : qword; external name 'FPC_MUL_QWORD';
  392. function fpc_mul_dword_to_qword(f1,f2 : dword) : qword;[public,alias: 'FPC_MUL_DWORD_TO_QWORD']; compilerproc;
  393. begin
  394. fpc_mul_dword_to_qword:=fpc_mul_qword_compilerproc(f1,f2);
  395. end;
  396. {$endif FPC_SYSTEM_HAS_MUL_DWORD_TO_QWORD}
  397. {$ifdef VER3_0}
  398. {$ifndef FPC_SYSTEM_HAS_MUL_INT64}
  399. function fpc_mul_int64(f1,f2 : int64;checkoverflow : longbool) : int64;[public,alias: 'FPC_MUL_INT64']; compilerproc;
  400. var
  401. sign : boolean;
  402. q1,q2,q3 : qword;
  403. begin
  404. {$ifdef EXCLUDE_COMPLEX_PROCS}
  405. runerror(219);
  406. {$else EXCLUDE_COMPLEX_PROCS}
  407. { there's no difference between signed and unsigned multiplication,
  408. when the destination size is equal to the source size and overflow
  409. checking is off }
  410. if not checkoverflow then
  411. { qword(f1)*qword(f2) is coded as a call to mulqword }
  412. fpc_mul_int64:=int64(qword(f1)*qword(f2))
  413. else
  414. begin
  415. sign:=false;
  416. if f1<0 then
  417. begin
  418. sign:=not(sign);
  419. q1:=qword(-f1);
  420. end
  421. else
  422. q1:=f1;
  423. if f2<0 then
  424. begin
  425. sign:=not(sign);
  426. q2:=qword(-f2);
  427. end
  428. else
  429. q2:=f2;
  430. { the q1*q2 is coded as call to mulqword }
  431. q3:=q1*q2;
  432. if (q1 <> 0) and (q2 <>0) and
  433. ((q1>q3) or (q2>q3) or
  434. { the bit 63 can be only set if we have $80000000 00000000 }
  435. { and sign is true }
  436. (q3 shr 63<>0) and
  437. ((q3<>qword(qword(1) shl 63)) or not(sign))
  438. ) then
  439. HandleErrorAddrFrameInd(215,get_pc_addr,get_frame);
  440. if sign then
  441. fpc_mul_int64:=-q3
  442. else
  443. fpc_mul_int64:=q3;
  444. end;
  445. {$endif EXCLUDE_COMPLEX_PROCS}
  446. end;
  447. {$endif FPC_SYSTEM_HAS_MUL_INT64}
  448. {$else VER3_0}
  449. {$ifndef FPC_SYSTEM_HAS_MUL_INT64}
  450. function fpc_mul_int64(f1,f2 : int64) : int64;[public,alias: 'FPC_MUL_INT64']; compilerproc;
  451. begin
  452. { there's no difference between signed and unsigned multiplication,
  453. when the destination size is equal to the source size and overflow
  454. checking is off }
  455. { qword(f1)*qword(f2) is coded as a call to mulqword }
  456. result:=int64(qword(f1)*qword(f2));
  457. end;
  458. function fpc_mul_int64_checkoverflow(f1,f2 : int64) : int64;[public,alias: 'FPC_MUL_INT64_CHECKOVERFLOW']; compilerproc;
  459. {$ifdef EXCLUDE_COMPLEX_PROCS}
  460. begin
  461. runerror(217);
  462. end;
  463. {$else EXCLUDE_COMPLEX_PROCS}
  464. var
  465. sign : boolean;
  466. q1,q2,q3 : qword;
  467. begin
  468. sign:=false;
  469. if f1<0 then
  470. begin
  471. sign:=not(sign);
  472. q1:=qword(-f1);
  473. end
  474. else
  475. q1:=f1;
  476. if f2<0 then
  477. begin
  478. sign:=not(sign);
  479. q2:=qword(-f2);
  480. end
  481. else
  482. q2:=f2;
  483. { the q1*q2 is coded as call to mulqword }
  484. q3:=q1*q2;
  485. if (q1 <> 0) and (q2 <>0) and
  486. ((q1>q3) or (q2>q3) or
  487. { the bit 63 can be only set if we have $80000000 00000000 }
  488. { and sign is true }
  489. (q3 shr 63<>0) and
  490. ((q3<>qword(qword(1) shl 63)) or not(sign))
  491. ) then
  492. HandleErrorAddrFrameInd(215,get_pc_addr,get_frame);
  493. if sign then
  494. result:=-q3
  495. else
  496. result:=q3;
  497. end;
  498. {$endif EXCLUDE_COMPLEX_PROCS}
  499. {$endif FPC_SYSTEM_HAS_MUL_INT64}
  500. {$endif VER3_0}
  501. {$ifndef FPC_SYSTEM_HAS_MUL_LONGINT_TO_INT64}
  502. function fpc_mul_int64_compilerproc(f1,f2 : int64) : int64; external name 'FPC_MUL_INT64';
  503. function fpc_mul_longint_to_int64(f1,f2 : longint) : int64;[public,alias: 'FPC_MUL_LONGINT_TO_INT64']; compilerproc;
  504. {$ifdef EXCLUDE_COMPLEX_PROCS}
  505. begin
  506. runerror(217);
  507. end;
  508. {$else EXCLUDE_COMPLEX_PROCS}
  509. begin
  510. fpc_mul_longint_to_int64:=fpc_mul_int64_compilerproc(f1,f2);
  511. end;
  512. {$endif EXCLUDE_COMPLEX_PROCS}
  513. {$endif FPC_SYSTEM_HAS_MUL_LONGINT_TO_INT64}
  514. {$ifndef FPC_SYSTEM_HAS_DIV_CURRENCY}
  515. function fpc_div_currency(n,z : currency) : currency; [public,alias: 'FPC_DIV_CURRENCY']; compilerproc;
  516. begin
  517. Result:=(int64(z)*10000) div int64(n);
  518. end;
  519. {$endif FPC_SYSTEM_HAS_DIV_CURRENCY}
  520. {$ifndef FPC_SYSTEM_HAS_MOD_CURRENCY}
  521. function fpc_mod_currency(n,z : currency) : currency; [public,alias: 'FPC_MOD_CURRENCY']; compilerproc;
  522. begin
  523. Result:=int64(z) mod int64(n);
  524. end;
  525. {$endif FPC_SYSTEM_HAS_MOD_CURRENCY}