浏览代码

+ 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 -

florian 16 年之前
父节点
当前提交
a14db25c64
共有 4 个文件被更改,包括 140 次插入9 次删除
  1. 1 0
      .gitattributes
  2. 55 0
      rtl/i386/mathu.inc
  3. 25 9
      rtl/objpas/math.pp
  4. 59 0
      tests/test/units/math/tdivmod.pp

+ 1 - 0
.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

+ 55 - 0
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;

+ 25 - 9
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;

+ 59 - 0
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.
+