Browse Source

* correct masking of exceptions in genmath code

git-svn-id: trunk@5965 -
florian 18 years ago
parent
commit
b3a1868ff0
9 changed files with 160 additions and 112 deletions
  1. 2 0
      rtl/i386/i386.inc
  2. 2 1
      rtl/inc/generic.inc
  3. 63 13
      rtl/inc/genmath.inc
  4. 18 0
      rtl/inc/mathh.inc
  5. 39 76
      rtl/inc/softfpu.pp
  6. 14 9
      rtl/powerpc/powerpc.inc
  7. 3 0
      rtl/win64/system.pp
  8. 1 0
      rtl/x86_64/mathu.inc
  9. 18 13
      rtl/x86_64/x86_64.inc

+ 2 - 0
rtl/i386/i386.inc

@@ -1206,6 +1206,8 @@ Procedure SysResetFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
        { setup sse exceptions }
        ldmxcsr mxcsr
       end;
+    softfloat_exception_flags:=0;
+    softfloat_exception_mask:=float_flag_underflow or float_flag_inexact or float_flag_denormal;
   end;
 
 

+ 2 - 1
rtl/inc/generic.inc

@@ -1240,7 +1240,8 @@ end;
 
 procedure SysResetFpu;{$ifdef SYSTEMINLINE}inline;{$endif}
 begin
-  { nothing todo }
+  softfloat_exception_flags:=0;
+  softfloat_exception_mask:=float_flag_underflow or float_flag_inexact or float_flag_denormal;
 end;
 
 {$endif FPC_SYSTEM_HAS_SYSRESETFPU}

+ 63 - 13
rtl/inc/genmath.inc

@@ -100,6 +100,33 @@ type
   flag = byte;
 {$endif FPC_SYSTEM_HAS_flag}
 
+{*
+-------------------------------------------------------------------------------
+Raises the exceptions specified by `flags'.  Floating-point traps can be
+defined here if desired.  It is currently not possible for such a trap
+to substitute a result value.  If traps are not implemented, this routine
+should be simply `softfloat_exception_flags |= flags;'.
+-------------------------------------------------------------------------------
+*}
+procedure float_raise( i: shortint );
+Begin
+  softfloat_exception_flags := softfloat_exception_flags or i;
+  if ((softfloat_exception_flags and not(softfloat_exception_mask)) and float_flag_invalid) <> 0 then
+     RunError(207)
+  else
+  if ((softfloat_exception_flags and not(softfloat_exception_mask)) and float_flag_divbyzero) <> 0 then
+     RunError(200)
+  else
+  if ((softfloat_exception_flags and not(softfloat_exception_mask)) and float_flag_overflow) <> 0 then
+     RunError(205)
+  else
+  if ((softfloat_exception_flags and not(softfloat_exception_mask)) and float_flag_underflow) <> 0 then
+     RunError(206)
+  else
+  if ((softfloat_exception_flags and not(softfloat_exception_mask)) and float_flag_inexact) <> 0 then
+     RunError(207);
+end;
+
 
 {$ifndef FPC_SYSTEM_HAS_extractFloat64Frac0}
   Function extractFloat64Frac0(const a: float64): longint;
@@ -156,6 +183,8 @@ type
        aExp, shiftCount: smallint;
        aSig0, aSig1, absZ, aSigExtra: longint;
        z: longint;
+     label
+       invalid;
      Begin
        aSig1 := extractFloat64Frac1( a );
        aSig0 := extractFloat64Frac0( a );
@@ -165,7 +194,7 @@ type
        if 0<=shiftCount then
        Begin
           if (aExp=$7FF)  and ((aSig0 or aSig1)<>0) then
-            HandleError(207);
+            goto invalid;
           shortShift64Left(aSig0 OR  $00100000, aSig1, shiftCount, absZ, aSigExtra );
        End
        else
@@ -184,8 +213,19 @@ type
        else
          z:=absZ;
        if ((aSign<>0) xor (z<0)) AND  (z<>0) then
-         HandleError(207);
-      float64_to_int32_round_to_zero := z;
+         begin
+invalid:
+           float_raise(float_flag_invalid);
+           if (aSign <> 0) then
+             float64_to_int32_round_to_zero:=$80000000
+           else
+             float64_to_int32_round_to_zero:=$7FFFFFFF;
+           exit;
+         end;
+       if ( aSigExtra <> 0) then
+         float_raise(float_flag_inexact);
+
+       float64_to_int32_round_to_zero := z;
      End;
 
 
