{ 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.