int64.inc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611
  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_not_working_correct}
  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. begin
  216. if n=0 then
  217. HandleErrorFrame(200,get_frame);
  218. { can the fpu do the work? }
  219. begin
  220. sign:=false;
  221. if z<0 then
  222. begin
  223. sign:=not(sign);
  224. q1:=qword(-z);
  225. end
  226. else
  227. q1:=z;
  228. if n<0 then
  229. begin
  230. sign:=not(sign);
  231. q2:=qword(-n);
  232. end
  233. else
  234. q2:=n;
  235. { the div is coded by the compiler as call to divqword }
  236. if sign then
  237. fpc_div_int64:=-(q1 div q2)
  238. else
  239. fpc_div_int64:=q1 div q2;
  240. end;
  241. end;
  242. function fpc_mod_int64(n,z : int64) : int64;[public,alias: 'FPC_MOD_INT64']; {$ifdef hascompilerproc} compilerproc; {$endif}
  243. var
  244. signed : boolean;
  245. r,nq,zq : qword;
  246. begin
  247. if n=0 then
  248. HandleErrorFrame(200,get_frame);
  249. if n<0 then
  250. begin
  251. nq:=-n;
  252. signed:=true;
  253. end
  254. else
  255. begin
  256. signed:=false;
  257. nq:=n;
  258. end;
  259. if z<0 then
  260. begin
  261. zq:=qword(-z);
  262. signed:=not(signed);
  263. end
  264. else
  265. zq:=z;
  266. r:=zq mod nq;
  267. if signed then
  268. fpc_mod_int64:=-int64(r)
  269. else
  270. fpc_mod_int64:=r;
  271. end;
  272. { multiplies two qwords
  273. the longbool for checkoverflow avoids a misaligned stack
  274. }
  275. function fpc_mul_qword(f1,f2 : qword;checkoverflow : longbool) : qword;[public,alias: 'FPC_MUL_QWORD']; {$ifdef hascompilerproc} compilerproc; {$endif}
  276. var
  277. _f1,bitpos : qword;
  278. l : longint;
  279. {$ifdef i386}
  280. r : qword;
  281. {$endif i386}
  282. begin
  283. {$ifdef i386}
  284. if not(checkoverflow) then
  285. begin
  286. { the following piece of code is taken from the }
  287. { AMD Athlon Processor x86 Code Optimization manual }
  288. asm
  289. movl f1+4,%edx
  290. movl f2+4,%ecx
  291. orl %ecx,%edx
  292. movl f2,%edx
  293. movl f1,%eax
  294. jnz .Lqwordmultwomul
  295. mull %edx
  296. jmp .Lqwordmulready
  297. .Lqwordmultwomul:
  298. imul f1+4,%edx
  299. imul %eax,%ecx
  300. addl %edx,%ecx
  301. mull f2
  302. add %ecx,%edx
  303. .Lqwordmulready:
  304. movl %eax,r
  305. movl %edx,r+4
  306. end;
  307. fpc_mul_qword:=r;
  308. end
  309. else
  310. {$endif i386}
  311. begin
  312. fpc_mul_qword:=0;
  313. bitpos:=1;
  314. // store f1 for overflow checking
  315. _f1:=f1;
  316. for l:=0 to 63 do
  317. begin
  318. if (f2 and bitpos)<>0 then
  319. fpc_mul_qword:=fpc_mul_qword+f1;
  320. f1:=f1 shl 1;
  321. bitpos:=bitpos shl 1;
  322. end;
  323. { if one of the operands is greater than the result an }
  324. { overflow occurs }
  325. if checkoverflow and (_f1 <> 0) and (f2 <>0) and
  326. ((_f1>fpc_mul_qword) or (f2>fpc_mul_qword)) then
  327. HandleErrorFrame(215,get_frame);
  328. end;
  329. end;
  330. function fpc_mul_int64(f1,f2 : int64;checkoverflow : longbool) : int64;[public,alias: 'FPC_MUL_INT64']; {$ifdef hascompilerproc} compilerproc; {$endif}
  331. var
  332. sign : boolean;
  333. q1,q2,q3 : qword;
  334. begin
  335. begin
  336. sign:=false;
  337. if f1<0 then
  338. begin
  339. sign:=not(sign);
  340. q1:=qword(-f1);
  341. end
  342. else
  343. q1:=f1;
  344. if f2<0 then
  345. begin
  346. sign:=not(sign);
  347. q2:=qword(-f2);
  348. end
  349. else
  350. q2:=f2;
  351. { the q1*q2 is coded as call to mulqword }
  352. q3:=q1*q2;
  353. if checkoverflow and (q1 <> 0) and (q2 <>0) and
  354. ((q1>q3) or (q2>q3) or
  355. { the bit 63 can be only set if we have $80000000 00000000 }
  356. { and sign is true }
  357. ((tqwordrec(q3).high and dword($80000000))<>0) and
  358. ((q3<>(qword(1) shl 63)) or not(sign))
  359. ) then
  360. HandleErrorFrame(215,get_frame);
  361. if sign then
  362. fpc_mul_int64:=-q3
  363. else
  364. fpc_mul_int64:=q3;
  365. end;
  366. end;
  367. procedure qword_str(value : qword;var s : string);
  368. var
  369. hs : string;
  370. begin
  371. hs:='';
  372. repeat
  373. hs:=chr(longint(value mod qword(10))+48)+hs;
  374. value:=value div qword(10);
  375. until value=0;
  376. s:=hs;
  377. end;
  378. procedure int64_str(value : int64;var s : string);
  379. var
  380. hs : string;
  381. q : qword;
  382. begin
  383. if value<0 then
  384. begin
  385. q:=qword(-value);
  386. qword_str(q,hs);
  387. s:='-'+hs;
  388. end
  389. else
  390. qword_str(qword(value),s);
  391. end;
  392. procedure fpc_shortstr_qword(v : qword;len : longint;var s : shortstring);[public,alias:'FPC_SHORTSTR_QWORD']; {$ifdef hascompilerproc} compilerproc; {$endif}
  393. begin
  394. qword_str(v,s);
  395. if length(s)<len then
  396. s:=space(len-length(s))+s;
  397. end;
  398. procedure fpc_shortstr_int64(v : int64;len : longint;var s : shortstring);[public,alias:'FPC_SHORTSTR_INT64']; {$ifdef hascompilerproc} compilerproc; {$endif}
  399. begin
  400. int64_str(v,s);
  401. if length(s)<len then
  402. s:=space(len-length(s))+s;
  403. end;
  404. procedure fpc_ansistr_qword(v : qword;len : longint;var s : ansistring);[public,alias:'FPC_ANSISTR_QWORD']; {$ifdef hascompilerproc} compilerproc; {$endif}
  405. var
  406. ss : shortstring;
  407. begin
  408. str(v:len,ss);
  409. s:=ss;
  410. end;
  411. procedure fpc_ansistr_int64(v : int64;len : longint;var s : ansistring);[public,alias:'FPC_ANSISTR_INT64']; {$ifdef hascompilerproc} compilerproc; {$endif}
  412. var
  413. ss : shortstring;
  414. begin
  415. str(v:len,ss);
  416. s:=ss;
  417. end;
  418. {$ifdef HASWIDESTRING}
  419. procedure fpc_widestr_qword(v : qword;len : longint;var s : widestring);[public,alias:'FPC_WIDESTR_QWORD']; {$ifdef hascompilerproc} compilerproc; {$endif}
  420. var
  421. ss : shortstring;
  422. begin
  423. str(v:len,ss);
  424. s:=ss;
  425. end;
  426. procedure fpc_widestr_int64(v : int64;len : longint;var s : widestring);[public,alias:'FPC_WIDESTR_INT64']; {$ifdef hascompilerproc} compilerproc; {$endif}
  427. var
  428. ss : shortstring;
  429. begin
  430. str(v:len,ss);
  431. s:=ss;
  432. end;
  433. {$endif HASWIDESTRING}
  434. Function fpc_val_int64_shortstr(Const S: ShortString; var Code: ValSInt): Int64; [public, alias:'FPC_VAL_INT64_SHORTSTR']; {$ifdef hascompilerproc} compilerproc; {$endif}
  435. type
  436. QWordRec = packed record
  437. l1,l2: longint;
  438. end;
  439. var
  440. u, temp, prev, maxint64, maxqword : qword;
  441. base : byte;
  442. negative : boolean;
  443. begin
  444. fpc_val_int64_shortstr := 0;
  445. Temp:=0;
  446. Code:=InitVal(s,negative,base);
  447. if Code>length(s) then
  448. exit;
  449. { high(int64) produces 0 in version 1.0 (JM) }
  450. with qwordrec(maxint64) do
  451. begin
  452. l1 := longint($ffffffff);
  453. l2 := $7fffffff;
  454. end;
  455. with qwordrec(maxqword) do
  456. begin
  457. l1 := longint($ffffffff);
  458. l2 := longint($ffffffff);
  459. end;
  460. while Code<=Length(s) do
  461. begin
  462. case s[Code] of
  463. '0'..'9' : u:=Ord(S[Code])-Ord('0');
  464. 'A'..'F' : u:=Ord(S[Code])-(Ord('A')-10);
  465. 'a'..'f' : u:=Ord(S[Code])-(Ord('a')-10);
  466. else
  467. u:=16;
  468. end;
  469. Prev:=Temp;
  470. Temp:=Temp*Int64(base);
  471. If (u >= base) or
  472. ((base = 10) and
  473. (maxint64-temp+ord(negative) < u)) or
  474. ((base <> 10) and
  475. (qword(maxqword-temp) < u)) or
  476. (prev > maxqword div qword(base)) Then
  477. Begin
  478. fpc_val_int64_shortstr := 0;
  479. Exit
  480. End;
  481. Temp:=Temp+u;
  482. inc(code);
  483. end;
  484. code:=0;
  485. fpc_val_int64_shortstr:=int64(Temp);
  486. If Negative Then
  487. fpc_val_int64_shortstr:=-fpc_val_int64_shortstr;
  488. end;
  489. Function fpc_val_qword_shortstr(Const S: ShortString; var Code: ValSInt): QWord; [public, alias:'FPC_VAL_QWORD_SHORTSTR']; {$ifdef hascompilerproc} compilerproc; {$endif}
  490. type qwordrec = packed record
  491. l1,l2: longint;
  492. end;
  493. var
  494. u, prev, maxqword: QWord;
  495. base : byte;
  496. negative : boolean;
  497. begin
  498. fpc_val_qword_shortstr:=0;
  499. Code:=InitVal(s,negative,base);
  500. If Negative or (Code>length(s)) Then
  501. Exit;
  502. with qwordrec(maxqword) do
  503. begin
  504. l1 := longint($ffffffff);
  505. l2 := longint($ffffffff);
  506. end;
  507. while Code<=Length(s) do
  508. begin
  509. case s[Code] of
  510. '0'..'9' : u:=Ord(S[Code])-Ord('0');
  511. 'A'..'F' : u:=Ord(S[Code])-(Ord('A')-10);
  512. 'a'..'f' : u:=Ord(S[Code])-(Ord('a')-10);
  513. else
  514. u:=16;
  515. end;
  516. prev := fpc_val_qword_shortstr;
  517. If (u>=base) or
  518. ((QWord(maxqword-u) div QWord(base))<prev) then
  519. Begin
  520. fpc_val_qword_shortstr := 0;
  521. Exit
  522. End;
  523. fpc_val_qword_shortstr:=fpc_val_qword_shortstr*QWord(base) + u;
  524. inc(code);
  525. end;
  526. code := 0;
  527. end;
  528. {
  529. $Log$
  530. Revision 1.17 2002-09-07 21:21:42 carl
  531. - remove FPUInt64 variable
  532. Revision 1.16 2002/09/07 15:07:45 peter
  533. * old logs removed and tabs fixed
  534. Revision 1.15 2002/09/01 14:44:01 peter
  535. * renamed conditional to insert optimized mod_qword for i386. The
  536. code is broken
  537. Revision 1.14 2002/07/01 16:29:05 peter
  538. * sLineBreak changed to normal constant like Kylix
  539. }