@@ -207,9 +247,17 @@ type
            if aExp>=$43e then
              begin
                if int64(a)<>$C3E0000000000000 then
-                 HandleError(207);
-               { pascal doesn't know Inf for int64 }
-               HandleError(207);
+                 begin
+                   float_raise(float_flag_invalid);
+                   if (aSign=0) or ((aExp=$7FF) and
+                      (aSig<>$0010000000000000 )) then
+                     begin
+                       result:=$7FFFFFFFFFFFFFFF;
+                       exit;
+                     end;
+                 end;
+               result:=$8000000000000000;
+               exit;
              end;
            z:=aSig shl shiftCount;
          end
@@ -270,13 +318,14 @@ type
          Begin
            if ( a <> Float32($CF000000) ) then
              Begin
+               float_raise( float_flag_invalid );
                if ( (aSign=0) or ( ( aExp = $FF ) and (aSig<>0) ) ) then
                  Begin
-                   HandleError(207);
+                   float32_to_int32_round_to_zero:=$7fffffff;
                    exit;
                  end;
              End;
-           HandleError(207);
+           float32_to_int32_round_to_zero:=$80000000;
            exit;
          End
        else
@@ -561,8 +610,8 @@ type
     begin
        if( d <= 0.0 ) then
        begin
-           if( d < 0.0 ) then
-               HandleError(207);
+           if d < 0.0 then
+             d:=0/0;
            result := 0.0;
        end
      else
@@ -1005,7 +1054,10 @@ type
     Label Ldone;
     begin
        if( d <= 0.0 ) then
-          HandleError(207);
+         begin
+           float_raise(float_flag_invalid);
+           exit;
+         end;
        d := frexp( d, e );
 
     { logarithm using log(x) = z + z**3 P(z)/Q(z),
@@ -1455,5 +1507,3 @@ function FPower10(val: Extended; Power: Longint): Extended;
       end;
   end;
 {$endif SUPPORT_EXTENDED}
-
-

+ 18 - 0
rtl/inc/mathh.inc

@@ -24,8 +24,26 @@
     function GetSSECSR : dword;
 {$endif}
 
+const
+{*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point exception flags.
+-------------------------------------------------------------------------------
+*}
+    float_flag_invalid   =  1;
+    float_flag_denormal  =  2;
+    float_flag_divbyzero =  4;
+    float_flag_overflow  =  8;
+    float_flag_underflow = 16;
+    float_flag_inexact   = 32;
    { declarations of the math routines }
 
+threadvar
+  softfloat_exception_mask : Byte;
+  softfloat_exception_flags : Byte;
+
+procedure float_raise(i: shortint);
+
 {$ifdef cpui386}
   {$define INTERNMATH}
 {$endif}

+ 39 - 76
rtl/inc/softfpu.pp

@@ -468,17 +468,6 @@ rounded down.
     float_round_up           = 2;
     float_round_to_zero      = 3;
 
-{*
--------------------------------------------------------------------------------
-Software IEC/IEEE floating-point exception flags.
--------------------------------------------------------------------------------
-*}
-    float_flag_invalid   =  1;
-    float_flag_divbyzero =  4;
-    float_flag_overflow  =  8;
-    float_flag_underflow = 16;
-    float_flag_inexact   = 32;
-
 {*
 -------------------------------------------------------------------------------
 Floating-point rounding mode and exception flags.
@@ -486,7 +475,6 @@ Floating-point rounding mode and exception flags.
 *}
 const
  float_rounding_mode : Byte = float_round_nearest_even;
- float_exception_flags : Byte = 0;
 
 {*
 -------------------------------------------------------------------------------
@@ -505,31 +493,6 @@ implementation
 
 
 {$if not(defined(fpc_softfpu_interface))}
-{*
--------------------------------------------------------------------------------
-Raises the exceptions specified by `flags'.  Floating-point traps can be
-defined here if desired.  It is currently not possible for such a trap
-to substitute a result value.  If traps are not implemented, this routine
-should be simply `float_exception_flags |= flags;'.
--------------------------------------------------------------------------------
-*}
-procedure float_raise( i: shortint );
-Begin
-  float_exception_flags := float_exception_flags or i;
-  if (float_exception_flags and float_flag_invalid) <> 0 then
-     RunError(207)
-  else
-  if (float_exception_flags and float_flag_divbyzero) <> 0 then
-     RunError(200)
-  else
-  if (float_exception_flags and float_flag_overflow) <> 0 then
-     RunError(205)
-  else
-  if (float_exception_flags and float_flag_underflow) <> 0 then
-     RunError(206);
-end;
-
-
 (*****************************************************************************)
 (*----------------------------------------------------------------------------*)
 (* Primitive arithmetic functions, including multi-word arithmetic, and       *)
@@ -595,7 +558,7 @@ begin
         exit;
     end;
     if ( roundBits<>0 ) then
-      float_exception_flags := float_exception_flags or float_flag_inexact;
+      softfloat_exception_flags := softfloat_exception_flags or float_flag_inexact;
     result:=z;
 end;
 
@@ -658,7 +621,7 @@ begin
           result:=int64($7FFFFFFFFFFFFFFF);
     end;
     if ( absZ1<>0 ) then
-      float_exception_flags := float_exception_flags or float_flag_inexact;
+      softfloat_exception_flags := softfloat_exception_flags or float_flag_inexact;
     result:=z;
 end;
 
@@ -2169,7 +2132,7 @@ Function roundAndPackFloat32( zSign : Flag; zExp : Int16; zSig : Bits32 ) : floa
           End;
     End;
     if ( roundBits )<> 0 then
-       float_exception_flags := float_flag_inexact OR float_exception_flags;
+       softfloat_exception_flags := float_flag_inexact OR softfloat_exception_flags;
     zSig := ( zSig + roundIncrement ) shr 7;
     zSig := zSig AND not bits32( bits32( ( roundBits XOR $40 ) = 0 ) and roundNearestEven );
     if ( zSig = 0 ) then zExp := 0;
@@ -2432,7 +2395,7 @@ Procedure
         End;
     End;
     if ( zSig2 )<>0 then
-       float_exception_flags := float_exception_flags OR  float_flag_inexact;
+       softfloat_exception_flags := softfloat_exception_flags OR  float_flag_inexact;
     if ( increment )<>0 then
       Begin
         add64( zSig0, zSig1, 0, 1, zSig0, zSig1 );
@@ -2522,7 +2485,7 @@ begin
         end
     end;
     if ( roundBits<>0 ) then
-      float_exception_flags := float_exception_flags or float_flag_inexact;
+      softfloat_exception_flags := softfloat_exception_flags or float_flag_inexact;
     zSig := ( zSig + roundIncrement ) shr 10;
     zSig := zSig and not( ord( ( roundBits xor $200 ) = 0 ) and roundNearestEven );
     if ( zSig = 0 ) then
@@ -2695,7 +2658,7 @@ Function float32_to_int32( a : float32rec) : int32;compilerproc;
             z := aSig shr ( - shiftCount );
          End;
         if ( aSigExtra<>0 ) then
-          float_exception_flags := float_exception_flags
+          softfloat_exception_flags := softfloat_exception_flags
              or float_flag_inexact;
         roundingMode := float_rounding_mode;
         if ( roundingMode = float_round_nearest_even ) then
@@ -2766,8 +2729,8 @@ Function float32_to_int32_round_to_zero( a: Float32rec ): int32;compilerproc;
       if ( aExp <= $7E ) then
       Begin
         if ( aExp or aSig )<>0 then
-           float_exception_flags :=
-             float_exception_flags or float_flag_inexact;
+           softfloat_exception_flags :=
+             softfloat_exception_flags or float_flag_inexact;
         float32_to_int32_round_to_zero := 0;
         exit;
       End;
@@ -2775,8 +2738,8 @@ Function float32_to_int32_round_to_zero( a: Float32rec ): int32;compilerproc;
     z := aSig shr ( - shiftCount );
     if ( bits32 ( aSig shl ( shiftCount and 31 ) )<> 0 ) then
       Begin
-           float_exception_flags :=
-             float_exception_flags or float_flag_inexact;
+           softfloat_exception_flags :=
+             softfloat_exception_flags or float_flag_inexact;
       End;
     if ( aSign<>0 ) then z := - z;
     float32_to_int32_round_to_zero := z;
@@ -2859,8 +2822,8 @@ Function float32_round_to_int( a: float32rec): float32rec;compilerproc;
              float32_round_to_int:=a;
              exit;
           end;
-        float_exception_flags
-          := float_exception_flags OR  float_flag_inexact;
+        softfloat_exception_flags
+          := softfloat_exception_flags OR  float_flag_inexact;
         aSign := extractFloat32Sign( a.float32 );
 
         case ( float_rounding_mode ) of
@@ -2912,7 +2875,7 @@ Function float32_round_to_int( a: float32rec): float32rec;compilerproc;
       End;
     z := z and not roundBitsMask;
     if ( z <> a.float32 ) then
-      float_exception_flags := float_exception_flags or float_flag_inexact;
+      softfloat_exception_flags := softfloat_exception_flags or float_flag_inexact;
     float32_round_to_int.float32 := z;
   End;
 
@@ -3820,7 +3783,7 @@ Begin
         exit;
     End;
     if ( aSigExtra <> 0) then
-       float_exception_flags := float_exception_flags or float_flag_inexact;
+       softfloat_exception_flags := softfloat_exception_flags or float_flag_inexact;
     float64_to_int32 := z;
 End;
 
@@ -3867,8 +3830,8 @@ Var
         Begin
             if ( aExp OR  aSig0 OR  aSig1 )<>0 then
             Begin
-                float_exception_flags :=
-                  float_exception_flags or float_flag_inexact;
+                softfloat_exception_flags :=
+                  softfloat_exception_flags or float_flag_inexact;
             End;
             float64_to_int32_round_to_zero := 0;
             exit;
@@ -3892,7 +3855,7 @@ Var
         exit;
     End;
     if ( aSigExtra <> 0) then
-       float_exception_flags := float_exception_flags or float_flag_inexact;
+       softfloat_exception_flags := softfloat_exception_flags or float_flag_inexact;
     float64_to_int32_round_to_zero := z;
  End;
 
@@ -4010,7 +3973,7 @@ Begin
                 result := a;
                 exit;
             End;
-            float_exception_flags := float_exception_flags or
+            softfloat_exception_flags := softfloat_exception_flags or
                float_flag_inexact;
             aSign := extractFloat64Sign( a );
             case ( float_rounding_mode ) of
@@ -4072,8 +4035,8 @@ Begin
     End;
     if ( ( z.low <> a.low ) OR ( z.high <> a.high ) ) then
     Begin
-        float_exception_flags :=
-          float_exception_flags or float_flag_inexact;
+        softfloat_exception_flags :=
+          softfloat_exception_flags or float_flag_inexact;
     End;
     result := z;
 End;
@@ -5453,7 +5416,7 @@ begin
             zExp := 0;
             roundBits := zSig0 and roundMask;
             if ( isTiny and roundBits ) float_raise( float_flag_underflow );
-            if ( roundBits ) float_exception_flags |= float_flag_inexact;
+            if ( roundBits ) softfloat_exception_flags |= float_flag_inexact;
             zSig0 += roundIncrement;
             if ( (sbits64) zSig0 < 0 ) zExp := 1;
             roundIncrement := roundMask + 1;
@@ -5464,7 +5427,7 @@ begin
             result:=packFloatx80( zSign, zExp, zSig0 );
         end;
     end;
-    if ( roundBits ) float_exception_flags |= float_flag_inexact;
+    if ( roundBits ) softfloat_exception_flags |= float_flag_inexact;
     zSig0 += roundIncrement;
     if ( zSig0 < roundIncrement ) begin
         ++zExp;
@@ -5519,7 +5482,7 @@ begin
             shift64ExtraRightJamming( zSig0, zSig1, 1 - zExp, &zSig0, &zSig1 );
             zExp := 0;
             if ( isTiny and zSig1 ) float_raise( float_flag_underflow );
-            if ( zSig1 ) float_exception_flags |= float_flag_inexact;
+            if ( zSig1 ) softfloat_exception_flags |= float_flag_inexact;
             if ( roundNearestEven ) begin
                 increment := ( (sbits64) zSig1 < 0 );
             end;
@@ -5540,7 +5503,7 @@ begin
             result:=packFloatx80( zSign, zExp, zSig0 );
         end;
     end;
-    if ( zSig1 ) float_exception_flags |= float_flag_inexact;
+    if ( zSig1 ) softfloat_exception_flags |= float_flag_inexact;
     if ( increment ) begin
         ++zSig0;
         if ( zSig0 = 0 ) begin
@@ -5636,7 +5599,7 @@ begin
         goto invalid;
     end;
     else if ( aExp < $3FFF ) begin
-        if ( aExp or aSig ) float_exception_flags or= float_flag_inexact;
+        if ( aExp or aSig ) softfloat_exception_flags or= float_flag_inexact;
         result := 0;
     end;
     shiftCount := $403E - aExp;
@@ -5650,7 +5613,7 @@ begin
         result := aSign ? (sbits32) $80000000 : $7FFFFFFF;
     end;
     if ( ( aSig shl shiftCount ) <> savedASig ) begin
-        float_exception_flags or= float_flag_inexact;
+        softfloat_exception_flags or= float_flag_inexact;
     end;
     result := z;
 
@@ -5729,12 +5692,12 @@ begin
         result := (sbits64) LIT64( $8000000000000000 );
     end;
     else if ( aExp < $3FFF ) begin
-        if ( aExp or aSig ) float_exception_flags or= float_flag_inexact;
+        if ( aExp or aSig ) softfloat_exception_flags or= float_flag_inexact;
         result := 0;
     end;
     z := aSig>>( - shiftCount );
     if ( (bits64) ( aSig shl ( shiftCount and 63 ) ) ) begin
-        float_exception_flags or= float_flag_inexact;
+        softfloat_exception_flags or= float_flag_inexact;
     end;
     if ( aSign ) z := - z;
     result := z;
@@ -5851,7 +5814,7 @@ begin
              and ( (bits64) ( extractFloatx80Frac( a ) shl 1 ) = 0 ) ) begin
             result := a;
         end;
-        float_exception_flags or= float_flag_inexact;
+        softfloat_exception_flags or= float_flag_inexact;
         aSign := extractFloatx80Sign( a );
         switch ( float_rounding_mode ) begin
          case float_round_nearest_even:
@@ -5892,7 +5855,7 @@ begin
         ++z.high;
         z.low := LIT64( $8000000000000000 );
     end;
-    if ( z.low <> a.low ) float_exception_flags or= float_flag_inexact;
+    if ( z.low <> a.low ) softfloat_exception_flags or= float_flag_inexact;
     result := z;
 
 end;
@@ -6789,7 +6752,7 @@ begin
         end;
     end;
     if ( zSig2<>0 ) then
-      float_exception_flags := float_exception_flags or float_flag_inexact;
+      softfloat_exception_flags := softfloat_exception_flags or float_flag_inexact;
     if ( increment<>0 ) then
     begin
         add128( zSig0, zSig1, 0, 1, zSig0, zSig1 );
@@ -6903,7 +6866,7 @@ begin
     else if ( aExp < $3FFF ) then
     begin
         if ( aExp or aSig0 )<>0 then
-          float_exception_flags := float_exception_flags or float_flag_inexact;
+          softfloat_exception_flags := softfloat_exception_flags or float_flag_inexact;
         result := 0;
         exit;
     end;
@@ -6926,7 +6889,7 @@ begin
     end;
     if ( ( aSig0 shl shiftCount ) <> savedASig ) then
     begin
-        float_exception_flags := float_exception_flags or float_flag_inexact;
+        softfloat_exception_flags := softfloat_exception_flags or float_flag_inexact;
     end;
     result := z;
 end;
@@ -7011,7 +6974,7 @@ begin
                  and ( aSig1 < int64( $0002000000000000 ) ) ) then
             begin
                 if ( aSig1<>0 ) then
-                  float_exception_flags := float_exception_flags or float_flag_inexact;
+                  softfloat_exception_flags := softfloat_exception_flags or float_flag_inexact;
             end
             else begin
                 float_raise( float_flag_invalid );
@@ -7027,7 +6990,7 @@ begin
         z := ( aSig0 shl shiftCount ) or ( aSig1>>( ( - shiftCount ) and 63 ) );
         if ( int64( aSig1 shl shiftCount )<>0 ) then
         begin
-            float_exception_flags := float_exception_flags or float_flag_inexact;
+            softfloat_exception_flags := softfloat_exception_flags or float_flag_inexact;
         end;
     end
     else begin
@@ -7035,7 +6998,7 @@ begin
         begin
             if ( aExp or aSig0 or aSig1 )<>0 then
             begin
-                float_exception_flags := float_exception_flags or float_flag_inexact;
+                softfloat_exception_flags := softfloat_exception_flags or float_flag_inexact;
             end;
             result := 0;
             exit;
@@ -7044,7 +7007,7 @@ begin
         if (    (aSig1<>0)
              or ( (shiftCount<>0) and (int64( aSig0 shl ( shiftCount and 63 ) )<>0) ) ) then
         begin
-            float_exception_flags := float_exception_flags or float_flag_inexact;
+            softfloat_exception_flags := softfloat_exception_flags or float_flag_inexact;
         end;
     end;
     if ( aSign<>0 ) then
@@ -7239,7 +7202,7 @@ begin
                 result := a;
                 exit;
               end;
-            float_exception_flags := float_exception_flags or float_flag_inexact;
+            softfloat_exception_flags := softfloat_exception_flags or float_flag_inexact;
             aSign := extractFloat128Sign( a );
             case float_rounding_mode of
             float_round_nearest_even:
@@ -7291,7 +7254,7 @@ begin
         z.high &= ~ roundBitsMask;
     end;
     if ( ( z.low <> a.low ) or ( z.high <> a.high ) ) begin
-        float_exception_flags or= float_flag_inexact;
+        softfloat_exception_flags or= float_flag_inexact;
     end;
     result := z;
 

+ 14 - 9
rtl/powerpc/powerpc.inc

@@ -1237,14 +1237,19 @@ end;
 {$IFDEF MORPHOS}
 { this is only required for MorphOS }
 {$define FPC_SYSTEM_HAS_SYSRESETFPU}
-procedure SysResetFPU;assembler;{$ifdef SYSTEMINLINE}inline;{$endif}
-var tmp: array[0..1] of dword;
-asm
-   { setting fpu to round to nearest mode }
-   li r3,0
-   stw r3,8(r1)
-   stw r3,12(r1)
-   lfd f1,8(r1)
-   mtfsf 7,f1
+procedure SysResetFPU;$ifdef SYSTEMINLINE}inline;{$endif}
+  var tmp: array[0..1] of dword;
+begin
+  asm
+     { setting fpu to round to nearest mode }
+     li r3,0
+     stw r3,8(r1)
+     stw r3,12(r1)
+     lfd f1,8(r1)
+     mtfsf 7,f1
+  end;
+  { powerpc might use softfloat code }
+  softfloat_exception_flags:=0;
+  softfloat_exception_mask:=float_flag_underflow or float_flag_inexact or float_flag_denormal;
 end;
 {$ENDIF}

