int64.inc 17 KB

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