mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-20 19:29:26 +02:00
+ software handling of exceptions on arm
* reworked software handling of exceptions so they can be check lazily git-svn-id: trunk@42525 -
This commit is contained in:
parent
847ac91d1d
commit
b3ed34592f
@ -61,6 +61,8 @@ unit cgcpu;
|
||||
procedure a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); override;
|
||||
procedure a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference); override;
|
||||
|
||||
procedure g_check_for_fpu_exception(list : TAsmList; force,clear : boolean); override;
|
||||
|
||||
procedure a_loadfpu_ref_cgpara(list : TAsmList;size : tcgsize;const ref : treference;const paraloc : TCGPara);override;
|
||||
{ comparison operations }
|
||||
procedure a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : tcgint;reg : tregister;
|
||||
@ -1720,6 +1722,33 @@ unit cgcpu;
|
||||
end;
|
||||
|
||||
|
||||
procedure tbasecgarm.g_check_for_fpu_exception(list: TAsmList;force,clear : boolean);
|
||||
var
|
||||
r : TRegister;
|
||||
ai: taicpu;
|
||||
l: TAsmLabel;
|
||||
begin
|
||||
if ((cs_check_fpu_exceptions in current_settings.localswitches) and
|
||||
(force or current_procinfo.FPUExceptionCheckNeeded)) then
|
||||
begin
|
||||
r:=getintregister(list,OS_INT);
|
||||
list.concat(taicpu.op_reg_reg(A_FMRX,r,NR_FPSCR));
|
||||
list.concat(setoppostfix(taicpu.op_reg_reg_const(A_AND,r,r,$9f),PF_S));
|
||||
current_asmdata.getjumplabel(l);
|
||||
ai:=taicpu.op_sym(A_B,l);
|
||||
ai.is_jmp:=true;
|
||||
ai.condition:=C_EQ;
|
||||
list.concat(ai);
|
||||
alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
|
||||
cg.a_call_name(current_asmdata.CurrAsmList,'FPC_THROWFPUEXCEPTION',false);
|
||||
dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
|
||||
a_label(list,l);
|
||||
if clear then
|
||||
current_procinfo.FPUExceptionCheckNeeded:=false;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
{ comparison operations }
|
||||
procedure tbasecgarm.a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : tcgint;reg : tregister;
|
||||
l : tasmlabel);
|
||||
@ -3069,6 +3098,7 @@ unit cgcpu;
|
||||
else
|
||||
;
|
||||
end;
|
||||
maybe_check_for_fpu_exception(list);
|
||||
end;
|
||||
|
||||
|
||||
@ -3134,6 +3164,7 @@ unit cgcpu;
|
||||
|
||||
if (tmpmmreg<>reg) then
|
||||
a_loadmm_reg_reg(list,fromsize,tosize,tmpmmreg,reg,shuffle);
|
||||
maybe_check_for_fpu_exception(list);
|
||||
end;
|
||||
|
||||
|
||||
@ -3199,6 +3230,7 @@ unit cgcpu;
|
||||
begin
|
||||
handle_load_store(list,A_VSTR,PF_None,tmpmmreg,ref);
|
||||
end;
|
||||
maybe_check_for_fpu_exception(list);
|
||||
end;
|
||||
|
||||
|
||||
@ -3214,6 +3246,7 @@ unit cgcpu;
|
||||
not shufflescalar(shuffle) then
|
||||
internalerror(2009112516);
|
||||
list.concat(taicpu.op_reg_reg(A_VMOV,mmreg,intreg));
|
||||
maybe_check_for_fpu_exception(list);
|
||||
end;
|
||||
|
||||
|
||||
@ -3229,6 +3262,7 @@ unit cgcpu;
|
||||
not shufflescalar(shuffle) then
|
||||
internalerror(2009112514);
|
||||
list.concat(taicpu.op_reg_reg(A_VMOV,intreg,mmreg));
|
||||
maybe_check_for_fpu_exception(list);
|
||||
end;
|
||||
|
||||
|
||||
@ -3356,6 +3390,7 @@ unit cgcpu;
|
||||
if (mmsize<>OS_F64) then
|
||||
internalerror(2009112405);
|
||||
list.concat(taicpu.op_reg_reg_reg(A_VMOV,mmreg,intreg.reglo,intreg.reghi));
|
||||
cg.maybe_check_for_fpu_exception(list);
|
||||
end;
|
||||
|
||||
|
||||
@ -3366,6 +3401,7 @@ unit cgcpu;
|
||||
if (mmsize<>OS_F64) then
|
||||
internalerror(2009112406);
|
||||
list.concat(taicpu.op_reg_reg_reg(A_VMOV,intreg.reglo,intreg.reghi,mmreg));
|
||||
cg.maybe_check_for_fpu_exception(list);
|
||||
end;
|
||||
|
||||
|
||||
@ -5196,6 +5232,7 @@ unit cgcpu;
|
||||
instr:=setoppostfix(taicpu.op_reg_reg(A_VMOV,reg2,reg1), PF_F32);
|
||||
list.Concat(instr);
|
||||
add_move_instruction(instr);
|
||||
maybe_check_for_fpu_exception(list);
|
||||
end
|
||||
else if (fromsize=OS_F64) and
|
||||
(tosize=OS_F64) then
|
||||
@ -5221,6 +5258,7 @@ unit cgcpu;
|
||||
procedure tthumb2cgarm.a_loadmm_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference; shuffle: pmmshuffle);
|
||||
begin
|
||||
handle_load_store(list,A_VSTR,PF_None,reg,ref);
|
||||
maybe_check_for_fpu_exception(list);
|
||||
end;
|
||||
|
||||
|
||||
@ -5238,7 +5276,10 @@ unit cgcpu;
|
||||
begin
|
||||
if //(shuffle=nil) and
|
||||
(fromsize=OS_F32) then
|
||||
list.Concat(taicpu.op_reg_reg(A_VMOV,intreg,mmreg))
|
||||
begin
|
||||
list.Concat(taicpu.op_reg_reg(A_VMOV,intreg,mmreg));
|
||||
maybe_check_for_fpu_exception(list);
|
||||
end
|
||||
else
|
||||
internalerror(2012100814);
|
||||
end;
|
||||
|
@ -238,6 +238,7 @@ interface
|
||||
|
||||
current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg_reg(op,
|
||||
location.register,left.location.register,right.location.register),pf));
|
||||
cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
||||
end;
|
||||
fpu_fpv4_s16:
|
||||
begin
|
||||
@ -263,6 +264,7 @@ interface
|
||||
end;
|
||||
|
||||
current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg_reg(op, location.register,left.location.register,right.location.register), PF_F32));
|
||||
cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
||||
end;
|
||||
fpu_soft:
|
||||
{ this case should be handled already by pass1 }
|
||||
@ -325,6 +327,7 @@ interface
|
||||
|
||||
current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(op,
|
||||
left.location.register,right.location.register), pf));
|
||||
cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
||||
cg.a_reg_alloc(current_asmdata.CurrAsmList,NR_DEFAULTFLAGS);
|
||||
current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_VMRS,NR_APSR_nzcv,NR_FPSCR));
|
||||
location.resflags:=GetFpuResFlags;
|
||||
@ -341,6 +344,7 @@ interface
|
||||
|
||||
current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(op,
|
||||
left.location.register,right.location.register),PF_F32));
|
||||
cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
||||
cg.a_reg_alloc(current_asmdata.CurrAsmList,NR_DEFAULTFLAGS);
|
||||
current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg(A_VMRS, NR_APSR_nzcv, NR_FPSCR));
|
||||
end;
|
||||
|
@ -272,9 +272,13 @@ implementation
|
||||
else
|
||||
pf:=PF_F64;
|
||||
current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_VABS,location.register,left.location.register),pf));
|
||||
cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
||||
end;
|
||||
fpu_fpv4_s16:
|
||||
current_asmdata.CurrAsmList.Concat(setoppostfix(taicpu.op_reg_reg(A_VABS,location.register,left.location.register), PF_F32));
|
||||
begin
|
||||
current_asmdata.CurrAsmList.Concat(setoppostfix(taicpu.op_reg_reg(A_VABS,location.register,left.location.register), PF_F32));
|
||||
cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
||||
end;
|
||||
fpu_soft:
|
||||
begin
|
||||
if singleprec then
|
||||
@ -309,9 +313,13 @@ implementation
|
||||
else
|
||||
pf:=PF_F64;
|
||||
current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg_reg(A_VMUL,location.register,left.location.register,left.location.register),pf));
|
||||
cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
||||
end;
|
||||
fpu_fpv4_s16:
|
||||
current_asmdata.CurrAsmList.Concat(setoppostfix(taicpu.op_reg_reg_reg(A_VMUL,location.register,left.location.register,left.location.register), PF_F32));
|
||||
begin
|
||||
current_asmdata.CurrAsmList.Concat(setoppostfix(taicpu.op_reg_reg_reg(A_VMUL,location.register,left.location.register,left.location.register), PF_F32));
|
||||
cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
||||
end;
|
||||
else
|
||||
internalerror(2009111403);
|
||||
end;
|
||||
@ -339,9 +347,13 @@ implementation
|
||||
else
|
||||
pf:=PF_F64;
|
||||
current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_VSQRT,location.register,left.location.register),pf));
|
||||
cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
||||
end;
|
||||
fpu_fpv4_s16:
|
||||
current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_VSQRT,location.register,left.location.register), PF_F32));
|
||||
begin
|
||||
current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_VSQRT,location.register,left.location.register), PF_F32));
|
||||
cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
||||
end;
|
||||
else
|
||||
internalerror(2009111402);
|
||||
end;
|
||||
@ -515,6 +527,7 @@ implementation
|
||||
oppostfix:=PF_F32;
|
||||
current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg_reg(op[negproduct,negop3],
|
||||
location.register,paraarray[1].location.register,paraarray[2].location.register),oppostfix));
|
||||
cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
||||
end
|
||||
else
|
||||
internalerror(2014032301);
|
||||
|
@ -435,6 +435,7 @@ implementation
|
||||
|
||||
current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_VNEG,
|
||||
location.register,left.location.register), pf));
|
||||
cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
||||
end;
|
||||
fpu_fpv4_s16:
|
||||
begin
|
||||
@ -444,6 +445,7 @@ implementation
|
||||
location.register:=cg.getmmregister(current_asmdata.CurrAsmList,location.size);
|
||||
current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_VNEG,
|
||||
location.register,left.location.register), PF_F32));
|
||||
cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
||||
end;
|
||||
fpu_soft:
|
||||
begin
|
||||
|
@ -453,7 +453,8 @@ unit cgobj;
|
||||
|
||||
{ some CPUs do not support hardware fpu exceptions, this procedure is called after instructions which
|
||||
might set FPU exception related flags, so it has to check these flags if needed and throw an exeception }
|
||||
procedure g_check_for_fpu_exception(list: TAsmList); virtual;
|
||||
procedure g_check_for_fpu_exception(list : TAsmList; force,clear : boolean); virtual;
|
||||
procedure maybe_check_for_fpu_exception(list: TAsmList);
|
||||
|
||||
protected
|
||||
function g_indirect_sym_load(list:TAsmList;const symname: string; const flags: tindsymflags): tregister;virtual;
|
||||
@ -2930,12 +2931,18 @@ implementation
|
||||
end;
|
||||
|
||||
|
||||
procedure tcg.g_check_for_fpu_exception(list: TAsmList);
|
||||
procedure tcg.g_check_for_fpu_exception(list: TAsmList;force,clear : boolean);
|
||||
begin
|
||||
{ empty by default }
|
||||
end;
|
||||
|
||||
|
||||
procedure tcg.maybe_check_for_fpu_exception(list: TAsmList);
|
||||
begin
|
||||
current_procinfo.FPUExceptionCheckNeeded:=true;
|
||||
g_check_for_fpu_exception(list,false,true);
|
||||
end;
|
||||
|
||||
{*****************************************************************************
|
||||
TCG64
|
||||
*****************************************************************************}
|
||||
|
@ -1280,7 +1280,7 @@ implementation
|
||||
|
||||
{ check for fpu exceptions }
|
||||
if cnf_check_fpu_exceptions in callnodeflags then
|
||||
cg.g_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
||||
cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
||||
|
||||
{ perhaps i/o check ? }
|
||||
if (cs_check_io in current_settings.localswitches) and
|
||||
|
@ -136,6 +136,10 @@ unit procinfo;
|
||||
Requires different entry code for some targets. }
|
||||
ConstructorCallingConstructor: boolean;
|
||||
|
||||
{ true, if an FPU instruction has been generated which could raise an exception and where the flags
|
||||
need to be checked explicitly like on RISC-V or certain ARM architectures }
|
||||
FPUExceptionCheckNeeded : Boolean;
|
||||
|
||||
constructor create(aparent:tprocinfo);virtual;
|
||||
destructor destroy;override;
|
||||
|
||||
|
@ -72,7 +72,7 @@ unit cgrv;
|
||||
procedure a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); override;
|
||||
procedure a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference); override;
|
||||
|
||||
procedure g_check_for_fpu_exception(list: TAsmList); override;
|
||||
procedure g_check_for_fpu_exception(list: TAsmList;force,clear : boolean); override;
|
||||
protected
|
||||
function fixref(list: TAsmList; var ref: treference): boolean;
|
||||
procedure maybeadjustresult(list: TAsmList; op: topcg; size: tcgsize; dst: tregister);
|
||||
@ -614,7 +614,7 @@ unit cgrv;
|
||||
if fromsize<>tosize then
|
||||
begin
|
||||
list.concat(taicpu.op_reg_reg(convOp[fromsize,tosize],reg2,reg1));
|
||||
g_check_for_fpu_exception(list);
|
||||
maybe_check_for_fpu_exception(list);
|
||||
end
|
||||
else
|
||||
begin
|
||||
@ -786,7 +786,7 @@ unit cgrv;
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgrv.g_check_for_fpu_exception(list: TAsmList);
|
||||
procedure tcgrv.g_check_for_fpu_exception(list: TAsmList;force,clear : boolean);
|
||||
var
|
||||
r : TRegister;
|
||||
ai: taicpu;
|
||||
|
@ -423,12 +423,12 @@ implementation
|
||||
if not cmpop then
|
||||
begin
|
||||
current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op,location.register,left.location.register,right.location.register));
|
||||
cg.g_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
||||
cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
||||
end
|
||||
else
|
||||
begin
|
||||
current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op,location.register,left.location.register,right.location.register));
|
||||
cg.g_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
||||
cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
||||
|
||||
if inv then
|
||||
current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_XORI,location.register,location.register,1));
|
||||
|
@ -160,13 +160,13 @@ implementation
|
||||
begin
|
||||
current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FSQRT_S,location.register,
|
||||
left.location.register));
|
||||
cg.g_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
||||
cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
||||
end;
|
||||
OS_F64:
|
||||
begin
|
||||
current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FSQRT_D,location.register,
|
||||
left.location.register));
|
||||
cg.g_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
||||
cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
||||
end
|
||||
else
|
||||
inherited;
|
||||
@ -199,7 +199,7 @@ implementation
|
||||
else
|
||||
op := A_FMUL_D;
|
||||
current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op,location.register,left.location.register,left.location.register));
|
||||
cg.g_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
||||
cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
||||
end;
|
||||
|
||||
|
||||
@ -237,7 +237,7 @@ implementation
|
||||
{$endif}
|
||||
|
||||
current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op,location.register,left.location.register));
|
||||
cg.g_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
||||
cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
||||
end;
|
||||
|
||||
|
||||
@ -275,7 +275,7 @@ implementation
|
||||
{$endif}
|
||||
|
||||
current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_roundingmode(op,location.register,left.location.register,RM_RTZ));
|
||||
cg.g_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
||||
cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
||||
end;
|
||||
|
||||
|
||||
@ -349,7 +349,7 @@ implementation
|
||||
location.register:=cg.getfpuregister(current_asmdata.CurrAsmList,location.size);
|
||||
|
||||
current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_reg(op[def_cgsize(resultdef), negproduct,negop3],location.register,paraarray[1].location.register,paraarray[2].location.register,paraarray[2].location.register));
|
||||
cg.g_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
||||
cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
||||
end
|
||||
else
|
||||
internalerror(2014032301);
|
||||
|
@ -47,6 +47,63 @@ begin
|
||||
end;
|
||||
end;
|
||||
{$else}
|
||||
|
||||
|
||||
const
|
||||
fpu_nx = 1 shl 0;
|
||||
fpu_uf = 1 shl 1;
|
||||
fpu_of = 1 shl 2;
|
||||
fpu_dz = 1 shl 3;
|
||||
fpu_nv = 1 shl 4;
|
||||
|
||||
function getfpscr: sizeuint; nostackframe; assembler;
|
||||
asm
|
||||
fmrx r0,fpscr
|
||||
end;
|
||||
|
||||
|
||||
procedure setfpscr(flags : sizeuint); nostackframe; assembler;
|
||||
asm
|
||||
fmxr fpscr,r0
|
||||
end;
|
||||
|
||||
|
||||
const
|
||||
FPSCR_IOC = 1;
|
||||
FPSCR_DZC = 1 shl 1;
|
||||
FPSCR_OFC = 1 shl 2;
|
||||
FPSCR_UFC = 1 shl 3;
|
||||
FPSCR_IXC = 1 shl 4;
|
||||
FPSCR_IDC = 1 shl 7;
|
||||
|
||||
|
||||
procedure fpc_throwfpuexception;[public,alias:'FPC_THROWFPUEXCEPTION'];
|
||||
var
|
||||
fpscr : longint;
|
||||
f: TFPUException;
|
||||
begin
|
||||
{ at this point, we know already, that an exception will be risen }
|
||||
fpscr:=getfpscr;
|
||||
|
||||
if (fpscr and FPSCR_DZC) <> 0 then
|
||||
float_raise(exZeroDivide);
|
||||
if (fpscr and FPSCR_OFC) <> 0 then
|
||||
float_raise(exOverflow);
|
||||
if (fpscr and FPSCR_UFC) <> 0 then
|
||||
float_raise(exUnderflow);
|
||||
if (fpscr and FPSCR_IOC) <> 0 then
|
||||
float_raise(exInvalidOp);
|
||||
if (fpscr and FPSCR_IXC) <> 0 then
|
||||
float_raise(exPrecision);
|
||||
if (fpscr and FPSCR_IDC) <> 0 then
|
||||
float_raise(exDenormalized);
|
||||
|
||||
{ now the soft float exceptions }
|
||||
for f in softfloat_exception_flags do
|
||||
float_raise(f);
|
||||
end;
|
||||
|
||||
|
||||
Procedure SysInitFPU;{$ifdef SYSTEMINLINE}inline;{$endif}
|
||||
begin
|
||||
{ Enable FPU exceptions, but disable INEXACT, UNDERFLOW, DENORMAL }
|
||||
|
Loading…
Reference in New Issue
Block a user