int64.inc 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by the Free Pascal development team
  4. This file contains some helper routines for int64 and qword
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$Q- no overflow checking }
  12. {$R- no range checking }
  13. type
  14. {$ifdef ENDIAN_LITTLE}
  15. tqwordrec = packed record
  16. low : dword;
  17. high : dword;
  18. end;
  19. {$endif ENDIAN_LITTLE}
  20. {$ifdef ENDIAN_BIG}
  21. tqwordrec = packed record
  22. high : dword;
  23. low : dword;
  24. end;
  25. {$endif ENDIAN_BIG}
  26. {$ifdef FPC_INCLUDE_SOFTWARE_SHIFT_INT64}
  27. {$ifndef FPC_SYSTEM_HAS_SHL_QWORD}
  28. function fpc_shl_qword(value,shift : qword) : qword; [public,alias: 'FPC_SHL_QWORD']; compilerproc;
  29. begin
  30. shift:=shift and 63;
  31. if shift=0 then
  32. result:=value
  33. else if shift>31 then
  34. begin
  35. tqwordrec(result).low:=0;
  36. tqwordrec(result).high:=tqwordrec(value).low shl (shift-32);
  37. end
  38. else
  39. begin
  40. tqwordrec(result).low:=tqwordrec(value).low shl shift;
  41. tqwordrec(result).high:=(tqwordrec(value).high shl shift) or (tqwordrec(value).low shr (32-shift));
  42. end;
  43. end;
  44. {$endif FPC_SYSTEM_HAS_SHL_QWORD}
  45. {$ifndef FPC_SYSTEM_HAS_SHR_QWORD}
  46. function fpc_shr_qword(value,shift : qword) : qword; [public,alias: 'FPC_SHR_QWORD']; compilerproc;
  47. begin
  48. shift:=shift and 63;
  49. if shift=0 then
  50. result:=value
  51. else if shift>31 then
  52. begin
  53. tqwordrec(result).high:=0;
  54. tqwordrec(result).low:=tqwordrec(value).high shr (shift-32);
  55. end
  56. else
  57. begin
  58. tqwordrec(result).high:=tqwordrec(value).high shr shift;
  59. tqwordrec(result).low:=(tqwordrec(value).low shr shift) or (tqwordrec(value).high shl (32-shift));
  60. end;
  61. end;
  62. {$endif FPC_SYSTEM_HAS_SHR_QWORD}
  63. {$ifndef FPC_SYSTEM_HAS_SHL_INT64}
  64. function fpc_shl_int64(value,shift : int64) : int64; [public,alias: 'FPC_SHL_INT64']; compilerproc;
  65. begin
  66. shift:=shift and 63;
  67. if shift=0 then
  68. result:=value
  69. else if shift>31 then
  70. begin
  71. tqwordrec(result).low:=0;
  72. tqwordrec(result).high:=tqwordrec(value).low shl (shift-32);
  73. end
  74. else
  75. begin
  76. tqwordrec(result).low:=tqwordrec(value).low shl shift;
  77. tqwordrec(result).high:=(tqwordrec(value).high shl shift) or (tqwordrec(value).low shr (32-shift));
  78. end;
  79. end;
  80. {$endif FPC_SYSTEM_HAS_SHL_INT64}
  81. {$ifndef FPC_SYSTEM_HAS_SHR_INT64}
  82. function fpc_shr_int64(value,shift : int64) : int64; [public,alias: 'FPC_SHR_INT64']; compilerproc;
  83. begin
  84. shift:=shift and 63;
  85. if shift=0 then
  86. result:=value
  87. else if shift>31 then
  88. begin
  89. tqwordrec(result).high:=0;
  90. tqwordrec(result).low:=tqwordrec(value).high shr (shift-32);
  91. end
  92. else
  93. begin
  94. tqwordrec(result).high:=tqwordrec(value).high shr shift;
  95. tqwordrec(result).low:=(tqwordrec(value).low shr shift) or (tqwordrec(value).high shl (32-shift));
  96. end;
  97. end;
  98. {$endif FPC_SYSTEM_HAS_SHR_INT64}
  99. {$endif FPC_INCLUDE_SOFTWARE_SHIFT_INT64}
  100. {$ifndef FPC_SYSTEM_HAS_DIV_QWORD}
  101. function fpc_div_qword(n,z : qword) : qword;[public,alias: 'FPC_DIV_QWORD']; compilerproc;
  102. var
  103. shift,lzz,lzn : longint;
  104. begin
  105. fpc_div_qword:=0;
  106. if n=0 then
  107. HandleErrorAddrFrameInd(200,get_pc_addr,get_frame);
  108. if z=0 then
  109. exit;
  110. lzz:=BsrQWord(z);
  111. lzn:=BsrQWord(n);
  112. { if the denominator contains less zeros }
  113. { than the numerator }
  114. { then d is greater than the n }
  115. if lzn>lzz then
  116. exit;
  117. shift:=lzz-lzn;
  118. n:=n shl shift;
  119. for shift:=shift downto 0 do
  120. begin
  121. if z>=n then
  122. begin
  123. z:=z-n;
  124. fpc_div_qword:=fpc_div_qword+(qword(1) shl shift);
  125. end;
  126. n:=n shr 1;
  127. end;
  128. end;
  129. {$endif FPC_SYSTEM_HAS_DIV_QWORD}
  130. {$ifndef FPC_SYSTEM_HAS_MOD_QWORD}
  131. function fpc_mod_qword(n,z : qword) : qword;[public,alias: 'FPC_MOD_QWORD']; compilerproc;
  132. var
  133. shift,lzz,lzn : longint;
  134. begin
  135. fpc_mod_qword:=0;
  136. if n=0 then
  137. HandleErrorAddrFrameInd(200,get_pc_addr,get_frame);
  138. if z=0 then
  139. exit;
  140. lzz:=BsrQword(z);
  141. lzn:=BsrQword(n);
  142. { if the denominator contains less zeros }
  143. { then the numerator }
  144. { the d is greater than the n }
  145. if lzn>lzz then
  146. begin
  147. fpc_mod_qword:=z;
  148. exit;
  149. end;
  150. shift:=lzz-lzn;
  151. n:=n shl shift;
  152. for shift:=shift downto 0 do
  153. begin
  154. if z>=n then
  155. z:=z-n;
  156. n:=n shr 1;
  157. end;
  158. fpc_mod_qword:=z;
  159. end;
  160. {$endif FPC_SYSTEM_HAS_MOD_QWORD}
  161. {$ifndef FPC_SYSTEM_HAS_DIV_INT64}
  162. function fpc_div_int64(n,z : int64) : int64;[public,alias: 'FPC_DIV_INT64']; compilerproc;
  163. var
  164. sign : boolean;
  165. q1,q2 : qword;
  166. begin
  167. if n=0 then
  168. HandleErrorAddrFrameInd(200,get_pc_addr,get_frame);
  169. { can the fpu do the work? }
  170. begin
  171. sign:=false;
  172. if z<0 then
  173. begin
  174. sign:=not(sign);
  175. q1:=qword(-z);
  176. end
  177. else
  178. q1:=z;
  179. if n<0 then
  180. begin
  181. sign:=not(sign);
  182. q2:=qword(-n);
  183. end
  184. else
  185. q2:=n;
  186. { the div is coded by the compiler as call to divqword }
  187. if sign then
  188. fpc_div_int64:=-(q1 div q2)
  189. else
  190. fpc_div_int64:=q1 div q2;
  191. end;
  192. end;
  193. {$endif FPC_SYSTEM_HAS_DIV_INT64}
  194. {$ifndef FPC_SYSTEM_HAS_MOD_INT64}
  195. function fpc_mod_int64(n,z : int64) : int64;[public,alias: 'FPC_MOD_INT64']; compilerproc;
  196. var
  197. signed : boolean;
  198. r,nq,zq : qword;
  199. begin
  200. if n=0 then
  201. HandleErrorAddrFrameInd(200,get_pc_addr,get_frame);
  202. if n<0 then
  203. nq:=-n
  204. else
  205. nq:=n;
  206. if z<0 then
  207. begin
  208. signed:=true;
  209. zq:=qword(-z)
  210. end
  211. else
  212. begin
  213. signed:=false;
  214. zq:=z;
  215. end;
  216. r:=zq mod nq;
  217. if signed then
  218. fpc_mod_int64:=-int64(r)
  219. else
  220. fpc_mod_int64:=r;
  221. end;
  222. {$endif FPC_SYSTEM_HAS_MOD_INT64}
  223. {$ifndef FPC_SYSTEM_HAS_MUL_QWORD}
  224. { multiplies two qwords
  225. the longbool for checkoverflow avoids a misaligned stack
  226. }
  227. function fpc_mul_qword(f1,f2 : qword;checkoverflow : longbool) : qword;[public,alias: 'FPC_MUL_QWORD']; compilerproc;
  228. var
  229. _f1,bitpos : qword;
  230. l : longint;
  231. f1overflowed : boolean;
  232. begin
  233. fpc_mul_qword:=0;
  234. bitpos:=1;
  235. f1overflowed:=false;
  236. for l:=0 to 63 do
  237. begin
  238. if (f2 and bitpos)<>0 then
  239. begin
  240. _f1:=fpc_mul_qword;
  241. fpc_mul_qword:=fpc_mul_qword+f1;
  242. { if one of the operands is greater than the result an
  243. overflow occurs }
  244. if checkoverflow and (f1overflowed or ((_f1<>0) and (f1<>0) and
  245. ((_f1>fpc_mul_qword) or (f1>fpc_mul_qword)))) then
  246. HandleErrorAddrFrameInd(215,get_pc_addr,get_frame);
  247. end;
  248. { when bootstrapping, we forget about overflow checking for qword :) }
  249. f1overflowed:=f1overflowed or ((f1 and (1 shl 63))<>0);
  250. f1:=f1 shl 1;
  251. bitpos:=bitpos shl 1;
  252. end;
  253. end;
  254. {$endif FPC_SYSTEM_HAS_MUL_QWORD}
  255. {$ifndef FPC_SYSTEM_HAS_MUL_INT64}
  256. function fpc_mul_int64(f1,f2 : int64;checkoverflow : longbool) : int64;[public,alias: 'FPC_MUL_INT64']; compilerproc;
  257. var
  258. sign : boolean;
  259. q1,q2,q3 : qword;
  260. begin
  261. begin
  262. sign:=false;
  263. if f1<0 then
  264. begin
  265. sign:=not(sign);
  266. q1:=qword(-f1);
  267. end
  268. else
  269. q1:=f1;
  270. if f2<0 then
  271. begin
  272. sign:=not(sign);
  273. q2:=qword(-f2);
  274. end
  275. else
  276. q2:=f2;
  277. { the q1*q2 is coded as call to mulqword }
  278. q3:=q1*q2;
  279. if checkoverflow and (q1 <> 0) and (q2 <>0) and
  280. ((q1>q3) or (q2>q3) or
  281. { the bit 63 can be only set if we have $80000000 00000000 }
  282. { and sign is true }
  283. (q3 shr 63<>0) and
  284. ((q3<>qword(qword(1) shl 63)) or not(sign))
  285. ) then
  286. HandleErrorAddrFrameInd(215,get_pc_addr,get_frame);
  287. if sign then
  288. fpc_mul_int64:=-q3
  289. else
  290. fpc_mul_int64:=q3;
  291. end;
  292. end;
  293. {$endif FPC_SYSTEM_HAS_MUL_INT64}