fpc/compiler/xtensa/ncpumat.pas
2020-10-13 19:59:01 +00:00

346 lines
13 KiB
ObjectPascal

{
Copyright (c) 1998-2002 by Florian Klaempfl
Generate Xtensa assembler for math 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 ncpumat;
{$i fpcdefs.inc}
interface
uses
cgbase,node,nmat,ncgmat;
type
tcpumoddivnode = class(tcgmoddivnode)
function first_moddivint: tnode; override;
procedure emit_div_reg_reg(signed: boolean; denum, num: tregister); override;
procedure emit_mod_reg_reg(signed: boolean; denum, num: tregister); override;
end;
tcpunotnode = class(tcgnotnode)
procedure second_boolean;override;
function pass_1: tnode;override;
end;
tcpuunaryminusnode = class(tcgunaryminusnode)
function pass_1: tnode; override;
procedure second_float;override;
end;
tcpushlshrnode = class(tcgshlshrnode)
procedure second_64bit;override;
function pass_1: tnode;override;
end;
implementation
uses
globtype,compinnr,
cutils,verbose,globals,constexp,
aasmbase,aasmcpu,aasmtai,aasmdata,
defutil,
symtype,symconst,symtable,
cgobj,hlcgobj,cgutils,
pass_2,procinfo,
ncon,ncnv,ncal,ninl,
cpubase,cpuinfo,
ncgutil,
nadd,pass_1,symdef;
{*****************************************************************************
TCPUMODDIVNODE
*****************************************************************************}
procedure tcpumoddivnode.emit_div_reg_reg(signed: boolean; denum, num: tregister);
var
op: TAsmOp;
begin
if signed then
op:=A_QUOS
else
op:=A_QUOU;
current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(op,num,num,denum));
end;
procedure tcpumoddivnode.emit_mod_reg_reg(signed: boolean; denum, num: tregister);
var
op: TAsmOp;
begin
if signed then
op:=A_REMS
else
op:=A_REMU;
current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(op,num,num,denum));
end;
function tcpumoddivnode.first_moddivint: tnode;
begin
if (not is_64bitint(resultdef)) and
(CPUXTENSA_HAS_DIV in cpu_capabilities[current_settings.cputype]) then
Result:=nil
else
result:=inherited;
end;
{*****************************************************************************
TCPUNOTNODE
*****************************************************************************}
function tcpunotnode.pass_1 : tnode;
begin
result:=nil;
firstpass(left);
expectloc:=LOC_REGISTER;
end;
procedure tcpunotnode.second_boolean;
var
tmpreg, hreg1, hreg2, hreg3: TRegister;
instr: taicpu;
begin
secondpass(left);
if is_64bit(resultdef) then
begin
if not(left.location.loc in [LOC_CREGISTER,LOC_REGISTER]) then
hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,resultdef,resultdef,false);
hreg1:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,OP_OR,OS_INT,left.location.register64.reglo,left.location.register64.reghi,hreg1);
hreg2:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_INT,0,hreg2);
hreg3:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
if is_cbool(resultdef) then
cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_INT,-1,hreg3)
else
cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_INT,1,hreg3);
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);
if is_cbool(resultdef) then
begin
instr:=taicpu.op_reg_reg_reg(A_MOV,location.register64.reglo,hreg3,hreg1);
instr.condition:=C_EQZ;
current_asmdata.CurrAsmList.concat(instr);
instr:=taicpu.op_reg_reg_reg(A_MOV,location.register64.reghi,hreg3,hreg1);
instr.condition:=C_EQZ;
current_asmdata.CurrAsmList.concat(instr);
instr:=taicpu.op_reg_reg_reg(A_MOV,location.register64.reglo,hreg2,hreg1);
instr.condition:=C_NEZ;
current_asmdata.CurrAsmList.concat(instr);
instr:=taicpu.op_reg_reg_reg(A_MOV,location.register64.reghi,hreg2,hreg1);
instr.condition:=C_NEZ;
current_asmdata.CurrAsmList.concat(instr);
end
else
begin
cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_INT,0,location.register64.reghi);
instr:=taicpu.op_reg_reg_reg(A_MOV,location.register64.reglo,hreg3,hreg1);
instr.condition:=C_EQZ;
current_asmdata.CurrAsmList.concat(instr);
instr:=taicpu.op_reg_reg_reg(A_MOV,location.register64.reglo,hreg2,hreg1);
instr.condition:=C_NEZ;
current_asmdata.CurrAsmList.concat(instr);
end
end
else
begin
location:=left.location;
hlcg.location_force_reg(current_asmdata.CurrAsmList,location,resultdef,resultdef,false);
if is_cbool(resultdef) then
begin
{ normalize }
hreg3:=cg.getintregister(current_asmdata.CurrAsmList,def_cgsize(resultdef));
cg.a_load_const_reg(current_asmdata.CurrAsmList,def_cgsize(resultdef),-1,hreg3);
instr:=taicpu.op_reg_reg_reg(A_MOV,location.register,hreg3,location.register);
instr.condition:=C_NEZ;
current_asmdata.CurrAsmList.concat(instr);
cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_NOT,def_cgsize(resultdef), location.register, location.register)
end
else
cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_XOR,def_cgsize(resultdef),1, location.register, location.register)
end;
end;
{*****************************************************************************
TXTENSAUNARYMINUSNODE
*****************************************************************************}
function tcpuunaryminusnode.pass_1: tnode;
var
procname: string[31];
fdef : tdef;
begin
Result:=nil;
if (current_settings.fputype=fpu_soft) and
(left.resultdef.typ=floatdef) then
begin
result:=nil;
firstpass(left);
expectloc:=LOC_REGISTER;
exit;
end;
result:=nil;
firstpass(left);
if codegenerror then
exit;
expectloc:=LOC_REGISTER;
end;
procedure tcpuunaryminusnode.second_float;
var
ai : taicpu;
begin
secondpass(left);
if (current_settings.fputype=fpu_soft) or (tfloatdef(left.resultdef).floattype<>s32real) or
not(FPUXTENSA_SINGLE in fpu_capabilities[current_settings.fputype]) then
begin
if not(left.location.loc in [LOC_CREGISTER,LOC_REGISTER]) then
hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,false);
location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
if location.size in [OS_64,OS_S64,OS_F64] 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);
case location.size of
OS_32:
cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_XOR,OS_32,tcgint($80000000),left.location.register,location.register);
OS_64:
begin
cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_XOR,OS_32,tcgint($80000000),left.location.registerhi,location.registerhi);
cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_32,OS_32,left.location.register64.reglo,location.register64.reglo);
end;
else
internalerror(2014033102);
end;
end
else
begin
if not(left.location.loc in [LOC_CFPUREGISTER,LOC_FPUREGISTER]) then
hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,false);
location_reset(location,LOC_FPUREGISTER,def_cgsize(resultdef));
location.register:=cg.getfpuregister(current_asmdata.CurrAsmList,location.size);
ai:=taicpu.op_reg_reg(A_NEG,location.register,left.location.register);
ai.oppostfix := PF_S;
current_asmdata.CurrAsmList.Concat(ai);
end;
end;
function tcpushlshrnode.pass_1 : tnode;
begin
{ the xtensa code generator can handle 64 bit shifts by constants directly }
if is_constintnode(right) and is_64bit(resultdef) and
(((nodetype=shln) and (tordconstnode(right).value>=0) and (tordconstnode(right).value<=16)) or
((nodetype=shrn) and (tordconstnode(right).value>0) and (tordconstnode(right).value<16)) or
(tordconstnode(right).value=32)) then
begin
result:=nil;
firstpass(left);
firstpass(right);
if codegenerror then
exit;
expectloc:=LOC_REGISTER;
end
else
Result:=inherited pass_1;
end;
procedure tcpushlshrnode.second_64bit;
var
op: topcg;
opsize: TCgSize;
opdef: tdef;
shiftval: longint;
hcountreg: TRegister;
begin
{ determine operator }
case nodetype of
shln: op:=OP_SHL;
shrn: op:=OP_SHR;
else
internalerror(2020082208);
end;
opsize:=left.location.size;
opdef:=left.resultdef;
if not(left.location.loc in [LOC_CREGISTER,LOC_REGISTER]) or
{ location_force_reg can be also used to change the size of a register }
(left.location.size<>opsize) then
hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,opdef,true);
location_reset(location,LOC_REGISTER,opsize);
location.register:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
location.registerhi:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
{ shifting by a constant directly coded: }
if right.nodetype=ordconstn then
begin
{ shl/shr must "wrap around", so use ... and 31 }
{ In TP, "byte/word shl 16 = 0", so no "and 15" in case of
a 16 bit ALU }
if tcgsize2size[opsize]<=4 then
shiftval:=tordconstnode(right).value.uvalue and 31
else
shiftval:=tordconstnode(right).value.uvalue and 63;
cg64.a_op64_const_reg_reg(current_asmdata.CurrAsmList,op,location.size,
shiftval,left.location.register64,location.register64)
end
else
begin
internalerror(2020082204);
{ load right operators in a register - this
is done since most target cpu which will use this
node do not support a shift count in a mem. location (cec)
}
hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,sinttype,true);
hlcg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,op,opdef,right.location.register,left.location.register,location.register);
end;
{ shl/shr nodes return the same type as left, which can be different
from opdef }
if opdef<>resultdef then
begin
hcountreg:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,opdef,resultdef,location.register,hcountreg);
location.register:=hcountreg;
end;
end;
begin
cmoddivnode:=tcpumoddivnode;
cnotnode:=tcpunotnode;
cunaryminusnode:=tcpuunaryminusnode;
cshlshrnode:=tcpushlshrnode;
end.