int64.inc 16 KB

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