fpc/compiler/llvm/agllvm.pas

1818 lines
62 KiB
ObjectPascal

{
Copyright (c) 1998-2013 by the Free Pascal team
This unit implements the generic part of the LLVM IR writer
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 agllvm;
{$i fpcdefs.inc}
interface
uses
cclasses,
globtype,globals,systems,
aasmbase,aasmtai,aasmdata,
assemble,
aasmllvm, aasmllvmmetadata;
type
tmetadatakind = (
mk_none,
mk_normal,
mk_specialised,
mk_specialised_bool,
mk_specialised_enum
);
TLLVMInstrWriter = class;
TLLVMModuleInlineAssemblyDecorator = class(IExternalAssemblerOutputFileDecorator)
function LineFilter(const s: AnsiString): AnsiString;
function LinePrefix: AnsiString;
function LinePostfix: AnsiString;
function LineEnding(const deflineending: ShortString): ShortString;
end;
TLLVMFunctionInlineAssemblyDecorator = class(IExternalAssemblerOutputFileDecorator)
function LineFilter(const s: AnsiString): AnsiString;
function LinePrefix: AnsiString;
function LinePostfix: AnsiString;
function LineEnding(const deflineending: ShortString): ShortString;
end;
TLLVMAssember=class(texternalassembler)
protected
ffuncinlasmdecorator: TLLVMFunctionInlineAssemblyDecorator;
fdecllevel: longint;
procedure WriteExtraHeader;virtual;
procedure WriteExtraFooter;virtual;
procedure WriteInstruction(hp: tai);
procedure WriteLlvmInstruction(hp: tai);
procedure WriteDirectiveName(dir: TAsmDirective); virtual;
procedure WriteRealConst(hp: tai_realconst; do_line: boolean);
procedure WriteOrdConst(hp: tai_const; inmetadatakind: tmetadatakind);
procedure WriteTai(const replaceforbidden: boolean; const do_line: boolean; inmetadatakind: tmetadatakind; var InlineLevel: cardinal; var asmblock: boolean; var hp: tai);
public
constructor CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean); override;
procedure WriteTree(p:TAsmList);override;
procedure WriteAsmList;override;
procedure WriteFunctionInlineAsmList(list: tasmlist);
destructor destroy; override;
protected
InstrWriter: TLLVMInstrWriter;
end;
TLLVMClangAssember=class(TLLVMAssember)
public
function MakeCmdLine: TCmdStr; override;
function DoAssemble: boolean; override;
function RerunAssembler: boolean; override;
protected
function DoPipe: boolean; override;
private
fnextpass: byte;
end;
{# This is the base class for writing instructions.
The WriteInstruction() method must be overridden
to write a single instruction to the assembler
file.
}
TLLVMInstrWriter = class
constructor create(_owner: TLLVMAssember);
procedure WriteInstruction(hp : tai);
procedure WriterInstructionMetadata(sep: TSymStr; metatai: tai);
protected
owner: TLLVMAssember;
function getopcodestr(hp: taillvm): TSymStr;
function getopstr(const o:toper; refwithalign: boolean) : TSymStr;
procedure writetaioper(ai: tai);
procedure writeparas(const paras: tfplist; asmblock: boolean);
procedure WriteAsmRegisterAllocationClobbers(list: tasmlist);
end;
implementation
uses
SysUtils,
cutils,cfileutl,
fmodule,verbose,
objcasm,
aasmcnst,symconst,symdef,symtable,
llvmbase,itllvm,llvmdef,
cgbase,cgutils,cpubase,cpuinfo,triplet,llvminfo;
const
line_length = 70;
type
{$ifdef cpuextended}
t80bitarray = array[0..9] of byte;
{$endif cpuextended}
t64bitarray = array[0..7] of byte;
t32bitarray = array[0..3] of byte;
{****************************************************************************}
{ Support routines }
{****************************************************************************}
function single2str(d : single) : string;
var
hs : string;
begin
str(d,hs);
{ replace space with + }
if hs[1]=' ' then
hs[1]:='+';
single2str:=hs
end;
function double2str(d : double) : string;
var
hs : string;
begin
str(d,hs);
{ replace space with + }
if hs[1]=' ' then
hs[1]:='+';
double2str:=hs
end;
function extended2str(e : extended) : string;
var
hs : string;
begin
str(e,hs);
{ replace space with + }
if hs[1]=' ' then
hs[1]:='+';
extended2str:=hs
end;
{****************************************************************************}
{ Decorator for module-level inline assembly }
{****************************************************************************}
function TLLVMModuleInlineAssemblyDecorator.LineFilter(const s: AnsiString): AnsiString;
var
i: longint;
begin
result:='';
for i:=1 to length(s) do
begin
case s[i] of
#0..#31,
#127..#255,
'"','\':
result:=result+
'\'+
chr((ord(s[i]) shr 4)+ord('0'))+
chr((ord(s[i]) and $f)+ord('0'));
else
result:=result+s[i];
end;
end;
end;
function TLLVMModuleInlineAssemblyDecorator.LinePrefix: AnsiString;
begin
result:='module asm "';
end;
function TLLVMModuleInlineAssemblyDecorator.LinePostfix: AnsiString;
begin
result:='"';
end;
function TLLVMModuleInlineAssemblyDecorator.LineEnding(const deflineending: ShortString): ShortString;
begin
result:=deflineending
end;
{****************************************************************************}
{ Decorator for function-level inline assembly }
{****************************************************************************}
function TLLVMFunctionInlineAssemblyDecorator.LineFilter(const s: AnsiString): AnsiString;
var
i: longint;
begin
result:='';
for i:=1 to length(s) do
begin
case s[i] of
{ escape dollars }
'$':
result:=result+'$$';
{ ` is used as placeholder for a single dollar (reference to
argument to the inline assembly) }
'`':
result:=result+'$';
#0..#31,
#127..#255,
'"','\':
result:=result+
'\'+
chr((ord(s[i]) shr 4)+ord('0'))+
chr((ord(s[i]) and $f)+ord('0'));
else
result:=result+s[i];
end;
end;
end;
function TLLVMFunctionInlineAssemblyDecorator.LinePrefix: AnsiString;
begin
result:='';
end;
function TLLVMFunctionInlineAssemblyDecorator.LinePostfix: AnsiString;
begin
result:='';
end;
function TLLVMFunctionInlineAssemblyDecorator.LineEnding(const deflineending: ShortString): ShortString;
begin
result:='\0A';
end;
{****************************************************************************}
{ LLVM Instruction writer }
{****************************************************************************}
function getregisterstring(reg: tregister): ansistring;
begin
if getregtype(reg)=R_METADATAREGISTER then
result:='!"'+tllvmmetadata.getregstring(reg)+'"'
else
begin
if getregtype(reg)=R_TEMPREGISTER then
result:='%tmp.'
else
result:='%reg.'+tostr(byte(getregtype(reg)))+'_';
result:=result+tostr(getsupreg(reg));
end;
end;
function getreferencealignstring(var ref: treference) : ansistring;
begin
result:=', align '+tostr(ref.alignment);
end;
function getreferencestring(var ref : treference; withalign: boolean) : ansistring;
begin
result:='';
if assigned(ref.relsymbol) or
(assigned(ref.symbol) and
(ref.base<>NR_NO)) or
(ref.index<>NR_NO) or
(ref.offset<>0) then
begin
result:=' **(error ref: ';
if assigned(ref.symbol) then
result:=result+'sym='+ref.symbol.name+', ';
if assigned(ref.relsymbol) then
result:=result+'sym='+ref.relsymbol.name+', ';
if ref.base=NR_NO then
result:=result+'base=NR_NO, ';
if ref.index<>NR_NO then
result:=result+'index<>NR_NO, ';
if ref.offset<>0 then
result:=result+'offset='+tostr(ref.offset);
result:=result+')**';
internalerror(2013060203);
end;
if ref.base<>NR_NO then
result:=result+getregisterstring(ref.base)
else if assigned(ref.symbol) then
result:=result+LlvmAsmSymName(ref.symbol)
else
result:=result+'null';
if withalign then
result:=result+getreferencealignstring(ref);
end;
procedure TLLVMInstrWriter.writeparas(const paras: tfplist; asmblock: boolean);
var
hp: tai;
para: pllvmcallpara;
i: longint;
tmpinline: cardinal;
metadatakind: tmetadatakind;
tmpasmblock: boolean;
begin
tmpinline:=1;
tmpasmblock:=false;
owner.writer.AsmWrite('(');
for i:=0 to paras.count-1 do
begin
if i<>0 then
owner.writer.AsmWrite(', ');
para:=pllvmcallpara(paras[i]);
if (lcp_metadata in para^.flags) and
(para^.def<>llvm_metadatatype) then
begin
owner.writer.AsmWrite('metadata ')
end;
owner.writer.AsmWrite(llvmencodetypename(para^.def));
if para^.valueext<>lve_none then
owner.writer.AsmWrite(llvmvalueextension2str[para^.valueext]);
if lcp_byval in para^.flags then
owner.writer.AsmWrite(llvmparatypeattr(' byval',para^.def,true));
if lcp_sret in para^.flags then
owner.writer.AsmWrite(llvmparatypeattr(' sret',para^.def,true));
if asmblock and
(([llvmflag_opaque_ptr_transition,llvmflag_opaque_ptr]*llvmversion_properties[current_settings.llvmversion])<>[]) and
(para^.def.typ=pointerdef) then
owner.writer.AsmWrite(llvmparatypeattr(' elementtype',para^.def,true));
{ For byval, this means "alignment on the stack" and of the passed source data.
For other pointer parameters, this means "alignment of the passed source data" }
if (para^.alignment<>std_param_align) or
(para^.alignment<0) then
begin
owner.writer.AsmWrite(' align ');
owner.writer.AsmWrite(tostr(abs(para^.alignment)));
end;
case para^.val.typ of
top_reg:
begin
owner.writer.AsmWrite(' ');
owner.writer.AsmWrite(getregisterstring(para^.val.register));
end;
top_ref:
begin
owner.writer.AsmWrite(' ');
owner.writer.AsmWrite(llvmasmsymname(para^.val.sym));
end;
top_const:
begin
owner.writer.AsmWrite(' ');
owner.writer.AsmWrite(tostr(para^.val.value));
end;
top_tai:
begin
owner.writer.AsmWrite(' ');
tmpinline:=1;
tmpasmblock:=false;
hp:=para^.val.ai;
if para^.def<>llvm_metadatatype then
metadatakind:=mk_none
else
metadatakind:=mk_normal;
inc(owner.fdecllevel);
owner.WriteTai(false,false,metadatakind,tmpinline,tmpasmblock,hp);
dec(owner.fdecllevel);
end;
{ empty records }
top_undef:
owner.writer.AsmWrite(' undef');
else
internalerror(2014010801);
end;
end;
owner.writer.AsmWrite(')');
end;
function llvmdoubletostr(const d: double): TSymStr;
type
tdoubleval = record
case byte of
1: (d: double);
2: (i: int64);
end;
begin
{ "When using the hexadecimal form, constants of types half,
float, and double are represented using the 16-digit form shown
above (which matches the IEEE754 representation for double)"
And always in big endian form (sign bit leftmost)
}
result:='0x'+hexstr(tdoubleval(d).i,16);
end;
{$if defined(cpuextended) and (defined(FPC_HAS_TYPE_EXTENDED) or defined(FPC_SOFT_FPUX80))}
function llvmextendedtostr(const e: extended): TSymStr;
var
extendedval: record
case byte of
1: (e: extended);
2: (r: packed record
{$ifdef FPC_LITTLE_ENDIAN}
l: int64;
h: word;
{$else FPC_LITTLE_ENDIAN}
h: int64;
l: word;
{$endif FPC_LITTLE_ENDIAN}
end;
);
end;
begin
extendedval.e:=e;
{ hex format is always big endian in llvm }
result:='0xK'+hexstr(extendedval.r.h,sizeof(extendedval.r.h)*2)+
hexstr(extendedval.r.l,sizeof(extendedval.r.l)*2);
end;
{$endif cpuextended}
function TLLVMInstrWriter.getopstr(const o:toper; refwithalign: boolean) : TSymStr;
var
hp: tai;
begin
case o.typ of
top_reg:
getopstr:=getregisterstring(o.reg);
top_const:
getopstr:=tostr(int64(o.val));
top_ref:
if o.ref^.refaddr=addr_full then
begin
getopstr:='';
if assigned(o.ref^.symbol) then
getopstr:=LlvmAsmSymName(o.ref^.symbol)
else
getopstr:='null';
if o.ref^.offset<>0 then
internalerror(2013060202);
end
else
getopstr:=getreferencestring(o.ref^,refwithalign);
top_def:
begin
getopstr:=llvmencodetypename(o.def);
end;
top_cond:
begin
getopstr:=llvm_cond2str[o.cond];
end;
top_fpcond:
begin
getopstr:=llvm_fpcond2str[o.fpcond];
end;
top_single,
top_double:
begin
{ "When using the hexadecimal form, constants of types half,
float, and double are represented using the 16-digit form shown
above (which matches the IEEE754 representation for double)"
And always in big endian form (sign bit leftmost)
}
if o.typ=top_double then
result:=llvmdoubletostr(o.dval)
else
result:=llvmdoubletostr(o.sval)
end;
top_para:
begin
writeparas(o.paras,false);
result:='';
end;
top_tai:
begin
if assigned(o.ai) then
begin
writetaioper(o.ai);
end;
result:='';
end;
{$if defined(cpuextended) and (defined(FPC_HAS_TYPE_EXTENDED) or defined(FPC_SOFT_FPUX80))}
top_extended80:
begin
result:=llvmextendedtostr(o.eval);
end;
{$endif cpuextended}
top_undef:
result:='undef';
top_callingconvention:
result:=llvm_callingconvention_name(o.callingconvention);
else
internalerror(2013060227);
end;
end;
procedure TLLVMInstrWriter.writetaioper(ai: tai);
var
tmpinline: cardinal;
tmpasmblock: boolean;
begin
tmpinline:=1;
tmpasmblock:=false;
owner.WriteTai(false,false,mk_none,tmpinline,tmpasmblock,ai);
end;
procedure TLLVMInstrWriter.WriteAsmRegisterAllocationClobbers(list: tasmlist);
var
hp: tai;
begin
hp:=tai(list.first);
while assigned(hp) do
begin
if (hp.typ=ait_regalloc) and
(tai_regalloc(hp).ratype=ra_alloc) then
begin
owner.writer.AsmWrite(',~{');
owner.writer.AsmWrite(std_regname(tai_regalloc(hp).reg));
owner.writer.AsmWrite('}');
end;
hp:=tai(hp.next);
end;
end;
procedure TLLVMInstrWriter.WriteInstruction(hp: tai);
var
op: tllvmop;
tmpstr,
sep: TSymStr;
i, opstart: longint;
nested: boolean;
opdone,
done: boolean;
begin
op:=taillvm(hp).llvmopcode;
{ we write everything immediately rather than adding it into a string,
because operands may contain other tai that will also write things out
(and their output must come after everything that was processed in this
instruction, such as its opcode or previous operands) }
if owner.fdecllevel=0 then
owner.writer.AsmWrite(#9);
sep:=' ';
opdone:=false;
done:=false;
opstart:=0;
nested:=false;
case op of
la_type:
begin
owner.writer.AsmWrite(llvmtypeidentifier(taillvm(hp).oper[0]^.def));
owner.writer.AsmWrite(' = type ');
owner.writer.AsmWrite(llvmencodetypedecl(taillvm(hp).oper[0]^.def));
done:=true;
end;
la_asmblock:
begin
owner.writer.AsmWrite('call void asm sideeffect "');
owner.WriteFunctionInlineAsmList(taillvm(hp).oper[0]^.asmlist);
owner.writer.AsmWrite('","');
{ we pass all accessed local variables as in/out address parameters,
since we don't analyze the assembly code to determine what exactly
happens to them; this is also compatible with the regular code
generators, which always place local place local variables
accessed from assembly code in memory }
for i:=0 to taillvm(hp).oper[1]^.paras.Count-1 do
begin
owner.writer.AsmWrite('=*m,');
end;
owner.writer.AsmWrite('~{memory},~{fpsr},~{flags}');
WriteAsmRegisterAllocationClobbers(taillvm(hp).oper[0]^.asmlist);
owner.writer.AsmWrite('"');
writeparas(taillvm(hp).oper[1]^.paras,true);
done:=true;
end;
la_load,
la_getelementptr:
begin
if (taillvm(hp).oper[0]^.typ<>top_reg) or
(taillvm(hp).oper[0]^.reg<>NR_NO) then
owner.writer.AsmWrite(getopstr(taillvm(hp).oper[0]^,false)+' = ')
else
nested:=true;
opstart:=1;
owner.writer.AsmWrite(getopcodestr(taillvm(hp)));
opdone:=true;
if nested then
owner.writer.AsmWrite(' (')
else
owner.writer.AsmWrite(' ');
tmpstr:=llvmencodetypename(taillvm(hp).spilling_get_reg_type(0),op=la_getelementptr);
owner.writer.AsmWrite(tmpstr);
owner.writer.AsmWrite(',');
end;
la_ret, la_br, la_switch, la_indirectbr,
la_resume,
la_unreachable,
la_store,
la_fence,
la_cmpxchg,
la_atomicrmw,
la_catch,
la_filter,
la_cleanup:
begin
{ instructions that never have a result }
end;
la_call,
la_invoke:
begin
if taillvm(hp).oper[1]^.reg<>NR_NO then
owner.writer.AsmWrite(getregisterstring(taillvm(hp).oper[1]^.reg)+' = ');
opstart:=2;
owner.writer.AsmWrite(getopcodestr(taillvm(hp)));
tmpstr:=llvm_callingconvention_name(taillvm(hp).oper[2]^.callingconvention);
if tmpstr<>'' then
begin
owner.writer.AsmWrite(' ');
owner.writer.AsmWrite(tmpstr);
end;
opdone:=true;
owner.writer.AsmWrite(' ');
owner.writer.AsmWrite(llvmencodetypename(taillvm(hp).oper[taillvm.callpdopernr]^.def,true));
opstart:=4;
end;
la_blockaddress:
begin
{ nested -> no type }
if owner.fdecllevel = 0 then
begin
owner.writer.AsmWrite(getopstr(taillvm(hp).oper[0]^,false));
owner.writer.AsmWrite(' ');
end;
owner.writer.AsmWrite('blockaddress(');
owner.writer.AsmWrite(getopstr(taillvm(hp).oper[1]^,false));
{ getopstr would add a "label" qualifier, which blockaddress does
not want }
owner.writer.AsmWrite(',%');
with taillvm(hp).oper[2]^ do
begin
if (typ<>top_ref) or
(ref^.refaddr<>addr_full) then
internalerror(2016112001);
owner.writer.AsmWrite(ref^.symbol.name);
end;
nested:=true;
done:=true;
end;
la_alloca:
begin
owner.writer.AsmWrite(getreferencestring(taillvm(hp).oper[0]^.ref^,false)+' = ');
sep:=' ';
opstart:=1;
end;
la_trunc, la_zext, la_sext, la_fptrunc, la_fpext,
la_fptoui, la_fptosi, la_uitofp, la_sitofp,
la_ptrtoint, la_inttoptr,
la_bitcast:
begin
{ destination can be empty in case of nested constructs, or
data initialisers }
if (taillvm(hp).oper[0]^.typ<>top_reg) or
(taillvm(hp).oper[0]^.reg<>NR_NO) then
owner.writer.AsmWrite(getopstr(taillvm(hp).oper[0]^,false)+' = ')
else
nested:=true;
owner.writer.AsmWrite(getopcodestr(taillvm(hp)));
if not nested then
owner.writer.AsmWrite(' ')
else
owner.writer.AsmWrite(' (');
owner.writer.AsmWrite(getopstr(taillvm(hp).oper[1]^,false));
{ if there's a tai operand, its def is used instead of an
explicit def operand }
if taillvm(hp).ops=4 then
begin
owner.writer.AsmWrite(' ');
owner.writer.AsmWrite(getopstr(taillvm(hp).oper[2]^,false));
opstart:=3;
end
else
opstart:=2;
owner.writer.AsmWrite(' to ');
owner.writer.AsmWrite(getopstr(taillvm(hp).oper[opstart]^,false));
done:=true;
end
else
begin
if (taillvm(hp).oper[0]^.typ<>top_reg) or
(taillvm(hp).oper[0]^.reg<>NR_NO) then
begin
owner.writer.AsmWrite(getopstr(taillvm(hp).oper[0]^,true)+' = ');
end
else
nested:=true;
sep:=' ';
opstart:=1
end;
end;
{ process operands }
if not done then
begin
if not opdone then
begin
owner.writer.AsmWrite(getopcodestr(taillvm(hp)));
if nested then
owner.writer.AsmWrite(' (');
end;
if taillvm(hp).ops<>0 then
begin
for i:=opstart to taillvm(hp).ops-1 do
begin
owner.writer.AsmWrite(sep);
{ special invoke interjections: "to label X unwind label Y" }
if (op=la_invoke) then
case i of
6: owner.writer.AsmWrite('to ');
7: owner.writer.AsmWrite('unwind ');
end;
owner.writer.AsmWrite(getopstr(taillvm(hp).oper[i]^,op in [la_load,la_store]));
if (taillvm(hp).oper[i]^.typ in [top_def,top_cond,top_fpcond]) or
(op in [la_call,la_invoke,la_landingpad,la_catch,la_filter,la_cleanup]) then
sep :=' '
else
sep:=', ';
end;
end;
end;
if op=la_alloca then
owner.writer.AsmWrite(getreferencealignstring(taillvm(hp).oper[0]^.ref^));
WriterInstructionMetadata(', ',taillvm(hp).metadata);
if nested then
owner.writer.AsmWrite(')')
else if owner.fdecllevel=0 then
owner.writer.AsmLn;
end;
procedure TLLVMInstrWriter.WriterInstructionMetadata(sep: TSymStr; metatai: tai);
begin
while assigned(metatai) do
begin
owner.writer.AsmWrite(sep);
sep:=', ';
writetaioper(metatai);
metatai:=tai(metatai.next);
end;
end;
function TLLVMInstrWriter.getopcodestr(hp: taillvm): TSymStr;
begin
result:=llvm_op2str[hp.llvmopcode];
case hp.llvmopcode of
la_load:
begin
if vol_read in hp.oper[2]^.ref^.volatility then
result:=result+' volatile';
end;
la_store:
begin
if vol_write in hp.oper[3]^.ref^.volatility then
result:=result+' volatile';
end;
else
;
end;
end;
{****************************************************************************}
{ LLVM Assembler writer }
{****************************************************************************}
destructor TLLVMAssember.Destroy;
begin
InstrWriter.free;
ffuncinlasmdecorator.free;
inherited destroy;
end;
procedure TLLVMAssember.WriteTree(p:TAsmList);
var
hp : tai;
InlineLevel : cardinal;
asmblock: boolean;
do_line : boolean;
replaceforbidden: boolean;
begin
if not assigned(p) then
exit;
replaceforbidden:=asminfo^.dollarsign<>'$';
InlineLevel:=0;
asmblock:=false;
{ lineinfo is only needed for al_procedures (PFV) }
do_line:=(cs_asm_source in current_settings.globalswitches) or
((cs_lineinfo in current_settings.moduleswitches)
and (p=current_asmdata.asmlists[al_procedures]));
hp:=tai(p.first);
while assigned(hp) do
begin
prefetch(pointer(hp.next)^);
if not(hp.typ in SkipLineInfo) then
begin
current_filepos:=tailineinfo(hp).fileinfo;
{ no line info for inlined code }
if do_line and (inlinelevel=0) then
WriteSourceLine(hp as tailineinfo);
end;
if hp.typ=ait_section then
ResetSourceLines;
WriteTai(replaceforbidden,do_line,mk_none,InlineLevel,asmblock,hp);
hp:=tai(hp.next);
end;
end;
procedure TLLVMAssember.WriteExtraHeader;
begin
writer.AsmWrite('target datalayout = "');
writer.AsmWrite(target_info.llvmdatalayout);
writer.AsmWriteln('"');
writer.AsmWrite('target triple = "');
writer.AsmWrite(targettriplet(triplet_llvm));
writer.AsmWriteln('"');
end;
procedure TLLVMAssember.WriteExtraFooter;
begin
end;
procedure TLLVMAssember.WriteInstruction(hp: tai);
begin
end;
procedure TLLVMAssember.WriteLlvmInstruction(hp: tai);
begin
InstrWriter.WriteInstruction(hp);
end;
procedure TLLVMAssember.WriteRealConst(hp: tai_realconst; do_line: boolean);
begin
if fdecllevel=0 then
begin
case tai_realconst(hp).realtyp of
aitrealconst_s32bit:
writer.AsmWriteLn(asminfo^.comment+'value: '+single2str(tai_realconst(hp).value.s32val));
aitrealconst_s64bit:
writer.AsmWriteLn(asminfo^.comment+'value: '+double2str(tai_realconst(hp).value.s64val));
{$if defined(cpuextended) and (defined(FPC_HAS_TYPE_EXTENDED) or defined(FPC_SOFT_FPUX80))}
{ can't write full 80 bit floating point constants yet on non-x86 }
aitrealconst_s80bit:
writer.AsmWriteLn(asminfo^.comment+'value: '+extended2str(tai_realconst(hp).value.s80val));
{$endif cpuextended}
aitrealconst_s64comp:
writer.AsmWriteLn(asminfo^.comment+'value: '+extended2str(tai_realconst(hp).value.s64compval));
else
internalerror(2014050603);
end;
internalerror(2016120202);
end;
case hp.realtyp of
aitrealconst_s32bit:
writer.AsmWrite(llvmdoubletostr(hp.value.s32val));
aitrealconst_s64bit:
writer.AsmWriteln(llvmdoubletostr(hp.value.s64val));
{$if defined(cpuextended) and (defined(FPC_HAS_TYPE_EXTENDED) or defined(FPC_SOFT_FPUX80))}
aitrealconst_s80bit:
writer.AsmWrite(llvmextendedtostr(hp.value.s80val));
{$endif defined(cpuextended)}
aitrealconst_s64comp:
{ handled as int64 most of the time in llvm }
writer.AsmWrite(tostr(round(hp.value.s64compval)));
else
internalerror(2014062401);
end;
end;
procedure TLLVMAssember.WriteOrdConst(hp: tai_const; inmetadatakind: tmetadatakind);
var
consttyp: taiconst_type;
begin
if fdecllevel=0 then
internalerror(2016120203);
consttyp:=hp.consttype;
case consttyp of
aitconst_got,
aitconst_gotoff_symbol,
aitconst_uleb128bit,
aitconst_sleb128bit,
aitconst_rva_symbol,
aitconst_secrel32_symbol,
aitconst_darwin_dwarf_delta32,
aitconst_darwin_dwarf_delta64,
aitconst_half16bit,
aitconst_gs:
internalerror(2014052901);
aitconst_128bit,
aitconst_64bit,
aitconst_32bit,
aitconst_16bit,
aitconst_8bit,
aitconst_16bit_unaligned,
aitconst_32bit_unaligned,
aitconst_64bit_unaligned:
begin
if fdecllevel=0 then
writer.AsmWrite(asminfo^.comment);
{ can't have compile-time differences between symbols; these are
normally for PIC, but llvm takes care of that for us }
if assigned(hp.endsym) then
internalerror(2014052902);
if assigned(hp.sym) then
begin
writer.AsmWrite(LlvmAsmSymName(hp.sym));
{ can't have offsets }
if hp.value<>0 then
if fdecllevel<>0 then
internalerror(2014052903)
else
writer.AsmWrite(' -- symbol offset: ' + tostr(hp.value));
end
else if inmetadatakind=mk_specialised_bool then
begin
if hp.value=0 then
writer.AsmWrite('false')
else
writer.AsmWrite('true')
end
else if (hp.value=0) and
(inmetadatakind=mk_none) then
writer.AsmWrite('zeroinitializer')
else
writer.AsmWrite(tostr(hp.value));
{
// activate in case of debugging IE 2016120203
if fdecllevel=0 then
writer.AsmLn;
}
end;
else
internalerror(2007042504);
end;
end;
procedure TLLVMAssember.WriteTai(const replaceforbidden: boolean; const do_line: boolean; inmetadatakind: tmetadatakind; var InlineLevel: cardinal; var asmblock: boolean; var hp: tai);
procedure WriteLinkageVibilityFlags(bind: TAsmSymBind; is_definition: boolean);
begin
{ re-declaration of a symbol defined in the current module (in an
assembler block) }
if not is_definition then
begin
writer.AsmWrite(' external');
exit;
end;
case bind of
AB_EXTERNAL,
AB_EXTERNAL_INDIRECT:
writer.AsmWrite(' external');
AB_COMMON:
writer.AsmWrite(' common');
AB_LOCAL:
writer.AsmWrite(' internal');
AB_GLOBAL,
AB_INDIRECT:
;
AB_WEAK_EXTERNAL:
writer.AsmWrite(' extern_weak');
AB_PRIVATE_EXTERN:
writer.AsmWrite(' hidden')
else
internalerror(2014020104);
end;
end;
procedure WriteFunctionFlags(pd: tprocdef);
begin
{ function attributes }
if (pos('FPC_SETJMP',upper(pd.mangledname))<>0) or
(pd.mangledname=(target_info.cprefix+'setjmp')) then
writer.AsmWrite(' returns_twice');
if po_inline in pd.procoptions then
writer.AsmWrite(' inlinehint')
else if (po_noinline in pd.procoptions) or
(pio_inline_forbidden in pd.implprocoptions) then
writer.AsmWrite(' noinline');
{ ensure that functions that happen to have the same name as a
standard C library function, but which are implemented in Pascal,
are not considered to have the same semantics as the C function with
the same name }
if not(po_external in pd.procoptions) then
writer.AsmWrite(' nobuiltin');
if po_noreturn in pd.procoptions then
writer.AsmWrite(' noreturn');
if pio_thunk in pd.implprocoptions then
writer.AsmWrite(' "thunk"');
if llvmflag_null_pointer_valid_new in llvmversion_properties[current_settings.llvmversion] then
writer.AsmWrite(' null_pointer_is_valid')
else
writer.AsmWrite(' "null-pointer-is-valid"="true"');
if not(pio_fastmath in pd.implprocoptions) then
writer.AsmWrite(' strictfp');
if cs_sanitize_address in current_settings.moduleswitches then
writer.AsmWrite(' sanitize_address');
end;
procedure WriteTypedConstData(hp: tai_abstracttypedconst; metadatakind: tmetadatakind);
var
p: tai_abstracttypedconst;
pval: tai;
defstr: TSymStr;
first, gotstring, isspecialised: boolean;
begin
if (hp.def<>llvm_metadatatype) and (metadatakind<mk_specialised) then
begin
defstr:=llvmencodetypename(hp.def)
end
else
begin
defstr:=''
end;
{ write the struct, array or simple type }
case hp.adetyp of
tck_record:
begin
if metadatakind=mk_none then
begin
writer.AsmWrite(defstr);
if not(df_llvm_no_struct_packing in hp.def.defoptions) then
writer.AsmWrite(' <{')
else
writer.AsmWrite(' {')
end
else
begin
writer.AsmWrite(' !{');
end;
first:=true;
for p in tai_aggregatetypedconst(hp) do
begin
if not first then
writer.AsmWrite(', ')
else
first:=false;
WriteTypedConstData(p,metadatakind);
end;
if metadatakind=mk_none then
begin
if not(df_llvm_no_struct_packing in hp.def.defoptions) then
writer.AsmWrite(' }>')
else
writer.AsmWrite(' }')
end
else
begin
writer.AsmWrite(' }');
end;
end;
tck_array:
begin
if metadatakind=mk_none then
begin
writer.AsmWrite(defstr);
end;
first:=true;
gotstring:=false;
for p in tai_aggregatetypedconst(hp) do
begin
if not first then
writer.AsmWrite(', ')
else
begin
writer.AsmWrite(' ');
if (tai_abstracttypedconst(p).adetyp=tck_simple) and
assigned(tai_simpletypedconst(p).val) and
(tai_simpletypedconst(p).def<>charpointertype) and
(tai_simpletypedconst(p).val.typ=ait_string) then
begin
gotstring:=true;
end
else
begin
if metadatakind=mk_none then
begin
writer.AsmWrite('[');
end
else
begin
writer.AsmWrite('!{');
end;
end;
first:=false;
end;
{ cannot concat strings and other things }
if gotstring and
(metadatakind=mk_none) and
((tai_abstracttypedconst(p).adetyp<>tck_simple) or
(tai_simpletypedconst(p).val.typ<>ait_string)) then
internalerror(2014062701);
WriteTypedConstData(p,metadatakind);
end;
if not gotstring then
begin
if first then
begin
if metadatakind=mk_none then
begin
writer.AsmWrite(' [');
end
else
begin
writer.AsmWrite(' !{');
end;
end;
if metadatakind=mk_none then
begin
writer.AsmWrite(']');
end
else
begin
writer.AsmWrite('}');
end;
end;
end;
tck_simple:
begin
pval:=tai_simpletypedconst(hp).val;
if not assigned(pval) then
begin
if metadatakind>=mk_normal then
writer.asmWrite('null')
else
internalerror(2022041301);
exit;
end;
if (pval.typ<>ait_string) and
(defstr<>'') then
begin
writer.AsmWrite(defstr);
writer.AsmWrite(' ');
end;
WriteTai(replaceforbidden,do_line,metadatakind,InlineLevel,asmblock,pval);
end;
end;
end;
procedure WriteString(hp: tai_string);
var
i: longint;
s: string;
ch: ansichar;
endQuotes: boolean;
begin
if fdecllevel=0 then
internalerror(2016120201);
endQuotes:=true;
case inmetadatakind of
mk_none:
writer.AsmWrite('c"');
mk_normal:
writer.AsmWrite('!"');
mk_specialised:
writer.AsmWrite('"');
mk_specialised_bool:
internalerror(2022041201);
mk_specialised_enum:
endQuotes:=false;
end;
for i:=1 to tai_string(hp).len do
begin
ch:=tai_string(hp).str[i-1];
case ch of
#0, {This can't be done by range, because a bug in FPC}
#1..#31,
#128..#255,
'"',
'\' : s:='\'+hexStr(ord(ch),2);
else
s:=ch;
end;
writer.AsmWrite(s);
end;
if endQuotes then
writer.AsmWrite('"');
end;
procedure WriteSpecialisedMetadataNode(hp: tai_llvmspecialisedmetadatanode);
var
element: tai_abstracttypedconst;
specialised_element: tllvmspecialisedmetaitem;
s: shortstring;
metadatakind: tmetadatakind;
first: boolean;
begin
if hp.IsDistinct then
writer.AsmWrite(' distinct !')
else
writer.AsmWrite(' !');
str(hp.kind,s);
writer.AsmWrite(s);
writer.AsmWrite('(');
first:=true;
for element in hp do
begin
if not first then
writer.AsmWrite(', ')
else
first:=false;
specialised_element:=tllvmspecialisedmetaitem(element);
if specialised_element.itemname<>'' then
begin
writer.AsmWrite(specialised_element.itemname);
writer.AsmWrite(': ');
end;
case specialised_element.itemkind of
lsmik_boolean:
metadatakind:=mk_specialised_bool;
lsmik_enum:
metadatakind:=mk_specialised_enum;
else
metadatakind:=mk_specialised;
end;
WriteTypedConstData(specialised_element,metadatakind);
end;
writer.AsmWrite(')');
end;
procedure WriteLlvmMetadataNode(hp: tai_llvmbasemetadatanode);
begin
{ must only appear at the top level }
if fdecllevel<>0 then
internalerror(2019050111);
writer.AsmWrite('!');
writer.AsmWrite(tai_llvmbasemetadatanode(hp).name);
writer.AsmWrite(' =');
inc(fdecllevel);
if hp.isspecialised then
WriteSpecialisedMetadataNode(tai_llvmspecialisedmetadatanode(hp))
else
WriteTypedConstData(hp,mk_normal);
writer.AsmLn;
dec(fdecllevel);
end;
var
hp2: tai;
sstr: TSymStr;
i: longint;
begin
case hp.typ of
ait_align,
ait_section :
begin
{ ignore, specified as part of declarations -- don't write
comment, because could appear in the middle of an aggregate
constant definition }
end;
ait_datablock :
begin
writer.AsmWrite(asminfo^.comment);
writer.AsmWriteln('datablock');
end;
ait_const:
begin
WriteOrdConst(tai_const(hp),inmetadatakind);
end;
ait_realconst :
begin
WriteRealConst(tai_realconst(hp), do_line);
end;
ait_string :
begin
WriteString(tai_string(hp));
end;
ait_label :
begin
if not asmblock and
(tai_label(hp).labsym.is_used) then
begin
if (tai_label(hp).labsym.bind=AB_PRIVATE_EXTERN) then
begin
{ should be emitted as part of the variable/function def }
internalerror(2013010703);
end;
if tai_label(hp).labsym.bind in [AB_GLOBAL, AB_PRIVATE_EXTERN] then
begin
{ should be emitted as part of the variable/function def }
//internalerror(2013010704);
writer.AsmWriteln(asminfo^.comment+'global/privateextern label: '+tai_label(hp).labsym.name);
end;
if replaceforbidden then
writer.AsmWrite(ApplyAsmSymbolRestrictions(tai_label(hp).labsym.name))
else
writer.AsmWrite(tai_label(hp).labsym.name);
writer.AsmWriteLn(':');
end;
end;
ait_symbol :
begin
if fdecllevel=0 then
writer.AsmWrite(asminfo^.comment);
writer.AsmWriteln(LlvmAsmSymName(tai_symbol(hp).sym));
{ todo }
if tai_symbol(hp).has_value then
internalerror(2014062402);
end;
ait_llvmdecl:
begin
if taillvmdecl(hp).def.typ=procdef then
begin
if not(ldf_definition in taillvmdecl(hp).flags) then
begin
writer.AsmWrite('declare');
writer.AsmWrite(llvmencodeproctype(tprocdef(taillvmdecl(hp).def), taillvmdecl(hp).namesym.name, lpd_decl));
WriteFunctionFlags(tprocdef(taillvmdecl(hp).def));
writer.AsmLn;
end
else
begin
writer.AsmWrite('define');
if ldf_weak in taillvmdecl(hp).flags then
writer.AsmWrite(' weak');
WriteLinkageVibilityFlags(taillvmdecl(hp).namesym.bind, true);
writer.AsmWrite(llvmencodeproctype(tprocdef(taillvmdecl(hp).def), '', lpd_def));
WriteFunctionFlags(tprocdef(taillvmdecl(hp).def));
if assigned(tprocdef(taillvmdecl(hp).def).personality) then
begin
if not(llvmflag_opaque_ptr in llvmversion_properties[current_settings.llvmversion]) then
begin
writer.AsmWrite(' personality i8* bitcast (');
writer.AsmWrite(llvmencodeproctype(tprocdef(taillvmdecl(hp).def).personality, '', lpd_procvar));
writer.AsmWrite('* ');
writer.AsmWrite(llvmmangledname(tprocdef(taillvmdecl(hp).def).personality.mangledname));
writer.AsmWrite(' to i8*)');
end
else
begin
writer.AsmWrite(' personality ptr ');
writer.AsmWrite(llvmmangledname(tprocdef(taillvmdecl(hp).def).personality.mangledname));
end;
end;
InstrWriter.WriterInstructionMetadata(' ', taillvmdecl(hp).metadata);
writer.AsmWriteln(' {');
end;
end
else
begin
writer.AsmWrite(LlvmAsmSymName(taillvmdecl(hp).namesym));
writer.AsmWrite(' =');
if ldf_weak in taillvmdecl(hp).flags then
writer.AsmWrite(' weak');
if ldf_appending in taillvmdecl(hp).flags then
writer.AsmWrite(' appending');
WriteLinkageVibilityFlags(taillvmdecl(hp).namesym.bind, ldf_definition in taillvmdecl(hp).flags);
writer.AsmWrite(' ');
if (ldf_tls in taillvmdecl(hp).flags) then
writer.AsmWrite('thread_local ');
if ldf_unnamed_addr in taillvmdecl(hp).flags then
writer.AsmWrite('unnamed_addr ');
if taillvmdecl(hp).sec in [sec_rodata,sec_rodata_norel] then
writer.AsmWrite('constant ')
else
writer.AsmWrite('global ');
if not assigned(taillvmdecl(hp).initdata) then
begin
writer.AsmWrite(llvmencodetypename(taillvmdecl(hp).def));
if ldf_definition in taillvmdecl(hp).flags then
writer.AsmWrite(' zeroinitializer');
end
else
begin
inc(fdecllevel);
{ can't have an external symbol with initialisation data }
if taillvmdecl(hp).namesym.bind in [AB_EXTERNAL, AB_WEAK_EXTERNAL] then
internalerror(2014052905);
{ bitcast initialisation data to the type of the constant }
{ write initialisation data }
hp2:=tai(taillvmdecl(hp).initdata.first);
while assigned(hp2) do
begin
WriteTai(replaceforbidden,do_line,inmetadatakind,InlineLevel,asmblock,hp2);
hp2:=tai(hp2.next);
end;
dec(fdecllevel);
end;
{ custom section name? }
case taillvmdecl(hp).sec of
sec_user:
begin
writer.AsmWrite(', section "');
writer.AsmWrite(taillvmdecl(hp).secname);
writer.AsmWrite('"');
end;
low(TObjCAsmSectionType)..high(TObjCAsmSectionType):
begin
writer.AsmWrite(', section "');
writer.AsmWrite(objc_section_name(taillvmdecl(hp).sec));
writer.AsmWrite('"');
end;
else
;
end;
{ sections whose name starts with 'llvm.' are for LLVM
internal use and don't have an alignment }
if pos('llvm.',taillvmdecl(hp).secname)<>1 then
begin
{ alignment }
writer.AsmWrite(', align ');
writer.AsmWrite(tostr(taillvmdecl(hp).alignment));
end;
{ address sanitizer adds a red zone after global variables,
while vectorized sections like resource strings are indexed
like arrays by Pascal code -> the red zones completely mess
up this indexing }
if (ldf_vectorized in (taillvmdecl(hp).flags)) and
(cs_sanitize_address in current_settings.moduleswitches) and
(llvmflag_sanitizer_attributes in llvmversion_properties[current_settings.llvmversion]) then
begin
writer.AsmWrite(', no_sanitize_address')
end;
InstrWriter.WriterInstructionMetadata(', ',taillvmdecl(hp).metadata);
writer.AsmLn;
end;
end;
ait_llvmalias:
begin
writer.AsmWrite(LlvmAsmSymName(taillvmalias(hp).newsym));
writer.AsmWrite(' = alias ');
WriteLinkageVibilityFlags(taillvmalias(hp).bind, true);
if taillvmalias(hp).def.typ=procdef then
sstr:=llvmencodeproctype(tabstractprocdef(taillvmalias(hp).def), '', lpd_alias)
else
sstr:=llvmencodetypename(taillvmalias(hp).def);
writer.AsmWrite(sstr);
writer.AsmWrite(', ');
if not(llvmflag_opaque_ptr in llvmversion_properties[current_settings.llvmversion]) then
begin
writer.AsmWrite(sstr);
writer.AsmWrite('* ');
end
else
begin
writer.AsmWrite('ptr ');
end;
writer.AsmWriteln(LlvmAsmSymName(taillvmalias(hp).oldsym));
end;
ait_llvmmetadatanode:
begin
WriteLlvmMetadataNode(tai_llvmbasemetadatanode(hp));
end;
ait_llvmmetadatareftypedconst:
begin
{ must only appear as an element in a typed const }
if fdecllevel=0 then
internalerror(2019050110);
writer.AsmWrite('!');
writer.AsmWrite(tai_llvmbasemetadatanode(tai_llvmmetadatareftypedconst(hp).val).name);
end;
ait_llvmmetadatarefoperand:
begin
inc(fdecllevel);
writer.AsmWrite('!');
writer.AsmWrite(tai_llvmmetadatareferenceoperand(hp).id);
writer.AsmWrite(' ');
hp2:=tai_llvmmetadatareferenceoperand(hp).value;
WriteTai(replaceforbidden,do_line,mk_normal,inlinelevel,asmblock,hp2);
dec(fdecllevel);
end;
ait_symbolpair:
begin
{ should be emitted as part of the symbol def }
internalerror(2013010708);
end;
ait_symbol_end :
begin
if tai_symbol_end(hp).sym.typ=AT_FUNCTION then
writer.AsmWriteln('}')
else
writer.AsmWriteln('; ait_symbol_end error, should not be generated');
// internalerror(2013010711);
end;
ait_instruction :
begin
WriteInstruction(hp);
end;
ait_llvmins:
begin
WriteLlvmInstruction(hp);
end;
ait_stab :
begin
internalerror(2013010712);
end;
ait_force_line,
ait_function_name :
;
ait_cutobject :
begin
end;
ait_marker :
case
tai_marker(hp).kind of
mark_NoLineInfoStart:
inc(InlineLevel);
mark_NoLineInfoEnd:
dec(InlineLevel);
{ these cannot be nested }
mark_AsmBlockStart:
asmblock:=true;
mark_AsmBlockEnd:
asmblock:=false;
else
;
end;
ait_directive :
begin
{ CPU directive is commented out for the LLVM }
if tai_directive(hp).directive=asd_cpu then
writer.AsmWrite(asminfo^.comment);
WriteDirectiveName(tai_directive(hp).directive);
if tai_directive(hp).name <>'' then
writer.AsmWrite(tai_directive(hp).name);
if fdecllevel<>0 then
internalerror(2015090602);
writer.AsmLn;
end;
ait_seh_directive :
begin
internalerror(2013010713);
end;
ait_typedconst:
begin
WriteTypedConstData(tai_abstracttypedconst(hp),inmetadatakind);
end
else
if not WriteComments(hp) then
internalerror(2019012010);
end;
end;
constructor TLLVMAssember.CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean);
begin
inherited;
InstrWriter:=TLLVMInstrWriter.create(self);
end;
procedure TLLVMAssember.WriteDirectiveName(dir: TAsmDirective);
begin
writer.AsmWrite('.'+directivestr[dir]+' ');
end;
procedure TLLVMAssember.WriteAsmList;
var
hal : tasmlisttype;
a: TExternalAssembler;
decorator: TLLVMModuleInlineAssemblyDecorator;
begin
WriteExtraHeader;
for hal:=low(TasmlistType) to high(TasmlistType) do
begin
if not assigned(current_asmdata.asmlists[hal]) or
current_asmdata.asmlists[hal].Empty then
continue;
writer.AsmWriteLn(asminfo^.comment+'Begin asmlist '+AsmlistTypeStr[hal]);
if not(hal in [al_pure_assembler,al_dwarf_frame]) then
writetree(current_asmdata.asmlists[hal])
else
begin
{ write routines using the target-specific external assembler
writer, filtered using the LLVM module-level assembly
decorator }
decorator:=TLLVMModuleInlineAssemblyDecorator.Create;
writer.decorator:=decorator;
a:=GetExternalGnuAssemblerWithAsmInfoWriter(asminfo,writer);
a.WriteTree(current_asmdata.asmlists[hal]);
writer.decorator:=nil;
decorator.free;
a.free;
end;
writer.AsmWriteLn(asminfo^.comment+'End asmlist '+AsmlistTypeStr[hal]);
end;
writer.AsmLn;
end;
procedure TLLVMAssember.WriteFunctionInlineAsmList(list: tasmlist);
var
a: TExternalAssembler;
begin
if not assigned(ffuncinlasmdecorator) then
ffuncinlasmdecorator:=TLLVMFunctionInlineAssemblyDecorator.create;
if assigned(writer.decorator) then
internalerror(2016110201);
writer.decorator:=ffuncinlasmdecorator;
a:=GetExternalGnuAssemblerWithAsmInfoWriter(asminfo,writer);
a.WriteTree(list);
a.free;
writer.decorator:=nil;
end;
{****************************************************************************}
{ LLVM Instruction Writer }
{****************************************************************************}
constructor TLLVMInstrWriter.create(_owner: TLLVMAssember);
begin
inherited create;
owner := _owner;
end;
{****************************************************************************}
{ clang Assember }
{****************************************************************************}
function TLLVMClangAssember.MakeCmdLine: TCmdStr;
var
wpostr,
optstr: TCmdStr;
begin
wpostr:='';
if cs_lto in current_settings.moduleswitches then
begin
case fnextpass of
0:
begin
ObjFileName:=ChangeFileExt(ObjFileName,'.bc');
wpostr:=' -flto';
end;
1:
begin
ObjFileName:=ChangeFileExt(ObjFileName,'.o');
end;
end;
end;
result:=inherited;
if cs_opt_level3 in current_settings.optimizerswitches then
optstr:='-O3'
else if cs_opt_level2 in current_settings.optimizerswitches then
optstr:='-O2'
else if cs_opt_level1 in current_settings.optimizerswitches then
optstr:='-O1'
else
optstr:='-O0';
optstr:=optstr+wpostr;
{ stack frame elimination }
if not(cs_opt_stackframe in current_settings.optimizerswitches) then
optstr:=optstr+' -fno-omit-frame-pointer'
else
optstr:=optstr+' -fomit-frame-pointer';
{ fast math }
if cs_opt_fastmath in current_settings.optimizerswitches then
optstr:=optstr+' -ffast-math';
{ smart linking }
if cs_create_smart in current_settings.moduleswitches then
optstr:=optstr+' -fdata-sections -ffunction-sections';
{ pic }
if cs_create_pic in current_settings.moduleswitches then
optstr:=optstr+' -fpic'
else if not(target_info.system in systems_darwin) then
optstr:=optstr+' -static'
else
optstr:=optstr+' -mdynamic-no-pic';
if fputypestrllvm[current_settings.fputype]<>'' then
optstr:=optstr+' -m'+fputypestrllvm[current_settings.fputype];
{ restrict march to aarch64 for now to fix x86_64 compilation failure }
if (cputypestr[current_settings.cputype]<>'')
and (target_info.system in [system_aarch64_darwin, system_aarch64_linux]) then
optstr:=optstr+' -march='+cputypestr[current_settings.cputype];
if ([cs_sanitize_address]*current_settings.moduleswitches)<>[] then
begin
optstr:=optstr+' -fsanitize=';
if cs_sanitize_address in current_settings.moduleswitches then
begin
optstr:=optstr+'address';
end;
end;
replace(result,'$OPT',optstr);
inc(fnextpass);
end;
function TLLVMClangAssember.DoAssemble: boolean;
begin
fnextpass:=0;
result:=inherited;
end;
function TLLVMClangAssember.RerunAssembler: boolean;
begin
result:=
(cs_lto in current_settings.moduleswitches) and
(fnextpass<=1);
end;
function TLLVMClangAssember.DoPipe: boolean;
begin
result:=
not(cs_lto in current_settings.moduleswitches) and
inherited;
end;
const
as_clang_llvm_info : tasminfo =
(
id : as_clang_llvm;
idtxt : 'CLANG-LLVM';
asmbin : 'clang';
asmcmd: '-x ir $OPT -target $TRIPLET -c -o $OBJ $ASM $EXTRAOPT';
supported_targets : [system_x86_64_linux,system_aarch64_linux,system_arm_linux];
flags : [af_smartlink_sections,af_llvm];
labelprefix : '.L';
labelmaxlen : -1;
comment : '; ';
dollarsign: '$';
);
as_clang_llvm_darwin_info : tasminfo =
(
id : as_clang_llvm_darwin;
idtxt : 'CLANG-LLVM-DARWIN';
asmbin : 'clang';
asmcmd: '-x ir $OPT -target $TRIPLET -c -o $OBJ $ASM $EXTRAOPT';
supported_targets : systems_darwin;
flags : [af_smartlink_sections,af_llvm];
labelprefix : 'L';
labelmaxlen : -1;
comment : '; ';
dollarsign: '$';
);
begin
RegisterAssembler(as_clang_llvm_info,TLLVMClangAssember);
RegisterAssembler(as_clang_llvm_darwin_info,TLLVMClangAssember);
end.