* started to integrate the code of David Zhang's MIPS code from fpc-mips on sf into fpc trunk

git-svn-id: trunk@14219 -
This commit is contained in:
florian 2009-11-19 22:07:10 +00:00
parent 79ec403774
commit e5ebb2a26e
13 changed files with 2914 additions and 183 deletions

5
.gitattributes vendored
View File

@ -234,10 +234,15 @@ compiler/m68k/ra68k.pas svneol=native#text/plain
compiler/m68k/ra68kmot.pas svneol=native#text/plain
compiler/m68k/rgcpu.pas svneol=native#text/plain
compiler/mips/aasmcpu.pas svneol=native#text/plain
compiler/mips/cgcpu.pas svneol=native#text/pascal
compiler/mips/cpubase.pas svneol=native#text/plain
compiler/mips/cpuinfo.pas svneol=native#text/plain
compiler/mips/cpupara.pas svneol=native#text/pascal
compiler/mips/cpupi.pas svneol=native#text/pascal
compiler/mips/itcpugas.pas svneol=native#text/plain
compiler/mips/mipsreg.dat svneol=native#text/plain
compiler/mips/opcode.inc svneol=native#text/plain
compiler/mips/rgcpu.pas svneol=native#text/pascal
compiler/mips/rmipscon.inc svneol=native#text/plain
compiler/mips/rmipsdwf.inc svneol=native#text/plain
compiler/mips/rmipsgas.inc svneol=native#text/plain

View File

@ -70,7 +70,7 @@ interface
addr_full,
addr_pic,
addr_pic_no_got
{$IF defined(POWERPC) or defined(POWERPC64) or defined(SPARC)}
{$IF defined(POWERPC) or defined(POWERPC64) or defined(SPARC) or defined(MIPS)}
,
addr_low, // bits 48-63
addr_high, // bits 32-47

View File

