fpc/compiler/mips/ncpuadd.pas
2022-02-03 23:15:34 +01:00

463 lines
14 KiB
ObjectPascal

{
Copyright (c) 2000-2009 by Florian Klaempfl and David Zhang
Code generation for add nodes on the FVM32
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 ncpuadd;
{$i fpcdefs.inc}
interface
uses
node, ncgadd, cpubase, aasmbase, cgbase;
type
{ tmipsaddnode }
tmipsaddnode = class(tcgaddnode)
private
{$ifdef cpu32bit}
procedure cmp64_lt(left_reg, right_reg: TRegister64;unsigned:boolean);
procedure cmp64_le(left_reg, right_reg: TRegister64;unsigned:boolean);
procedure second_mul64bit;
{$endif cpu32bit}
procedure second_generic_cmp32(unsigned,is_smallset: boolean);
protected
procedure second_addfloat; override;
procedure second_cmpfloat; override;
procedure second_cmpboolean; override;
procedure second_cmpsmallset; override;
{$ifdef cpu32bit}
procedure second_add64bit; override;
procedure second_cmp64bit; override;
{$endif cpu32bit}
procedure second_cmpordinal; override;
procedure second_addordinal; override;
{$ifdef cpu32bit}
public
function use_generic_mul32to64: boolean; override;
function use_generic_mul64bit: boolean; override;
{$endif cpu32bit}
end;
implementation
uses
systems, globtype, globals,
cutils, verbose,
paramgr,
aasmtai, aasmcpu, aasmdata,
defutil,
cpuinfo,
{cgbase,} cgcpu, cgutils,
cpupara,
procinfo,
symconst,symdef,
ncon, nset, nadd,
ncgutil, hlcgobj, cgobj;
{*****************************************************************************
tmipsaddnode
*****************************************************************************}
procedure tmipsaddnode.second_generic_cmp32(unsigned,is_smallset: boolean);
var
cond: TOpCmp;
allow_constant : boolean;
dreg : tregister;
begin
pass_left_right;
allow_constant:=(not is_smallset) or not (nodetype in [lten,gten]);
force_reg_left_right(True, allow_constant);
location_reset(location,LOC_FLAGS,OS_NO);
cond:=cmpnode2topcmp(unsigned);
if nf_swapped in flags then
cond:=swap_opcmp(cond);
if is_smallset and (nodetype in [lten,gten]) then
begin
if ((nodetype=lten) and not (nf_swapped in flags)) or
((nodetype=gten) and (nf_swapped in flags)) then
dreg:=right.location.register
else
dreg:=left.location.register;
current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(A_AND,dreg,right.location.register,left.location.register));
cond:=OC_EQ;
end;
location.resflags.cond:=cond;
location.resflags.reg1:=left.location.register;
location.resflags.use_const:=(right.location.loc=LOC_CONSTANT);
if location.resflags.use_const then
location.resflags.value:=right.location.value
else
location.resflags.reg2:=right.location.register;
end;
{$ifdef cpu32bit}
procedure tmipsaddnode.second_add64bit;
begin
if (nodetype=muln) then
second_mul64bit
else
inherited second_add64bit;
end;
{$endif cpu32bit}
const
cmpops: array[boolean] of TOpCmp = (OC_LT,OC_B);
{$ifdef cpu32bit}
procedure tmipsaddnode.cmp64_lt(left_reg, right_reg: TRegister64;unsigned: boolean);
begin
cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,cmpops[unsigned],right_reg.reghi,left_reg.reghi,location.truelabel);
cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_NE,left_reg.reghi,right_reg.reghi,location.falselabel);
cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_B,right_reg.reglo,left_reg.reglo,location.truelabel);
cg.a_jmp_always(current_asmdata.CurrAsmList,location.falselabel);
end;
procedure tmipsaddnode.cmp64_le(left_reg, right_reg: TRegister64;unsigned: boolean);
begin
cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,cmpops[unsigned],left_reg.reghi,right_reg.reghi,location.falselabel);
cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_NE,left_reg.reghi,right_reg.reghi,location.truelabel);
cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_B,left_reg.reglo,right_reg.reglo,location.falselabel);
cg.a_jmp_always(current_asmdata.CurrAsmList,location.truelabel);
end;
procedure tmipsaddnode.second_cmp64bit;
var
truelabel,
falselabel: tasmlabel;
unsigned: boolean;
left_reg,right_reg: TRegister64;
begin
current_asmdata.getjumplabel(truelabel);
current_asmdata.getjumplabel(falselabel);
location_reset_jump(location,truelabel,falselabel);
pass_left_right;
force_reg_left_right(true,true);
unsigned:=not(is_signed(left.resultdef)) or
not(is_signed(right.resultdef));
left_reg:=left.location.register64;
if (right.location.loc=LOC_CONSTANT) then
begin
if lo(right.location.value64)=0 then
right_reg.reglo:=NR_R0
else
begin
right_reg.reglo:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_INT,lo(right.location.value64),right_reg.reglo);
end;
if hi(right.location.value64)=0 then
right_reg.reghi:=NR_R0
else
begin
right_reg.reghi:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_INT,hi(right.location.value64),right_reg.reghi);
end;
end
else
right_reg:=right.location.register64;
case NodeType of
equaln:
begin
cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_NE,left_reg.reghi,right_reg.reghi,location.falselabel);
cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_NE,left_reg.reglo,right_reg.reglo,location.falselabel);
cg.a_jmp_always(current_asmdata.CurrAsmList,location.truelabel);
end;
unequaln:
begin
cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_NE,left_reg.reghi,right_reg.reghi,location.truelabel);
cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_NE,left_reg.reglo,right_reg.reglo,location.truelabel);
cg.a_jmp_always(current_asmdata.CurrAsmList,location.falselabel);
end;
else
if nf_swapped in flags then
case NodeType of
ltn:
cmp64_lt(right_reg, left_reg,unsigned);
lten:
cmp64_le(right_reg, left_reg,unsigned);
gtn:
cmp64_lt(left_reg, right_reg,unsigned);
gten:
cmp64_le(left_reg, right_reg,unsigned);
else
internalerror(2019051034);
end
else
case NodeType of
ltn:
cmp64_lt(left_reg, right_reg,unsigned);
lten:
cmp64_le(left_reg, right_reg,unsigned);
gtn:
cmp64_lt(right_reg, left_reg,unsigned);
gten:
cmp64_le(right_reg, left_reg,unsigned);
else
internalerror(2019051033);
end;
end;
end;
{$endif cpu32bit}
procedure tmipsaddnode.second_addfloat;
var
op: TAsmOp;
begin
pass_left_right;
if (nf_swapped in flags) then
swapleftright;
{ force fpureg as location, left right doesn't matter
as both will be in a fpureg }
hlcg.location_force_fpureg(current_asmdata.CurrAsmList, left.location, left.resultdef, True);
hlcg.location_force_fpureg(current_asmdata.CurrAsmList, right.location, right.resultdef, True);
location_reset(location, LOC_FPUREGISTER, def_cgsize(resultdef));
location.register:=cg.getfpuregister(current_asmdata.CurrAsmList,location.size);
case nodetype of
addn:
begin
if location.size = OS_F64 then
op := A_ADD_D
else
op := A_ADD_S;
end;
muln:
begin
if location.size = OS_F64 then
op := A_MUL_D
else
op := A_MUL_S;
end;
subn:
begin
if location.size = OS_F64 then
op := A_SUB_D
else
op := A_SUB_S;
end;
slashn:
begin
if location.size = OS_F64 then
op := A_DIV_D
else
op := A_DIV_S;
end;
else
internalerror(200306014);
end;
current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op,
location.Register, left.location.Register, right.location.Register));
end;
const
ops_cmpfloat: array[boolean,ltn..unequaln] of TAsmOp = (
// ltn lten gtn gten equaln unequaln
(A_C_LT_S, A_C_LE_S, A_C_LT_S, A_C_LE_S, A_C_EQ_S, A_C_EQ_S),
(A_C_LT_D, A_C_LE_D, A_C_LT_D, A_C_LE_D, A_C_EQ_D, A_C_EQ_D)
);
procedure tmipsaddnode.second_cmpfloat;
var
op: tasmop;
lreg,rreg: tregister;
begin
pass_left_right;
if nf_swapped in flags then
swapleftright;
hlcg.location_force_fpureg(current_asmdata.CurrAsmList, left.location, left.resultdef, True);
hlcg.location_force_fpureg(current_asmdata.CurrAsmList, right.location, right.resultdef, True);
location_reset(location, LOC_FLAGS, OS_NO);
op:=ops_cmpfloat[left.location.size=OS_F64,nodetype];
if (nodetype in [gtn,gten]) then
begin
lreg:=right.location.register;
rreg:=left.location.register;
end
else
begin
lreg:=left.location.register;
rreg:=right.location.register;
end;
current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op,lreg,rreg));
location.resflags.reg1:=NR_FCC0;
if (nodetype=unequaln) then
location.resflags.cond:=OC_EQ
else
location.resflags.cond:=OC_NE;
end;
procedure tmipsaddnode.second_cmpboolean;
begin
second_generic_cmp32(true,false);
end;
procedure tmipsaddnode.second_cmpsmallset;
begin
second_generic_cmp32(true,true);
end;
procedure tmipsaddnode.second_cmpordinal;
var
unsigned: boolean;
begin
unsigned := not (is_signed(left.resultdef)) or not (is_signed(right.resultdef));
second_generic_cmp32(unsigned,false);
end;
const
multops: array[boolean] of TAsmOp = (A_MULT, A_MULTU);
procedure tmipsaddnode.second_addordinal;
var
unsigned: boolean;
begin
{$ifdef cpu32bit}
unsigned:=not(is_signed(left.resultdef)) or
not(is_signed(right.resultdef));
if (nodetype=muln) and is_64bit(resultdef) then
begin
pass_left_right;
force_reg_left_right(true,false);
location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
location.register64.reglo:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
location.register64.reghi:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg(multops[unsigned],left.location.register,right.location.register));
current_asmdata.CurrAsmList.Concat(taicpu.op_reg(A_MFLO,location.register64.reglo));
current_asmdata.CurrAsmList.Concat(taicpu.op_reg(A_MFHI,location.register64.reghi));
end
else
{$endif cpu32bit}
inherited second_addordinal;
end;
{$ifdef cpu32bit}
procedure tmipsaddnode.second_mul64bit;
var
list: TAsmList;
hreg1,hreg2,tmpreg: TRegister;
begin
list:=current_asmdata.CurrAsmList;
pass_left_right;
location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
hlcg.location_force_reg(list,left.location,left.resultdef,left.resultdef,true);
{ calculate 32-bit terms lo(right)*hi(left) and hi(left)*lo(right) }
hreg1:=NR_NO;
hreg2:=NR_NO;
tmpreg:=NR_NO;
if (right.location.loc=LOC_CONSTANT) then
begin
{ Omit zero terms, if any }
if hi(right.location.value64)<>0 then
begin
hreg2:=cg.getintregister(list,OS_INT);
tmpreg:=cg.getintregister(list,OS_INT);
cg.a_load_const_reg(list,OS_INT,longint(hi(right.location.value64)),tmpreg);
list.concat(taicpu.op_reg_reg_reg(A_MUL,hreg2,tmpreg,left.location.register64.reglo));
end;
tmpreg:=NR_NO;
if lo(right.location.value64)<>0 then
begin
hreg1:=cg.getintregister(list,OS_INT);
tmpreg:=cg.getintregister(list,OS_INT);
cg.a_load_const_reg(list,OS_INT,longint(lo(right.location.value64)),tmpreg);
list.concat(taicpu.op_reg_reg_reg(A_MUL,hreg1,tmpreg,left.location.register64.reghi));
end;
end
else
begin
hlcg.location_force_reg(list,right.location,right.resultdef,right.resultdef,true);
tmpreg:=right.location.register64.reglo;
hreg1:=cg.getintregister(list,OS_INT);
hreg2:=cg.getintregister(list,OS_INT);
list.concat(taicpu.op_reg_reg_reg(A_MUL,hreg1,right.location.register64.reglo,left.location.register64.reghi));
list.concat(taicpu.op_reg_reg_reg(A_MUL,hreg2,right.location.register64.reghi,left.location.register64.reglo));
end;
{ At this point, tmpreg is either lo(right) or NR_NO if lo(left)*lo(right) is zero }
if (tmpreg=NR_NO) then
begin
if (hreg2<>NR_NO) and (hreg1<>NR_NO) then
begin
location.register64.reghi:=cg.getintregister(list,OS_INT);
list.concat(taicpu.op_reg_reg_reg(A_ADDU,location.register64.reghi,hreg1,hreg2));
end
else if (hreg2<>NR_NO) then
location.register64.reghi:=hreg2
else if (hreg1<>NR_NO) then
location.register64.reghi:=hreg1
else
InternalError(2014122701);
location.register64.reglo:=NR_R0;
end
else
begin
list.concat(taicpu.op_reg_reg(A_MULTU,left.location.register64.reglo,tmpreg));
location.register64.reghi:=cg.getintregister(list,OS_INT);
location.register64.reglo:=cg.getintregister(list,OS_INT);
current_asmdata.CurrAsmList.Concat(taicpu.op_reg(A_MFLO,location.register64.reglo));
current_asmdata.CurrAsmList.Concat(taicpu.op_reg(A_MFHI,location.register64.reghi));
if (hreg2<>NR_NO) then
list.concat(taicpu.op_reg_reg_reg(A_ADDU,location.register64.reghi,location.register64.reghi,hreg2));
if (hreg1<>NR_NO) then
list.concat(taicpu.op_reg_reg_reg(A_ADDU,location.register64.reghi,location.register64.reghi,hreg1));
end;
end;
function tmipsaddnode.use_generic_mul32to64: boolean;
begin
result:=false;
end;
function tmipsaddnode.use_generic_mul64bit: boolean;
begin
result:=needoverflowcheck or
(not (CPUMIPS_HAS_ISA32R2 in cpu_capabilities[current_settings.cputype]));
end;
{$endif cpu32bit}
begin
caddnode := tmipsaddnode;
end.