mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-05-02 04:53:42 +02:00

pasbool8type for this results in too much trouble (we mustn't use i1 for parameters, because then LLVM will try to apply the ABI convention for passing "1 bit" values, or in records because then this may result in unwanted bitpacking). Downside: the new LLVMBool1 type is also exposed in the system unit, because we need it to define LLVM intrinsics... git-svn-id: trunk@33726 -
327 lines
10 KiB
ObjectPascal
327 lines
10 KiB
ObjectPascal
{
|
|
Copyright (c) 2013 by Jonas Maebe
|
|
|
|
Generate LLVM bytecode for add 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 nllvmadd;
|
|
|
|
{$i fpcdefs.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
node,
|
|
ncgadd;
|
|
|
|
type
|
|
tllvmaddnode = class(tcgaddnode)
|
|
public
|
|
function pass_1: tnode; override;
|
|
procedure force_reg_left_right(allow_swap, allow_constant: boolean); override;
|
|
protected
|
|
procedure second_cmpsmallset; override;
|
|
procedure second_cmpordinal; override;
|
|
procedure second_add64bit; override;
|
|
procedure second_cmp64bit; override;
|
|
procedure second_addfloat; override;
|
|
procedure second_cmpfloat; override;
|
|
end;
|
|
|
|
|
|
implementation
|
|
|
|
uses
|
|
verbose,globtype,
|
|
aasmdata,
|
|
symconst,symtype,symdef,defutil,
|
|
llvmbase,aasmllvm,
|
|
cgbase,cgutils,
|
|
hlcgobj,
|
|
nadd
|
|
;
|
|
|
|
{ tllvmaddnode }
|
|
|
|
function tllvmaddnode.pass_1: tnode;
|
|
begin
|
|
result:=inherited pass_1;
|
|
{ there are no flags in LLVM }
|
|
if expectloc=LOC_FLAGS then
|
|
expectloc:=LOC_REGISTER;
|
|
end;
|
|
|
|
|
|
procedure tllvmaddnode.force_reg_left_right(allow_swap, allow_constant: boolean);
|
|
begin
|
|
{ comparison with pointer -> no immediate, as icmp can't handle pointer
|
|
immediates (except for nil as "null", but we don't generate that) }
|
|
if (nodetype in [equaln,unequaln,gtn,gten,ltn,lten]) and
|
|
((left.nodetype in [pointerconstn,niln]) or
|
|
(right.nodetype in [pointerconstn,niln])) then
|
|
allow_constant:=false;
|
|
inherited;
|
|
{ pointer - pointer = integer -> make all defs pointer since we can't
|
|
subtract pointers }
|
|
if (nodetype=subn) and
|
|
(left.resultdef.typ=pointerdef) and
|
|
(right.resultdef.typ=pointerdef) then
|
|
begin
|
|
hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,resultdef,true);
|
|
hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,resultdef,true);
|
|
end
|
|
{ pointer +/- integer -> make defs the same since a_op_* only gets a
|
|
single type as argument }
|
|
else if (nodetype in [addn,subn]) and
|
|
((left.resultdef.typ=pointerdef)<>(right.resultdef.typ=pointerdef)) then
|
|
begin
|
|
{ the result is a pointerdef -> typecast both arguments to pointer;
|
|
a_op_*_reg will convert them back to integer as needed }
|
|
if left.resultdef.typ<>pointerdef then
|
|
hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,resultdef,true);
|
|
if right.resultdef.typ<>pointerdef then
|
|
hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,resultdef,true);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure tllvmaddnode.second_cmpsmallset;
|
|
var
|
|
tmpreg,
|
|
tmpreg2: tregister;
|
|
cmpop : topcmp;
|
|
begin
|
|
pass_left_right;
|
|
|
|
location_reset(location,LOC_REGISTER,OS_8);
|
|
location.register:=hlcg.getintregister(current_asmdata.CurrAsmList,llvmbool1type);
|
|
|
|
force_reg_left_right(false,false);
|
|
|
|
case nodetype of
|
|
equaln,
|
|
unequaln:
|
|
begin
|
|
if nodetype=equaln then
|
|
cmpop:=OC_EQ
|
|
else
|
|
cmpop:=OC_NE;
|
|
current_asmdata.CurrAsmList.concat(taillvm.op_reg_cond_size_reg_reg(la_icmp,
|
|
location.register,cmpop,left.resultdef,left.location.register,right.location.register));
|
|
end;
|
|
lten,
|
|
gten:
|
|
begin
|
|
if (not(nf_swapped in flags) and
|
|
(nodetype = lten)) or
|
|
((nf_swapped in flags) and
|
|
(nodetype = gten)) then
|
|
swapleftright;
|
|
{ set1<=set2 <-> set2 and not(set1) = 0 }
|
|
tmpreg:=hlcg.getintregister(current_asmdata.CurrAsmList,left.resultdef);
|
|
hlcg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_NOT,left.resultdef,left.location.register,tmpreg);
|
|
tmpreg2:=hlcg.getintregister(current_asmdata.CurrAsmList,left.resultdef);
|
|
hlcg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,OP_AND,left.resultdef,right.location.register,tmpreg,tmpreg2);
|
|
current_asmdata.CurrAsmList.concat(taillvm.op_reg_cond_size_reg_const(la_icmp,
|
|
location.register,OC_EQ,left.resultdef,tmpreg2,0));
|
|
end;
|
|
else
|
|
internalerror(2012042701);
|
|
end;
|
|
tmpreg:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
|
|
hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,llvmbool1type,resultdef,location.register,tmpreg);
|
|
location.register:=tmpreg;
|
|
end;
|
|
|
|
|
|
procedure tllvmaddnode.second_cmpordinal;
|
|
var
|
|
tmpreg: tregister;
|
|
cmpop: topcmp;
|
|
unsigned : boolean;
|
|
begin
|
|
pass_left_right;
|
|
force_reg_left_right(true,true);
|
|
|
|
unsigned:=not(is_signed(left.resultdef)) or
|
|
not(is_signed(right.resultdef));
|
|
|
|
case nodetype of
|
|
ltn:
|
|
if unsigned then
|
|
cmpop:=OC_B
|
|
else
|
|
cmpop:=OC_LT;
|
|
lten:
|
|
if unsigned then
|
|
cmpop:=OC_BE
|
|
else
|
|
cmpop:=OC_LTE;
|
|
gtn:
|
|
if unsigned then
|
|
cmpop:=OC_A
|
|
else
|
|
cmpop:=OC_GT;
|
|
gten:
|
|
if unsigned then
|
|
cmpop:=OC_AE
|
|
else
|
|
cmpop:=OC_GTE;
|
|
equaln:
|
|
cmpop:=OC_EQ;
|
|
unequaln:
|
|
cmpop:=OC_NE;
|
|
else
|
|
internalerror(2015031505);
|
|
end;
|
|
if nf_swapped in flags then
|
|
cmpop:=swap_opcmp(cmpop);
|
|
|
|
location_reset(location,LOC_REGISTER,OS_8);
|
|
location.register:=hlcg.getintregister(current_asmdata.CurrAsmList,llvmbool1type);
|
|
|
|
if right.location.loc=LOC_CONSTANT then
|
|
current_asmdata.CurrAsmList.concat(taillvm.op_reg_cond_size_reg_const(la_icmp,
|
|
location.register,cmpop,left.resultdef,left.location.register,right.location.value64))
|
|
else
|
|
current_asmdata.CurrAsmList.concat(taillvm.op_reg_cond_size_reg_reg(la_icmp,
|
|
location.register,cmpop,left.resultdef,left.location.register,right.location.register));
|
|
|
|
tmpreg:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
|
|
hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,llvmbool1type,resultdef,location.register,tmpreg);
|
|
location.register:=tmpreg;
|
|
end;
|
|
|
|
|
|
procedure tllvmaddnode.second_add64bit;
|
|
begin
|
|
second_addordinal;
|
|
end;
|
|
|
|
|
|
procedure tllvmaddnode.second_cmp64bit;
|
|
begin
|
|
second_cmpordinal;
|
|
end;
|
|
|
|
|
|
procedure tllvmaddnode.second_addfloat;
|
|
var
|
|
tmpreg: tregister;
|
|
op : tllvmop;
|
|
llvmfpcmp : tllvmfpcmp;
|
|
size : tdef;
|
|
cmpop,
|
|
singleprec : boolean;
|
|
begin
|
|
pass_left_right;
|
|
|
|
cmpop:=false;
|
|
singleprec:=tfloatdef(left.resultdef).floattype=s32real;
|
|
{ avoid uninitialised warning }
|
|
llvmfpcmp:=lfc_invalid;
|
|
case nodetype of
|
|
addn :
|
|
op:=la_fadd;
|
|
muln :
|
|
op:=la_fmul;
|
|
subn :
|
|
op:=la_fsub;
|
|
slashn :
|
|
op:=la_fdiv;
|
|
ltn,lten,gtn,gten,
|
|
equaln,unequaln :
|
|
begin
|
|
op:=la_fcmp;
|
|
cmpop:=true;
|
|
case nodetype of
|
|
ltn:
|
|
llvmfpcmp:=lfc_olt;
|
|
lten:
|
|
llvmfpcmp:=lfc_ole;
|
|
gtn:
|
|
llvmfpcmp:=lfc_ogt;
|
|
gten:
|
|
llvmfpcmp:=lfc_oge;
|
|
equaln:
|
|
llvmfpcmp:=lfc_oeq;
|
|
unequaln:
|
|
llvmfpcmp:=lfc_one;
|
|
else
|
|
internalerror(2015031506);
|
|
end;
|
|
end;
|
|
else
|
|
internalerror(2013102401);
|
|
end;
|
|
|
|
{ get the operands in the correct order; there are no special cases here,
|
|
everything is register-based }
|
|
if nf_swapped in flags then
|
|
swapleftright;
|
|
|
|
{ put both operands in a register }
|
|
hlcg.location_force_fpureg(current_asmdata.CurrAsmList,right.location,right.resultdef,true);
|
|
hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true);
|
|
|
|
{ initialize the result location }
|
|
if not cmpop then
|
|
begin
|
|
location_reset(location,LOC_FPUREGISTER,def_cgsize(resultdef));
|
|
location.register:=hlcg.getfpuregister(current_asmdata.CurrAsmList,resultdef);
|
|
end
|
|
else
|
|
begin
|
|
location_reset(location,LOC_REGISTER,OS_8);
|
|
location.register:=hlcg.getintregister(current_asmdata.CurrAsmList,llvmbool1type);
|
|
end;
|
|
|
|
{ see comment in thlcgllvm.a_loadfpu_ref_reg }
|
|
if tfloatdef(left.resultdef).floattype in [s64comp,s64currency] then
|
|
size:=sc80floattype
|
|
else
|
|
size:=left.resultdef;
|
|
|
|
{ emit the actual operation }
|
|
if not cmpop then
|
|
begin
|
|
current_asmdata.CurrAsmList.concat(taillvm.op_reg_size_reg_reg(op,location.register,size,
|
|
left.location.register,right.location.register))
|
|
end
|
|
else
|
|
begin
|
|
current_asmdata.CurrAsmList.concat(taillvm.op_reg_fpcond_size_reg_reg(op,
|
|
location.register,llvmfpcmp,size,left.location.register,right.location.register));
|
|
tmpreg:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
|
|
hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,llvmbool1type,resultdef,location.register,tmpreg);
|
|
location.register:=tmpreg;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure tllvmaddnode.second_cmpfloat;
|
|
begin
|
|
second_addfloat;
|
|
end;
|
|
|
|
|
|
begin
|
|
caddnode:=tllvmaddnode;
|
|
end.
|
|
|