{ Copyright (c) 2014 by Jonas Maebe Generate LLVM bytecode for call 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 nllvmcal; {$i fpcdefs.inc} interface uses parabase, ncal,ncgcal, cgutils; type tllvmcallparanode = class(tcgcallparanode) procedure push_formal_para; override; end; tllvmcallnode = class(tcgcallnode) protected function paraneedsinlinetemp(para: tcallparanode; const pushconstaddr, complexpara: boolean): boolean; override; function can_call_ref(var ref: treference): boolean; override; procedure pushparas; override; procedure pass_generate_code; override; end; implementation uses verbose, aasmbase,aasmdata,aasmllvm, symconst,symdef; procedure tllvmcallparanode.push_formal_para; begin if parasym.vardef<>llvm_metadatatype then begin; inherited; exit; end; push_value_para; end; {***************************************************************************** TLLVMCALLNODE *****************************************************************************} function tllvmcallnode.paraneedsinlinetemp(para: tcallparanode; const pushconstaddr, complexpara: boolean): boolean; begin { We don't insert type conversions for self node trees to the type of the self parameter (and doing so is quite hard due to all kinds of ugly hacks with this parameter). This means that if we pass on a self parameter through multiple levels of inlining, it may no longer match the actual type of the parameter it has been passed to -> always store in a temp which by definition will have the right type (if it's a pointer-like type) } if (vo_is_self in para.parasym.varoptions) and (is_class_or_interface_or_dispinterface(para.parasym.vardef) or is_classhelper(para.parasym.vardef) or ((para.parasym.vardef.typ=classrefdef) and is_class(tclassrefdef(para.parasym.vardef).pointeddef))) then result:=true else result:=inherited; end; function tllvmcallnode.can_call_ref(var ref: treference): boolean; begin result:=false; end; procedure tllvmcallnode.pushparas; var n: tcgcallparanode; paraindex: longint; begin { we just pass the temp paralocs here } if not assigned(varargsparas) then setlength(paralocs,procdefinition.paras.count) else setlength(paralocs,procdefinition.paras.count+varargsparas.count); n:=tcgcallparanode(left); while assigned(n) do begin { TODO: check whether this is correct for left-to-right calling conventions, may also depend on whether or not llvm knows about the calling convention } if not(cpf_varargs_para in n.callparaflags) then paraindex:=procdefinition.paras.indexof(n.parasym) else paraindex:=procdefinition.paras.count+varargsparas.indexof(n.parasym); if paraindex=-1 then internalerror(2014010602); paralocs[paraindex]:=@n.tempcgpara; n:=tcgcallparanode(n.right); end; end; procedure tllvmcallnode.pass_generate_code; var asmsym: tasmsymbol; begin inherited; if assigned(overrideprocnamedef) and not overrideprocnamedef.in_currentunit then begin { insert an llvm declaration for this def if it's not defined in the current unit, because otherwise we will define it in the LLVM IR using the def for which this procdef's name is used first, which may be something completely different from the original def. LLVM can take the original def into account to load certain registers, so if we use a wrong def this can result in wrong code generation. } asmsym:=current_asmdata.RefAsmSymbol(overrideprocnamedef.mangledname,AT_FUNCTION); if not asmsym.declared then begin current_asmdata.AsmLists[al_imports].Concat(taillvmdecl.createdecl(asmsym,symtableprocentry,overrideprocnamedef,nil,sec_code,overrideprocnamedef.alignment)); end; end; end; begin ccallparanode:=tllvmcallparanode; ccallnode:=tllvmcallnode; end.