瀏覽代碼

* improved floating point signal handling on x86/linux

git-svn-id: branches/debug_eh@41451 -
florian 6 年之前
父節點
當前提交
62f890efa3
共有 5 個文件被更改,包括 138 次插入51 次删除
  1. 8 0
      rtl/i386/i386.inc
  2. 52 28
      rtl/linux/i386/sighnd.inc
  3. 22 5
      rtl/linux/i386/sighndh.inc
  4. 48 17
      rtl/linux/x86_64/sighnd.inc
  5. 8 1
      rtl/x86_64/x86_64.inc

+ 8 - 0
rtl/i386/i386.inc

@@ -1295,6 +1295,14 @@ const
   FPU_StackOverflow = $40;
   FPU_ExceptionMask = $ff;
 
+  MM_Invalid = 1;
+  MM_Denormal = 2;
+  MM_DivisionByZero = 4;
+  MM_Overflow = 8;
+  MM_Underflow = $10;
+  MM_Precicion = $20;
+  MM_ExceptionMask = $3f;
+
   MM_MaskInvalidOp = %0000000010000000;
   MM_MaskDenorm    = %0000000100000000;
   MM_MaskDivZero   = %0000001000000000;

+ 52 - 28
rtl/linux/i386/sighnd.inc

@@ -25,7 +25,7 @@ end;
 
 procedure SignalToRunerror(sig : longint; SigInfo: PSigInfo; UContext: Pucontext);public name '_FPC_DEFAULTSIGHANDLER';cdecl;
 var
-  res,fpustate : word;
+  res,fpustate,MMState : word;
 begin
   res:=0;
   case sig of
@@ -34,35 +34,59 @@ begin
         { this is not allways necessary but I don't know yet
           how to tell if it is or not PM }
         res:=200;
-        if assigned(ucontext^.uc_mcontext.fpstate) then
+        if SigInfo^.si_code<>FPE_INTDIV then
           begin
-            FpuState:=ucontext^.uc_mcontext.fpstate^.sw;
-            if (FpuState and FPU_ExceptionMask) <> 0 then
+            if assigned(ucontext^.uc_mcontext.fpstate) then
               begin
-                { first check the more precise options }
-                if (FpuState and FPU_DivisionByZero)<>0 then
-                  res:=200
-                else if (FpuState and (FPU_StackOverflow or FPU_StackUnderflow or FPU_Invalid))<>0 Then
-                  res:=207
-                else if (FpuState and FPU_Overflow)<>0 then
-                  res:=205
-                else if (FpuState and FPU_Underflow)<>0 then
-                  res:=206
-                else if (FpuState and FPU_Denormal)<>0 then
-                  res:=216
-                else
-                  res:=207;  {'Coprocessor Error'}
-              end;
-            with ucontext^.uc_mcontext.fpstate^ do
-              begin
-                { Reset Status word }
-                sw:=sw and not FPU_ExceptionMask;
-                { Restoree default control word }
-                cw:=Default8087CW;
-                { Reset Tag word to $ffff for all empty }
-                tag:=$ffff;
-              end;
-           end;
+                FpuState:=ucontext^.uc_mcontext.fpstate^.sw;
+                if (FpuState and FPU_ExceptionMask) <> 0 then
+                  begin
+                    { first check the more precise options }
+                    if (FpuState and FPU_DivisionByZero)<>0 then
+                      res:=208
+                    else if (FpuState and (FPU_StackOverflow or FPU_StackUnderflow or FPU_Invalid))<>0 Then
+                      res:=207
+                    else if (FpuState and FPU_Overflow)<>0 then
+                      res:=205
+                    else if (FpuState and FPU_Underflow)<>0 then
+                      res:=206
+                    else if (FpuState and FPU_Denormal)<>0 then
+                      res:=216
+                    else
+                      res:=207;  {'Coprocessor Error'}
+                  end;
+                { SSE data? }
+                if ucontext^.uc_mcontext.fpstate^.magic<>$ffff then
+                  begin
+                    MMState:=ucontext^.uc_mcontext.fpstate^.mxcsr;
+                    if (MMState and MM_ExceptionMask)<>0 then
+                      begin
+                        { first check the more precise options }
+                        if (MMState and MM_DivisionByZero)<>0 then
+                          res:=208
+                        else if (MMState and MM_Invalid)<>0 Then
+                          res:=207
+                        else if (MMState and MM_Overflow)<>0 then
+                          res:=205
+                        else if (MMState and MM_Underflow)<>0 then
+                          res:=206
+                        else if (MMState and MM_Denormal)<>0 then
+                          res:=216
+                        else
+                          res:=207;  {'Coprocessor Error'}
+                      end;
+                  end;
+                with ucontext^.uc_mcontext.fpstate^ do
+                  begin
+                    { Reset Status word }
+                    sw:=sw and not FPU_ExceptionMask;
+                    { Restoree default control word }
+                    cw:=Default8087CW;
+                    { Reset Tag word to $ffff for all empty }
+                    tag:=$ffff;
+                  end;
+               end;
+          end;
       end;
     SIGBUS:
       res:=214;

+ 22 - 5
rtl/linux/i386/sighndh.inc

@@ -18,15 +18,32 @@
 
 type
   tfpreg = record
-          significand: array[0..3] of word;
-          exponent: word;
+    significand: array[0..3] of word;
+    exponent: word;
   end;
 
