fpc/compiler/aarch64/agcpugas.pas
Jonas Maebe 7c594b0288 + added support for using Clang as an assembler, and make it the default
for all non-ppc(32/64) Darwin platforms
   o pass the macosx-version-min/iphoneos-version-min to clang as an assembler,
     so that it properly sets this information starting with Xcode 7 (solves
     errors when targeting the iOS simulator, and warnings about object files
     being compiled for a different OS X version when targeting (Mac) OS X)
   o the old assembler is still selectable via -Aas-darwin (required with
     Xcode 3.1.x and older)
   o since the first Xcode version that shipped with Clang is Xcode 3.2, which
     is available for Mac OS X 10.6, most users should not encounter any issues
     with the new default (in fact, it fixes some tests for x86 because Clang
     supports some instructions that "as" doesn't). Clang does not support
     Stabs however, so -gs does require the use of -Aas-darwin

git-svn-id: trunk@31830 -
2015-09-25 18:31:54 +00:00

303 lines
10 KiB
ObjectPascal

{
Copyright (c) 2003,2014 by Florian Klaempfl and Jonas Maebe
This unit implements an asm for AArch64
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.
****************************************************************************
}
{ This unit implements the GNU Assembler writer for AArch64
}
unit agcpugas;
{$i fpcdefs.inc}
interface
uses
globtype,systems,
aasmtai,
aggas,
cpubase,cpuinfo;
type
TAArch64InstrWriter=class(TCPUInstrWriter)
procedure WriteInstruction(hp : tai);override;
end;
TAArch64Assembler=class(TGNUassembler)
constructor create(info: pasminfo; smart: boolean); override;
end;
TAArch64AppleAssembler=class(TAppleGNUassembler)
constructor create(info: pasminfo; smart: boolean); override;
end;
const
gas_shiftmode2str : array[tshiftmode] of string[4] = (
'','lsl','lsr','asr',
'uxtb','uxth','uxtw','uxtx',
'sxtb','sxth','sxtw','sxtx');
const
cputype_to_gas_march : array[tcputype] of string = (
'', // cpu_none
'armv8'
);
implementation
uses
cutils,globals,verbose,
assemble,
aasmcpu,
itcpugas,
cgbase,cgutils;
{****************************************************************************}
{ AArch64 Assembler writer }
{****************************************************************************}
constructor TAArch64Assembler.create(info: pasminfo; smart: boolean);
begin
inherited;
InstrWriter := TAArch64InstrWriter.create(self);
end;
{****************************************************************************}
{ Apple AArch64 Assembler writer }
{****************************************************************************}
constructor TAArch64AppleAssembler.create(info: pasminfo; smart: boolean);
begin
inherited;
InstrWriter := TAArch64InstrWriter.create(self);
end;
{****************************************************************************}
{ Helper routines for Instruction Writer }
{****************************************************************************}
function getreferencestring(asminfo: pasminfo; var ref : treference) : string;
const
darwin_addrpage2str: array[addr_page..addr_gotpageoffset] of string[11] =
('@PAGE','@PAGEOFF','@GOTPAGE','@GOTPAGEOFF');
linux_addrpage2str: array[addr_page..addr_gotpageoffset] of string[10] =
('',':lo12:',':got:',':got_lo12:');
begin
if ref.base=NR_NO then
begin
case ref.refaddr of
addr_gotpage,
addr_page,
addr_gotpageoffset,
addr_pageoffset:
begin
if not assigned(ref.symbol) or
(ref.base<>NR_NO) or
(ref.index<>NR_NO) or
(ref.shiftmode<>SM_None) or
(ref.offset<>0) then
internalerror(2014121501);
if target_info.system in systems_darwin then
result:=ref.symbol.name+darwin_addrpage2str[ref.refaddr]
else
result:=linux_addrpage2str[ref.refaddr]+ref.symbol.name
end
else
internalerror(2015022301);
end
end
else
begin
result:='['+gas_regname(ref.base);
if ref.addressmode=AM_POSTINDEXED then
result:=result+']';
if ref.index<>NR_NO then
begin
if (ref.offset<>0) or
assigned(ref.symbol) then
internalerror(2014121504);
result:=result+', '+gas_regname(ref.index);
case ref.shiftmode of
SM_None: ;
SM_LSL,
SM_UXTW, SM_UXTX, SM_SXTW, SM_SXTX:
begin
result:=result+', '+gas_shiftmode2str[ref.shiftmode];
if (ref.shiftmode=SM_LSL) or
(ref.shiftimm<>0) then
result:=result+' #'+tostr(ref.shiftimm);
end
else
internalerror(2014121505);
end;
end
else
begin
if assigned(ref.symbol) then
begin
case ref.refaddr of
addr_gotpageoffset,
addr_pageoffset:
begin
if target_info.system in systems_darwin then
result:=result+', '+ref.symbol.name+darwin_addrpage2str[ref.refaddr]
else
result:=result+', '+linux_addrpage2str[ref.refaddr]+ref.symbol.name
end
else
{ todo: not yet generated/don't know syntax }
internalerror(2014121506);
end;
end
else
begin
if ref.refaddr<>addr_no then
internalerror(2014121506);
if (ref.offset<>0) then
result:=result+', #'+tostr(ref.offset);
end;
end;
case ref.addressmode of
AM_OFFSET:
result:=result+']';
AM_PREINDEXED:
result:=result+']!';
end;
end;
end;
function getopstr(asminfo: pasminfo; hp: taicpu; opnr: longint; const o: toper): string;
begin
case o.typ of
top_reg:
{ we cannot yet represent "umov w0, v4.s[0]" or "ins v4.d[0], x1",
so for now we use "s4" or "d4" instead -> translate here }
if ((hp.opcode=A_INS) or
(hp.opcode=A_UMOV)) and
(getregtype(hp.oper[opnr]^.reg)=R_MMREGISTER) then
begin
case getsubreg(hp.oper[opnr]^.reg) of
R_SUBMMS:
getopstr:='v'+tostr(getsupreg(hp.oper[opnr]^.reg))+'.S[0]';
R_SUBMMD:
getopstr:='v'+tostr(getsupreg(hp.oper[opnr]^.reg))+'.D[0]';
else
internalerror(2014122907);
end;
end
else
getopstr:=gas_regname(o.reg);
top_shifterop:
begin
getopstr:=gas_shiftmode2str[o.shifterop^.shiftmode];
if o.shifterop^.shiftimm<>0 then
getopstr:=getopstr+' #'+tostr(o.shifterop^.shiftimm)
end;
top_const:
if o.val>=0 then
getopstr:='#'+tostr(o.val)
else
getopstr:='#0x'+hexStr(o.val,16);
top_conditioncode:
getopstr:=cond2str[o.cc];
top_ref:
if is_calljmp(hp.opcode) then
begin
if o.ref^.refaddr<>addr_full then
internalerror(2014122220);
if not assigned(o.ref^.symbol) or
assigned(o.ref^.relsymbol) or
(o.ref^.base<>NR_NO) or
(o.ref^.index<>NR_NO) or
(o.ref^.offset<>0) then
internalerror(2014122221);
getopstr:=o.ref^.symbol.name;
end
else
getopstr:=getreferencestring(asminfo,o.ref^);
else
internalerror(2014121507);
end;
end;
procedure TAArch64InstrWriter.WriteInstruction(hp : tai);
var
op: TAsmOp;
s: string;
i: byte;
sep: string[3];
begin
op:=taicpu(hp).opcode;
s:=#9+gas_op2str[op]+oppostfix2str[taicpu(hp).oppostfix];
if taicpu(hp).condition<>C_NONE then
s:=s+'.'+cond2str[taicpu(hp).condition];
if taicpu(hp).ops<>0 then
begin
sep:=#9;
for i:=0 to taicpu(hp).ops-1 do
begin
// debug code
// writeln(s);
// writeln(taicpu(hp).fileinfo.line);
s:=s+sep+getopstr(owner.asminfo,taicpu(hp),i,taicpu(hp).oper[i]^);
sep:=',';
end;
end;
owner.writer.AsmWriteLn(s);
end;
const
as_aarch64_gas_info : tasminfo =
(
id : as_gas;
idtxt : 'AS';
asmbin : 'as';
asmcmd : '-o $OBJ $EXTRAOPT $ASM';
supported_targets : [system_aarch64_linux];
flags : [af_needar,af_smartlink_sections];
labelprefix : '.L';
comment : '// ';
dollarsign: '$';
);
as_aarch64_clang_darwin_info : tasminfo =
(
id : as_clang;
idtxt : 'CLANG';
asmbin : 'clang';
asmcmd : '-c -o $OBJ $EXTRAOPT -arch arm64 $DARWINVERSION -x assembler $ASM';
supported_targets : [system_aarch64_darwin];
flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
labelprefix : 'L';
comment : '# ';
dollarsign: '$';
);
begin
RegisterAssembler(as_aarch64_gas_info,TAArch64Assembler);
RegisterAssembler(as_aarch64_clang_darwin_info,TAArch64AppleAssembler);
end.