+ 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:
florian 2019-07-28 21:06:36 +00:00
parent 847ac91d1d
commit b3ed34592f
11 changed files with 146 additions and 18 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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