123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363 |
- {
- This file is part of the Free Pascal run time library.
- Copyright (c) 1999-2000 by the Free Pascal development team
- This file contains some helper routines for int64 and qword
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- {$Q- no overflow checking }
- {$R- no range checking }
- type
- {$ifdef ENDIAN_LITTLE}
- tqwordrec = packed record
- low : dword;
- high : dword;
- end;
- {$endif ENDIAN_LITTLE}
- {$ifdef ENDIAN_BIG}
- tqwordrec = packed record
- high : dword;
- low : dword;
- end;
- {$endif ENDIAN_BIG}
- {$ifdef FPC_INCLUDE_SOFTWARE_SHIFT_INT64}
- {$ifndef FPC_SYSTEM_HAS_SHL_QWORD}
- function fpc_shl_qword(value,shift : qword) : qword; [public,alias: 'FPC_SHL_QWORD']; compilerproc;
- begin
- shift:=shift and 63;
- if shift=0 then
- result:=value
- else if shift>31 then
- begin
- tqwordrec(result).low:=0;
- tqwordrec(result).high:=tqwordrec(value).low shl (shift-32);
- end
- else
- begin
- tqwordrec(result).low:=tqwordrec(value).low shl shift;
- tqwordrec(result).high:=(tqwordrec(value).high shl shift) or (tqwordrec(value).low shr (32-shift));
- end;
- end;
- {$endif FPC_SYSTEM_HAS_SHL_QWORD}
- {$ifndef FPC_SYSTEM_HAS_SHR_QWORD}
- function fpc_shr_qword(value,shift : qword) : qword; [public,alias: 'FPC_SHR_QWORD']; compilerproc;
- begin
- shift:=shift and 63;
- if shift=0 then
- result:=value
- else if shift>31 then
- begin
- tqwordrec(result).high:=0;
- tqwordrec(result).low:=tqwordrec(value).high shr (shift-32);
- end
- else
- begin
- tqwordrec(result).high:=tqwordrec(value).high shr shift;
- tqwordrec(result).low:=(tqwordrec(value).low shr shift) or (tqwordrec(value).high shl (32-shift));
- end;
- end;
- {$endif FPC_SYSTEM_HAS_SHR_QWORD}
- {$ifndef FPC_SYSTEM_HAS_SHL_INT64}
- function fpc_shl_int64(value,shift : int64) : int64; [public,alias: 'FPC_SHL_INT64']; compilerproc;
- begin
- shift:=shift and 63;
- if shift=0 then
- result:=value
- else if shift>31 then
- begin
- tqwordrec(result).low:=0;
- tqwordrec(result).high:=tqwordrec(value).low shl (shift-32);
- end
- else
- begin
- tqwordrec(result).low:=tqwordrec(value).low shl shift;
- tqwordrec(result).high:=(tqwordrec(value).high shl shift) or (tqwordrec(value).low shr (32-shift));
- end;
- end;
- {$endif FPC_SYSTEM_HAS_SHL_INT64}
- {$ifndef FPC_SYSTEM_HAS_SHR_INT64}
- function fpc_shr_int64(value,shift : int64) : int64; [public,alias: 'FPC_SHR_INT64']; compilerproc;
- begin
- shift:=shift and 63;
- if shift=0 then
- result:=value
- else if shift>31 then
- begin
- tqwordrec(result).high:=0;
- tqwordrec(result).low:=tqwordrec(value).high shr (shift-32);
- end
- else
- begin
- tqwordrec(result).high:=tqwordrec(value).high shr shift;
- tqwordrec(result).low:=(tqwordrec(value).low shr shift) or (tqwordrec(value).high shl (32-shift));
- end;
- end;
- {$endif FPC_SYSTEM_HAS_SHR_INT64}
- {$endif FPC_INCLUDE_SOFTWARE_SHIFT_INT64}
- function count_leading_zeros(q : qword) : longint;
- var
- r,i : longint;
- begin
- r:=0;
- for i:=0 to 31 do
- begin
- if (tqwordrec(q).high and (dword($80000000) shr i))<>0 then
- begin
- count_leading_zeros:=r;
- exit;
- end;
- inc(r);
- end;
- for i:=0 to 31 do
- begin
- if (tqwordrec(q).low and (dword($80000000) shr i))<>0 then
- begin
- count_leading_zeros:=r;
- exit;
- end;
- inc(r);
- end;
- count_leading_zeros:=r;
- end;
- {$ifndef FPC_SYSTEM_HAS_DIV_QWORD}
- function fpc_div_qword(n,z : qword) : qword;[public,alias: 'FPC_DIV_QWORD']; compilerproc;
- var
- shift,lzz,lzn : longint;
- begin
- fpc_div_qword:=0;
- if n=0 then
- HandleErrorFrame(200,get_frame);
- lzz:=count_leading_zeros(z);
- lzn:=count_leading_zeros(n);
- { if the denominator contains less zeros }
- { then the numerator }
- { the d is greater than the n }
- if lzn<lzz then
- exit;
- shift:=lzn-lzz;
- n:=n shl shift;
- repeat
- if z>=n then
- begin
- z:=z-n;
- fpc_div_qword:=fpc_div_qword+(qword(1) shl shift);
- end;
- dec(shift);
- n:=n shr 1;
- until shift<0;
- end;
- {$endif FPC_SYSTEM_HAS_DIV_QWORD}
- {$ifndef FPC_SYSTEM_HAS_MOD_QWORD}
- function fpc_mod_qword(n,z : qword) : qword;[public,alias: 'FPC_MOD_QWORD']; compilerproc;
- var
- shift,lzz,lzn : longint;
- begin
- fpc_mod_qword:=0;
- if n=0 then
- HandleErrorFrame(200,get_frame);
- lzz:=count_leading_zeros(z);
- lzn:=count_leading_zeros(n);
- { if the denominator contains less zeros }
- { then the numerator }
- { the d is greater than the n }
- if lzn<lzz then
- begin
- fpc_mod_qword:=z;
- exit;
- end;
- shift:=lzn-lzz;
- n:=n shl shift;
- repeat
- if z>=n then
- z:=z-n;
- dec(shift);
- n:=n shr 1;
- until shift<0;
- fpc_mod_qword:=z;
- end;
- {$endif FPC_SYSTEM_HAS_MOD_QWORD}
- {$ifndef FPC_SYSTEM_HAS_DIV_INT64}
- function fpc_div_int64(n,z : int64) : int64;[public,alias: 'FPC_DIV_INT64']; compilerproc;
- var
- sign : boolean;
- q1,q2 : qword;
- begin
- if n=0 then
- HandleErrorFrame(200,get_frame);
- { can the fpu do the work? }
- begin
- sign:=false;
- if z<0 then
- begin
- sign:=not(sign);
- q1:=qword(-z);
- end
- else
- q1:=z;
- if n<0 then
- begin
- sign:=not(sign);
- q2:=qword(-n);
- end
- else
- q2:=n;
- { the div is coded by the compiler as call to divqword }
- if sign then
- fpc_div_int64:=-(q1 div q2)
- else
- fpc_div_int64:=q1 div q2;
- end;
- end;
- {$endif FPC_SYSTEM_HAS_DIV_INT64}
- {$ifndef FPC_SYSTEM_HAS_MOD_INT64}
- function fpc_mod_int64(n,z : int64) : int64;[public,alias: 'FPC_MOD_INT64']; compilerproc;
- var
- signed : boolean;
- r,nq,zq : qword;
- begin
- if n=0 then
- HandleErrorFrame(200,get_frame);
- if n<0 then
- nq:=-n
- else
- nq:=n;
- if z<0 then
- begin
- signed:=true;
- zq:=qword(-z)
- end
- else
- begin
- signed:=false;
- zq:=z;
- end;
- r:=zq mod nq;
- if signed then
- fpc_mod_int64:=-int64(r)
- else
- fpc_mod_int64:=r;
- end;
- {$endif FPC_SYSTEM_HAS_MOD_INT64}
- {$ifndef FPC_SYSTEM_HAS_MUL_QWORD}
- { multiplies two qwords
- the longbool for checkoverflow avoids a misaligned stack
- }
- function fpc_mul_qword(f1,f2 : qword;checkoverflow : longbool) : qword;[public,alias: 'FPC_MUL_QWORD']; compilerproc;
- var
- _f1,bitpos : qword;
- l : longint;
- f1overflowed : boolean;
- begin
- fpc_mul_qword:=0;
- bitpos:=1;
- f1overflowed:=false;
- for l:=0 to 63 do
- begin
- if (f2 and bitpos)<>0 then
- begin
- _f1:=fpc_mul_qword;
- fpc_mul_qword:=fpc_mul_qword+f1;
- { if one of the operands is greater than the result an
- overflow occurs }
- if checkoverflow and (f1overflowed or ((_f1<>0) and (f1<>0) and
- ((_f1>fpc_mul_qword) or (f1>fpc_mul_qword)))) then
- HandleErrorFrame(215,get_frame);
- end;
- { when bootstrapping, we forget about overflow checking for qword :) }
- f1overflowed:=f1overflowed or ((f1 and (1 shl 63))<>0);
- f1:=f1 shl 1;
- bitpos:=bitpos shl 1;
- end;
- end;
- {$endif FPC_SYSTEM_HAS_MUL_QWORD}
- {$ifndef FPC_SYSTEM_HAS_MUL_INT64}
- function fpc_mul_int64(f1,f2 : int64;checkoverflow : longbool) : int64;[public,alias: 'FPC_MUL_INT64']; compilerproc;
- var
- sign : boolean;
- q1,q2,q3 : qword;
- begin
- begin
- sign:=false;
- if f1<0 then
- begin
- sign:=not(sign);
- q1:=qword(-f1);
- end
- else
- q1:=f1;
- if f2<0 then
- begin
- sign:=not(sign);
- q2:=qword(-f2);
- end
- else
- q2:=f2;
- { the q1*q2 is coded as call to mulqword }
- q3:=q1*q2;
- if checkoverflow and (q1 <> 0) and (q2 <>0) and
- ((q1>q3) or (q2>q3) or
- { the bit 63 can be only set if we have $80000000 00000000 }
- { and sign is true }
- (q3 shr 63<>0) and
- ((q3<>qword(qword(1) shl 63)) or not(sign))
- ) then
- HandleErrorFrame(215,get_frame);
- if sign then
- fpc_mul_int64:=-q3
- else
- fpc_mul_int64:=q3;
- end;
- end;
- {$endif FPC_SYSTEM_HAS_MUL_INT64}
|