fpc/compiler/llvm/aasmllvmmetadata.pas

509 lines
16 KiB
ObjectPascal

{
Copyright (c) 2019 by Jonas Maebe,
member of the Free Pascal Compiler development team
Support for LLVM metadata
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 aasmllvmmetadata;
{$i fpcdefs.inc}
interface
uses
globtype,cclasses,
cgbase,
aasmtai,aasmcnst,
symtype;
{$push}{$ScopedEnums on}
type
tspecialisedmetadatanodekind = (
DICompileUnit,
DIFile,
DIBasicType,
DISubroutineType,
DIDerivedType,
DICompositeType,
DISubrange,
DIEnumerator,
DITemplateTypeParameter,
DITemplateValueParameter,
DINamespace,
DIGlobalVariable,
DIGlobalVariableExpression,
DISubprogram,
DILexicalBlock,
DILexicalBlockFile,
DILocation,
DILocalVariable,
DIExpression,
DIObjCProperty,
DIImportedEntity,
DIMacro,
DIMacroFile
);
{$pop}
// represented by a tai_simpletypedconst() with inside a metadata struct,
// or as a metadata register (for parameters)
// tai_llvmmetadatastring = class
tai_llvmbasemetadatanode = class abstract(tai_aggregatetypedconst)
strict protected
function getname: ansistring; virtual; abstract;
public
procedure addvalue(val: tai_abstracttypedconst); override;
property name: ansistring read getname;
constructor create; reintroduce;
class function isspecialised: boolean; virtual;
end;
(* !0 = !{ type1 value1, ... } *)
tai_llvmunnamedmetadatanode = class(tai_llvmbasemetadatanode)
strict private
class function getnextid: cardinal;
strict protected
fnameval: cardinal;
public
constructor create; reintroduce;
function getname: ansistring; override;
end;
(* !name = !{ type1 value1, ... } *)
tai_llvmnamedmetadatanode = class(tai_llvmbasemetadatanode)
strict protected
fname: ansistring;
function getname: ansistring; override;
public
constructor create(const aName: ansistring);
end;
{ reference to a metadata node inside an expression, i.e., !X }
tai_llvmmetadatareftypedconst = class(tai_simple)
strict private
fval: tai_llvmbasemetadatanode;
public
constructor create(_val: tai_llvmbasemetadatanode);
property val: tai_llvmbasemetadatanode read fval;
end;
{ @g1 = global i32 0, *!id !value.name* }
tai_llvmmetadatareferenceoperand = class(tai_simple)
strict private
fid: ansistring;
fvalue: tai_llvmmetadatareftypedconst;
public
constructor createreferenceto(const anID: ansistring; aValue: tai_llvmbasemetadatanode);
destructor destroy; override;
property id: ansistring read fid;
property value: tai_llvmmetadatareftypedconst read fvalue;
end;
tllvmspecialmetaitemkind = (
lsmik_boolean,
lsmik_int64,
lsmik_qword,
lsmik_metadataref,
lsmik_string,
{ difference with string: not quoted }
lsmik_enum
);
tllvmspecialisedmetaitem = class(tai_simpletypedconst)
private
fitemkind: tllvmspecialmetaitemkind;
fitemname: TSymStr;
public
constructor createboolean(const aitemname: TSymStr; boolval: boolean);
constructor createint64(const aitemname: TSymStr; intval: int64);
constructor createqword(const aitemname: TSymStr; qwval: qword);
constructor createmetadataref(const aitemname: TSymStr; aival: tai_llvmmetadatareftypedconst);
constructor createstring(const aitemname: TSymStr; const stringval: TSymStr);
constructor createenum(const aitemname: TSymStr; const enumval: TSymStr);
property itemname: TSymStr read fitemname;
property itemkind: tllvmspecialmetaitemkind read fitemkind;
end;
{ !name = !kindname(field1: value1, ...) }
tai_llvmspecialisedmetadatanode = class(tai_llvmunnamedmetadatanode)
strict private
{ identifies name and fieldnames }
fkind: tspecialisedmetadatanodekind;
{ adds the item, appropriating its contents (so don't destroy the original
afterwards) }
procedure addemplaceitem(const item: tllvmspecialisedmetaitem);
public
constructor create(aKind: tspecialisedmetadatanodekind);
procedure addvalue(val: tai_abstracttypedconst); override; deprecated 'use addboolean/addinteger/addmetadataref/addstring/addenum';
procedure addboolean(const aitemname: TSymStr; boolval: boolean);
procedure addint64(const aitemname: TSymStr; intval: int64);
procedure addqword(const aitemname: TSymStr; qwval: qword);
procedure addmetadatarefto(const aitemname: TSymStr; aival: tai_llvmbasemetadatanode);
procedure addstring(const aitemname: TSymStr; const stringval: TSymStr);
procedure addenum(const aitemname: TSymStr; const enumval: TSymStr);
{ only allowed before adding any items; needed because when generating
debug info, we first generat everything as DIDerivedType (works for
typedefs and most other types, and switch it later when necessary).
Make it an explicit proc rather than a setter for kind to avoid
accidental usage }
procedure switchkind(newKind: tspecialisedmetadatanodekind);
property kind: tspecialisedmetadatanodekind read fkind;
function IsDistinct: boolean;
class function isspecialised: boolean; override;
end;
{$push}
{$scopedenums on}
{ not clear what the difference is between LineTablesOnly and DebugDirectivesOnly }
tllvmdebugemissionkind = (NoDebug, FullDebug, LineTablesOnly, DebugDirectivesOnly);
{$pop}
tllvmmetadata = class
strict private
class function addstring(const s: TSymstr): TSuperRegister;
class function regtostring(reg: TRegister): TSymStr;
public
class function getstringreg(const s: TSymstr): TRegister;
class function getpcharreg(p: pchar; len: longint): TRegister;
class function getregstring(reg: TRegister): TSymStr;
end;
function llvm_getmetadatareftypedconst(metadata: tai_llvmbasemetadatanode): tai_simpletypedconst;
function llvm_constrainedexceptmodestring: ansistring;
implementation
uses
verbose,globals,cutils,
fmodule,
symdef,
dbgdwarfconst,
aasmdata,aasmllvm;
function llvm_getmetadatareftypedconst(metadata: tai_llvmbasemetadatanode): tai_simpletypedconst;
begin
if assigned(metadata) then
result:=tai_simpletypedconst.create(llvm_metadatatype, tai_llvmmetadatareftypedconst.create(metadata))
else
result:=nil
end;
function llvm_constrainedexceptmodestring: ansistring;
begin
if not(cs_opt_fastmath in current_settings.optimizerswitches) then
result:='fpexcept.maytrap'
else
result:='fpexcept.ignore'
end;
/////////////////////////////////////////////////
procedure tai_llvmbasemetadatanode.addvalue(val: tai_abstracttypedconst);
begin
{ bypass string merging attempts, as we add tai_strings directly here }
fvalues.add(val);
end;
constructor tai_llvmbasemetadatanode.create;
begin
inherited create(tck_array, llvm_metadatatype);
typ:=ait_llvmmetadatanode;
end;
class function tai_llvmbasemetadatanode.isspecialised: boolean;
begin
result:=false;
end;
class function tai_llvmunnamedmetadatanode.getnextid: cardinal;
begin
result:=tllvmasmdata(current_asmdata).fnextmetaid;
inc(tllvmasmdata(current_asmdata).fnextmetaid);
end;
function tai_llvmunnamedmetadatanode.getname: ansistring;
begin
str(fnameval,result);
end;
constructor tai_llvmunnamedmetadatanode.create;
begin
inherited;
fnameval:=getnextid;
end;
function tai_llvmnamedmetadatanode.getname: ansistring;
begin
result:=fname;
end;
constructor tai_llvmnamedmetadatanode.create(const aName: ansistring);
begin
inherited create;
fname:=aName;
end;
constructor tai_llvmmetadatareftypedconst.create(_val: tai_llvmbasemetadatanode);
begin
inherited create(ait_llvmmetadatareftypedconst);
fval:=_val;
end;
constructor tai_llvmmetadatareferenceoperand.createreferenceto(const anID: ansistring; aValue: tai_llvmbasemetadatanode);
begin
inherited create(ait_llvmmetadatarefoperand);
fid:=anID;
fvalue:=tai_llvmmetadatareftypedconst.create(aValue);
end;
destructor tai_llvmmetadatareferenceoperand.destroy;
begin
fvalue.free;
inherited;
end;
/////////////////////////////////////////////////
constructor tllvmspecialisedmetaitem.createboolean(const aitemname: TSymStr; boolval: boolean);
begin
fitemname:=aitemname;
fitemkind:=lsmik_boolean;
inherited create(llvmbool1type,tai_const.Create_8bit(ord(boolval)));
end;
constructor tllvmspecialisedmetaitem.createint64(const aitemname: TSymStr; intval: int64);
begin
fitemname:=aitemname;
fitemkind:=lsmik_int64;
inherited create(llvmbool1type,tai_const.Create_64bit(intval));
end;
constructor tllvmspecialisedmetaitem.createqword(const aitemname: TSymStr; qwval: qword);
begin
fitemname:=aitemname;
fitemkind:=lsmik_qword;
inherited create(llvmbool1type,tai_const.Create_64bit(int64(qwval)));
end;
constructor tllvmspecialisedmetaitem.createmetadataref(const aitemname: TSymStr; aival: tai_llvmmetadatareftypedconst);
begin
fitemname:=aitemname;
fitemkind:=lsmik_metadataref;
inherited create(llvm_metadatatype,aival);
end;
constructor tllvmspecialisedmetaitem.createstring(const aitemname: TSymStr; const stringval: TSymStr);
begin
fitemname:=aitemname;
fitemkind:=lsmik_string;
inherited create(charpointertype,tai_string.Create(stringval));
end;
constructor tllvmspecialisedmetaitem.createenum(const aitemname: TSymStr; const enumval: TSymStr);
begin
fitemname:=aitemname;
fitemkind:=lsmik_enum;
inherited create(charpointertype,tai_string.Create(enumval));
end;
constructor tai_llvmspecialisedmetadatanode.create(aKind: tspecialisedmetadatanodekind);
begin
inherited create;
fkind:=aKind;
end;
procedure tai_llvmspecialisedmetadatanode.addemplaceitem(const item: tllvmspecialisedmetaitem);
begin
inherited addvalue(item);
end;
procedure tai_llvmspecialisedmetadatanode.switchkind(newKind: tspecialisedmetadatanodekind);
begin
if fvalues.Count<>0 then
internalerror(2022110611);
fkind:=newKind;
end;
procedure tai_llvmspecialisedmetadatanode.addvalue(val: tai_abstracttypedconst);
begin
internalerror(2021121601);
end;
procedure tai_llvmspecialisedmetadatanode.addboolean(const aitemname: TSymStr; boolval: boolean);
var
item: tllvmspecialisedmetaitem;
begin
item:=tllvmspecialisedmetaitem.createboolean(aitemname, boolval);
addemplaceitem(item);
end;
procedure tai_llvmspecialisedmetadatanode.addint64(const aitemname: TSymStr; intval: int64);
var
item: tllvmspecialisedmetaitem;
begin
item:=tllvmspecialisedmetaitem.createint64(aitemname, intval);
addemplaceitem(item);
end;
procedure tai_llvmspecialisedmetadatanode.addqword(const aitemname: TSymStr; qwval: qword);
var
item: tllvmspecialisedmetaitem;
begin
item:=tllvmspecialisedmetaitem.createqword(aitemname, qwval);
addemplaceitem(item);
end;
procedure tai_llvmspecialisedmetadatanode.addmetadatarefto(const aitemname: TSymStr; aival: tai_llvmbasemetadatanode);
var
item: tllvmspecialisedmetaitem;
begin
if assigned(aival) then
item:=tllvmspecialisedmetaitem.createmetadataref(aitemname, tai_llvmmetadatareftypedconst.create(aival))
else
item:=tllvmspecialisedmetaitem.createmetadataref(aitemname, nil);
addemplaceitem(item);
end;
procedure tai_llvmspecialisedmetadatanode.addstring(const aitemname: TSymStr; const stringval: TSymStr);
var
item: tllvmspecialisedmetaitem;
begin
item:=tllvmspecialisedmetaitem.createstring(aitemname, stringval);
addemplaceitem(item);
end;
procedure tai_llvmspecialisedmetadatanode.addenum(const aitemname: TSymStr; const enumval: TSymStr);
var
item: tllvmspecialisedmetaitem;
begin
item:=tllvmspecialisedmetaitem.createenum(aitemname, enumval);
addemplaceitem(item);
end;
function tai_llvmspecialisedmetadatanode.IsDistinct: boolean;
begin
case fkind of
tspecialisedmetadatanodekind.DICompileUnit,
tspecialisedmetadatanodekind.DISubprogram,
tspecialisedmetadatanodekind.DIGlobalVariable,
tspecialisedmetadatanodekind.DICompositeType,
tspecialisedmetadatanodekind.DILexicalBlock,
tspecialisedmetadatanodekind.DIMacro:
result:=true;
tspecialisedmetadatanodekind.DIFile,
tspecialisedmetadatanodekind.DIBasicType,
tspecialisedmetadatanodekind.DIDerivedType,
tspecialisedmetadatanodekind.DISubrange,
tspecialisedmetadatanodekind.DIEnumerator,
tspecialisedmetadatanodekind.DITemplateTypeParameter,
tspecialisedmetadatanodekind.DITemplateValueParameter,
tspecialisedmetadatanodekind.DINamespace,
tspecialisedmetadatanodekind.DIGlobalVariableExpression,
tspecialisedmetadatanodekind.DILexicalBlockFile,
tspecialisedmetadatanodekind.DILocation,
tspecialisedmetadatanodekind.DILocalVariable,
tspecialisedmetadatanodekind.DIExpression,
tspecialisedmetadatanodekind.DIObjCProperty,
tspecialisedmetadatanodekind.DIImportedEntity,
tspecialisedmetadatanodekind.DISubroutineType,
tspecialisedmetadatanodekind.DIMacroFile:
result:=false;
end;
end;
class function tai_llvmspecialisedmetadatanode.isspecialised: boolean;
begin
result:=true;
end;
/////////////////////////////////////////////////
class function tllvmmetadata.addstring(const s: TSymStr): TSuperRegister;
var
index: longint;
begin
index:=current_module.llvmmetadatastrings.Add(s,nil);
if index>high(result) then
internalerror(2019122806);
result:=index;
end;
class function tllvmmetadata.regtostring(reg: TRegister): TSymStr;
begin
if getregtype(reg)<>R_METADATAREGISTER then
internalerror(2019122807);
if getsubreg(reg)<>R_SUBMETASTRING then
internalerror(2019122808);
result:=current_module.llvmmetadatastrings.NameOfIndex(getsupreg(reg));
end;
class function tllvmmetadata.getstringreg(const s: TSymstr): TRegister;
var
supreg: TSuperRegister;
index: longint;
begin
index:=current_module.llvmmetadatastrings.FindIndexOf(s);
if index<>-1 then
supreg:=index
else
supreg:=addstring(s);
result:=newreg(R_METADATAREGISTER,supreg,R_SUBMETASTRING);
end;
class function tllvmmetadata.getpcharreg(p: pchar; len: longint): TRegister;
var
str: TSymStr;
begin
if len>0 then
begin
setlength(str,len);
move(p[0],str[1],len);
result:=getstringreg(str);
end
else
result:=getstringreg('');
end;
class function tllvmmetadata.getregstring(reg: TRegister): TSymStr;
begin
result:=regtostring(reg);
end;
end.