fpc/compiler/llvm/aasmllvmmetadata.pas
Jonas Maebe e865ab4c3a llvmdbg: handle nil in more places
"void" is represented as "null" in LLVM debug information, which we represent
by nil
2022-05-21 22:32:35 +02:00

498 lines
15 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;
tllvmspecialisedmetaitems = array of tllvmspecialisedmetaitem;
{ !name = !kindname(field1: value1, ...) }
tai_llvmspecialisedmetadatanode = class(tai_llvmunnamedmetadatanode)
strict private
{ identifies name and fieldnames }
fkind: tspecialisedmetadatanodekind;
fnritems: longint;
{ 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);
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.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.