@ -326,6 +326,7 @@ unit cgobj;
procedure a_jmp_name(list : TAsmList;const s : string); virtual; abstract;
procedure a_jmp_always(list : TAsmList;l: tasmlabel); virtual; abstract;
{$ifdef cpuflags}
procedure a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel); virtual; abstract;
{# Depending on the value to check in the flags, either sets the register reg to one (if the flag is set)
@ -333,6 +334,7 @@ unit cgobj;
}
procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: tresflags; reg: TRegister); virtual; abstract;
procedure g_flags2ref(list: TAsmList; size: TCgSize; const f: tresflags; const ref:TReference); virtual;
{$endif cpuflags}
{
This routine tries to optimize the op_const_reg/ref opcode, and should be
@ -3463,6 +3465,7 @@ implementation
end;
{$ifdef cpuflags}
procedure tcg.g_flags2ref(list: TAsmList; size: TCgSize; const f: tresflags; const ref:TReference);
var
@ -3472,6 +3475,7 @@ implementation
g_flags2reg(list,size,f,tmpreg);
a_load_reg_ref(list,size,size,tmpreg,ref);
end;
{$endif cpuflags}
procedure tcg.g_maybe_testself(list : TAsmList;reg:tregister);

View File

@ -80,7 +80,9 @@ unit cgutils;
loc : TCGLoc;
size : TCGSize;
case TCGLoc of
{$ifdef cpuflags}
LOC_FLAGS : (resflags : tresflags);
{$endif cpuflags}
LOC_CONSTANT : (
case longint of
{$ifdef FPC_BIG_ENDIAN}

View File

@ -120,6 +120,15 @@
{$define cpunodefaultint}
{$endif avr}
{$ifdef mips}
{$define cpu32bitalu}
{$define cpu32bitaddr}
{ $define cpuflags}
{$define cputargethasfixedstack}
{$define cpurequiresproperalignment}
{$define cpumm}
{$endif mips}
{$IFDEF MACOS}
{$DEFINE USE_FAKE_SYSUTILS}
{$ENDIF MACOS}

View File

@ -401,6 +401,11 @@ interface
optimizecputype : cpuinfo.cpu_avr;
fputype : fpu_none;
{$endif avr}
{$ifdef mips}
cputype : cpu_mips32;
optimizecputype : cpu_mips32;
fputype : fpu_mips2;
{$endif mips}
asmmode : asmmode_standard;
interfacetype : it_interfacecom;
defproccall : pocall_default;

1972
compiler/mips/cgcpu.pas Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
{
Copyright (c) 1998-2002 by Florian Klaempfl and Peter Vreman
Contains the base types for the ARM
Contains the base types for MIPS
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
@ -43,28 +43,7 @@ unit cpubase;
*****************************************************************************}
type
TAsmOp=(A_ABS_D,A_ABS_S,A_ADD,A_ADD_D,A_ADD_S,A_ADDI,A_ADDIU,A_ADDU,
A_AND,A_ANDI,A_BC1F,A_BC1FL,A_BC1T,A_BC1TL,A_BC2F,A_BC2FL,
A_BC2T,A_BC2TL,A_BEQ,A_BEQL,A_BGEZ,A_BGEZAL,A_BGEZALL,A_BGEZL,
A_BGTZ,A_BGTZL,A_BLEZ,A_BLEZL,A_BLTZ,A_BLTZAL,A_BLTZALL,A_BLTZL,
A_BNE,A_BNEL,A_BREAK,A_C_cond_D,A_C_cond_S,A_CACHE,A_CEIL_W_D,A_CEIL_W_S,
A_CFC1,A_CFC2,A_CLO,A_CLZ,A_COP2,A_CTC1,A_CTC2,A_CVT_D_S,
A_CVT_D_W,A_CVT_S_D,A_CVT_S_W,A_CVT_W_D,A_CVT_W_S,A_DIV,A_DIV_D,A_DIV_S,
A_DIVU,A_ERET,A_FLOOR_W_D,A_FLOOR_W_S,A_J,A_JAL,A_JALR,A_JR,
A_LB,A_LBU,A_LDC1,A_LDC2,A_LH,A_LHU,A_LL,A_LUI,
A_LW,A_LWC1,A_LWC2,A_LWL,A_LWR,A_MADD,A_MADDU,A_MFC0,
A_MFC1,A_MFC2,A_MFHI,A_MFLO,A_MOV_D,A_MOV_S,A_MOVF,A_MOVF_D,
A_MOVF_S,A_MOVN,A_MOVN_D,A_MOVN_S,A_MOVT,A_MOVT_D,A_MOVT_S,A_MOVZ,
A_MOVZ_D,A_MOVZ_S,A_MSUB,A_MSUBU,A_MTC0,A_MTC1,A_MTC2,A_MTHI,
A_MTLO,A_MUL,A_MUL_D,A_MUL_S,A_MULT,A_MULTU,A_NEG_D,A_NEG_S,
A_NOR,A_OR,A_ORI,A_PREF,A_ROUND_W_D,A_ROUND_W_S,A_SB,A_SC,
A_SDC1,A_SDC2,A_SH,A_SLL,A_SLLV,A_SLT,A_SLTI,A_SLTIU,
A_SLTU,A_SQRT_D,A_SQRT_S,A_SRA,A_SRAV,A_SRL,A_SRLV,A_SSNOP,
A_SUB,A_SUB_D,A_SUB_S,A_SUBU,A_SW,A_SWC1,A_SWC2,A_SWL,
A_SWR,A_SYNC,A_SYSCALL,A_TEQ,A_TEQI,A_TGE,A_TGEI,A_TGEIU,
A_TGEU,A_TLBP,A_TLBR,A_TLBWI,A_TLBWR,A_TLT,A_TLTI,A_TLTIU,
A_TLTU,A_TNE,A_TNEI,A_TRUNC_W_D,A_TRUNC_W_S,A_WAIT,A_XOR,A_XORI
);
TAsmOp=({$i opcode.inc});
{ This should define the array of instructions as string }
op2strtable=array[tasmop] of string[11];
@ -126,94 +105,28 @@ unit cpubase;
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
or floating point single }
PF_S,
{ floating point size }
PF_D,PF_E,PF_P,PF_EP,
{ load/store }
PF_B,PF_SB,PF_BT,PF_H,PF_SH,PF_T,
{ multiple load/store address modes }
PF_IA,PF_IB,PF_DA,PF_DB,PF_FD,PF_FA,PF_ED,PF_EA
);
TRoundingMode = (RM_None,RM_P,RM_M,RM_Z);
const
cgsize2fpuoppostfix : array[OS_NO..OS_F128] of toppostfix = (
PF_E,
PF_None,PF_None,PF_None,PF_None,PF_None,PF_None,PF_None,PF_None,PF_None,PF_None,
PF_S,PF_D,PF_E,PF_None,PF_None);
oppostfix2str : array[TOpPostfix] of string[2] = ('',
's',
'd','e','p','ep',
'b','sb','bt','h','sh','t',
'ia','ib','da','db','fd','fa','ed','ea');
roundingmode2str : array[TRoundingMode] of string[1] = ('',
'p','m','z');
{*****************************************************************************
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
C_EQ, C_NE, C_LT, C_LE, C_GT, C_GE, C_LTU, C_LEU, C_GTU, C_GEU,
C_FEQ, {Equal}
C_FNE, {Not Equal}
C_FGT, {Greater}
C_FLT, {Less}
C_FGE, {Greater or Equal}
C_FLE {Less or Equal}
);
const
cond2str : array[TAsmCond] of string[2]=('',
'eq','ne','cs','cc','mi','pl','vs','vc','hi','ls',
'ge','lt','gt','le','al','nv'
cond2str : array[TAsmCond] of string[3]=('',
'eq','ne','lt','le','gt','ge','ltu','leu','gtu','geu',
'feq','fne','fgt','flt','fge','fle'
);
uppercond2str : array[TAsmCond] of string[2]=('',
'EQ','NE','CS','CC','MI','PL','VS','VC','HI','LS',
'GE','LT','GT','LE','AL','NV'
);
inverse_cond : 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
);
{*****************************************************************************
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;
{*****************************************************************************
Constants
*****************************************************************************}
@ -224,7 +137,7 @@ unit cpubase;
{ Constant defining possibly all registers which might require saving }
ALL_OTHERREGISTERS = [];
general_superregisters = [RS_R0..RS_PC];
general_superregisters = [RS_R0..RS_R31];
{ Table of registers which can be allocated by the code generator
internally, when generating the code.
@ -238,7 +151,7 @@ unit cpubase;
{ passing on ABI's that define this) }
{ c_countusableregsxxx = amount of registers in the usableregsxxx set }
maxintregs = 15;
maxintregs = 31;
{ to determine how many registers to use for regvars }
maxintscratchregs = 3;
usableregsint = [RS_R4..RS_R10];
@ -300,44 +213,61 @@ unit cpubase;
Generic Register names
*****************************************************************************}
{ Stack pointer register }
NR_STACK_POINTER_REG = NR_R13;
RS_STACK_POINTER_REG = RS_R13;
{ Frame pointer register }
RS_FRAME_POINTER_REG = RS_R11;
NR_FRAME_POINTER_REG = NR_R11;
{ 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_R9;
STK2_PTR = NR_R23;
NR_GP = NR_R28;
NR_SP = NR_R29;
NR_S8 = NR_R30;
NR_FP = NR_R30;
NR_RA = NR_R31;
RS_GP = RS_R28;
RS_SP = RS_R29;
RS_S8 = RS_R30;
RS_FP = RS_R30;
RS_RA = RS_R31;
{# Stack pointer register }
NR_STACK_POINTER_REG = NR_SP;
RS_STACK_POINTER_REG = RS_SP;
{# Frame pointer register }
NR_FRAME_POINTER_REG = NR_FP;
RS_FRAME_POINTER_REG = RS_FP;
NR_RETURN_ADDRESS_REG = NR_R7;
{ the return_result_reg, is used inside the called function to store its return
value when that is a scalar value otherwise a pointer to the address of the
result is placed inside it }
{ Results are returned in this register (32-bit values) }
NR_FUNCTION_RETURN_REG = NR_R0;
RS_FUNCTION_RETURN_REG = RS_R0;
NR_FUNCTION_RETURN_REG = NR_R2;
RS_FUNCTION_RETURN_REG = RS_R2;
{ Low part of 64bit return value }
NR_FUNCTION_RETURN64_LOW_REG = NR_R0;
RS_FUNCTION_RETURN64_LOW_REG = RS_R0;
NR_FUNCTION_RETURN64_LOW_REG = NR_R2;
RS_FUNCTION_RETURN64_LOW_REG = RS_R2;
{ High part of 64bit return value }
NR_FUNCTION_RETURN64_HIGH_REG = NR_R1;
RS_FUNCTION_RETURN64_HIGH_REG = RS_R1;
NR_FUNCTION_RETURN64_HIGH_REG = NR_R3;
RS_FUNCTION_RETURN64_HIGH_REG = RS_R3;
{ 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_FUNCTION_RESULT_REG = NR_R2;
RS_FUNCTION_RESULT_REG = RS_R2;
{ The lowh part of 64bit value returned from a function }
NR_FUNCTION_RESULT64_LOW_REG = NR_FUNCTION_RETURN64_LOW_REG;
RS_FUNCTION_RESULT64_LOW_REG = RS_FUNCTION_RETURN64_LOW_REG;
NR_FUNCTION_RESULT64_LOW_REG = NR_R2;
RS_FUNCTION_RESULT64_LOW_REG = RS_R2;
{ The high part of 64bit value returned from a function }
NR_FUNCTION_RESULT64_HIGH_REG = NR_FUNCTION_RETURN64_HIGH_REG;
RS_FUNCTION_RESULT64_HIGH_REG = RS_FUNCTION_RETURN64_HIGH_REG;
NR_FUNCTION_RESULT64_HIGH_REG = NR_R3;
RS_FUNCTION_RESULT64_HIGH_REG = RS_R3;
NR_FPU_RESULT_REG = NR_F0;
NR_MM_RESULT_REG = NR_NO;
NR_RETURN_ADDRESS_REG = NR_FUNCTION_RETURN_REG;
NR_TCR0 = NR_R15;
NR_TCR1 = NR_R3;
NR_TCR10 = NR_R20;
NR_TCR11 = NR_R21;
NR_TCR12 = NR_R18;
NR_TCR13 = NR_R19;
{ Offset where the parent framepointer is pushed }
PARENT_FRAMEPOINTER_OFFSET = 0;
{*****************************************************************************
GCC /ABI linking information
@ -351,12 +281,12 @@ unit cpubase;
This value can be deduced from the CALLED_USED_REGISTERS array in the
GCC source.
}
saved_standard_registers : array[0..8] of tsuperregister =
(RS_R16,RS_R17,RS_R18,RS_R19,RS_R20,RS_R21,RS_R22,RS_R23,RS_R30);
saved_standard_registers : array[0..0] of tsuperregister =
(RS_NO);
{ this is only for the generic code which is not used for this architecture }
saved_mm_registers : array[0..0] of tsuperregister = (RS_NO);
{ Required parameter alignment when calling a routine declared as
stdcall and cdecl. The alignment value should be the one defined
by GCC or the target ABI.
@ -373,17 +303,12 @@ unit cpubase;
{ Returns the tcgsize corresponding with the size of reg.}
function reg_cgsize(const reg: tregister) : tcgsize;
function cgsize2subreg(s:Tcgsize):Tsubregister;
function cgsize2subreg(regtype: tregistertype; s:tcgsize):tsubregister;
function is_calljmp(o:tasmop):boolean;
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;
procedure shifterop_reset(var so : tshifterop);
function is_pc(const r : tregister) : boolean;
implementation
uses
@ -404,21 +329,27 @@ unit cpubase;
);
function cgsize2subreg(s:Tcgsize):Tsubregister;
function cgsize2subreg(regtype: tregistertype; s:tcgsize):tsubregister;
begin
cgsize2subreg:=R_SUBWHOLE;
if s in [OS_64,OS_S64] then
cgsize2subreg:=R_SUBQ
else
cgsize2subreg:=R_SUBWHOLE;
end;
function reg_cgsize(const reg: tregister): tcgsize;
const subreg2cgsize:array[Tsubregister] of Tcgsize =
(OS_NO,OS_8,OS_8,OS_16,OS_32,OS_64,OS_NO,OS_NO,OS_NO);
begin
case getregtype(reg) of
R_INTREGISTER :
reg_cgsize:=OS_32;
R_FPUREGISTER :
reg_cgsize:=OS_F80;
begin
if getsubreg(reg)=R_SUBFD then
result:=OS_F64
else
result:=OS_F32;
end;
else
internalerror(200303181);
end;
@ -435,29 +366,21 @@ unit cpubase;
end;
procedure inverse_flags(var f: TResFlags);
function inverse_cond(const c: TAsmCond): TAsmCond; {$ifdef USEINLINE}inline;{$endif USEINLINE}
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);
inverse: array[TAsmCond] of TAsmCond=(C_None,
C_EQ, C_NE, C_LT, C_LE, C_GT, C_GE, C_LTU, C_LEU, C_GTU, C_GEU,
C_FEQ, {Equal}
C_FNE, {Not Equal}
C_FGT, {Greater}
C_FLT, {Less}
C_FGE, {Greater or Equal}
C_FLE {Less or Equal}
);
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;
result := inverse[c];
end; function findreg_by_number(r:Tregister):tregisterindex;
begin
result:=rgBase.findreg_by_number_table(r,regnumber_index);
end;
@ -481,15 +404,4 @@ unit cpubase;
end;
procedure shifterop_reset(var so : tshifterop);
begin
FillChar(so,sizeof(so),0);
end;
function is_pc(const r : tregister) : boolean;
begin
is_pc:=(r=NR_R15);
end;
end.

View File

@ -32,13 +32,10 @@ Type
{ possible supported processors for this target }
tcputype =
(cpu_none,
mips32
cpu_mips32
);
tfputype =
(fpu_none,
fpu_fpu
);
tfputype =(fpu_none,fpu_soft,fpu_mips2,fpu_mips3);
Const
{# Size of native extended floating point type }
@ -63,7 +60,8 @@ Const
);
fputypestr : array[tfputype] of string[6] = ('',
'FPU'
'SOFT',
'FPU_MIPS2','FPU_MIPS3'
);
{ Supported optimizations, only used for information }

342
compiler/mips/cpupara.pas Normal file
View File

@ -0,0 +1,342 @@
{
Copyright (c) 1998-2002 by Florian Klaempfl and David Zhang
Calling conventions for the MIPSEL
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 cpupara;
{$i fpcdefs.inc}
interface
uses
globtype,
cclasses,
aasmtai,
cpubase,cpuinfo,
symconst,symbase,symsym,symtype,symdef,paramgr,parabase,cgbase;
type
TMIPSELParaManager=class(TParaManager)
function push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override;
function get_volatile_registers_int(calloption : tproccalloption):TCpuRegisterSet;override;
function get_volatile_registers_fpu(calloption : tproccalloption):TCpuRegisterSet;override;
{Returns a structure giving the information on the storage of the parameter
(which must be an integer parameter)
@param(nr Parameter number of routine, starting from 1)}
procedure getintparaloc(calloption : tproccalloption; nr : longint;var cgpara : TCGPara);override;
function create_paraloc_info(p : TAbstractProcDef; side: tcallercallee):longint;override;
function create_varargs_paraloc_info(p : TAbstractProcDef; varargspara:tvarargsparalist):longint;override;
private
procedure create_funcretloc_info(p : tabstractprocdef; side: tcallercallee);
procedure create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
var intparareg,parasize:longint);
end;
implementation
uses
cutils,verbose,systems,
defutil,
cgutils,cgobj;
type
tparasupregs = array[0..5] of tsuperregister;
pparasupregs = ^tparasupregs;
const
paraoutsupregs : tparasupregs = (RS_R4, RS_R5, RS_R6, RS_R7, RS_R8, RS_R9);
parainsupregs : tparasupregs = (RS_R4, RS_R5, RS_R6, RS_R7, RS_R8, RS_R9);
function TMIPSELParaManager.get_volatile_registers_int(calloption : tproccalloption):TCpuRegisterSet;
begin
result:=[RS_R16..RS_R23];
end;
function tMIPSELparamanager.get_volatile_registers_fpu(calloption : tproccalloption):TCpuRegisterSet;
begin
result:=[RS_F0..RS_F31];
end;
procedure TMIPSELParaManager.GetIntParaLoc(calloption : tproccalloption; nr : longint;var cgpara : tcgpara);
var
paraloc : pcgparalocation;
begin
if nr<1 then
InternalError(2002100806);
cgpara.reset;
cgpara.size:=OS_INT;
cgpara.intsize:=tcgsize2size[OS_INT];
cgpara.alignment:=std_param_align;
paraloc:=cgpara.add_location;
with paraloc^ do
begin
{ The six first parameters are passed into registers } {MIPS first four}
dec(nr);
if nr<6 then //MIPSEL nr<6
begin
loc:=LOC_REGISTER;
register:=newreg(R_INTREGISTER,(RS_R4+nr),R_SUBWHOLE);
end
else
begin
{ The other parameters are passed on the stack }
loc:=LOC_REFERENCE;
reference.index:=NR_STACK_POINTER_REG;
reference.offset:=92+(nr-6)*4;
end;
size:=OS_INT;
end;
end;
{ true if a parameter is too large to copy and only the address is pushed }
function tMIPSELparamanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
begin
result:=false;
{ var,out always require address }
if varspez in [vs_var,vs_out] then
begin
result:=true;
exit;
end;
case def.typ of
recorddef,
arraydef,
variantdef,
formaldef :
push_addr_param:=true;
objectdef :
result:=is_object(def);
stringdef :
result:=(tstringdef(def).stringtype in [st_shortstring,st_longstring]);
procvardef :
result:=(po_methodpointer in tprocvardef(def).procoptions);
setdef :
result:=not(is_smallset(def));
end;
end;
procedure tMIPSELparamanager.create_funcretloc_info(p : tabstractprocdef; side: tcallercallee);
var
retcgsize : tcgsize;
begin
{ Constructors return self instead of a boolean }
if (p.proctypeoption=potype_constructor) then
retcgsize:=OS_ADDR
else
retcgsize:=def_cgsize(p.returndef);
location_reset(p.funcretloc[side],LOC_INVALID,OS_NO);
p.funcretloc[side].size:=retcgsize;
{ void has no location }
if is_void(p.returndef) then
begin
p.funcretloc[side].loc:=LOC_VOID;
exit;
end;
{ Return in FPU register? }
if p.returndef.typ=floatdef then
begin
p.funcretloc[side].loc:=LOC_FPUREGISTER;
p.funcretloc[side].register:=NR_FPU_RESULT_REG;
if retcgsize=OS_F64 then
setsubreg(p.funcretloc[side].register,R_SUBFD);
p.funcretloc[side].size:=retcgsize;
end
else
{ Return in register? }
if not ret_in_param(p.returndef,p.proccalloption) then
begin
{$ifndef cpu64bit}
if retcgsize in [OS_64,OS_S64] then
begin
p.funcretloc[side].loc:=LOC_REGISTER;
{ high }
if side=callerside then
p.funcretloc[side].register64.reghi:=NR_FUNCTION_RESULT64_HIGH_REG
else
p.funcretloc[side].register64.reghi:=NR_FUNCTION_RETURN64_HIGH_REG;
{ low }
if side=callerside then
p.funcretloc[side].register64.reglo:=NR_FUNCTION_RESULT64_LOW_REG
else
p.funcretloc[side].register64.reglo:=NR_FUNCTION_RETURN64_LOW_REG;
end
else
{$endif cpu64bit}
begin
p.funcretloc[side].loc:=LOC_REGISTER;
p.funcretloc[side].size:=retcgsize;
if side=callerside then
p.funcretloc[side].register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,cgsize2subreg(R_INTREGISTER,retcgsize))
else
p.funcretloc[side].register:=newreg(R_INTREGISTER,RS_FUNCTION_RETURN_REG,cgsize2subreg(R_INTREGISTER,retcgsize));
end;
end
else
begin
p.funcretloc[side].loc:=LOC_REFERENCE;
p.funcretloc[side].size:=retcgsize;
end;
end;
var
param_offset:array[0..20] of ^Aint;
procedure tMIPSELparamanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee;paras:tparalist;
var intparareg,parasize:longint);
var
paraloc : pcgparalocation;
i : integer;
hp : tparavarsym;
paracgsize : tcgsize;
hparasupregs : pparasupregs;
paralen : longint;
begin
if side=callerside then
hparasupregs:=@paraoutsupregs
else
hparasupregs:=@parainsupregs;
for i:=0 to paras.count-1 do
begin
param_offset[i] := Nil;
hp:=tparavarsym(paras[i]);
{ currently only support C-style array of const,
there should be no location assigned to the vararg array itself }
if (p.proccalloption in [pocall_cdecl,pocall_cppdecl]) and
is_array_of_const(hp.vardef) then
begin
paraloc:=hp.paraloc[side].add_location;
{ hack: the paraloc must be valid, but is not actually used }
paraloc^.loc:=LOC_REGISTER;
paraloc^.register:=NR_R0;
paraloc^.size:=OS_ADDR;
break;
end;
if push_addr_param(hp.varspez,hp.vardef,p.proccalloption) then
paracgsize:=OS_ADDR
else
begin
paracgsize:=def_cgSize(hp.vardef);
if paracgsize=OS_NO then
paracgsize:=OS_ADDR;
end;
hp.paraloc[side].reset;
hp.paraloc[side].size:=paracgsize;
hp.paraloc[side].Alignment:=std_param_align;
paralen:=tcgsize2size[paracgsize];
hp.paraloc[side].intsize:=paralen;
while paralen>0 do
begin
paraloc:=hp.paraloc[side].add_location;
{ Floats are passed in int registers,
We can allocate at maximum 32 bits per register }
if paracgsize in [OS_64,OS_S64,OS_F32,OS_F64] then
paraloc^.size:=OS_32
else
paraloc^.size:=paracgsize;
{ ret in param? }
if vo_is_funcret in hp.varoptions then
begin
paraloc^.loc:=LOC_REFERENCE;
if side=callerside then
begin
paraloc^.reference.index := NR_STACK_POINTER_REG;
paraloc^.reference.offset:=target_info.first_parm_offset{1000}-12 - parasize;
end
else
begin
paraloc^.reference.index := NR_FRAME_POINTER_REG;
paraloc^.reference.offset:=target_info.first_parm_offset{1000}-4 - parasize;
param_offset[i] := @paraloc^.reference.offset;
end;
inc(parasize,align(tcgsize2size[paraloc^.size],sizeof(aint)));
end
else if (intparareg<=high(tparasupregs)) then
begin
paraloc^.loc:=LOC_REGISTER;
paraloc^.register:=newreg(R_INTREGISTER,hparasupregs^[intparareg],R_SUBWHOLE);
inc(intparareg);
end
else
begin
paraloc^.loc:=LOC_REFERENCE;
if side=callerside then
begin
paraloc^.reference.index := {NR_R17;//}NR_STACK_POINTER_REG;
paraloc^.reference.offset:=target_info.first_parm_offset{1000}-12 - parasize;
end
else
begin
paraloc^.reference.index := {NR_R18;//}NR_FRAME_POINTER_REG;
paraloc^.reference.offset:=target_info.first_parm_offset{1000}-4 - parasize;
param_offset[i] := @paraloc^.reference.offset;
end;
{ Parameters are aligned at 4 bytes }
inc(parasize,align(tcgsize2size[paraloc^.size],sizeof(aint)));
end;
dec(paralen,tcgsize2size[paraloc^.size]);
end;
end;
for i:=0 to paras.count-1 do
begin
if (side = calleeside) and (param_offset[i] <> nil) then
param_offset[i]^ := param_offset[i]^ + parasize - 8;
end;
end;
function TMIPSELParaManager.create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;
var
intparareg,
parasize : longint;
begin
intparareg:=0;
parasize:=0;
{ calculate the registers for the normal parameters }
create_paraloc_info_intern(p,callerside,p.paras,intparareg,parasize);
{ append the varargs }
create_paraloc_info_intern(p,callerside,varargspara,intparareg,parasize);
result:=parasize;
end;
function tMIPSELparamanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
var
intparareg,
parasize : longint;
begin
intparareg:=0;
parasize:=0;
create_paraloc_info_intern(p,side,p.paras,intparareg,parasize);
{ Create Function result paraloc }
create_funcretloc_info(p,side);
{ We need to return the size allocated on the stack }
result:=parasize;
end;
begin
ParaManager:=TMIPSELParaManager.create;
end.

76
compiler/mips/cpupi.pas Normal file
View File

@ -0,0 +1,76 @@
{
Copyright (c) 2002-2009 by Florian Klaempfl and David Zhang
This unit contains the CPU specific part of tprocinfo
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 cpupi;
{$i fpcdefs.inc}
interface
uses
cutils,
procinfo,cpuinfo,
psub;
type
TMIPSProcInfo=class(tcgprocinfo)
public
constructor create(aparent:tprocinfo);override;
function calc_stackframe_size:longint;override;
end;
implementation
uses
systems,globals,
tgobj,paramgr,symconst;
constructor tmipsprocinfo.create(aparent:tprocinfo);
begin
inherited create(aparent);
maxpushedparasize:=0;
end;
function TMIPSProcInfo.calc_stackframe_size:longint;
begin
{
Stackframe layout:
%fp
<locals>
<temp>
<arguments 6-n for calling>
%sp+92
<space for arguments 0-5> \
<return pointer for calling> | included in first_parm_offset
<register window save area for calling> /
%sp
Alignment must be the max available, as doubles require
8 byte alignment
}
result:=Align(tg.direction*tg.lasttemp+maxpushedparasize+target_info.first_parm_offset,current_settings.alignment.localalignmax);
end;
begin
cprocinfo:=TMIPSProcInfo;
end.

241
compiler/mips/opcode.inc Normal file
View File

@ -0,0 +1,241 @@
A_NONE,
A_P_STK2,
A_P_LW,
A_P_SET_NOREORDER,
A_P_SET_NOMACRO,
A_P_SET_MACRO,
A_P_SET_REORDER,
A_P_FRAME,
A_P_MASK,
A_P_FMASK,
A_P_SW,
A_SPARC8UNIMP,
A_NOP,
A_NOT,
A_NEG,
A_NEGU,
A_B,
A_LI,
A_DLI,
A_LA,
A_MOVE,
A_LB,
A_LBU,
A_LH,
A_LHU,
A_LW,
A_LWU,
A_LWL,
A_LWR,
A_LD,
A_LDL,
A_LDR,
A_LL,
A_LLD,
A_SB,
A_SH,
A_SW,
A_SWL,
A_SWR,
A_SD,
A_SDL,
A_SDR,
A_SC,
A_SCD,
A_SYNC,
A_ADDI,
A_DADDI,
A_ADDIU,
A_DADDIU,
A_SLTI,
A_SLTIU,
A_ANDI,
A_ORI,
A_XORI,
A_LUI,
A_DNEG,
A_DNEGU,
A_ADD,
A_DADD,
A_ADDU,
A_DADDU,
A_SUB,
A_DSUB,
A_SUBU,
A_DSUBU,
A_SLT,
A_SLTU,
A_AND,
A_OR,
A_XOR,
A_NOR,
A_MUL,
A_MULO,
A_MULOU,
A_DMUL,
A_DMULO,
A_DMULOU,
A_DIV,
A_DIVU,
A_DDIV,
A_DDIVU,
A_REM,
A_REMU,
A_DREM,
A_DREMU,
A_MULT,
A_DMULT,
A_MULTU,
A_DMULTU,
A_MFHI,
A_MTHI,
A_MFLO,
A_MTLO,
A_MULTG,
A_DMULTG,
A_MULTUG,
A_DMULTUG,
A_DIVG,
A_DDIVG,
A_DIVUG,
A_DDIVUG,
A_MODG,
A_DMODG,
A_MODUG,
A_DMODUG,
A_J,
A_JAL,
A_JR,
A_JALR,
A_BEQ,
A_BNE,
A_BLEZ,
A_BGTZ,
A_BLTZ,
A_BGEZ,
A_BLTZAL,
A_BGEZAL,
A_BEQL,
A_BNEL,
A_BLEZL,
A_BGTZL,
A_BLTZL,
A_BGEZL,
A_BLTZALL,
A_BGEZALL,
A_SLL,
A_SRL,
A_SRA,
A_SLLV,
A_SRLV,
A_SRAV,
A_DSLL,
A_DSRL,
A_DSRA,
A_DSLLV,
A_DSRLV,
A_DSRAV,
A_DSLL32,
A_DSRL32,
A_DSRA32,
A_LWC1,
A_SWC1,
A_LDC1,
A_SDC1,
A_MTC1,
A_MFC1,
A_DMTC1,
A_DMFC1,
A_CTC1,
A_CFC1,
A_ADD_S,
A_ADD_D,
A_SUB_S,
A_SUB_D,
A_MUL_S,
A_MUL_D,
A_DIV_S,
A_DIV_D,
A_ABS_S,
A_ABS_D,
A_NEG_S,
A_NEG_D,
A_SQRT_S,
A_SQRT_D,
A_MOV_S,
A_MOV_D,
A_CVT_S_D,
A_CVT_S_W,
A_CVT_S_L,
A_CVT_D_S,
A_CVT_D_W,
A_CVT_D_L,
A_CVT_W_S,
A_CVT_W_D,
A_CVT_L_S,
A_CVT_L_D,
A_ROUND_W_S,
A_ROUND_W_D,
A_ROUND_L_S,
A_ROUND_L_D,
A_TRUNC_W_S,
A_TRUNC_W_D,
A_TRUNC_L_S,
A_TRUNC_L_D,
A_CEIL_W_S,
A_CEIL_W_D,
A_CEIL_L_S,
A_CEIL_L_D,
A_FLOOR_W_S,
A_FLOOR_W_D,
A_FLOOR_L_S,
A_FLOOR_L_D,
A_BC1T,
A_BC1F,
A_BC1TL,
A_BC1FL,
A_C_EQ_D,
A_C_EQ_S,
A_C_LE_D,
A_C_LE_S,
A_C_LT_D,
A_C_LT_S,
A_BEQI,
A_BNEI,
A_BLTI,
A_BLEI,
A_BGTI,
A_BGEI,
A_BLTUI,
A_BLEUI,
A_BGTUI,
A_BGEUI,
A_BLT,
A_BLE,
A_BGT,
A_BGE,
A_BLTU,
A_BLEU,
A_BGTU,
A_BGEU,
A_SEQ,
A_SGE,
A_SGEU,
A_SGT,
A_SGTU,
A_SLE,
A_SLEU,
A_SNE,
A_SYSCALL,
A_ADD64SUB,
A_SUB64SUB,
A_MUL64SUB,
A_DIV64SUB,
A_NEG64SUB,
A_NOT64SUB,
A_OR64SUB,
A_SAR64SUB,
A_SHL64SUB,
A_SHR64SUB,
A_XOR64SUB,
A_END_DEF

165
compiler/mips/rgcpu.pas Normal file
View File

@ -0,0 +1,165 @@
{
Copyright (c) 1998-2009 by Florian Klaempfl and David Zhang
This unit implements the register allocator for MIPLEL
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 rgcpu;
{$i fpcdefs.inc}
interface
uses
aasmbase,aasmcpu,aasmtai,aasmdata,
cgbase,cgutils,
cpubase,
rgobj;
type
trgcpu=class(trgobj)
procedure add_constraints(reg:tregister);override;
function get_spill_subreg(r : tregister) : tsubregister;override;
procedure do_spill_read(list:tasmlist;pos:tai;const spilltemp:treference;tempreg:tregister);override;
procedure do_spill_written(list:tasmlist;pos:tai;const spilltemp:treference;tempreg:tregister);override;
end;
implementation
uses
globtype,
verbose,cutils,
cgobj;
procedure trgcpu.add_constraints(reg:tregister);
var
supreg,i : Tsuperregister;
begin
case getsubreg(reg) of
{ Let 64bit floats conflict with all odd float regs }
R_SUBFD:
begin
supreg:=getsupreg(reg);
i:=RS_F1;
while (i<=RS_F31) do
begin
add_edge(supreg,i);
inc(i,2);
end;
end;
{ Let 64bit ints conflict with all odd int regs }
R_SUBQ:
begin
supreg:=getsupreg(reg);
i:=RS_R1;
while (i<=RS_R31) do
begin
add_edge(supreg,i);
inc(i,2);
end;
end;
end;
end;
function trgcpu.get_spill_subreg(r : tregister) : tsubregister;
begin
if getregtype(r)=R_FPUREGISTER then
result:=getsubreg(r)
else
result:=defaultsub;
end;
procedure trgcpu.do_spill_read(list:tasmlist;pos:tai;const spilltemp:treference;tempreg:tregister);
var
helpins : tai;
tmpref : treference;
helplist : tasmlist;
hreg : tregister;
begin
if abs(spilltemp.offset)>4095 then
begin
helplist:=tasmlist.create;
if getregtype(tempreg)=R_INTREGISTER then
hreg:=tempreg
else
hreg:=cg.getintregister(helplist,OS_ADDR);
reference_reset(tmpref,sizeof(aint));
tmpref.offset:=spilltemp.offset;
tmpref.refaddr:=addr_high;
helplist.concat(taicpu.op_reg_ref(A_LUI,hreg,tmpref));
tmpref.refaddr:=addr_low;
helplist.concat(taicpu.op_reg_reg_ref(A_ADDIU,hreg,hreg,tmpref));
helplist.concat(taicpu.op_reg_reg_reg(A_ADDU,hreg,hreg,spilltemp.base));
reference_reset_base(tmpref,hreg,0,sizeof(aint));
helpins:=spilling_create_load(tmpref,tempreg);
helplist.concat(helpins);
list.insertlistafter(pos,helplist)
end
else
inherited do_spill_read(list,pos,spilltemp,tempreg);
end;
procedure trgcpu.do_spill_written(list:tasmlist;pos:tai;const spilltemp:treference;tempreg:tregister);
var
helpins : tai;
tmpref : treference;
helplist : tasmlist;
hreg : tregister;
begin
if abs(spilltemp.offset)>4095 then
begin
helplist:=tasmlist.create;
if getregtype(tempreg)=R_INTREGISTER then
hreg:=getregisterinline(helplist,R_SUBWHOLE)
else
hreg:=cg.getintregister(helplist,OS_ADDR);
reference_reset(tmpref,sizeof(aint));
tmpref.offset:=spilltemp.offset;
tmpref.refaddr:=addr_high;
helplist.concat(taicpu.op_reg_ref(A_LUI,hreg,tmpref));
tmpref.refaddr:=addr_low;
helplist.concat(taicpu.op_reg_reg_ref(A_ADDIU,hreg,hreg,tmpref));
helplist.concat(taicpu.op_reg_reg_reg(A_ADDU,hreg,hreg,spilltemp.base));
reference_reset_base(tmpref,hreg,0,sizeof(aint));
helpins:=spilling_create_store(tempreg,tmpref);
helplist.concat(helpins);
if getregtype(tempreg)=R_INTREGISTER then
ungetregisterinline(helplist,hreg);
list.insertlistafter(pos,helplist)
end
else
inherited do_spill_written(list,pos,spilltemp,tempreg);
end;
end.