+ first cpubase implementation for aarch64

git-svn-id: trunk@22901 -
This commit is contained in:
florian 2012-11-01 17:18:25 +00:00
parent 0197b84b7f
commit ca75588989
12 changed files with 468 additions and 6 deletions

1
.gitattributes vendored
View File

@ -13,6 +13,7 @@ compiler/aarch64/a64nop.inc svneol=native#text/plain
compiler/aarch64/a64op.inc svneol=native#text/plain
compiler/aarch64/a64reg.dat svneol=native#text/plain
compiler/aarch64/a64tab.inc svneol=native#text/plain
compiler/aarch64/cpubase.pas svneol=native#text/plain
compiler/aarch64/cpuinfo.pas svneol=native#text/plain
compiler/aarch64/ra64con.inc svneol=native#text/plain
compiler/aarch64/ra64dwa.inc svneol=native#text/plain

View File

@ -233,3 +233,6 @@ H31,$04,$03,$1F,h31,31,31
S31,$04,$09,$1F,s31,31,31
D31,$04,$0a,$1F,d31,31,31
Q31,$04,$05,$1F,q31,31,31
NZCV,$05,$00,$00,nzcv,0,0

View File

@ -0,0 +1,450 @@
{
Copyright (c) 1998-2012 by Florian Klaempfl and Peter Vreman
Contains the base types for ARM64
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.
****************************************************************************
}
{ Base unit for processor information. This unit contains
enumerations of registers, opcodes, sizes, and other
such things which are processor specific.
}
unit cpubase;
{$define USEINLINE}
{$i fpcdefs.inc}
interface
uses
cutils,cclasses,
globtype,globals,
cpuinfo,
aasmbase,
cgbase
;
{*****************************************************************************
Assembler Opcodes
*****************************************************************************}
type
TAsmOp= {$i a64op.inc}
{ This should define the array of instructions as string }
op2strtable=array[tasmop] of string[11];
const
{ First value of opcode enumeration }
firstop = low(tasmop);
{ Last value of opcode enumeration }
lastop = high(tasmop);
{*****************************************************************************
Registers
*****************************************************************************}
type
{ Number of registers used for indexing in tables }
tregisterindex=0..{$i ra64nor.inc}-1;
const
{ Available Superregisters }
{$i ra64sup.inc}
R_SUBWHOLE = R_SUBQ;
{ Available Registers }
{$i ra64con.inc}
{ Integer Super registers first and last }
first_int_supreg = RS_X0;
first_int_imreg = $20;
{ Integer Super registers first and last }
first_fpu_supreg = RS_S0;
first_fpu_imreg = $20;
{ MM Super register first and last }
first_mm_supreg = RS_S0;
first_mm_imreg = $20;
{ TODO: Calculate bsstart}
regnumber_count_bsstart = 64;
regnumber_table : array[tregisterindex] of tregister = (
{$i ra64num.inc}
);
regstabs_table : array[tregisterindex] of shortint = (
{$i ra64sta.inc}
);
regdwarf_table : array[tregisterindex] of shortint = (
{$i ra64dwa.inc}
);
{ registers which may be destroyed by calls }
VOLATILE_INTREGISTERS = [RS_X0..RS_X18,RS_X29..RS_X30];
VOLATILE_MMREGISTERS = [RS_D0..RS_D7,RS_D16..RS_D31];
type
totherregisterset = set of tregisterindex;
{*****************************************************************************
Instruction post fixes
*****************************************************************************}
type
{ ARM instructions load/store and arithmetic instructions
can have several instruction post fixes which are collected
in this enumeration
}
TOpPostfix = (PF_None,
{ update condition flags }
PF_S,
{ load/store }
PF_B,PF_SB,PF_H,PF_SH
);
TOpPostfixes = set of TOpPostfix;
const
oppostfix2str : array[TOpPostfix] of string[2] = ('',
's',
'b','sb','h','sh');
{*****************************************************************************
Conditions
*****************************************************************************}
type
TAsmCond=(C_None,
C_EQ,C_NE,C_CS,C_CC,C_MI,C_PL,C_VS,C_VC,C_HI,C_LS,
C_GE,C_LT,C_GT,C_LE,C_AL,C_NV
);
TAsmConds = set of TAsmCond;
const
cond2str : array[TAsmCond] of string[2]=('',
'eq','ne','cs','cc','mi','pl','vs','vc','hi','ls',
'ge','lt','gt','le','al','nv'
);
uppercond2str : array[TAsmCond] of string[2]=('',
'EQ','NE','CS','CC','MI','PL','VS','VC','HI','LS',
'GE','LT','GT','LE','AL','NV'
);
{*****************************************************************************
Flags
*****************************************************************************}
type
TResFlags = (F_EQ,F_NE,F_CS,F_CC,F_MI,F_PL,F_VS,F_VC,F_HI,F_LS,
F_GE,F_LT,F_GT,F_LE);
{*****************************************************************************
Operands
*****************************************************************************}
taddressmode = (AM_OFFSET,AM_PREINDEXED,AM_POSTINDEXED);
tshiftmode = (SM_None,SM_LSL,SM_LSR,SM_ASR,SM_ROR,SM_RRX);
tupdatereg = (UR_None,UR_Update);
pshifterop = ^tshifterop;
tshifterop = record
shiftmode : tshiftmode;
rs : tregister;
shiftimm : byte;
end;
tcpumodeflag = (mfA, mfI, mfF);
tcpumodeflags = set of tcpumodeflag;
tspecialregflag = (srC, srX, srS, srF);
tspecialregflags = set of tspecialregflag;
{*****************************************************************************
Constants
*****************************************************************************}
const
max_operands = 6;
maxintregs = 15;
maxfpuregs = 8;
maxaddrregs = 0;
{*****************************************************************************
Operand Sizes
*****************************************************************************}
type
topsize = (S_NO,
S_B,S_W,S_L,S_BW,S_BL,S_WL,
S_IS,S_IL,S_IQ,
S_FS,S_FL,S_FX,S_D,S_Q,S_FV,S_FXX
);
{*****************************************************************************
Default generic sizes
*****************************************************************************}
const
{ Defines the default address size for a processor, }
OS_ADDR = OS_64;
{ the natural int size for a processor,
has to match osuinttype/ossinttype as initialized in psystem }
OS_INT = OS_64;
OS_SINT = OS_S64;
{ the maximum float size for a processor, }
OS_FLOAT = OS_F64;
{ the size of a vector register for a processor }
OS_VECTOR = OS_M128;
{*****************************************************************************
Generic Register names
*****************************************************************************}
NR_SP = NR_XZR;
RS_SP = RS_XZR;
NR_WSP = NR_WZR;
RS_WSP = RS_WZR;
{ Stack pointer register }
NR_STACK_POINTER_REG = NR_SP;
RS_STACK_POINTER_REG = RS_SP;
{ Frame pointer register (initialized in tarmprocinfo.init_framepointer) }
RS_FRAME_POINTER_REG: tsuperregister = RS_X29;
NR_FRAME_POINTER_REG: tregister = NR_X29;
{ Register for addressing absolute data in a position independant way,
such as in PIC code. The exact meaning is ABI specific. For
further information look at GCC source : PIC_OFFSET_TABLE_REGNUM
}
NR_PIC_OFFSET_REG = NR_X18;
{ Results are returned in this register (32-bit values) }
NR_FUNCTION_RETURN_REG = NR_X0;
RS_FUNCTION_RETURN_REG = RS_X0;
{ The value returned from a function is available in this register }
NR_FUNCTION_RESULT_REG = NR_FUNCTION_RETURN_REG;
RS_FUNCTION_RESULT_REG = RS_FUNCTION_RETURN_REG;
NR_FPU_RESULT_REG = NR_NO;
NR_MM_RESULT_REG = NR_D0;
NR_RETURN_ADDRESS_REG = NR_FUNCTION_RETURN_REG;
{ Offset where the parent framepointer is pushed }
PARENT_FRAMEPOINTER_OFFSET = 0;
NR_DEFAULTFLAGS = NR_NZCV;
RS_DEFAULTFLAGS = RS_NZCV;
{*****************************************************************************
GCC /ABI linking information
*****************************************************************************}
const
{ Registers which must be saved when calling a routine declared as
cppdecl, cdecl, stdcall, safecall, palmossyscall. The registers
saved should be the ones as defined in the target ABI and / or GCC.
This value can be deduced from the CALLED_USED_REGISTERS array in the
GCC source.
}
saved_standard_registers : array[0..9] of tsuperregister =
(RS_X19,RS_X20,RS_X21,RS_X22,RS_X23,RS_X24,RS_X25,RS_X26,RS_X27,RS_X28);
{ this is only for the generic code which is not used for this architecture }
saved_mm_registers : array[0..7] of tsuperregister = (RS_D8,RS_D9,RS_D10,RS_D11,RS_D12,RS_D13,RS_D14,RS_D15);
{*****************************************************************************
Helpers
*****************************************************************************}
{ Returns the tcgsize corresponding with the size of reg.}
function reg_cgsize(const reg: tregister) : tcgsize;
function cgsize2subreg(regtype: tregistertype; s:Tcgsize):Tsubregister;
function is_calljmp(o:tasmop):boolean;{$ifdef USEINLINE}inline;{$endif USEINLINE}
procedure inverse_flags(var f: TResFlags);
function flags_to_cond(const f: TResFlags) : TAsmCond;
function findreg_by_number(r:Tregister):tregisterindex;
function std_regnum_search(const s:string):Tregister;
function std_regname(r:Tregister):string;
function inverse_cond(const c: TAsmCond): TAsmCond; {$ifdef USEINLINE}inline;{$endif USEINLINE}
function conditions_equal(const c1, c2: TAsmCond): boolean; {$ifdef USEINLINE}inline;{$endif USEINLINE}
procedure shifterop_reset(var so : tshifterop); {$ifdef USEINLINE}inline;{$endif USEINLINE}
function dwarf_reg(r:tregister):shortint;
implementation
uses
systems,rgBase,verbose;
const
std_regname_table : TRegNameTable = (
{$i ra64std.inc}
);
regnumber_index : array[tregisterindex] of tregisterindex = (
{$i ra64rni.inc}
);
std_regname_index : array[tregisterindex] of tregisterindex = (
{$i ra64sri.inc}
);
function cgsize2subreg(regtype: tregistertype; s:Tcgsize):Tsubregister;
begin
case regtype of
R_MMREGISTER:
begin
case s of
OS_F32:
cgsize2subreg:=R_SUBFS;
OS_F64:
cgsize2subreg:=R_SUBFD;
else
internalerror(2009112701);
end;
end;
else
cgsize2subreg:=R_SUBWHOLE;
end;
end;
function reg_cgsize(const reg: tregister): tcgsize;
begin
case getregtype(reg) of
R_INTREGISTER :
reg_cgsize:=OS_32;
R_FPUREGISTER :
reg_cgsize:=OS_F80;
R_MMREGISTER :
begin
case getsubreg(reg) of
R_SUBFD,
R_SUBWHOLE:
result:=OS_F64;
R_SUBFS:
result:=OS_F32;
else
internalerror(2009112903);
end;
end;
else
internalerror(200303181);
end;
end;
function is_calljmp(o:tasmop):boolean;{$ifdef USEINLINE}inline;{$endif USEINLINE}
begin
{ This isn't 100% perfect because the arm allows jumps also by writing to PC=R15.
To overcome this problem we simply forbid that FPC generates jumps by loading R15 }
is_calljmp:= o in [A_B,A_BLR,A_RET];
end;
procedure inverse_flags(var f: TResFlags);
const
inv_flags: array[TResFlags] of TResFlags =
(F_NE,F_EQ,F_CC,F_CS,F_PL,F_MI,F_VC,F_VS,F_LS,F_HI,
F_LT,F_GE,F_LE,F_GT);
begin
f:=inv_flags[f];
end;
function flags_to_cond(const f: TResFlags) : TAsmCond;
const
flag_2_cond: array[F_EQ..F_LE] of TAsmCond =
(C_EQ,C_NE,C_CS,C_CC,C_MI,C_PL,C_VS,C_VC,C_HI,C_LS,
C_GE,C_LT,C_GT,C_LE);
begin
if f>high(flag_2_cond) then
internalerror(200112301);
result:=flag_2_cond[f];
end;
function findreg_by_number(r:Tregister):tregisterindex;
begin
result:=rgBase.findreg_by_number_table(r,regnumber_index);
end;
function std_regnum_search(const s:string):Tregister;
begin
result:=regnumber_table[findreg_by_name_table(s,std_regname_table,std_regname_index)];
end;
function std_regname(r:Tregister):string;
var
p : tregisterindex;
begin
p:=findreg_by_number_table(r,regnumber_index);
if p<>0 then
result:=std_regname_table[p]
else
result:=generic_regname(r);
end;
procedure shifterop_reset(var so : tshifterop);{$ifdef USEINLINE}inline;{$endif USEINLINE}
begin
FillChar(so,sizeof(so),0);
end;
function inverse_cond(const c: TAsmCond): TAsmCond; {$ifdef USEINLINE}inline;{$endif USEINLINE}
const
inverse: array[TAsmCond] of TAsmCond=(C_None,
C_NE,C_EQ,C_CC,C_CS,C_PL,C_MI,C_VC,C_VS,C_LS,C_HI,
C_LT,C_GE,C_LE,C_GT,C_None,C_None
);
begin
result := inverse[c];
end;
function conditions_equal(const c1, c2: TAsmCond): boolean; {$ifdef USEINLINE}inline;{$endif USEINLINE}
begin
result := c1 = c2;
end;
function dwarf_reg(r:tregister):shortint;
begin
result:=regdwarf_table[findreg_by_number(r)];
if result=-1 then
internalerror(200603251);
end;
end.

View File

@ -224,3 +224,4 @@ NR_H31 = tregister($0403001F);
NR_S31 = tregister($0409001F);
NR_D31 = tregister($040a001F);
NR_Q31 = tregister($0405001F);
NR_NZCV = tregister($05000000);

View File

@ -223,4 +223,5 @@
31,
31,
31,
31
31,
0

View File

@ -1,2 +1,2 @@
{ don't edit, this file is generated from a64reg.dat }
225
226

View File

@ -223,4 +223,5 @@ tregister($0401001F),
tregister($0403001F),
tregister($0409001F),
tregister($040a001F),
tregister($0405001F)
tregister($0405001F),
tregister($05000000)

View File

@ -223,4 +223,5 @@
208,
213,
218,
223
223,
225

View File

@ -96,6 +96,7 @@
101,
106,
111,
225,
69,
74,
119,

View File

@ -223,4 +223,5 @@
31,
31,
31,
31
31,
0

View File

@ -223,4 +223,5 @@
'h31',
's31',
'd31',
'q31'
'q31',
'nzcv'

View File

@ -224,3 +224,4 @@ RS_H31 = $1F;
RS_S31 = $1F;
RS_D31 = $1F;
RS_Q31 = $1F;
RS_NZCV = $00;