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 : ALUUInt) : 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 : ALUUInt); [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 : ALUUInt) : 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 : ALUUInt); [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 : ALUUInt) : 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 : ALUUInt); [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 : ALUUInt) : 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 : ALUUInt); [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. b : byte;
  349. begin
  350. result:=0;
  351. for b:=0 to 63 do
  352. begin
  353. if odd(f2) then
  354. result:=result+f1;
  355. f1:=f1 shl 1;
  356. f2:=f2 shr 1;
  357. end;
  358. end;
  359. function fpc_mul_qword_checkoverflow(f1,f2 : qword) : qword;[public,alias: 'FPC_MUL_QWORD_CHECKOVERFLOW']; compilerproc;
  360. var
  361. _f1,bitpos : qword;
  362. b : byte;
  363. f1overflowed : boolean;
  364. begin
  365. result:=0;
  366. bitpos:=1;
  367. f1overflowed:=false;
  368. for b:=0 to 63 do
  369. begin
  370. if (f2 and bitpos)<>0 then
  371. begin
  372. _f1:=result;
  373. result:=result+f1;
  374. { if one of the operands is greater than the result an
  375. overflow occurs }
  376. if (f1overflowed or ((_f1<>0) and (f1<>0) and
  377. ((_f1>result) or (f1>result)))) then
  378. HandleErrorAddrFrameInd(215,get_pc_addr,get_frame);
  379. end;
  380. { when bootstrapping, we forget about overflow checking for qword :) }
  381. f1overflowed:=f1overflowed or ((f1 and (qword(1) shl 63))<>0);
  382. f1:=f1 shl 1;
  383. bitpos:=bitpos shl 1;
  384. end;
  385. end;
  386. {$endif FPC_SYSTEM_HAS_MUL_QWORD}
  387. {$endif VER3_0}
  388. {$ifndef FPC_SYSTEM_HAS_MUL_DWORD_TO_QWORD}
  389. function fpc_mul_qword_compilerproc(f1,f2 : qword) : qword; external name 'FPC_MUL_QWORD';
  390. function fpc_mul_dword_to_qword(f1,f2 : dword) : qword;[public,alias: 'FPC_MUL_DWORD_TO_QWORD']; compilerproc;
  391. begin
  392. fpc_mul_dword_to_qword:=fpc_mul_qword_compilerproc(f1,f2);
  393. end;
  394. {$endif FPC_SYSTEM_HAS_MUL_DWORD_TO_QWORD}
  395. {$ifdef VER3_0}
  396. {$ifndef FPC_SYSTEM_HAS_MUL_INT64}
  397. function fpc_mul_int64(f1,f2 : int64;checkoverflow : longbool) : int64;[public,alias: 'FPC_MUL_INT64']; compilerproc;
  398. var
  399. sign : boolean;
  400. q1,q2,q3 : qword;
  401. begin
  402. {$ifdef EXCLUDE_COMPLEX_PROCS}
  403. runerror(219);
  404. {$else EXCLUDE_COMPLEX_PROCS}
  405. { there's no difference between signed and unsigned multiplication,
  406. when the destination size is equal to the source size and overflow
  407. checking is off }
  408. if not checkoverflow then
  409. { qword(f1)*qword(f2) is coded as a call to mulqword }
  410. fpc_mul_int64:=int64(qword(f1)*qword(f2))
  411. else
  412. begin
  413. sign:=false;
  414. if f1<0 then
  415. begin
  416. sign:=not(sign);
  417. q1:=qword(-f1);
  418. end
  419. else
  420. q1:=f1;
  421. if f2<0 then
  422. begin
  423. sign:=not(sign);
  424. q2:=qword(-f2);
  425. end
  426. else
  427. q2:=f2;
  428. { the q1*q2 is coded as call to mulqword }
  429. q3:=q1*q2;
  430. if (q1 <> 0) and (q2 <>0) and
  431. ((q1>q3) or (q2>q3) or
  432. { the bit 63 can be only set if we have $80000000 00000000 }
  433. { and sign is true }
  434. (q3 shr 63<>0) and
  435. ((q3<>qword(qword(1) shl 63)) or not(sign))
  436. ) then
  437. HandleErrorAddrFrameInd(215,get_pc_addr,get_frame);
  438. if sign then
  439. fpc_mul_int64:=-q3
  440. else
  441. fpc_mul_int64:=q3;
  442. end;
  443. {$endif EXCLUDE_COMPLEX_PROCS}
  444. end;
  445. {$endif FPC_SYSTEM_HAS_MUL_INT64}
  446. {$else VER3_0}
  447. {$ifndef FPC_SYSTEM_HAS_MUL_INT64}
  448. function fpc_mul_int64(f1,f2 : int64) : int64;[public,alias: 'FPC_MUL_INT64']; compilerproc;
  449. begin
  450. { there's no difference between signed and unsigned multiplication,
  451. when the destination size is equal to the source size and overflow
  452. checking is off }
  453. { qword(f1)*qword(f2) is coded as a call to mulqword }
  454. result:=int64(qword(f1)*qword(f2));
  455. end;
  456. function fpc_mul_int64_checkoverflow(f1,f2 : int64) : int64;[public,alias: 'FPC_MUL_INT64_CHECKOVERFLOW']; compilerproc;
  457. {$ifdef EXCLUDE_COMPLEX_PROCS}
  458. begin
  459. runerror(217);
  460. end;
  461. {$else EXCLUDE_COMPLEX_PROCS}
  462. var
  463. sign : boolean;
  464. q1,q2,q3 : qword;
  465. begin
  466. if f1<0 then
  467. begin
  468. q1:=qword(-f1);
  469. sign:=true;
  470. end
  471. else
  472. begin
  473. q1:=f1;
  474. sign:=false;
  475. end;
  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}