+  tfpxreg = record
+    significand: array[0..3] of word;
+    exponent: word;
+    padding : array[0..2] of word;
+  end;
+
+  txmmreg = record
+    element : array[0..3] of dword;
+  end;
+
+
   pfpstate = ^tfpstate;
   tfpstate = record
-           cw, sw, tag, ipoff, cssel, dataoff, datasel: cardinal;
-           st: array[0..7] of tfpreg;
-           status: cardinal;
+    cw, sw, tag, ipoff, cssel, dataoff, datasel: cardinal;
+    st: array[0..7] of tfpreg;
+    status, magic: word;
+    fxsr_env : array[0..5] of dword;
+    mxcsr : dword;
+    reserved : dword;
+    fxsr_st : array[0..7] of tfpxreg;
+    xmmreg : array[0..7] of txmmreg;
+    padding : array[0..55] of dword;
   end;
 
   PSigContext = ^TSigContext;

+ 48 - 17
rtl/linux/x86_64/sighnd.inc

@@ -33,10 +33,21 @@ function GetFPUState(const SigContext : TSigContext) : word;
   {$endif SYSTEM_DEBUG}
   end;
 
+function GetMMState(const SigContext : TSigContext) : dword;
+  begin
+    if assigned(SigContext.fpstate) then
+      Result:=SigContext.fpstate^.mxcsr
+    else
+      Result:=0;
+  {$ifdef SYSTEM_DEBUG}
+    Writeln(stderr,'MMState = ',result);
+  {$endif SYSTEM_DEBUG}
+  end;
+
 
 procedure SignalToRunerror(sig : longint; SigInfo: PSigInfo; SigContext: PSigContext); public name '_FPC_DEFAULTSIGHANDLER'; cdecl;
   var
-    res,fpustate : word;
+    res,fpustate,MMState : word;
   begin
     res:=0;
     case sig of
@@ -45,24 +56,44 @@ procedure SignalToRunerror(sig : longint; SigInfo: PSigInfo; SigContext: PSigCon
           { this is not allways necessary but I don't know yet
             how to tell if it is or not PM }
           res:=200;
-          fpustate:=GetFPUState(SigContext^);
-          if (FpuState and FPU_All) <> 0 then
+          if SigInfo^.si_code<>FPE_INTDIV then
             begin
-              { first check the more precise options }
-              if (FpuState and FPU_DivisionByZero)<>0 then
-                res:=200
-              else if (FpuState and FPU_Overflow)<>0 then
-                res:=205
-              else if (FpuState and FPU_Underflow)<>0 then
-                res:=206
-              else if (FpuState and FPU_Denormal)<>0 then
-                res:=216
-              else if (FpuState and (FPU_StackOverflow or FPU_StackUnderflow or FPU_Invalid))<>0 Then
-                res:=207
-              else
-                res:=207;  {'Coprocessor Error'}
+              fpustate:=GetFPUState(SigContext^);
+              if (FpuState and FPU_All) <> 0 then
+                begin
+                  { first check the more precise options }
+                  if (FpuState and FPU_DivisionByZero)<>0 then
+                    res:=200
+                  else if (FpuState and FPU_Overflow)<>0 then
+                    res:=205
+                  else if (FpuState and FPU_Underflow)<>0 then
+                    res:=206
+                  else if (FpuState and FPU_Denormal)<>0 then
+                    res:=216
+                  else if (FpuState and (FPU_StackOverflow or FPU_StackUnderflow or FPU_Invalid))<>0 Then
+                    res:=207
+                  else
+                    res:=207;  {'Coprocessor Error'}
+                end;
+                MMState:=getMMState(SigContext^);
+                if (MMState and MM_ExceptionMask)<>0 then
+                  begin
+                    { first check the more precise options }
+                    if (MMState and MM_DivisionByZero)<>0 then
+                      res:=208
+                    else if (MMState and MM_Invalid)<>0 Then
+                      res:=207
+                    else if (MMState and MM_Overflow)<>0 then
+                      res:=205
+                    else if (MMState and MM_Underflow)<>0 then
+                      res:=206
+                    else if (MMState and MM_Denormal)<>0 then
+                      res:=216
+                    else
+                      res:=207;  {'Coprocessor Error'}
+                  end;
             end;
-            SysResetFPU;
+          SysResetFPU;
         end;
       SIGILL,
       SIGBUS,

+ 8 - 1
rtl/x86_64/x86_64.inc

@@ -933,6 +933,14 @@ const
   FPU_StackOverflow = $40;
   FPU_ExceptionMask = $ff;
 
+  MM_Invalid = 1;
+  MM_Denormal = 2;
+  MM_DivisionByZero = 4;
+  MM_Overflow = 8;
+  MM_Underflow = $10;
+  MM_Precicion = $20;
+  MM_ExceptionMask = $3f;
+
   MM_MaskInvalidOp = %0000000010000000;
   MM_MaskDenorm    = %0000000100000000;
   MM_MaskDivZero   = %0000001000000000;
@@ -940,7 +948,6 @@ const
   MM_MaskUnderflow = %0000100000000000;
   MM_MaskPrecision = %0001000000000000;
 
-
 procedure fpc_cpuinit;
   begin
     { don't let libraries influence the FPU cw set by the host program }