瀏覽代碼

* correctly reset fpu on x86_64-linux after a floating point exception, resolves second part of #37468

git-svn-id: trunk@46992 -
florian 4 年之前
父節點
當前提交
1a2b99bc09
共有 3 個文件被更改,包括 67 次插入25 次删除
  1. 1 0
      .gitattributes
  2. 38 25
      rtl/linux/x86_64/sighnd.inc
  3. 28 0
      tests/webtbs/tw37468b.pp

+ 1 - 0
.gitattributes

@@ -18461,6 +18461,7 @@ tests/webtbs/tw37428.pp svneol=native#text/pascal
 tests/webtbs/tw37449.pp svneol=native#text/pascal
 tests/webtbs/tw37465.pp svneol=native#text/plain
 tests/webtbs/tw37468.pp svneol=native#text/pascal
+tests/webtbs/tw37468b.pp svneol=native#text/pascal
 tests/webtbs/tw37477.pp svneol=native#text/pascal
 tests/webtbs/tw37493.pp svneol=native#text/pascal
 tests/webtbs/tw37508.pp svneol=native#text/pascal

+ 38 - 25
rtl/linux/x86_64/sighnd.inc

@@ -15,6 +15,7 @@
 
  **********************************************************************}
 
+{ $define SYSTEM_DEBUG}
 
 { use a trampoline which pushes the return address for proper unwinding }
 Procedure SignalToHandleErrorAddrFrame (Errno : longint;addr : CodePointer; frame : Pointer); nostackframe; assembler;
@@ -33,9 +34,8 @@ function GetFPUState(const SigContext : TSigContext) : word;
     else
       GetFPUState:=0;
   {$ifdef SYSTEM_DEBUG}
-    writeln('xx:',sigcontext.twd,' ',sigcontext.cwd);
-  {$endif SYSTEM_DEBUG}
-  {$ifdef SYSTEM_DEBUG}
+    if assigned(SigContext.fpstate) then
+    writeln('Tag: ',sigcontext.fpstate^.twd,' Cw: ',sigcontext.fpstate^.cwd);
     Writeln(stderr,'FpuState = ',result);
   {$endif SYSTEM_DEBUG}
   end;
@@ -85,32 +85,45 @@ procedure SignalToRunerror(sig : longint; SigInfo: PSigInfo; SigContext: PSigCon
                   { exceptions are handled, clear all flags
                     as we return from SignalToRunerrer, we have to clear the exception flags in the context }
                   if assigned(SigContext^.fpstate) then
-                    SigContext^.fpstate^.swd:=SigContext^.fpstate^.swd and not(FPU_All);
+                    SigContext^.fpstate^.swd:=SigContext^.fpstate^.swd and not($37ff);
                 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'}
+              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'}
 
-                    { exceptions are handled, clear all flags
-                      as we return from SignalToRunerrer, we have to clear the exception flags in the context }
-                    if assigned(SigContext^.fpstate) then
-                      SigContext^.fpstate^.mxcsr:=SigContext^.fpstate^.mxcsr and not(MM_ExceptionMask);
+                  { exceptions are handled, clear all flags
+                    as we return from SignalToRunerrer, we have to clear the exception flags in the context }
+                  if assigned(SigContext^.fpstate) then
+                    SigContext^.fpstate^.mxcsr:=SigContext^.fpstate^.mxcsr and not(MM_ExceptionMask);
+                end;
+              if assigned(SigContext^.fpstate) then
+                with SigContext^.fpstate^ do
+                  begin
+  {$ifdef SYSTEM_DEBUG}
+                    Writeln(stderr,'fpstate^.swd = ',swd);
+  {$endif SYSTEM_DEBUG}
+                    { acutally, I am not sure if we should really touch the controll word }
+                    cwd:=Default8087CW;
+                    { found by trial and error that setting to 0 means empty }
+                    twd:=$0;
+                    { clear top }
+                    swd:=swd and not($3700);
                   end;
+               SysResetFPU;
             end;
-          SysResetFPU;
         end;
       SIGILL,
       SIGBUS,

+ 28 - 0
tests/webtbs/tw37468b.pp

@@ -0,0 +1,28 @@
+program Project1;
+
+{$mode objfpc}{$H+}
+
+uses math, sysutils
+  { you can add units after this };
+
+begin
+  try
+    writeln(power(0, -4));
+  except
+    on e: Exception do ClearExceptions(false);
+  end;
+  try
+    writeln(power(0, -3));
+  except
+    on e: Exception do ClearExceptions(false);
+  end;
+  try
+    writeln(power(0, -4));
+  except
+    on e: Exception do ClearExceptions(false);
+  end;
+
+  writeln('caught');
+  writeln(power(16, 0.5));
+  writeln('done');
+end.