int64.inc 15 KB

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