diff --git a/compiler/fpcdefs.inc b/compiler/fpcdefs.inc index 5effa01914..1fb0d301e3 100644 --- a/compiler/fpcdefs.inc +++ b/compiler/fpcdefs.inc @@ -56,7 +56,7 @@ {$define SUPPORT_SAFECALL} {$define cpuneedsmulhelper} { TODO: add another define in order to disable the div helper for 16-bit divs? } - {$define cpuneedsdiv32helper} + {$define cpuneedsdivhelper} {$define VOLATILE_ES} {$define SUPPORT_GET_FRAME} {$endif i8086} @@ -145,7 +145,7 @@ {$define cpu32bitalu} {$define cpuflags} {$define cpufpemu} - {$define cpuneedsdiv32helper} + {$define cpuneedsdivhelper} {$define cpurox} {$define cputargethasfixedstack} {$define cpurefshaveindexreg} @@ -178,7 +178,7 @@ {$define cpufpemu} {$define cpurefshaveindexreg} {$define cpucapabilities} - {$define cpuneedsdiv32helper} + {$define cpuneedsdivhelper} {$endif m68k} {$ifdef avr} @@ -188,7 +188,7 @@ {$define cpuflags} {$define cpunofpu} {$define cpunodefaultint} - {$define cpuneedsdiv32helper} + {$define cpuneedsdivhelper} {$define cpuneedsmulhelper} {$define cpurefshaveindexreg} {$define cpucapabilities} diff --git a/compiler/nmat.pas b/compiler/nmat.pas index ba1ab2fbff..8ad96a19ca 100644 --- a/compiler/nmat.pas +++ b/compiler/nmat.pas @@ -393,7 +393,7 @@ implementation function tmoddivnode.first_moddivint: tnode; -{$ifdef cpuneedsdiv32helper} +{$ifdef cpuneedsdivhelper} var procname: string[31]; begin @@ -404,12 +404,25 @@ implementation procname := 'fpc_div_' else procname := 'fpc_mod_'; + { only qword needs the unsigned code, the signed code is also used for currency } - if is_signed(resultdef) then - procname := procname + 'longint' - else - procname := procname + 'dword'; + case torddef(resultdef).ordtype of + u8bit: + procname := procname + 'byte'; + s8bit: + procname := procname + 'shortint'; + u16bit: + procname := procname + 'word'; + s16bit: + procname := procname + 'smallint'; + u32bit: + procname := procname + 'dword'; + s32bit: + procname := procname + 'longint' + else + internalerror(2015070501); + end; result := ccallnode.createintern(procname,ccallparanode.create(left, ccallparanode.create(right,nil))); @@ -424,7 +437,7 @@ implementation if torddef(result.resultdef).ordtype <> torddef(resultdef).ordtype then inserttypeconv(result,resultdef); end; -{$else cpuneedsdiv32helper} +{$else cpuneedsdivhelper} begin result:=nil; end; diff --git a/rtl/inc/compproc.inc b/rtl/inc/compproc.inc index 5a3907503b..0f05efb8f0 100644 --- a/rtl/inc/compproc.inc +++ b/rtl/inc/compproc.inc @@ -568,6 +568,14 @@ function fpc_div_dword(n,z : dword) : dword; compilerproc; function fpc_mod_dword(n,z : dword) : dword; compilerproc; function fpc_div_longint(n,z : longint) : longint; compilerproc; function fpc_mod_longint(n,z : longint) : longint; compilerproc; +function fpc_div_word(n,z : word) : word; compilerproc; +function fpc_mod_word(n,z : word) : word; compilerproc; +function fpc_div_smallint(n,z : smallint) : smallint; compilerproc; +function fpc_mod_smallint(n,z : smallint) : smallint; compilerproc; +function fpc_div_byte(n,z : byte) : byte; compilerproc; +function fpc_mod_byte(n,z : byte) : byte; compilerproc; +function fpc_div_shortint(n,z : shortint) : shortint; compilerproc; +function fpc_mod_shortint(n,z : shortint) : shortint; compilerproc; {$endif FPC_INCLUDE_SOFTWARE_MOD_DIV} {$ifdef FPC_INCLUDE_SOFTWARE_MUL} diff --git a/rtl/inc/generic.inc b/rtl/inc/generic.inc index 7f11a30b4d..1b5eb8c296 100644 --- a/rtl/inc/generic.inc +++ b/rtl/inc/generic.inc @@ -1556,6 +1556,136 @@ function fpc_mod_dword(n,z : dword) : dword; [public,alias: 'FPC_MOD_DWORD']; co {$endif FPC_SYSTEM_HAS_MOD_DWORD} +{$ifndef FPC_SYSTEM_HAS_DIV_WORD} +function fpc_div_word(n,z : word) : word; [public,alias: 'FPC_DIV_WORD']; compilerproc; + var + shift,lzz,lzn : Byte; + begin + result:=0; + if n=0 then + HandleErrorAddrFrameInd(200,get_pc_addr,get_frame); + if z=0 then + exit; + lzz:=BsrWord(z); + lzn:=BsrWord(n); + { if the denominator contains less zeros + then the numerator + then d is greater than the n } + if lzn>lzz then + exit; + shift:=lzz-lzn; + n:=n shl shift; + for shift:=shift downto 0 do + begin + if z>=n then + begin + z:=z-n; + result:=result+word(word(1) shl shift); + end; + n:=n shr 1; + end; + end; +{$endif FPC_SYSTEM_HAS_DIV_WORD} + + +{$ifndef FPC_SYSTEM_HAS_MOD_WORD} +function fpc_mod_word(n,z : word) : word; [public,alias: 'FPC_MOD_WORD']; compilerproc; + var + shift,lzz,lzn : Byte; + begin + result:=0; + if n=0 then + HandleErrorAddrFrameInd(200,get_pc_addr,get_frame); + if z=0 then + exit; + lzz:=BsrWord(z); + lzn:=BsrWord(n); + { if the denominator contains less zeros + then the numerator + then d is greater than the n } + if lzn>lzz then + begin + result:=z; + exit; + end; + shift:=lzz-lzn; + n:=n shl shift; + for shift:=shift downto 0 do + begin + if z>=n then + z:=z-n; + n:=n shr 1; + end; + result:=z; + end; +{$endif FPC_SYSTEM_HAS_MOD_WORD} + + +{$ifndef FPC_SYSTEM_HAS_DIV_BYTE} +function fpc_div_byte(n,z : byte) : byte; [public,alias: 'FPC_DIV_BYTE']; compilerproc; + var + shift,lzz,lzn : Byte; + begin + result:=0; + if n=0 then + HandleErrorAddrFrameInd(200,get_pc_addr,get_frame); + if z=0 then + exit; + lzz:=BsrByte(z); + lzn:=BsrByte(n); + { if the denominator contains less zeros + then the numerator + then d is greater than the n } + if lzn>lzz then + exit; + shift:=lzz-lzn; + n:=n shl shift; + for shift:=shift downto 0 do + begin + if z>=n then + begin + z:=z-n; + result:=result+byte(byte(1) shl shift); + end; + n:=n shr 1; + end; + end; +{$endif FPC_SYSTEM_HAS_DIV_BYTE} + + +{$ifndef FPC_SYSTEM_HAS_MOD_BYTE} +function fpc_mod_byte(n,z : byte) : byte; [public,alias: 'FPC_MOD_BYTE']; compilerproc; + var + shift,lzz,lzn : Byte; + begin + result:=0; + if n=0 then + HandleErrorAddrFrameInd(200,get_pc_addr,get_frame); + if z=0 then + exit; + lzz:=BsrByte(z); + lzn:=BsrByte(n); + { if the denominator contains less zeros + then the numerator + then d is greater than the n } + if lzn>lzz then + begin + result:=z; + exit; + end; + shift:=lzz-lzn; + n:=n shl shift; + for shift:=shift downto 0 do + begin + if z>=n then + z:=z-n; + n:=n shr 1; + end; + result:=z; + end; +{$endif FPC_SYSTEM_HAS_MOD_BYTE} + + {$ifndef FPC_SYSTEM_HAS_DIV_LONGINT} function fpc_div_longint(n,z : longint) : longint; [public,alias: 'FPC_DIV_LONGINT']; compilerproc; var @@ -1618,8 +1748,133 @@ function fpc_mod_longint(n,z : longint) : longint; [public,alias: 'FPC_MOD_LONGI end; {$endif FPC_SYSTEM_HAS_MOD_LONGINT} -{$endif FPC_INCLUDE_SOFTWARE_MOD_DIV} +{$ifndef FPC_SYSTEM_HAS_DIV_SMALLINT} +function fpc_div_smallint(n,z : smallint) : smallint; [public,alias: 'FPC_DIV_SMALLINT']; compilerproc; + var + sign : boolean; + w1,w2 : word; + begin + if n=0 then + HandleErrorAddrFrameInd(200,get_pc_addr,get_frame); + sign:=false; + if z<0 then + begin + sign:=not(sign); + w1:=word(-z); + end + else + w1:=z; + if n<0 then + begin + sign:=not(sign); + w2:=word(-n); + end + else + w2:=n; + + { the div is coded by the compiler as call to divdword } + if sign then + result:=-(w1 div w2) + else + result:=w1 div w2; + end; +{$endif FPC_SYSTEM_HAS_DIV_SMALLINT} + + +{$ifndef FPC_SYSTEM_HAS_MOD_SMALLINT} +function fpc_mod_smallint(n,z : smallint) : smallint; [public,alias: 'FPC_MOD_SMALLINT']; compilerproc; + var + signed : boolean; + r,nq,zq : word; + begin + if n=0 then + HandleErrorAddrFrameInd(200,get_pc_addr,get_frame); + nq:=abs(n); + + if z<0 then + begin + zq:=word(-z); + signed:=true; + end + else + begin + zq:=z; + signed:=false; + end; + + r:=zq mod nq; + if signed then + result:=-smallint(r) + else + result:=r; + end; +{$endif FPC_SYSTEM_HAS_MOD_SMALLINT} + + +{$ifndef FPC_SYSTEM_HAS_DIV_SHORTINT} +function fpc_div_shortint(n,z : shortint) : shortint; [public,alias: 'FPC_DIV_SHORTINT']; compilerproc; + var + sign : boolean; + b1,b2 : byte; + begin + if n=0 then + HandleErrorAddrFrameInd(200,get_pc_addr,get_frame); + sign:=false; + if z<0 then + begin + sign:=not(sign); + b1:=byte(-z); + end + else + b1:=z; + if n<0 then + begin + sign:=not(sign); + b2:=byte(-n); + end + else + b2:=n; + + { the div is coded by the compiler as call to divdword } + if sign then + result:=-(b1 div b2) + else + result:=b1 div b2; + end; +{$endif FPC_SYSTEM_HAS_DIV_SHORTINT} + + +{$ifndef FPC_SYSTEM_HAS_MOD_SHORTINT} +function fpc_mod_shortint(n,z : shortint) : shortint; [public,alias: 'FPC_MOD_SHORTINT']; compilerproc; + var + signed : boolean; + r,nq,zq : byte; + begin + if n=0 then + HandleErrorAddrFrameInd(200,get_pc_addr,get_frame); + nq:=abs(n); + + if z<0 then + begin + zq:=byte(-z); + signed:=true; + end + else + begin + zq:=z; + signed:=false; + end; + + r:=zq mod nq; + if signed then + result:=-shortint(r) + else + result:=r; + end; +{$endif FPC_SYSTEM_HAS_MOD_SHORTINT} + +{$endif FPC_INCLUDE_SOFTWARE_MOD_DIV} {****************************************************************************}