mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-05 11:38:19 +02:00
509 lines
16 KiB
ObjectPascal
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.
|
|
|