int64.inc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687
  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. tqwordrec = packed record
  16. low : dword;
  17. high : dword;
  18. end;
  19. function count_leading_zeros(q : qword) : longint;
  20. var
  21. r,i : longint;
  22. begin
  23. r:=0;
  24. for i:=0 to 31 do
  25. begin
  26. if (tqwordrec(q).high and (dword($80000000) shr i))<>0 then
  27. begin
  28. count_leading_zeros:=r;
  29. exit;
  30. end;
  31. inc(r);
  32. end;
  33. for i:=0 to 31 do
  34. begin
  35. if (tqwordrec(q).low and (dword($80000000) shr i))<>0 then
  36. begin
  37. count_leading_zeros:=r;
  38. exit;
  39. end;
  40. inc(r);
  41. end;
  42. count_leading_zeros:=r;
  43. end;
  44. function fpc_div_qword(n,z : qword) : qword;[public,alias: 'FPC_DIV_QWORD']; {$ifdef hascompilerproc} compilerproc; {$endif}
  45. var
  46. shift,lzz,lzn : longint;
  47. { one : qword; }
  48. begin
  49. fpc_div_qword:=0;
  50. if n=0 then
  51. HandleErrorFrame(200,get_frame);
  52. {$ifdef i386}
  53. { the following piece of code is taken from the }
  54. { AMD Athlon Processor x86 Code Optimization manual }
  55. asm
  56. movl n+4,%ecx
  57. movl n,%ebx
  58. movl z+4,%edx
  59. movl z,%eax
  60. testl %ecx,%ecx
  61. jnz .Lqworddivbigdivisor
  62. cmpl %ebx,%edx
  63. jae .Lqworddivtwo_divs
  64. divl %ebx
  65. movl %ecx,%edx
  66. leave
  67. ret $16
  68. .Lqworddivtwo_divs:
  69. movl %eax,%ecx
  70. movl %edx,%eax
  71. xorl %edx,%edx
  72. divl %ebx
  73. xchgl %ecx,%eax
  74. divl %ebx
  75. movl %ecx,%edx
  76. leave
  77. ret $16
  78. .Lqworddivbigdivisor:
  79. movl %ecx,%edi
  80. shrl $1,%edx
  81. rcrl $1,%eax
  82. rorl $1,%edi
  83. rcrl $1,%ebx
  84. bsrl %ecx,%ecx
  85. shrdl %cl,%edi,%ebx
  86. shrdl %cl,%edx,%eax
  87. shrl %cl,%edx
  88. roll $1,%edi
  89. divl %ebx
  90. movl z,%ebx
  91. movl %eax,%ecx
  92. imull %eax,%edi
  93. mull n
  94. addl %edi,%edx
  95. subl %eax,%ebx
  96. movl %ecx,%eax
  97. movl z+4,%ecx
  98. sbbl %edx,%ecx
  99. sbbl $0,%eax
  100. xorl %edx,%edx
  101. leave
  102. ret $16
  103. end;
  104. {$else i386}
  105. lzz:=count_leading_zeros(z);
  106. lzn:=count_leading_zeros(n);
  107. { if the denominator contains less zeros }
  108. { then the numerator }
  109. { the d is greater than the n }
  110. if lzn<lzz then
  111. exit;
  112. shift:=lzn-lzz;
  113. n:=n shl shift;
  114. repeat
  115. if z>=n then
  116. begin
  117. z:=z-n;
  118. fpc_div_qword:=fpc_div_qword+(qword(1) shl shift);
  119. end;
  120. dec(shift);
  121. n:=n shr 1;
  122. until shift<0;
  123. {$endif i386}
  124. end;
  125. function fpc_mod_qword(n,z : qword) : qword;[public,alias: 'FPC_MOD_QWORD']; {$ifdef hascompilerproc} compilerproc; {$endif}
  126. var
  127. shift,lzz,lzn : longint;
  128. begin
  129. fpc_mod_qword:=0;
  130. if n=0 then
  131. HandleErrorFrame(200,get_frame);
  132. {$ifdef i386}
  133. { the following piece of code is taken from the }
  134. { AMD Athlon Processor x86 Code Optimization manual }
  135. asm
  136. movl n+4,%ecx
  137. movl n,%ebx
  138. movl z+4,%edx
  139. movl z,%eax
  140. testl %ecx,%ecx
  141. jnz .Lqwordmodr_big_divisior
  142. cmpl %ebx,%edx
  143. jae .Lqwordmodr_two_divs
  144. divl %ebx
  145. movl %edx,%eax
  146. movl %ecx,%edx
  147. leave
  148. ret $16
  149. .Lqwordmodr_two_divs:
  150. movl %eax,%ecx
  151. movl %edx,%eax
  152. xorl %edx,%edx
  153. divl %ebx
  154. movl %ecx,%eax
  155. divl %ebx
  156. movl %edx,%eax
  157. xorl %edx,%edx
  158. leave
  159. ret $16
  160. .Lqwordmodr_big_divisior:
  161. movl %ecx,%edi
  162. shrl $1,%edx
  163. rcrl $1,%eax
  164. rorl $1,%edi
  165. rcrl $1,%ebx
  166. bsrl %ecx,%ecx
  167. shrdl %cl,%edi,%ebx
  168. shrdl %cl,%edx,%eax
  169. shrl %cl,%edx
  170. rorl $1,%edi
  171. divl %ebx
  172. movl z,%ebx
  173. movl %eax,%ecx
  174. imull %eax,%edi
  175. mull n
  176. addl %edi,%edx
  177. subl %eax,%ebx
  178. movl z+4,%ecx
  179. movl n,%eax
  180. sbbl %edx,%ecx
  181. sbbl %edx,%edx
  182. andl %edx,%eax
  183. andl n+4,%edx
  184. addl %ebx,%eax
  185. adcl %ecx,%edx
  186. leave
  187. ret $16
  188. end;
  189. {$else i386}
  190. lzz:=count_leading_zeros(z);
  191. lzn:=count_leading_zeros(n);
  192. { if the denominator contains less zeros }
  193. { then the numerator }
  194. { the d is greater than the n }
  195. if lzn<lzz then
  196. begin
  197. fpc_mod_qword:=z;
  198. exit;
  199. end;
  200. shift:=lzn-lzz;
  201. n:=n shl shift;
  202. repeat
  203. if z>=n then
  204. z:=z-n;
  205. dec(shift);
  206. n:=n shr 1;
  207. until shift<0;
  208. fpc_mod_qword:=z;
  209. {$endif i386}
  210. end;
  211. function fpc_div_int64(n,z : int64) : int64;[public,alias: 'FPC_DIV_INT64']; {$ifdef hascompilerproc} compilerproc; {$endif}
  212. var
  213. sign : boolean;
  214. q1,q2 : qword;
  215. {$ifdef SUPPORT_COMP}
  216. c : comp;
  217. {$endif}
  218. begin
  219. if n=0 then
  220. HandleErrorFrame(200,get_frame);
  221. { can the fpu do the work? }
  222. {$ifdef support_comp}
  223. if fpuint64 then
  224. begin
  225. // the c:=comp(...) is necessary to shut up the compiler
  226. c:=comp(comp(z)/comp(n));
  227. fpc_div_int64:=qword(c);
  228. end
  229. else
  230. {$endif}
  231. begin
  232. sign:=false;
  233. if z<0 then
  234. begin
  235. sign:=not(sign);
  236. q1:=qword(-z);
  237. end
  238. else
  239. q1:=z;
  240. if n<0 then
  241. begin
  242. sign:=not(sign);
  243. q2:=qword(-n);
  244. end
  245. else
  246. q2:=n;
  247. { the div is coded by the compiler as call to divqword }
  248. if sign then
  249. fpc_div_int64:=-(q1 div q2)
  250. else
  251. fpc_div_int64:=q1 div q2;
  252. end;
  253. end;
  254. function fpc_mod_int64(n,z : int64) : int64;[public,alias: 'FPC_MOD_INT64']; {$ifdef hascompilerproc} compilerproc; {$endif}
  255. var
  256. signed : boolean;
  257. r,nq,zq : qword;
  258. begin
  259. if n=0 then
  260. HandleErrorFrame(200,get_frame);
  261. if n<0 then
  262. begin
  263. nq:=-n;
  264. signed:=true;
  265. end
  266. else
  267. begin
  268. signed:=false;
  269. nq:=n;
  270. end;
  271. if z<0 then
  272. begin
  273. zq:=qword(-z);
  274. signed:=not(signed);
  275. end
  276. else
  277. zq:=z;
  278. r:=zq mod nq;
  279. if signed then
  280. fpc_mod_int64:=-int64(r)
  281. else
  282. fpc_mod_int64:=r;
  283. end;
  284. { multiplies two qwords
  285. the longbool for checkoverflow avoids a misaligned stack
  286. }
  287. function fpc_mul_qword(f1,f2 : qword;checkoverflow : longbool) : qword;[public,alias: 'FPC_MUL_QWORD']; {$ifdef hascompilerproc} compilerproc; {$endif}
  288. var
  289. _f1,bitpos : qword;
  290. l : longint;
  291. {$ifdef i386}
  292. r : qword;
  293. {$endif i386}
  294. begin
  295. {$ifdef i386}
  296. if not(checkoverflow) then
  297. begin
  298. { the following piece of code is taken from the }
  299. { AMD Athlon Processor x86 Code Optimization manual }
  300. asm
  301. movl f1+4,%edx
  302. movl f2+4,%ecx
  303. orl %ecx,%edx
  304. movl f2,%edx
  305. movl f1,%eax
  306. jnz .Lqwordmultwomul
  307. mull %edx
  308. jmp .Lqwordmulready
  309. .Lqwordmultwomul:
  310. imul f1+4,%edx
  311. imul %eax,%ecx
  312. addl %edx,%ecx
  313. mull f2
  314. add %ecx,%edx
  315. .Lqwordmulready:
  316. movl %eax,r
  317. movl %edx,r+4
  318. end;
  319. fpc_mul_qword:=r;
  320. end
  321. else
  322. {$endif i386}
  323. begin
  324. fpc_mul_qword:=0;
  325. bitpos:=1;
  326. // store f1 for overflow checking
  327. _f1:=f1;
  328. for l:=0 to 63 do
  329. begin
  330. if (f2 and bitpos)<>0 then
  331. fpc_mul_qword:=fpc_mul_qword+f1;
  332. f1:=f1 shl 1;
  333. bitpos:=bitpos shl 1;
  334. end;
  335. { if one of the operands is greater than the result an }
  336. { overflow occurs }
  337. if checkoverflow and (_f1 <> 0) and (f2 <>0) and
  338. ((_f1>fpc_mul_qword) or (f2>fpc_mul_qword)) then
  339. HandleErrorFrame(215,get_frame);
  340. end;
  341. end;
  342. { multiplies two int64 ....
  343. fpuint64 = false:
  344. ... using the the qword multiplication
  345. fpuint64 = true:
  346. ... using the comp multiplication
  347. the longbool for checkoverflow avoids a misaligned stack
  348. }
  349. function fpc_mul_int64(f1,f2 : int64;checkoverflow : longbool) : int64;[public,alias: 'FPC_MUL_INT64']; {$ifdef hascompilerproc} compilerproc; {$endif}
  350. var
  351. sign : boolean;
  352. q1,q2,q3 : qword;
  353. {$ifdef support_comp}
  354. c : comp;
  355. {$endif}
  356. begin
  357. {$ifdef support_comp}
  358. { can the fpu do the work ? }
  359. if fpuint64 and not(checkoverflow) then
  360. begin
  361. // the c:=comp(...) is necessary to shut up the compiler
  362. c:=comp(comp(f1)*comp(f2));
  363. fpc_mul_int64:=int64(c);
  364. end
  365. else
  366. {$endif}
  367. begin
  368. sign:=false;
  369. if f1<0 then
  370. begin
  371. sign:=not(sign);
  372. q1:=qword(-f1);
  373. end
  374. else
  375. q1:=f1;
  376. if f2<0 then
  377. begin
  378. sign:=not(sign);
  379. q2:=qword(-f2);
  380. end
  381. else
  382. q2:=f2;
  383. { the q1*q2 is coded as call to mulqword }
  384. q3:=q1*q2;
  385. if checkoverflow and (q1 <> 0) and (q2 <>0) and
  386. ((q1>q3) or (q2>q3) or
  387. { the bit 63 can be only set if we have $80000000 00000000 }
  388. { and sign is true }
  389. ((tqwordrec(q3).high and dword($80000000))<>0) and
  390. ((q3<>(qword(1) shl 63)) or not(sign))
  391. ) then
  392. HandleErrorFrame(215,get_frame);
  393. if sign then
  394. fpc_mul_int64:=-q3
  395. else
  396. fpc_mul_int64:=q3;
  397. end;
  398. end;
  399. procedure qword_str(value : qword;var s : string);
  400. var
  401. hs : string;
  402. begin
  403. hs:='';
  404. repeat
  405. hs:=chr(longint(value mod qword(10))+48)+hs;
  406. value:=value div qword(10);
  407. until value=0;
  408. s:=hs;
  409. end;
  410. procedure int64_str(value : int64;var s : string);
  411. var
  412. hs : string;
  413. q : qword;
  414. begin
  415. if value<0 then
  416. begin
  417. q:=qword(-value);
  418. qword_str(q,hs);
  419. s:='-'+hs;
  420. end
  421. else
  422. qword_str(qword(value),s);
  423. end;
  424. procedure fpc_shortstr_qword(v : qword;len : longint;var s : shortstring);[public,alias:'FPC_SHORTSTR_QWORD']; {$ifdef hascompilerproc} compilerproc; {$endif}
  425. begin
  426. qword_str(v,s);
  427. if length(s)<len then
  428. s:=space(len-length(s))+s;
  429. end;
  430. procedure fpc_shortstr_int64(v : int64;len : longint;var s : shortstring);[public,alias:'FPC_SHORTSTR_INT64']; {$ifdef hascompilerproc} compilerproc; {$endif}
  431. begin
  432. int64_str(v,s);
  433. if length(s)<len then
  434. s:=space(len-length(s))+s;
  435. end;
  436. procedure fpc_ansistr_qword(v : qword;len : longint;var s : ansistring);[public,alias:'FPC_ANSISTR_QWORD']; {$ifdef hascompilerproc} compilerproc; {$endif}
  437. var
  438. ss : shortstring;
  439. begin
  440. str(v:len,ss);
  441. s:=ss;
  442. end;
  443. procedure fpc_ansistr_int64(v : int64;len : longint;var s : ansistring);[public,alias:'FPC_ANSISTR_INT64']; {$ifdef hascompilerproc} compilerproc; {$endif}
  444. var
  445. ss : shortstring;
  446. begin
  447. str(v:len,ss);
  448. s:=ss;
  449. end;
  450. {$ifdef HASWIDESTRING}
  451. procedure fpc_widestr_qword(v : qword;len : longint;var s : widestring);[public,alias:'FPC_WIDESTR_QWORD']; {$ifdef hascompilerproc} compilerproc; {$endif}
  452. var
  453. ss : shortstring;
  454. begin
  455. str(v:len,ss);
  456. s:=ss;
  457. end;
  458. procedure fpc_widestr_int64(v : int64;len : longint;var s : widestring);[public,alias:'FPC_WIDESTR_INT64']; {$ifdef hascompilerproc} compilerproc; {$endif}
  459. var
  460. ss : shortstring;
  461. begin
  462. str(v:len,ss);
  463. s:=ss;
  464. end;
  465. {$endif HASWIDESTRING}
  466. Function fpc_val_int64_shortstr(Const S: ShortString; var Code: ValSInt): Int64; [public, alias:'FPC_VAL_INT64_SHORTSTR']; {$ifdef hascompilerproc} compilerproc; {$endif}
  467. type
  468. QWordRec = packed record
  469. l1,l2: longint;
  470. end;
  471. var
  472. u, temp, prev, maxint64, maxqword : qword;
  473. base : byte;
  474. negative : boolean;
  475. begin
  476. fpc_val_int64_shortstr := 0;
  477. Temp:=0;
  478. Code:=InitVal(s,negative,base);
  479. if Code>length(s) then
  480. exit;
  481. { high(int64) produces 0 in version 1.0 (JM) }
  482. with qwordrec(maxint64) do
  483. begin
  484. l1 := longint($ffffffff);
  485. l2 := $7fffffff;
  486. end;
  487. with qwordrec(maxqword) do
  488. begin
  489. l1 := longint($ffffffff);
  490. l2 := longint($ffffffff);
  491. end;
  492. while Code<=Length(s) do
  493. begin
  494. case s[Code] of
  495. '0'..'9' : u:=Ord(S[Code])-Ord('0');
  496. 'A'..'F' : u:=Ord(S[Code])-(Ord('A')-10);
  497. 'a'..'f' : u:=Ord(S[Code])-(Ord('a')-10);
  498. else
  499. u:=16;
  500. end;
  501. Prev:=Temp;
  502. Temp:=Temp*Int64(base);
  503. If (u >= base) or
  504. ((base = 10) and
  505. (maxint64-temp+ord(negative) < u)) or
  506. ((base <> 10) and
  507. (qword(maxqword-temp) < u)) or
  508. (prev > maxqword div qword(base)) Then
  509. Begin
  510. fpc_val_int64_shortstr := 0;
  511. Exit
  512. End;
  513. Temp:=Temp+u;
  514. inc(code);
  515. end;
  516. code:=0;
  517. fpc_val_int64_shortstr:=int64(Temp);
  518. If Negative Then
  519. fpc_val_int64_shortstr:=-fpc_val_int64_shortstr;
  520. end;
  521. Function fpc_val_qword_shortstr(Const S: ShortString; var Code: ValSInt): QWord; [public, alias:'FPC_VAL_QWORD_SHORTSTR']; {$ifdef hascompilerproc} compilerproc; {$endif}
  522. type qwordrec = packed record
  523. l1,l2: longint;
  524. end;
  525. var
  526. u, prev, maxqword: QWord;
  527. base : byte;
  528. negative : boolean;
  529. begin
  530. fpc_val_qword_shortstr:=0;
  531. Code:=InitVal(s,negative,base);
  532. If Negative or (Code>length(s)) Then
  533. Exit;
  534. with qwordrec(maxqword) do
  535. begin
  536. l1 := longint($ffffffff);
  537. l2 := longint($ffffffff);
  538. end;
  539. while Code<=Length(s) do
  540. begin
  541. case s[Code] of
  542. '0'..'9' : u:=Ord(S[Code])-Ord('0');
  543. 'A'..'F' : u:=Ord(S[Code])-(Ord('A')-10);
  544. 'a'..'f' : u:=Ord(S[Code])-(Ord('a')-10);
  545. else
  546. u:=16;
  547. end;
  548. prev := fpc_val_qword_shortstr;
  549. If (u>=base) or
  550. ((QWord(maxqword-u) div QWord(base))<prev) then
  551. Begin
  552. fpc_val_qword_shortstr := 0;
  553. Exit
  554. End;
  555. fpc_val_qword_shortstr:=fpc_val_qword_shortstr*QWord(base) + u;
  556. inc(code);
  557. end;
  558. code := 0;
  559. end;
  560. {
  561. $Log$
  562. Revision 1.14 2002-07-01 16:29:05 peter
  563. * sLineBreak changed to normal constant like Kylix
  564. Revision 1.13 2001/11/15 00:07:42 florian
  565. * qword div qword for i386 improved
  566. Revision 1.12 2001/09/05 15:22:09 jonas
  567. * made multiplying, dividing and mod'ing of int64 and qword processor
  568. independent with compilerprocs (+ small optimizations by using shift/and
  569. where possible)
  570. Revision 1.11 2001/08/13 12:40:16 jonas
  571. * renamed some str(x,y) and val(x,y) helpers so the naming scheme is the
  572. same for all string types
  573. + added the str(x,y) and val(x,y,z) helpers for int64/qword to
  574. compproc.inc
  575. Revision 1.10 2001/04/23 18:25:45 peter
  576. * m68k updates
  577. Revision 1.9 2001/04/13 22:30:04 peter
  578. * remove warnings
  579. Revision 1.8 2001/03/03 12:39:09 jonas
  580. * fixed qword_str for values with bit 63 = 1
  581. Revision 1.7 2000/12/10 15:00:14 florian
  582. * val for int64 hopefully works now correct
  583. Revision 1.6 2000/12/09 20:52:40 florian
  584. * val for dword and qword didn't handle the max values
  585. correctly
  586. * val for qword works again
  587. + val with int64/qword and ansistring implemented
  588. Revision 1.5 2000/12/07 17:19:47 jonas
  589. * new constant handling: from now on, hex constants >$7fffffff are
  590. parsed as unsigned constants (otherwise, $80000000 got sign extended
  591. and became $ffffffff80000000), all constants in the longint range
  592. become longints, all constants >$7fffffff and <=cardinal($ffffffff)
  593. are cardinals and the rest are int64's.
  594. * added lots of longint typecast to prevent range check errors in the
  595. compiler and rtl
  596. * type casts of symbolic ordinal constants are now preserved
  597. * fixed bug where the original resulttype wasn't restored correctly
  598. after doing a 64bit rangecheck
  599. Revision 1.4 2000/11/17 17:01:23 jonas
  600. * fixed bug for val when processing -2147483648 and low(int64) (merged)
  601. Revision 1.3 2000/07/28 12:29:49 jonas
  602. * fixed web bug1069
  603. * fixed similar (and other) problems in val() for int64 and qword
  604. (both merged from fixes branch)
  605. Revision 1.2 2000/07/13 11:33:44 michael
  606. + removed logs
  607. }