From a14db25c6426fbb1cf15cd0fd781e4565948c41c Mon Sep 17 00:00:00 2001 From: florian Date: Sun, 9 Aug 2009 20:47:06 +0000 Subject: [PATCH] + procedure DivMod(Dividend: Integer; Divisor: integer; var Result, Remainder: integer); and procedure DivMod(Dividend: cardinal; Divisor: cardinal; var Result, Remainder: cardinal);, resolves #14286 + assembler implementations of DivMod for i386 git-svn-id: trunk@13508 - --- .gitattributes | 1 + rtl/i386/mathu.inc | 55 +++++++++++++++++++++++++++++ rtl/objpas/math.pp | 34 +++++++++++++----- tests/test/units/math/tdivmod.pp | 59 ++++++++++++++++++++++++++++++++ 4 files changed, 140 insertions(+), 9 deletions(-) create mode 100644 tests/test/units/math/tdivmod.pp diff --git a/.gitattributes b/.gitattributes index 5b53b4b946..1396ad96c5 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8445,6 +8445,7 @@ tests/test/units/fpcunit/testclasses.lpr svneol=native#text/plain tests/test/units/fpcunit/testcomps.pp svneol=native#text/plain tests/test/units/fpcunit/tstrutils.lpi svneol=native#text/plain tests/test/units/fpcunit/tstrutils.lpr svneol=native#text/plain +tests/test/units/math/tdivmod.pp svneol=native#text/plain tests/test/units/math/tmask.inc svneol=native#text/plain tests/test/units/math/tmask.pp svneol=native#text/plain tests/test/units/math/tmask2.pp svneol=native#text/plain diff --git a/rtl/i386/mathu.inc b/rtl/i386/mathu.inc index 853e8b89d5..03c074ffeb 100644 --- a/rtl/i386/mathu.inc +++ b/rtl/i386/mathu.inc @@ -58,11 +58,66 @@ function cotan(x : float) : float;assembler; end; +{$define FPC_MATH_HAS_DIVMOD} +procedure DivMod(Dividend: Integer; Divisor: Word; var Result, Remainder: Word);assembler; +asm + pushw %di + movw %dx,%di + movl %eax,%edx + shrl $16,%edx + div %di + movw %ax,(%ecx) + movl Remainder,%ecx + movw %dx,(%ecx) + popw %di +end; + + +procedure DivMod(Dividend: Integer; Divisor: Word; var Result, Remainder: SmallInt);assembler; +asm + pushw %di + movw %dx,%di + movl %eax,%edx + shrl $16,%edx + div %di + movw %ax,(%ecx) + movl Remainder,%ecx + movw %dx,(%ecx) + popw %di +end; + + +procedure DivMod(Dividend: DWord; Divisor: DWord; var Result, Remainder: DWord);assembler; +asm + pushl %edi + movl %edx,%edi + xorl %edx,%edx + div %edi + movl %eax,(%ecx) + movl Remainder,%ecx + movl %edx,(%ecx) + popl %edi +end; + + +procedure DivMod(Dividend: Integer; Divisor: Integer; var Result, Remainder: Integer);assembler; +asm + pushl %edi + movl %edx,%edi + xorl %edx,%edx + idiv %edi + movl %eax,(%ecx) + movl Remainder,%ecx + movl %edx,(%ecx) + popl %edi +end; + function GetRoundMode: TFPURoundingMode; begin Result := TFPURoundingMode((Get8087CW shr 10) and 3); end; + function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode; var CtlWord: Word; diff --git a/rtl/objpas/math.pp b/rtl/objpas/math.pp index 7d01058277..884da7eb40 100644 --- a/rtl/objpas/math.pp +++ b/rtl/objpas/math.pp @@ -171,7 +171,8 @@ function EnsureRange(const AValue, AMin, AMax: Double): Double;inline; overload procedure DivMod(Dividend: Integer; Divisor: Word; var Result, Remainder: Word); procedure DivMod(Dividend: Integer; Divisor: Word; var Result, Remainder: SmallInt); - +procedure DivMod(Dividend: DWord; Divisor: DWord; var Result, Remainder: DWord); +procedure DivMod(Dividend: Integer; Divisor: Integer; var Result, Remainder: Integer); // Sign functions Type @@ -1380,7 +1381,7 @@ begin m2 := reciprocalN * m2; m3 := reciprocalN * m3; m4 := reciprocalN * m4; - + skew := m3 / (sqrt(m2)*m2); kurtosis := m4 / (m2 * m2); end; @@ -1548,7 +1549,7 @@ begin m2 := reciprocalN * m2; m3 := reciprocalN * m3; m4 := reciprocalN * m4; - + skew := m3 / (sqrt(m2)*m2); kurtosis := m4 / (m2 * m2); end; @@ -1717,7 +1718,7 @@ begin m2 := reciprocalN * m2; m3 := reciprocalN * m3; m4 := reciprocalN * m4; - + skew := m3 / (sqrt(m2)*m2); kurtosis := m4 / (m2 * m2); end; @@ -2216,15 +2217,13 @@ begin end; // Some CPUs probably allow a faster way of doing this in a single operation... -// There weshould define CPUDIVMOD in the header mathuh.inc and implement it using asm. -{$ifndef CPUDIVMOD} +// There weshould define FPC_MATH_HAS_CPUDIVMOD in the header mathuh.inc and implement it using asm. +{$ifndef FPC_MATH_HAS_DIVMOD} procedure DivMod(Dividend: Integer; Divisor: Word; var Result, Remainder: Word); - begin Result:=Dividend Div Divisor; - Remainder:=Dividend Mod Divisor; + Remainder:=Dividend -(Result*Divisor); end; -{$endif} procedure DivMod(Dividend: Integer; Divisor: Word; var Result, Remainder: SmallInt); @@ -2236,6 +2235,23 @@ begin end; +procedure DivMod(Dividend: DWord; Divisor: DWord; var Result, Remainder: DWord); +begin + Result:=Dividend Div Divisor; + Remainder:=Dividend -(Result*Divisor); +end; + + +procedure DivMod(Dividend: Integer; Divisor: Integer; var Result, Remainder: Integer); +var + UnsignedResult: DWord absolute Result; + UnsignedRemainder: DWord absolute Remainder; +begin + DivMod(Dividend, Divisor, UnsignedResult, UnsignedRemainder); +end; +{$endif FPC_MATH_HAS_DIVMOD} + + function ifthen(val:boolean;const iftrue:integer; const iffalse:integer= 0) :integer; begin if val then result:=iftrue else result:=iffalse; diff --git a/tests/test/units/math/tdivmod.pp b/tests/test/units/math/tdivmod.pp new file mode 100644 index 0000000000..f16f5e52b4 --- /dev/null +++ b/tests/test/units/math/tdivmod.pp @@ -0,0 +1,59 @@ +uses + math; +{ tests: + procedure DivMod(Dividend: Integer; Divisor: Word; var Result, Remainder: Word); + procedure DivMod(Dividend: Integer; Divisor: Word; var Result, Remainder: SmallInt); + procedure DivMod(Dividend: DWord; Divisor: DWord; var Result, Remainder: DWord); + procedure DivMod(Dividend: Integer; Divisor: Integer; var Result, Remainder: Integer); +} +procedure doerror(i : integer); + begin + writeln('Error: ',i); + halt(1); + end; + + +var + QuotientWord,RemainderWord : Word; + QuotientSmallInt,RemainderSmallInt : SmallInt; + QuotientDWord,RemainderDWord : DWord; + QuotientInteger,RemainderInteger : Integer; + +begin + DivMod($ffff,65,QuotientWord,RemainderWord); + if QuotientWord<>1008 then + doerror(1); + if RemainderWord<>15 then + doerror(2); + + DivMod($ffff,65,QuotientSmallInt,RemainderSmallInt); + if QuotientSmallInt<>1008 then + doerror(1001); + if RemainderSmallInt<>15 then + doerror(2); + + DivMod($ffff,65,QuotientDWord,RemainderDWord); + if QuotientDWord<>1008 then + doerror(2001); + if RemainderDWord<>15 then + doerror(2002); + + DivMod(123456,23,QuotientDWord,RemainderDWord); + if QuotientDWord<>5367 then + doerror(2003); + if RemainderDWord<>15 then + doerror(2004); + + DivMod($ffff,65,QuotientInteger,RemainderInteger); + if QuotientInteger<>1008 then + doerror(3001); + if RemainderInteger<>15 then + doerror(3002); + + DivMod(123456,23,QuotientInteger,RemainderInteger); + if QuotientInteger<>5367 then + doerror(3003); + if RemainderInteger<>15 then + doerror(3004); +end. +