mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-05-02 06:33:39 +02:00

o they are implemented as a new metadata register class, whereby the subregister indicates the metadata type (currently always a string) and the superregister is an index in the metadata array (which contains the strings). LLVM metadata can only be passed as parameters to intrinsics in bitcode, so moves of metadata into other registers triggers internal errors and when moving them into parameters, we replace the parameter's register with the metadata register (and look up the corresponding string when writing out the bitcode) git-svn-id: trunk@43816 -
222 lines
8.5 KiB
ObjectPascal
222 lines
8.5 KiB
ObjectPascal
{
|
|
Copyright (c) 2013 by Jonas Maebe, member of the Free Pascal Compiler
|
|
development team
|
|
|
|
Generate llvm bitcode for constants
|
|
|
|
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 nllvmcon;
|
|
|
|
{$i fpcdefs.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
symtype,
|
|
node,ncgcon;
|
|
|
|
type
|
|
tllvmrealconstnode = class(tcgrealconstnode)
|
|
function pass_1 : tnode;override;
|
|
procedure pass_generate_code;override;
|
|
end;
|
|
|
|
tllvmstringconstnode = class(tcgstringconstnode)
|
|
constructor createpchar(s: pchar; l: longint; def: tdef); override;
|
|
function pass_typecheck: tnode; override;
|
|
function pass_1: tnode; override;
|
|
procedure pass_generate_code; override;
|
|
protected
|
|
procedure load_dynstring(const strpointerdef: tdef; const elementdef: tdef; const winlikewidestring: boolean); override;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
globtype,globals,verbose,cutils,
|
|
symbase,symtable,symconst,symdef,symsym,defutil,
|
|
aasmbase,aasmdata,aasmcnst,
|
|
ncon,
|
|
llvmbase,aasmllvm,aasmllvmmetadata,hlcgobj,
|
|
cgbase,cgutils,
|
|
cpubase;
|
|
|
|
{*****************************************************************************
|
|
tllvmstringconstnode
|
|
*****************************************************************************}
|
|
|
|
constructor tllvmstringconstnode.createpchar(s: pchar; l: longint; def: tdef);
|
|
begin
|
|
inherited;
|
|
if def=llvm_metadatatype then
|
|
begin
|
|
{ astringdef is only used if the constant type is ansitring }
|
|
cst_type:=cst_ansistring;
|
|
astringdef:=def;
|
|
end;
|
|
end;
|
|
|
|
|
|
function tllvmstringconstnode.pass_typecheck: tnode;
|
|
begin
|
|
if astringdef<>llvm_metadatatype then
|
|
begin
|
|
result:=inherited;
|
|
exit;
|
|
end;
|
|
resultdef:=llvm_metadatatype;
|
|
result:=nil;
|
|
end;
|
|
|
|
|
|
function tllvmstringconstnode.pass_1: tnode;
|
|
begin
|
|
if astringdef<>llvm_metadatatype then
|
|
begin
|
|
result:=inherited;
|
|
exit;
|
|
end;
|
|
expectloc:=LOC_CREGISTER;
|
|
result:=nil;
|
|
end;
|
|
|
|
|
|
procedure tllvmstringconstnode.pass_generate_code;
|
|
var
|
|
datadef, resptrdef: tdef;
|
|
hreg: tregister;
|
|
begin
|
|
if astringdef=llvm_metadatatype then
|
|
begin
|
|
location_reset(location,LOC_CREGISTER,OS_ADDR);
|
|
location.register:=tllvmmetadata.getpcharreg(value_str,len);
|
|
exit;
|
|
end;
|
|
inherited pass_generate_code;
|
|
if cst_type in [cst_conststring,cst_shortstring] then
|
|
begin
|
|
if location.loc<>LOC_CREFERENCE then
|
|
internalerror(2014071202);
|
|
case cst_type of
|
|
cst_conststring:
|
|
{ this kind of string const is used both for array of char
|
|
constants (-> excludes terminating #0) and pchars (-> includes
|
|
terminating #0). The resultdef excludes the #0 while the data
|
|
includes it -> insert typecast from datadef to resultdef }
|
|
datadef:=carraydef.getreusable(cansichartype,len+1);
|
|
cst_shortstring:
|
|
{ the resultdef of the string constant is the type of the
|
|
string to which it is assigned, which can be longer or shorter
|
|
than the length of the string itself -> typecast it to the
|
|
correct string type }
|
|
datadef:=carraydef.getreusable(cansichartype,min(len,255)+1);
|
|
else
|
|
internalerror(2014071203);
|
|
end;
|
|
{ get address of array as pchar }
|
|
resptrdef:=cpointerdef.getreusable(resultdef);
|
|
hreg:=hlcg.getaddressregister(current_asmdata.CurrAsmList,resptrdef);
|
|
hlcg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,datadef,resptrdef,location.reference,hreg);
|
|
hlcg.reference_reset_base(location.reference,resptrdef,hreg,0,location.reference.temppos,location.reference.alignment,location.reference.volatility);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure tllvmstringconstnode.load_dynstring(const strpointerdef: tdef; const elementdef: tdef; const winlikewidestring: boolean);
|
|
var
|
|
stringtype: tstringtype;
|
|
strrecdef: trecorddef;
|
|
offset: pint;
|
|
field: tfieldvarsym;
|
|
llvmfield: tllvmshadowsymtableentry;
|
|
dataptrdef: tdef;
|
|
reg: tregister;
|
|
href: treference;
|
|
begin
|
|
case cst_type of
|
|
cst_ansistring:
|
|
stringtype:=st_ansistring;
|
|
cst_unicodestring:
|
|
stringtype:=st_unicodestring;
|
|
cst_widestring:
|
|
stringtype:=st_widestring;
|
|
else
|
|
internalerror(2014040804);
|
|
end;
|
|
{ get the recorddef for this string constant }
|
|
strrecdef:=ctai_typedconstbuilder.get_dynstring_rec(stringtype,winlikewidestring,len);
|
|
{ offset in the record of the the string data }
|
|
offset:=ctai_typedconstbuilder.get_string_symofs(stringtype,winlikewidestring);
|
|
{ field corresponding to this offset }
|
|
field:=trecordsymtable(strrecdef.symtable).findfieldbyoffset(offset);
|
|
llvmfield:=trecordsymtable(strrecdef.symtable).llvmst[field];
|
|
if llvmfield.fieldoffset<>field.fieldoffset then
|
|
internalerror(2015061001);
|
|
{ pointerdef to the string data array }
|
|
dataptrdef:=cpointerdef.getreusable(field.vardef);
|
|
{ load the address of the string data }
|
|
reg:=hlcg.getaddressregister(current_asmdata.CurrAsmList,dataptrdef);
|
|
reference_reset_symbol(href,lab_str,0,const_align(strpointerdef.size),[]);
|
|
current_asmdata.CurrAsmList.concat(
|
|
taillvm.getelementptr_reg_size_ref_size_const(reg,cpointerdef.getreusable(strrecdef),href,
|
|
s32inttype,field.llvmfieldnr,true));
|
|
{ convert into a pointer to the individual elements }
|
|
hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,dataptrdef,strpointerdef,reg,location.register);
|
|
end;
|
|
|
|
{*****************************************************************************
|
|
tllvmrealconstnode
|
|
*****************************************************************************}
|
|
|
|
function tllvmrealconstnode.pass_1 : tnode;
|
|
begin
|
|
result:=nil;
|
|
expectloc:=LOC_FPUREGISTER;
|
|
end;
|
|
|
|
|
|
procedure tllvmrealconstnode.pass_generate_code;
|
|
begin
|
|
{ llvm supports floating point constants directly }
|
|
location_reset(location,LOC_FPUREGISTER,def_cgsize(resultdef));
|
|
location.register:=hlcg.getfpuregister(current_asmdata.CurrAsmList,resultdef);
|
|
case tfloatdef(resultdef).floattype of
|
|
s32real,s64real:
|
|
current_asmdata.CurrAsmList.concat(taillvm.op_reg_size_fpconst_size(la_bitcast,location.register,resultdef,value_real,resultdef));
|
|
{ comp and currency are handled as int64 at the llvm level }
|
|
s64comp:
|
|
{ sc80floattype instead of resultdef, see comment in thlcgllvm.a_loadfpu_ref_reg }
|
|
current_asmdata.CurrAsmList.concat(taillvm.op_reg_size_const_size(la_sitofp,location.register,s64inttype,trunc(value_real),sc80floattype));
|
|
s64currency:
|
|
{ sc80floattype instead of resultdef, see comment in thlcgllvm.a_loadfpu_ref_reg }
|
|
current_asmdata.CurrAsmList.concat(taillvm.op_reg_size_const_size(la_sitofp,location.register,s64inttype,round(value_real),sc80floattype));
|
|
{$ifdef cpuextended}
|
|
s80real,sc80real:
|
|
current_asmdata.CurrAsmList.concat(taillvm.op_reg_size_fpconst80_size(la_bitcast,location.register,resultdef,value_real,resultdef));
|
|
{$endif cpuextended}
|
|
else
|
|
internalerror(2013102501);
|
|
end;
|
|
end;
|
|
|
|
|
|
begin
|
|
cstringconstnode:=tllvmstringconstnode;
|
|
crealconstnode:=tllvmrealconstnode;
|
|
end.
|