int64.inc 17 KB

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