int64.inc 14 KB

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