mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-22 02:49:28 +02:00
* improved software floating point exception handling in the rtl
git-svn-id: trunk@43163 -
This commit is contained in:
parent
29bdbdba95
commit
c189af0e3d
@ -83,9 +83,9 @@ const
|
|||||||
FPSCR_UFC = 1 shl 3;
|
FPSCR_UFC = 1 shl 3;
|
||||||
FPSCR_IXC = 1 shl 4;
|
FPSCR_IXC = 1 shl 4;
|
||||||
FPSCR_IDC = 1 shl 7;
|
FPSCR_IDC = 1 shl 7;
|
||||||
|
FPSCR_EXCEPTIONS = FPSCR_IOC or FPSCR_DZC or FPSCR_OFC or FPSCR_UFC or FPSCR_IXC or FPSCR_IDC;
|
||||||
|
|
||||||
|
procedure RaisePendingExceptions;
|
||||||
procedure fpc_throwfpuexception;[public,alias:'FPC_THROWFPUEXCEPTION'];
|
|
||||||
var
|
var
|
||||||
fpscr : longint;
|
fpscr : longint;
|
||||||
f: TFPUException;
|
f: TFPUException;
|
||||||
@ -112,6 +112,34 @@ procedure fpc_throwfpuexception;[public,alias:'FPC_THROWFPUEXCEPTION'];
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure fpc_throwfpuexception;[public,alias:'FPC_THROWFPUEXCEPTION'];
|
||||||
|
var
|
||||||
|
fpscr : dword;
|
||||||
|
f: TFPUException;
|
||||||
|
begin
|
||||||
|
{ at this point, we know already, that an exception will be risen }
|
||||||
|
fpscr:=getfpscr;
|
||||||
|
|
||||||
|
{ check, if the exception is masked, as ARM without hardware exceptions have no masking functionality,
|
||||||
|
we use the software mask }
|
||||||
|
if ((fpscr and FPSCR_DZC) <> 0) and (exZeroDivide in softfloat_exception_mask) then
|
||||||
|
fpscr:=fpscr and not(FPSCR_DZC);
|
||||||
|
if ((fpscr and FPSCR_OFC) <> 0) and (exOverflow in softfloat_exception_mask) then
|
||||||
|
fpscr:=fpscr and not(FPSCR_OFC);
|
||||||
|
if ((fpscr and FPSCR_UFC) <> 0) and (exUnderflow in softfloat_exception_mask) then
|
||||||
|
fpscr:=fpscr and not(FPSCR_UFC);
|
||||||
|
if ((fpscr and FPSCR_IOC) <> 0) and (exInvalidOp in softfloat_exception_mask) then
|
||||||
|
fpscr:=fpscr and not(FPSCR_IOC);
|
||||||
|
if ((fpscr and FPSCR_IXC) <> 0) and (exPrecision in softfloat_exception_mask) then
|
||||||
|
fpscr:=fpscr and not(FPSCR_IXC);
|
||||||
|
if ((fpscr and FPSCR_IDC) <> 0) and (exDenormalized in softfloat_exception_mask) then
|
||||||
|
fpscr:=fpscr and not(FPSCR_IDC);
|
||||||
|
setfpscr(fpscr);
|
||||||
|
if (fpscr and FPSCR_EXCEPTIONS)<>0 then
|
||||||
|
RaisePendingExceptions;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
Procedure SysInitFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
|
Procedure SysInitFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
|
||||||
begin
|
begin
|
||||||
{ Enable FPU exceptions, but disable INEXACT, UNDERFLOW, DENORMAL }
|
{ Enable FPU exceptions, but disable INEXACT, UNDERFLOW, DENORMAL }
|
||||||
@ -133,7 +161,18 @@ begin
|
|||||||
{$endif}
|
{$endif}
|
||||||
fmxr fpscr,r0
|
fmxr fpscr,r0
|
||||||
end;
|
end;
|
||||||
|
softfloat_exception_mask:=[float_flag_underflow,float_flag_inexact,float_flag_denormal];
|
||||||
|
softfloat_exception_flags:=[];
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{$define FPC_SYSTEM_HAS_SYSRESETFPU}
|
||||||
|
Procedure SysResetFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
|
||||||
|
begin
|
||||||
|
softfloat_exception_flags:=[];
|
||||||
|
setfpscr(getfpscr and not(FPSCR_EXCEPTIONS));
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
{$endif}
|
{$endif}
|
||||||
{$endif}
|
{$endif}
|
||||||
|
|
||||||
|
@ -250,6 +250,11 @@ function VFPCw2ExceptionMask(cw: dword): TFPUExceptionMask;
|
|||||||
|
|
||||||
function GetExceptionMask: TFPUExceptionMask;
|
function GetExceptionMask: TFPUExceptionMask;
|
||||||
begin
|
begin
|
||||||
|
{ some ARM CPUs ignore writing to the hardware mask and just return 0, so we need to return
|
||||||
|
the softfloat mask which should be in sync with the hard one }
|
||||||
|
if VFP_GetCW=0 then
|
||||||
|
Result:=softfloat_exception_mask
|
||||||
|
else
|
||||||
Result:=VFPCw2ExceptionMask(VFP_GetCW);
|
Result:=VFPCw2ExceptionMask(VFP_GetCW);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -290,6 +295,7 @@ procedure ClearExceptions(RaisePending: Boolean =true);
|
|||||||
begin
|
begin
|
||||||
{ RaisePending has no effect on ARM, it always raises them at the correct location }
|
{ RaisePending has no effect on ARM, it always raises them at the correct location }
|
||||||
VFP_SetCW(VFP_GetCW and (not _VFP_EXCEPTIONS_PENDING_MASK));
|
VFP_SetCW(VFP_GetCW and (not _VFP_EXCEPTIONS_PENDING_MASK));
|
||||||
|
softfloat_exception_flags:=[];
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{$else FPUARM_HAS_VFP_EXTENSION}
|
{$else FPUARM_HAS_VFP_EXTENSION}
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
Procedure SysInitFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
|
Procedure SysInitFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
|
||||||
begin
|
begin
|
||||||
softfloat_exception_mask:=[float_flag_underflow,float_flag_inexact,float_flag_denormal];
|
softfloat_exception_mask:=[float_flag_underflow,float_flag_inexact,float_flag_denormal];
|
||||||
|
softfloat_exception_flags:=[];
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
@ -134,20 +134,21 @@ Begin
|
|||||||
pflags := @softfloat_exception_flags;
|
pflags := @softfloat_exception_flags;
|
||||||
pflags^:=pflags^ + i;
|
pflags^:=pflags^ + i;
|
||||||
unmasked_flags := pflags^ - softfloat_exception_mask;
|
unmasked_flags := pflags^ - softfloat_exception_mask;
|
||||||
|
{ before we raise the exception, we mark it as handled,
|
||||||
|
this behaviour is similiar to the hardware handler in SignalToRunerror }
|
||||||
|
SysResetFPU;
|
||||||
if (float_flag_invalid in unmasked_flags) then
|
if (float_flag_invalid in unmasked_flags) then
|
||||||
HandleError(207)
|
HandleError(207)
|
||||||
else
|
else if (float_flag_divbyzero in unmasked_flags) then
|
||||||
if (float_flag_divbyzero in unmasked_flags) then
|
|
||||||
HandleError(200)
|
HandleError(200)
|
||||||
else
|
else if (float_flag_overflow in unmasked_flags) then
|
||||||
if (float_flag_overflow in unmasked_flags) then
|
|
||||||
HandleError(205)
|
HandleError(205)
|
||||||
else
|
else if (float_flag_underflow in unmasked_flags) then
|
||||||
if (float_flag_underflow in unmasked_flags) then
|
|
||||||
HandleError(206)
|
HandleError(206)
|
||||||
else
|
else if (float_flag_inexact in unmasked_flags) then
|
||||||
if (float_flag_inexact in unmasked_flags) then
|
HandleError(207)
|
||||||
HandleError(207);
|
else if (float_flag_denormal in unmasked_flags) then
|
||||||
|
HandleError(216);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
@ -70,6 +70,7 @@ begin
|
|||||||
begin
|
begin
|
||||||
{ don't know how to find the different causes, maybe via xer? }
|
{ don't know how to find the different causes, maybe via xer? }
|
||||||
res := 207;
|
res := 207;
|
||||||
|
SysResetFPU;
|
||||||
end;
|
end;
|
||||||
SIGILL:
|
SIGILL:
|
||||||
{$ifdef FPC_SYSTEM_FPC_MOVE}
|
{$ifdef FPC_SYSTEM_FPC_MOVE}
|
||||||
|
Loading…
Reference in New Issue
Block a user