mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-27 00:03:43 +02:00
317 lines
10 KiB
ObjectPascal
317 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,
|
|
aasmtai,
|
|
aggas,
|
|
cpubase,cpuinfo;
|
|
|
|
type
|
|
TAArch64InstrWriter=class(TCPUInstrWriter)
|
|
procedure WriteInstruction(hp : tai);override;
|
|
end;
|
|
|
|
TAArch64Assembler=class(TGNUassembler)
|
|
constructor create(smart: boolean); override;
|
|
end;
|
|
|
|
TAArch64AppleAssembler=class(TAppleGNUassembler)
|
|
constructor create(smart: boolean); override;
|
|
function MakeCmdLine: TCmdStr; 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,
|
|
systems,
|
|
assemble,
|
|
aasmcpu,
|
|
itcpugas,
|
|
cgbase,cgutils;
|
|
|
|
|
|
{****************************************************************************}
|
|
{ AArch64 Assembler writer }
|
|
{****************************************************************************}
|
|
|
|
constructor TAArch64Assembler.create(smart: boolean);
|
|
begin
|
|
inherited create(smart);
|
|
InstrWriter := TAArch64InstrWriter.create(self);
|
|
end;
|
|
|
|
{****************************************************************************}
|
|
{ Apple AArch64 Assembler writer }
|
|
{****************************************************************************}
|
|
|
|
constructor TAArch64AppleAssembler.create(smart: boolean);
|
|
begin
|
|
inherited create(smart);
|
|
InstrWriter := TAArch64InstrWriter.create(self);
|
|
end;
|
|
|
|
function TAArch64AppleAssembler.MakeCmdLine: TCmdStr;
|
|
begin
|
|
{ 'as' calls through to clang for aarch64, and that one only supports
|
|
reading from standard input in case "-" is specified as input file
|
|
(in which case you also have to specify the language via -x) }
|
|
result:=inherited;
|
|
{$ifdef hasunix}
|
|
if DoPipe then
|
|
result:=result+' -x assembler -'
|
|
{$endif}
|
|
end;
|
|
|
|
|
|
{****************************************************************************}
|
|
{ Helper routines for Instruction Writer }
|
|
{****************************************************************************}
|
|
|
|
function getreferencestring(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_asm.id=as_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_asm.id=as_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(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(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(taicpu(hp),i,taicpu(hp).oper[i]^);
|
|
sep:=',';
|
|
end;
|
|
end;
|
|
owner.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_gas_darwin_info : tasminfo =
|
|
(
|
|
id : as_darwin;
|
|
idtxt : 'AS-Darwin';
|
|
asmbin : 'as';
|
|
asmcmd : '-o $OBJ $EXTRAOPT $ASM -arch arm64';
|
|
supported_targets : [system_aarch64_darwin];
|
|
flags : [af_needar,af_smartlink_sections,af_supports_dwarf,af_stabs_use_function_absolute_addresses];
|
|
labelprefix : 'L';
|
|
comment : '# ';
|
|
dollarsign: '$';
|
|
);
|
|
|
|
|
|
begin
|
|
RegisterAssembler(as_aarch64_gas_info,TAArch64Assembler);
|
|
RegisterAssembler(as_aarch64_gas_darwin_info,TAArch64AppleAssembler);
|
|
end.
|