123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422 |
- {
- Copyright (c) 2013 by Jonas Maebe
- This unit implements some LLVM type helper routines.
- 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.
- ****************************************************************************
- }
- {$i fpcdefs.inc}
- unit llvmdef;
- interface
- uses
- globtype,
- symbase,symtype,symdef;
- { Encode a type into the internal format used by LLVM. }
- function llvmencodetype(def: tdef): TSymStr;
- { incremental version of llvmencodetype(). "inaggregate" indicates whether
- this was a recursive call to get the type of an entity part of an
- aggregate type (array, record, ...) }
- procedure llvmaddencodedtype(def: tdef; inaggregate: boolean; var encodedstr: TSymStr);
- function llvmencodeproctype(def: tabstractprocdef; withprocname, withparanames: boolean): TSymStr;
- procedure llvmaddencodedproctype(def: tabstractprocdef; withprocname, withparanames: boolean; var encodedstr: TSymStr);
- implementation
- uses
- cutils,cclasses,constexp,
- verbose,systems,
- fmodule,
- symtable,symconst,symsym,
- llvmsym,
- defutil,cgbase,parabase,paramgr;
- {******************************************************************
- Type encoding
- *******************************************************************}
- procedure llvmaddencodedtype(def: tdef; inaggregate: boolean; var encodedstr: TSymStr);
- begin
- case def.typ of
- stringdef :
- begin
- case tstringdef(def).stringtype of
- st_widestring,
- st_unicodestring:
- { the variable does not point to the header, but to a
- null-terminated string/array with undefined bounds }
- encodedstr:=encodedstr+'[0 x i16]';
- st_ansistring:
- encodedstr:=encodedstr+'[0 x i8]';
- st_shortstring:
- { length byte followed by string bytes }
- if tstringdef(def).len>0 then
- encodedstr:=encodedstr+'{i8, ['+tostr(tstringdef(def).len)+' x i8]}'
- else
- encodedstr:=encodedstr+'{i8, [0 x i8]}';
- else
- internalerror(2013100201);
- end;
- end;
- enumdef:
- begin
- encodedstr:=encodedstr+'i'+tostr(def.size*8);
- end;
- orddef :
- begin
- if is_void(def) then
- encodedstr:=encodedstr+'void'
- { mainly required because comparison operations return i1, and
- otherwise we always have to immediatel extend them to i8 for
- no good reason; besides, Pascal booleans can only contain 0
- or 1 in valid code anyway (famous last words...) }
- else if torddef(def).ordtype=pasbool8 then
- encodedstr:=encodedstr+'i1'
- else
- encodedstr:=encodedstr+'i'+tostr(def.size*8);
- end;
- pointerdef :
- begin
- if is_voidpointer(def) then
- encodedstr:=encodedstr+'i8*'
- else
- begin
- llvmaddencodedtype(tpointerdef(def).pointeddef,false,encodedstr);
- encodedstr:=encodedstr+'*';
- end;
- end;
- floatdef :
- begin
- case tfloatdef(def).floattype of
- s32real:
- encodedstr:=encodedstr+'float';
- s64real:
- encodedstr:=encodedstr+'double';
- { necessary to be able to force our own size/alignment }
- s80real:
- { prevent llvm from allocating the standard ABI size for
- extended }
- if inaggregate then
- encodedstr:=encodedstr+'[10 x i8]'
- else
- encodedstr:=encodedstr+'x86_fp80';
- sc80real:
- encodedstr:=encodedstr+'x86_fp80';
- s64comp,
- s64currency:
- encodedstr:=encodedstr+'i64';
- s128real:
- {$if defined(powerpc) or defined(powerpc128)}
- encodedstr:=encodedstr+'ppc_fp128';
- {$else}
- encodedstr:=encodedstr+'fp128';
- {$endif}
- else
- internalerror(2013100202);
- end;
- end;
- filedef :
- begin
- case tfiledef(def).filetyp of
- ft_text :
- llvmaddencodedtype(search_system_type('TEXTREC').typedef,false,encodedstr);
- ft_typed,
- ft_untyped :
- llvmaddencodedtype(search_system_type('FILEREC').typedef,false,encodedstr);
- else
- internalerror(2013100203);
- end;
- end;
- recorddef :
- begin
- { for now don't encode the individual fields, because handling
- variant records is a pain. As far as correctness is concerned,
- the types of the fields only matter for the parameters and
- function result types, but for those we have to use what the
- parameter manager calculates anyway (because e.g. a record
- with two floats has to be passed in an SSE register on x86-64) }
- encodedstr:=encodedstr+'{[i8 x '+tostr(def.size)+']}'
- end;
- variantdef :
- begin
- llvmaddencodedtype(search_system_type('TVARDATA').typedef,false,encodedstr);
- end;
- classrefdef :
- begin
- { todo: define proper type for VMT and use that }
- encodedstr:=encodedstr+'i8*';
- end;
- setdef :
- begin
- { just an array as far as llvm is concerned; don't use a "packed
- array of i1" or so, this requires special support in backends
- and guarantees nothing about the internal format }
- encodedstr:=encodedstr+'['+tostr(tsetdef(def).size)+' x i8]';
- end;
- formaldef :
- begin
- { var/const/out x }
- encodedstr:=encodedstr+'i8*';
- end;
- arraydef :
- begin
- if is_array_of_const(def) then
- begin
- encodedstr:=encodedstr+'[0 x ';
- llvmaddencodedtype(search_system_type('TVARREC').typedef,true,encodedstr);
- encodedstr:=encodedstr+']';
- end
- else if is_open_array(def) then
- begin
- encodedstr:=encodedstr+'[0 x ';
- llvmaddencodedtype(tarraydef(def).elementdef,true,encodedstr);
- encodedstr:=encodedstr+']';
- end
- else if is_dynamic_array(def) then
- begin
- llvmaddencodedtype(tarraydef(def).elementdef,false,encodedstr);
- encodedstr:=encodedstr+'*';
- end
- else if is_packed_array(def) then
- begin
- encodedstr:=encodedstr+'['+tostr(tarraydef(def).size div tarraydef(def).elementdef.packedbitsize)+' x ';
- { encode as an array of integers with the size on which we
- perform the packedbits operations }
- llvmaddencodedtype(cgsize_orddef(int_cgsize(packedbitsloadsize(tarraydef(def).elementdef.packedbitsize))),true,encodedstr);
- encodedstr:=encodedstr+']';
- end
- else
- begin
- encodedstr:=encodedstr+'['+tostr(tarraydef(def).elecount)+' x ';
- llvmaddencodedtype(tarraydef(def).elementdef,true,encodedstr);
- encodedstr:=encodedstr+']';
- end;
- end;
- procvardef :
- begin
- if tprocvardef(def).is_addressonly then
- begin
- llvmaddencodedproctype(tprocdef(def),false,false,encodedstr);
- encodedstr:=encodedstr+'*';
- end
- else
- begin
- encodedstr:=encodedstr+'{';
- { code pointer }
- llvmaddencodedproctype(tprocvardef(def),false,false,encodedstr);
- { data pointer (maybe todo: generate actual layout if
- available) }
- encodedstr:=encodedstr+'*, i8*}';
- end;
- end;
- objectdef :
- case tobjectdef(def).objecttype of
- odt_class,
- odt_objcclass,
- odt_object,
- odt_cppclass:
- begin
- { for now don't handle fields yet }
- encodedstr:=encodedstr+'{[i8 x '+tostr(def.size)+']}';
- if is_implicit_pointer_object_type(def) then
- encodedstr:=encodedstr+'*'
- end;
- odt_interfacecom,
- odt_interfacecom_function,
- odt_interfacecom_property,
- odt_interfacecorba,
- odt_dispinterface,
- odt_objcprotocol:
- begin
- { opaque for now }
- encodedstr:=encodedstr+'i8*'
- end;
- else
- internalerror(2013100601);
- end;
- undefineddef,
- errordef :
- internalerror(2013100604);
- procdef :
- begin
- llvmaddencodedproctype(tprocdef(def),true,false,encodedstr);
- end;
- else
- internalerror(2013100603);
- end;
- end;
- procedure llvmrefineordinaldef(paradef, paralocdef: tdef; out usedef: tdef; out signextstr: TSymStr);
- begin
- { implicit zero/sign extension for ABI compliance? (yes, if the size
- of a paraloc is larger than the size of the entire parameter) }
- if is_ordinal(paradef) and
- is_ordinal(paralocdef) and
- (paradef.size<paralocdef.size) then
- begin
- usedef:=paradef;
- if is_signed(paradef) then
- signextstr:='signext '
- else
- signextstr:='zeroext '
- end
- else
- begin
- usedef:=paralocdef;
- signextstr:='';
- end;
- end;
- procedure llvmaddencodedparaloctype(hp: tparavarsym; const para: tcgpara; proccalloption: tproccalloption; withparaname: boolean; var first: boolean; var encodedstr: TSymStr);
- { the default for llvm is to pass aggregates in integer registers or
- on the stack (as the ABI prescribes). Records that require special
- handling, e.g. (partly) passing in fpu registers, have to be handled
- explicitly. This function returns whether an aggregate is handled
- specially }
- function hasnondefaultparaloc: boolean;
- var
- loc: PCGParaLocation;
- begin
- loc:=para.Location;
- result:=true;
- while assigned(loc) do
- begin
- if not(loc^.loc in [LOC_REGISTER,LOC_REFERENCE]) then
- exit;
- end;
- result:=false;
- end;
- var
- paraloc: PCGParaLocation;
- signextstr: TSymStr;
- usedef: tdef;
- closestruct: boolean;
- begin
- { byval: a pointer to a type that should actually be passed by
- value (e.g. a record that should be passed on the stack) }
- if assigned(hp) and
- (hp.vardef.typ in [arraydef,recorddef,objectdef]) and
- not paramanager.push_addr_param(hp.varspez,hp.vardef,proccalloption) and
- not hasnondefaultparaloc then
- begin
- llvmaddencodedtype(hp.vardef,false,encodedstr);
- encodedstr:=encodedstr+'* byval';
- if withparaname then
- encodedstr:=encodedstr+' '+para.location^.llvmloc.name;
- exit;
- end;
- closestruct:=false;
- paraloc:=para.location;
- if not assigned(hp) then
- begin
- { if a function returns a composite value (e.g. 2 sse register),
- those are represented as a struct }
- if assigned(paraloc^.next) then
- begin
- encodedstr:=encodedstr+'{';
- closestruct:=true;
- end;
- end;
- repeat
- usedef:=paraloc^.def;
- llvmrefineordinaldef(para.def,paraloc^.def,usedef,signextstr);
- { implicit zero/sign extension for ABI compliance? }
- if not assigned(hp) then
- encodedstr:=encodedstr+signextstr;
- if not first then
- encodedstr:=encodedstr+', '
- else
- first:=false;
- llvmaddencodedtype(usedef,false,encodedstr);
- { in case signextstr<>'', there should be only one paraloc -> no need
- to clear (reason: it means that the paraloc is larger than the
- original parameter) }
- if assigned(hp) then
- encodedstr:=encodedstr+signextstr;
- if assigned(hp) then
- begin
- { sret: hidden pointer for structured function result }
- if vo_is_funcret in hp.varoptions then
- encodedstr:=encodedstr+' sret'
- end;
- if withparaname then
- encodedstr:=encodedstr+' '+paraloc^.llvmloc.name;
- paraloc:=paraloc^.next;
- until not assigned(paraloc);
- if closestruct then
- encodedstr:=encodedstr+'}'
- end;
- function llvmencodeproctype(def: tabstractprocdef; withprocname, withparanames: boolean): TSymStr;
- begin
- result:='';
- llvmaddencodedproctype(def,withprocname,withparanames,result);
- end;
- procedure llvmaddencodedproctype(def: tabstractprocdef; withprocname, withparanames: boolean; var encodedstr: TSymStr);
- var
- paranr: longint;
- para: tcgpara;
- hp: tparavarsym;
- first: boolean;
- begin
- def.init_paraloc_info(calleeside);
- first:=true;
- { function result (return-by-ref is handled explicitly) }
- if not paramanager.ret_in_param(def.returndef,def) then
- llvmaddencodedparaloctype(nil,def.funcretloc[calleeside],def.proccalloption,false,first,encodedstr)
- else
- llvmaddencodedtype(voidtype,false,encodedstr);
- encodedstr:=encodedstr+' ';
- if withprocname and
- (def.typ=procdef) then
- encodedstr:=encodedstr+tprocdef(def).mangledname;
- encodedstr:=encodedstr+'(';
- { parameters }
- first:=true;
- for paranr:=0 to def.paras.count-1 do
- begin
- hp:=tparavarsym(def.paras[paranr]);
- llvmaddencodedparaloctype(hp,hp.paraloc[calleeside],def.proccalloption,withparanames,first,encodedstr);
- end;
- encodedstr:=encodedstr+')'
- end;
- function llvmencodetype(def: tdef): TSymStr;
- begin
- result:='';
- llvmaddencodedtype(def,false,result);
- end;
- end.
|