mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-22 09:29:26 +02:00

* reworked software handling of exceptions so they can be check lazily git-svn-id: trunk@42525 -
362 lines
12 KiB
ObjectPascal
362 lines
12 KiB
ObjectPascal
{
|
|
Copyright (c) 1998-2002 by Florian Klaempfl
|
|
|
|
Generate Risc-V32/64 inline nodes
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
****************************************************************************
|
|
}
|
|
unit nrvinl;
|
|
|
|
{$i fpcdefs.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
cpubase,
|
|
node,ninl,ncginl;
|
|
|
|
type
|
|
|
|
{ trvinlinenode }
|
|
|
|
trvinlinenode = class(tcginlinenode)
|
|
{ first pass override
|
|
so that the code generator will actually generate
|
|
these nodes.
|
|
}
|
|
function first_sqrt_real: tnode; override;
|
|
function first_abs_real: tnode; override;
|
|
function first_sqr_real: tnode; override;
|
|
function first_round_real: tnode; override;
|
|
function first_trunc_real: tnode; override;
|
|
|
|
function first_fma: tnode; override;
|
|
|
|
procedure second_sqrt_real; override;
|
|
procedure second_abs_real; override;
|
|
procedure second_sqr_real; override;
|
|
procedure second_round_real; override;
|
|
procedure second_trunc_real; override;
|
|
|
|
procedure second_fma; override;
|
|
protected
|
|
procedure load_fpu_location;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
ncal,
|
|
cutils,globals,verbose,globtype,
|
|
aasmtai,aasmdata,aasmcpu,
|
|
symconst,symdef,
|
|
defutil,
|
|
cgbase,pass_2,
|
|
cpuinfo,ncgutil,
|
|
hlcgobj,cgutils,cgobj,rgobj,tgobj;
|
|
|
|
|
|
{*****************************************************************************
|
|
trvinlinenode
|
|
*****************************************************************************}
|
|
|
|
function trvinlinenode.first_sqrt_real : tnode;
|
|
begin
|
|
if (current_settings.fputype >= fpu_fd) then
|
|
begin
|
|
expectloc:=LOC_FPUREGISTER;
|
|
first_sqrt_real := nil;
|
|
end
|
|
else
|
|
result:=inherited first_sqrt_real;
|
|
end;
|
|
|
|
|
|
function trvinlinenode.first_abs_real : tnode;
|
|
begin
|
|
if (current_settings.fputype >= fpu_fd) then
|
|
begin
|
|
expectloc:=LOC_FPUREGISTER;
|
|
first_abs_real := nil;
|
|
end
|
|
else
|
|
result:=inherited first_abs_real;
|
|
end;
|
|
|
|
|
|
function trvinlinenode.first_sqr_real : tnode;
|
|
begin
|
|
if (current_settings.fputype >= fpu_fd) then
|
|
begin
|
|
expectloc:=LOC_FPUREGISTER;
|
|
first_sqr_real := nil;
|
|
end
|
|
else
|
|
result:=inherited first_sqr_real;
|
|
end;
|
|
|
|
|
|
function trvinlinenode.first_round_real: tnode;
|
|
begin
|
|
if (current_settings.fputype >= fpu_fd) then
|
|
begin
|
|
expectloc:=LOC_FPUREGISTER;
|
|
first_round_real := nil;
|
|
end
|
|
else
|
|
result:=inherited first_round_real;
|
|
end;
|
|
|
|
|
|
function trvinlinenode.first_trunc_real: tnode;
|
|
begin
|
|
if (current_settings.fputype >= fpu_fd) then
|
|
begin
|
|
expectloc:=LOC_FPUREGISTER;
|
|
first_trunc_real := nil;
|
|
end
|
|
else
|
|
result:=inherited first_trunc_real;
|
|
end;
|
|
|
|
|
|
function trvinlinenode.first_fma: tnode;
|
|
begin
|
|
Result:=nil;
|
|
end;
|
|
|
|
|
|
{ load the FPU into the an fpu register }
|
|
procedure trvinlinenode.load_fpu_location;
|
|
begin
|
|
location_reset(location,LOC_FPUREGISTER,def_cgsize(resultdef));
|
|
secondpass(left);
|
|
hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true);
|
|
location.loc := LOC_FPUREGISTER;
|
|
location.register := cg.getfpuregister(current_asmdata.CurrAsmList,def_cgsize(resultdef));
|
|
end;
|
|
|
|
|
|
procedure trvinlinenode.second_sqrt_real;
|
|
begin
|
|
location.loc:=LOC_FPUREGISTER;
|
|
load_fpu_location;
|
|
case left.location.size of
|
|
OS_F32:
|
|
begin
|
|
current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FSQRT_S,location.register,
|
|
left.location.register));
|
|
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.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
|
end
|
|
else
|
|
inherited;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure trvinlinenode.second_abs_real;
|
|
var
|
|
op: TAsmOp;
|
|
begin
|
|
location.loc:=LOC_FPUREGISTER;
|
|
load_fpu_location;
|
|
if (left.location.size = OS_F32) then
|
|
op := A_FSGNJX_S
|
|
else
|
|
op := A_FSGNJX_D;
|
|
current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op,location.register,left.location.register,left.location.register));
|
|
end;
|
|
|
|
|
|
procedure trvinlinenode.second_sqr_real;
|
|
var
|
|
op: tasmop;
|
|
begin
|
|
location.loc:=LOC_FPUREGISTER;
|
|
load_fpu_location;
|
|
if (left.location.size = OS_F32) then
|
|
op := A_FMUL_S
|
|
else
|
|
op := A_FMUL_D;
|
|
current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op,location.register,left.location.register,left.location.register));
|
|
cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
|
end;
|
|
|
|
|
|
procedure trvinlinenode.second_round_real;
|
|
var
|
|
op: TAsmOp;
|
|
begin
|
|
secondpass(left);
|
|
hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true);
|
|
location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
|
|
{$ifdef RISCV32}
|
|
if (location.size in [OS_S64,OS_64]) then
|
|
begin
|
|
location.register64.reglo:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
|
|
location.register64.reghi:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
|
|
end
|
|
else
|
|
location.register:=cg.getintregister(current_asmdata.CurrAsmList,location.size);
|
|
{$else}
|
|
location.register:=cg.getintregister(current_asmdata.CurrAsmList,location.size);
|
|
{$endif}
|
|
{ convert to signed integer rounding towards zero (there's no "round to
|
|
integer using current rounding mode") }
|
|
|
|
{$ifdef RISCV32}
|
|
if (left.location.size = OS_F32) then
|
|
op := A_FCVT_W_S
|
|
else
|
|
op := A_FCVT_W_D;
|
|
{$else}
|
|
if (left.location.size = OS_F32) then
|
|
op := A_FCVT_L_S
|
|
else
|
|
op := A_FCVT_L_D;
|
|
{$endif}
|
|
|
|
current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op,location.register,left.location.register));
|
|
cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
|
end;
|
|
|
|
|
|
procedure trvinlinenode.second_trunc_real;
|
|
var
|
|
op: TAsmOp;
|
|
begin
|
|
secondpass(left);
|
|
hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true);
|
|
location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
|
|
{$ifdef RISCV32}
|
|
if (location.size in [OS_S64,OS_64]) then
|
|
begin
|
|
location.register64.reglo:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
|
|
location.register64.reghi:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
|
|
end
|
|
else
|
|
location.register:=cg.getintregister(current_asmdata.CurrAsmList,location.size);
|
|
{$else}
|
|
location.register:=cg.getintregister(current_asmdata.CurrAsmList,location.size);
|
|
{$endif}
|
|
{ convert to signed integer rounding towards zero (there's no "round to
|
|
integer using current rounding mode") }
|
|
|
|
{$ifdef RISCV32}
|
|
if (left.location.size = OS_F32) then
|
|
op := A_FCVT_W_S
|
|
else
|
|
op := A_FCVT_W_D;
|
|
{$else}
|
|
if (left.location.size = OS_F32) then
|
|
op := A_FCVT_L_S
|
|
else
|
|
op := A_FCVT_L_D;
|
|
{$endif}
|
|
|
|
current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_roundingmode(op,location.register,left.location.register,RM_RTZ));
|
|
cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
|
end;
|
|
|
|
|
|
procedure trvinlinenode.second_fma;
|
|
const
|
|
op : array[os_f32..os_f64,false..true,false..true] of TAsmOp =
|
|
(
|
|
(
|
|
(A_FMADD_S,A_FMSUB_S),
|
|
(A_FNMADD_S,A_FNMSUB_S)
|
|
),
|
|
(
|
|
(A_FMADD_D,A_FMSUB_D),
|
|
(A_FNMADD_D,A_FNMSUB_D)
|
|
)
|
|
);
|
|
var
|
|
paraarray : array[1..3] of tnode;
|
|
i : integer;
|
|
negop3,
|
|
negproduct : boolean;
|
|
begin
|
|
if current_settings.fputype in [fpu_fd] then
|
|
begin
|
|
negop3:=false;
|
|
negproduct:=false;
|
|
paraarray[1]:=tcallparanode(tcallparanode(tcallparanode(parameters).nextpara).nextpara).paravalue;
|
|
paraarray[2]:=tcallparanode(tcallparanode(parameters).nextpara).paravalue;
|
|
paraarray[3]:=tcallparanode(parameters).paravalue;
|
|
|
|
{ check if a neg. node can be removed
|
|
this is possible because changing the sign of
|
|
a floating point number does not affect its absolute
|
|
value in any way
|
|
}
|
|
if paraarray[1].nodetype=unaryminusn then
|
|
begin
|
|
paraarray[1]:=tunarynode(paraarray[1]).left;
|
|
{ do not release the unused unary minus node, it is kept and release together with the other nodes,
|
|
only no code is generated for it }
|
|
negproduct:=not(negproduct);
|
|
end;
|
|
|
|
if paraarray[2].nodetype=unaryminusn then
|
|
begin
|
|
paraarray[2]:=tunarynode(paraarray[2]).left;
|
|
{ do not release the unused unary minus node, it is kept and release together with the other nodes,
|
|
only no code is generated for it }
|
|
negproduct:=not(negproduct);
|
|
end;
|
|
|
|
if paraarray[3].nodetype=unaryminusn then
|
|
begin
|
|
paraarray[3]:=tunarynode(paraarray[3]).left;
|
|
{ do not release the unused unary minus node, it is kept and release together with the other nodes,
|
|
only no code is generated for it }
|
|
negop3:=true;
|
|
end;
|
|
|
|
for i:=1 to 3 do
|
|
secondpass(paraarray[i]);
|
|
|
|
{ no memory operand is allowed }
|
|
for i:=1 to 3 do
|
|
begin
|
|
if not(paraarray[i].location.loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER]) then
|
|
hlcg.location_force_fpureg(current_asmdata.CurrAsmList,paraarray[i].location,paraarray[i].resultdef,true);
|
|
end;
|
|
|
|
location_reset(location,LOC_FPUREGISTER,paraarray[1].location.size);
|
|
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.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
|
|
end
|
|
else
|
|
internalerror(2014032301);
|
|
end;
|
|
|
|
|
|
begin
|
|
cinlinenode:=trvinlinenode;
|
|
end.
|