* correct masking of exceptions in genmath code

git-svn-id: trunk@5965 -
This commit is contained in:
florian 2007-01-14 10:44:10 +00:00
parent 4f5c8cfe1f
commit b3a1868ff0
9 changed files with 160 additions and 112 deletions

View File

@ -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;

View File

@ -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}

View File

@ -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}

View File

@ -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}

View File

@ -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;

View File

@ -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}

View File

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

View File

@ -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;

View File

@ -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;