Browse Source

* Fixed overflow handling in i386 assembler implementations of fpc_div_qword and fpc_mod_qword.
Resolves #23963.

git-svn-id: trunk@24362 -

sergei 12 years ago
parent
commit
97152cc41b
3 changed files with 35 additions and 13 deletions
  1. 1 0
      .gitattributes
  2. 20 13
      rtl/i386/int64p.inc
  3. 14 0
      tests/webtbs/tw23963.pp

+ 1 - 0
.gitattributes

@@ -13383,6 +13383,7 @@ tests/webtbs/tw2382.pp svneol=native#text/plain
 tests/webtbs/tw2388.pp svneol=native#text/plain
 tests/webtbs/tw2388.pp svneol=native#text/plain
 tests/webtbs/tw23912.pp svneol=native#text/plain
 tests/webtbs/tw23912.pp svneol=native#text/plain
 tests/webtbs/tw23962.pp svneol=native#text/plain
 tests/webtbs/tw23962.pp svneol=native#text/plain
+tests/webtbs/tw23963.pp svneol=native#text/plain
 tests/webtbs/tw2397.pp svneol=native#text/plain
 tests/webtbs/tw2397.pp svneol=native#text/plain
 tests/webtbs/tw24007.pp svneol=native#text/plain
 tests/webtbs/tw24007.pp svneol=native#text/plain
 tests/webtbs/tw2409.pp svneol=native#text/plain
 tests/webtbs/tw2409.pp svneol=native#text/plain

+ 20 - 13
rtl/i386/int64p.inc

@@ -18,10 +18,10 @@
 {$define FPC_SYSTEM_HAS_DIV_QWORD}
 {$define FPC_SYSTEM_HAS_DIV_QWORD}
     function fpc_div_qword(n,z : qword) : qword;assembler;[public,alias: 'FPC_DIV_QWORD']; compilerproc;
     function fpc_div_qword(n,z : qword) : qword;assembler;[public,alias: 'FPC_DIV_QWORD']; compilerproc;
       var
       var
-         shift,lzz,lzn : longint;
-         saveebx,saveedi : longint;
+         saveebx,saveedi,saveesi : longint;
       asm
       asm
             movl %ebx,saveebx
             movl %ebx,saveebx
+            movl %esi,saveesi
             movl %edi,saveedi
             movl %edi,saveedi
             { the following piece of code is taken from the     }
             { the following piece of code is taken from the     }
             { AMD Athlon Processor x86 Code Optimization manual }
             { AMD Athlon Processor x86 Code Optimization manual }
@@ -68,18 +68,23 @@
             roll $1,%edi
             roll $1,%edi
             divl %ebx
             divl %ebx
             movl z,%ebx
             movl z,%ebx
-            movl %eax,%ecx
+            movl %eax,%esi             // save quotient to esi
             imull %eax,%edi
             imull %eax,%edi
             mull n
             mull n
             addl %edi,%edx
             addl %edi,%edx
+            setcb %cl                  // cl:edx:eax = 65 bits quotient*divisor
+
+            movl z+4,%edi              // edi:ebx = dividend
             subl %eax,%ebx
             subl %eax,%ebx
-            movl %ecx,%eax
-            movl z+4,%ecx
-            sbbl %edx,%ecx
-            sbbl $0,%eax
+            movb $0,%al
+            sbbl %edx,%edi
+            sbbb %cl,%al
+            sbbl $0,%esi
             xorl %edx,%edx
             xorl %edx,%edx
+            movl %esi,%eax
 .Lexit:
 .Lexit:
             movl saveebx,%ebx
             movl saveebx,%ebx
+            movl saveesi,%esi
             movl saveedi,%edi
             movl saveedi,%edi
       end;
       end;
 
 
@@ -87,7 +92,6 @@
 {$define FPC_SYSTEM_HAS_MOD_QWORD}
 {$define FPC_SYSTEM_HAS_MOD_QWORD}
     function fpc_mod_qword(n,z : qword) : qword;assembler;[public,alias: 'FPC_MOD_QWORD']; compilerproc;
     function fpc_mod_qword(n,z : qword) : qword;assembler;[public,alias: 'FPC_MOD_QWORD']; compilerproc;
       var
       var
-         shift,lzz,lzn : longint;
          saveebx,saveedi : longint;
          saveebx,saveedi : longint;
       asm
       asm
             movl %ebx,saveebx
             movl %ebx,saveebx
@@ -139,19 +143,22 @@
             roll $1,%edi
             roll $1,%edi
             divl %ebx
             divl %ebx
             movl z,%ebx
             movl z,%ebx
-            movl %eax,%ecx
             imull %eax,%edi
             imull %eax,%edi
             mull n
             mull n
             addl %edi,%edx
             addl %edi,%edx
-            subl %eax,%ebx
-            movl z+4,%ecx
+            setcb %cl                  // cl:edx:eax = 65 bits quotient*divisor
+            movl z+4,%edi
+            subl %eax,%ebx             // subtract (quotient*divisor) from dividend
+            movb $0,%al
+            sbbl %edx,%edi
+            sbbb %cl,%al               // if carry is set now, the quotient was off by 1,
+                                       // and we need to add divisor to result
             movl n,%eax
             movl n,%eax
-            sbbl %edx,%ecx
             sbbl %edx,%edx
             sbbl %edx,%edx
             andl %edx,%eax
             andl %edx,%eax
             andl n+4,%edx
             andl n+4,%edx
             addl %ebx,%eax
             addl %ebx,%eax
-            adcl %ecx,%edx
+            adcl %edi,%edx
 .Lexit:
 .Lexit:
             movl saveebx,%ebx
             movl saveebx,%ebx
             movl saveedi,%edi
             movl saveedi,%edi

+ 14 - 0
tests/webtbs/tw23963.pp

@@ -0,0 +1,14 @@
+{$mode objfpc}
+
+var
+  Dividend, Divisor, Quotient : QWord;
+begin
+  Dividend := QWord( $ffffffffffffffff );
+  Divisor := QWord( $100000003 );
+  Quotient := dividend div divisor;
+  if quotient <> $FFFFFFFD then
+    Halt(1);
+  Quotient := dividend mod divisor;
+  if quotient <> 8 then
+    Halt(2);
+end.