int64.inc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  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. function count_leading_zeros(q : qword) : longint;
  28. var
  29. r,i : longint;
  30. begin
  31. r:=0;
  32. for i:=0 to 31 do
  33. begin
  34. if (tqwordrec(q).high and (dword($80000000) shr i))<>0 then
  35. begin
  36. count_leading_zeros:=r;
  37. exit;
  38. end;
  39. inc(r);
  40. end;
  41. for i:=0 to 31 do
  42. begin
  43. if (tqwordrec(q).low and (dword($80000000) shr i))<>0 then
  44. begin
  45. count_leading_zeros:=r;
  46. exit;
  47. end;
  48. inc(r);
  49. end;
  50. count_leading_zeros:=r;
  51. end;
  52. function fpc_div_qword(n,z : qword) : qword;[public,alias: 'FPC_DIV_QWORD']; {$ifdef hascompilerproc} compilerproc; {$endif}
  53. var
  54. shift,lzz,lzn : longint;
  55. { one : qword; }
  56. begin
  57. fpc_div_qword:=0;
  58. if n=0 then
  59. HandleErrorFrame(200,get_frame);
  60. {$ifdef i386}
  61. { the following piece of code is taken from the }
  62. { AMD Athlon Processor x86 Code Optimization manual }
  63. asm
  64. movl n+4,%ecx
  65. movl n,%ebx
  66. movl z+4,%edx
  67. movl z,%eax
  68. testl %ecx,%ecx
  69. jnz .Lqworddivbigdivisor
  70. cmpl %ebx,%edx
  71. jae .Lqworddivtwo_divs
  72. divl %ebx
  73. movl %ecx,%edx
  74. leave
  75. ret $16
  76. .Lqworddivtwo_divs:
  77. movl %eax,%ecx
  78. movl %edx,%eax
  79. xorl %edx,%edx
  80. divl %ebx
  81. xchgl %ecx,%eax
  82. divl %ebx
  83. movl %ecx,%edx
  84. leave
  85. ret $16
  86. .Lqworddivbigdivisor:
  87. movl %ecx,%edi
  88. shrl $1,%edx
  89. rcrl $1,%eax
  90. rorl $1,%edi
  91. rcrl $1,%ebx
  92. bsrl %ecx,%ecx
  93. shrdl %cl,%edi,%ebx
  94. shrdl %cl,%edx,%eax
  95. shrl %cl,%edx
  96. roll $1,%edi
  97. divl %ebx
  98. movl z,%ebx
  99. movl %eax,%ecx
  100. imull %eax,%edi
  101. mull n
  102. addl %edi,%edx
  103. subl %eax,%ebx
  104. movl %ecx,%eax
  105. movl z+4,%ecx
  106. sbbl %edx,%ecx
  107. sbbl $0,%eax
  108. xorl %edx,%edx
  109. leave
  110. ret $16
  111. end;
  112. {$else i386}
  113. lzz:=count_leading_zeros(z);
  114. lzn:=count_leading_zeros(n);
  115. { if the denominator contains less zeros }
  116. { then the numerator }
  117. { the d is greater than the n }
  118. if lzn<lzz then
  119. exit;
  120. shift:=lzn-lzz;
  121. n:=n shl shift;
  122. repeat
  123. if z>=n then
  124. begin
  125. z:=z-n;
  126. fpc_div_qword:=fpc_div_qword+(qword(1) shl shift);
  127. end;
  128. dec(shift);
  129. n:=n shr 1;
  130. until shift<0;
  131. {$endif i386}
  132. end;
  133. function fpc_mod_qword(n,z : qword) : qword;[public,alias: 'FPC_MOD_QWORD']; {$ifdef hascompilerproc} compilerproc; {$endif}
  134. var
  135. shift,lzz,lzn : longint;
  136. begin
  137. fpc_mod_qword:=0;
  138. if n=0 then
  139. HandleErrorFrame(200,get_frame);
  140. {$ifdef i386_not_working_correct}
  141. { the following piece of code is taken from the }
  142. { AMD Athlon Processor x86 Code Optimization manual }
  143. asm
  144. movl n+4,%ecx
  145. movl n,%ebx
  146. movl z+4,%edx
  147. movl z,%eax
  148. testl %ecx,%ecx
  149. jnz .Lqwordmodr_big_divisior
  150. cmpl %ebx,%edx
  151. jae .Lqwordmodr_two_divs
  152. divl %ebx
  153. movl %edx,%eax
  154. movl %ecx,%edx
  155. leave
  156. ret $16
  157. .Lqwordmodr_two_divs:
  158. movl %eax,%ecx
  159. movl %edx,%eax
  160. xorl %edx,%edx
  161. divl %ebx
  162. movl %ecx,%eax
  163. divl %ebx
  164. movl %edx,%eax
  165. xorl %edx,%edx
  166. leave
  167. ret $16
  168. .Lqwordmodr_big_divisior:
  169. movl %ecx,%edi
  170. shrl $1,%edx
  171. rcrl $1,%eax
  172. rorl $1,%edi
  173. rcrl $1,%ebx
  174. bsrl %ecx,%ecx
  175. shrdl %cl,%edi,%ebx
  176. shrdl %cl,%edx,%eax
  177. shrl %cl,%edx
  178. rorl $1,%edi
  179. divl %ebx
  180. movl z,%ebx
  181. movl %eax,%ecx
  182. imull %eax,%edi
  183. mull n
  184. addl %edi,%edx
  185. subl %eax,%ebx
  186. movl z+4,%ecx
  187. movl n,%eax
  188. sbbl %edx,%ecx
  189. sbbl %edx,%edx
  190. andl %edx,%eax
  191. andl n+4,%edx
  192. addl %ebx,%eax
  193. adcl %ecx,%edx
  194. leave
  195. ret $16
  196. end;
  197. {$else i386}
  198. lzz:=count_leading_zeros(z);
  199. lzn:=count_leading_zeros(n);
  200. { if the denominator contains less zeros }
  201. { then the numerator }
  202. { the d is greater than the n }
  203. if lzn<lzz then
  204. begin
  205. fpc_mod_qword:=z;
  206. exit;
  207. end;
  208. shift:=lzn-lzz;
  209. n:=n shl shift;
  210. repeat
  211. if z>=n then
  212. z:=z-n;
  213. dec(shift);
  214. n:=n shr 1;
  215. until shift<0;
  216. fpc_mod_qword:=z;
  217. {$endif i386}
  218. end;
  219. function fpc_div_int64(n,z : int64) : int64;[public,alias: 'FPC_DIV_INT64']; {$ifdef hascompilerproc} compilerproc; {$endif}
  220. var
  221. sign : boolean;
  222. q1,q2 : qword;
  223. begin
  224. if n=0 then
  225. HandleErrorFrame(200,get_frame);
  226. { can the fpu do the work? }
  227. begin
  228. sign:=false;
  229. if z<0 then
  230. begin
  231. sign:=not(sign);
  232. q1:=qword(-z);
  233. end
  234. else
  235. q1:=z;
  236. if n<0 then
  237. begin
  238. sign:=not(sign);
  239. q2:=qword(-n);
  240. end
  241. else
  242. q2:=n;
  243. { the div is coded by the compiler as call to divqword }
  244. if sign then
  245. fpc_div_int64:=-(q1 div q2)
  246. else
  247. fpc_div_int64:=q1 div q2;
  248. end;
  249. end;
  250. function fpc_mod_int64(n,z : int64) : int64;[public,alias: 'FPC_MOD_INT64']; {$ifdef hascompilerproc} compilerproc; {$endif}
  251. var
  252. signed : boolean;
  253. r,nq,zq : qword;
  254. begin
  255. if n=0 then
  256. HandleErrorFrame(200,get_frame);
  257. if n<0 then
  258. begin
  259. nq:=-n;
  260. signed:=true;
  261. end
  262. else
  263. begin
  264. signed:=false;
  265. nq:=n;
  266. end;
  267. if z<0 then
  268. begin
  269. zq:=qword(-z);
  270. signed:=not(signed);
  271. end
  272. else
  273. zq:=z;
  274. r:=zq mod nq;
  275. if signed then
  276. fpc_mod_int64:=-int64(r)
  277. else
  278. fpc_mod_int64:=r;
  279. end;
  280. { multiplies two qwords
  281. the longbool for checkoverflow avoids a misaligned stack
  282. }
  283. function fpc_mul_qword(f1,f2 : qword;checkoverflow : longbool) : qword;[public,alias: 'FPC_MUL_QWORD']; {$ifdef hascompilerproc} compilerproc; {$endif}
  284. var
  285. _f1,bitpos : qword;
  286. l : longint;
  287. {$ifdef i386}
  288. r : qword;
  289. {$endif i386}
  290. begin
  291. {$ifdef i386}
  292. if not(checkoverflow) then
  293. begin
  294. { the following piece of code is taken from the }
  295. { AMD Athlon Processor x86 Code Optimization manual }
  296. asm
  297. movl f1+4,%edx
  298. movl f2+4,%ecx
  299. orl %ecx,%edx
  300. movl f2,%edx
  301. movl f1,%eax
  302. jnz .Lqwordmultwomul
  303. mull %edx
  304. jmp .Lqwordmulready
  305. .Lqwordmultwomul:
  306. imul f1+4,%edx
  307. imul %eax,%ecx
  308. addl %edx,%ecx
  309. mull f2
  310. add %ecx,%edx
  311. .Lqwordmulready:
  312. movl %eax,r
  313. movl %edx,r+4
  314. end;
  315. fpc_mul_qword:=r;
  316. end
  317. else
  318. {$endif i386}
  319. begin
  320. fpc_mul_qword:=0;
  321. bitpos:=1;
  322. // store f1 for overflow checking
  323. _f1:=f1;
  324. for l:=0 to 63 do
  325. begin
  326. if (f2 and bitpos)<>0 then
  327. fpc_mul_qword:=fpc_mul_qword+f1;
  328. f1:=f1 shl 1;
  329. bitpos:=bitpos shl 1;
  330. end;
  331. { if one of the operands is greater than the result an }
  332. { overflow occurs }
  333. if checkoverflow and (_f1 <> 0) and (f2 <>0) and
  334. ((_f1>fpc_mul_qword) or (f2>fpc_mul_qword)) then
  335. HandleErrorFrame(215,get_frame);
  336. end;
  337. end;
  338. function fpc_mul_int64(f1,f2 : int64;checkoverflow : longbool) : int64;[public,alias: 'FPC_MUL_INT64']; {$ifdef hascompilerproc} compilerproc; {$endif}
  339. var
  340. sign : boolean;
  341. q1,q2,q3 : qword;
  342. begin
  343. begin
  344. sign:=false;
  345. if f1<0 then
  346. begin
  347. sign:=not(sign);
  348. q1:=qword(-f1);
  349. end
  350. else
  351. q1:=f1;
  352. if f2<0 then
  353. begin
  354. sign:=not(sign);
  355. q2:=qword(-f2);
  356. end
  357. else
  358. q2:=f2;
  359. { the q1*q2 is coded as call to mulqword }
  360. q3:=q1*q2;
  361. if checkoverflow and (q1 <> 0) and (q2 <>0) and
  362. ((q1>q3) or (q2>q3) or
  363. { the bit 63 can be only set if we have $80000000 00000000 }
  364. { and sign is true }
  365. ((tqwordrec(q3).high and dword($80000000))<>0) and
  366. ((q3<>(qword(1) shl 63)) or not(sign))
  367. ) then
  368. HandleErrorFrame(215,get_frame);
  369. if sign then
  370. fpc_mul_int64:=-q3
  371. else
  372. fpc_mul_int64:=q3;
  373. end;
  374. end;
  375. procedure qword_str(value : qword;var s : string);
  376. var
  377. hs : string;
  378. begin
  379. hs:='';
  380. repeat
  381. hs:=chr(longint(value mod qword(10))+48)+hs;
  382. value:=value div qword(10);
  383. until value=0;
  384. s:=hs;
  385. end;
  386. procedure int64_str(value : int64;var s : string);
  387. var
  388. hs : string;
  389. q : qword;
  390. begin
  391. if value<0 then
  392. begin
  393. q:=qword(-value);
  394. qword_str(q,hs);
  395. s:='-'+hs;
  396. end
  397. else
  398. qword_str(qword(value),s);
  399. end;
  400. procedure fpc_shortstr_qword(v : qword;len : longint;var s : shortstring);[public,alias:'FPC_SHORTSTR_QWORD']; {$ifdef hascompilerproc} compilerproc; {$endif}
  401. begin
  402. qword_str(v,s);
  403. if length(s)<len then
  404. s:=space(len-length(s))+s;
  405. end;
  406. procedure fpc_shortstr_int64(v : int64;len : longint;var s : shortstring);[public,alias:'FPC_SHORTSTR_INT64']; {$ifdef hascompilerproc} compilerproc; {$endif}
  407. begin
  408. int64_str(v,s);
  409. if length(s)<len then
  410. s:=space(len-length(s))+s;
  411. end;
  412. procedure fpc_ansistr_qword(v : qword;len : longint;var s : ansistring);[public,alias:'FPC_ANSISTR_QWORD']; {$ifdef hascompilerproc} compilerproc; {$endif}
  413. var
  414. ss : shortstring;
  415. begin
  416. str(v:len,ss);
  417. s:=ss;
  418. end;
  419. procedure fpc_ansistr_int64(v : int64;len : longint;var s : ansistring);[public,alias:'FPC_ANSISTR_INT64']; {$ifdef hascompilerproc} compilerproc; {$endif}
  420. var
  421. ss : shortstring;
  422. begin
  423. str(v:len,ss);
  424. s:=ss;
  425. end;
  426. {$ifdef HASWIDESTRING}
  427. procedure fpc_widestr_qword(v : qword;len : longint;var s : widestring);[public,alias:'FPC_WIDESTR_QWORD']; {$ifdef hascompilerproc} compilerproc; {$endif}
  428. var
  429. ss : shortstring;
  430. begin
  431. str(v:len,ss);
  432. s:=ss;
  433. end;
  434. procedure fpc_widestr_int64(v : int64;len : longint;var s : widestring);[public,alias:'FPC_WIDESTR_INT64']; {$ifdef hascompilerproc} compilerproc; {$endif}
  435. var
  436. ss : shortstring;
  437. begin
  438. str(v:len,ss);
  439. s:=ss;
  440. end;
  441. {$endif HASWIDESTRING}
  442. Function fpc_val_int64_shortstr(Const S: ShortString; var Code: ValSInt): Int64; [public, alias:'FPC_VAL_INT64_SHORTSTR']; {$ifdef hascompilerproc} compilerproc; {$endif}
  443. type
  444. QWordRec = packed record
  445. l1,l2: longint;
  446. end;
  447. var
  448. u, temp, prev, maxint64, maxqword : qword;
  449. base : byte;
  450. negative : boolean;
  451. begin
  452. fpc_val_int64_shortstr := 0;
  453. Temp:=0;
  454. Code:=InitVal(s,negative,base);
  455. if Code>length(s) then
  456. exit;
  457. { high(int64) produces 0 in version 1.0 (JM) }
  458. with qwordrec(maxint64) do
  459. begin
  460. l1 := longint($ffffffff);
  461. l2 := $7fffffff;
  462. end;
  463. with qwordrec(maxqword) do
  464. begin
  465. l1 := longint($ffffffff);
  466. l2 := longint($ffffffff);
  467. end;
  468. while Code<=Length(s) do
  469. begin
  470. case s[Code] of
  471. '0'..'9' : u:=Ord(S[Code])-Ord('0');
  472. 'A'..'F' : u:=Ord(S[Code])-(Ord('A')-10);
  473. 'a'..'f' : u:=Ord(S[Code])-(Ord('a')-10);
  474. else
  475. u:=16;
  476. end;
  477. Prev:=Temp;
  478. Temp:=Temp*Int64(base);
  479. If (u >= base) or
  480. ((base = 10) and
  481. (maxint64-temp+ord(negative) < u)) or
  482. ((base <> 10) and
  483. (qword(maxqword-temp) < u)) or
  484. (prev > maxqword div qword(base)) Then
  485. Begin
  486. fpc_val_int64_shortstr := 0;
  487. Exit
  488. End;
  489. Temp:=Temp+u;
  490. inc(code);
  491. end;
  492. code:=0;
  493. fpc_val_int64_shortstr:=int64(Temp);
  494. If Negative Then
  495. fpc_val_int64_shortstr:=-fpc_val_int64_shortstr;
  496. end;
  497. Function fpc_val_qword_shortstr(Const S: ShortString; var Code: ValSInt): QWord; [public, alias:'FPC_VAL_QWORD_SHORTSTR']; {$ifdef hascompilerproc} compilerproc; {$endif}
  498. type qwordrec = packed record
  499. l1,l2: longint;
  500. end;
  501. var
  502. u, prev, maxqword: QWord;
  503. base : byte;
  504. negative : boolean;
  505. begin
  506. fpc_val_qword_shortstr:=0;
  507. Code:=InitVal(s,negative,base);
  508. If Negative or (Code>length(s)) Then
  509. Exit;
  510. with qwordrec(maxqword) do
  511. begin
  512. l1 := longint($ffffffff);
  513. l2 := longint($ffffffff);
  514. end;
  515. while Code<=Length(s) do
  516. begin
  517. case s[Code] of
  518. '0'..'9' : u:=Ord(S[Code])-Ord('0');
  519. 'A'..'F' : u:=Ord(S[Code])-(Ord('A')-10);
  520. 'a'..'f' : u:=Ord(S[Code])-(Ord('a')-10);
  521. else
  522. u:=16;
  523. end;
  524. prev := fpc_val_qword_shortstr;
  525. If (u>=base) or
  526. ((QWord(maxqword-u) div QWord(base))<prev) then
  527. Begin
  528. fpc_val_qword_shortstr := 0;
  529. Exit
  530. End;
  531. fpc_val_qword_shortstr:=fpc_val_qword_shortstr*QWord(base) + u;
  532. inc(code);
  533. end;
  534. code := 0;
  535. end;
  536. {
  537. $Log$
  538. Revision 1.20 2003-05-12 11:17:55 florian
  539. * fixed my commit, strange, it didn't give any conflicts with Jonas patch
  540. Revision 1.19 2003/05/12 11:16:21 florian
  541. * qword division fixed (MSB/LSB problem)
  542. Revision 1.18 2003/05/12 07:19:04 jonas
  543. * fixed for big endian systems (since Florian doesn't seem to want to
  544. commit this fix :)
  545. Revision 1.17 2002/09/07 21:21:42 carl
  546. - remove FPUInt64 variable
  547. Revision 1.16 2002/09/07 15:07:45 peter
  548. * old logs removed and tabs fixed
  549. Revision 1.15 2002/09/01 14:44:01 peter
  550. * renamed conditional to insert optimized mod_qword for i386. The
  551. code is broken
  552. Revision 1.14 2002/07/01 16:29:05 peter
  553. * sLineBreak changed to normal constant like Kylix
  554. }