+ 3 - 0
rtl/win64/system.pp

@@ -16,6 +16,9 @@
 unit System;
 interface
 
+
+{ $define SYSTEMEXCEPTIONDEBUG}
+
 {$ifdef SYSTEMDEBUG}
   {$define SYSTEMEXCEPTIONDEBUG}
 {$endif SYSTEMDEBUG}

+ 1 - 0
rtl/x86_64/mathu.inc

@@ -94,6 +94,7 @@ begin
   CtlWord:=Get8087CW;
   Set8087CW((CtlWord and $FFC0) or Byte(Longint(Mask)));
   SetSSECSR((GetSSECSR and $ffffe07f) or (dword(Mask) shl 7));
+  softfloat_exception_mask:=dword(Mask);
   Result:=GetExceptionMask;
 end;
 

+ 18 - 13
rtl/x86_64/x86_64.inc

@@ -592,22 +592,27 @@ const
   mxcsr : dword = MM_MaskUnderflow or MM_MaskPrecision or MM_MaskDenorm;
 
 {$define FPC_SYSTEM_HAS_SYSRESETFPU}
-Procedure SysResetFPU;assembler;{$ifdef SYSTEMINLINE}inline;{$endif}
-asm
+Procedure SysResetFPU;
+begin
+  asm
 {$ifndef WIN64}
-  { initialize fpu }
-  fninit
-  fwait
+    { initialize fpu }
+    fninit
+    fwait
 {$endif WIN64}
 {$ifdef FPC_PIC}
-  movq fpucw@GOTPCREL(%rip),%rax
-  fldcw (%rax)
-  { set sse exceptions }
-  movq mxcsr@GOTPCREL(%rip),%rax
-  ldmxcsr (%rax)
+    movq fpucw@GOTPCREL(%rip),%rax
+    fldcw (%rax)
+    { set sse exceptions }
+    movq mxcsr@GOTPCREL(%rip),%rax
+    ldmxcsr (%rax)
 {$else FPC_PIC}
-  fldcw fpucw
-  { set sse exceptions }
-  ldmxcsr mxcsr
+    fldcw fpucw
+    { set sse exceptions }
+    ldmxcsr mxcsr
 {$endif FPC_PIC}
+  end ['RAX'];
+  { x86-64 might use softfloat code }
+  softfloat_exception_flags:=0;
+  softfloat_exception_mask:=float_flag_underflow or float_flag_inexact or float_flag_denormal;
 end;