diff --git a/.gitattributes b/.gitattributes index f630b0425a..e73d168eaa 100644 --- a/.gitattributes +++ b/.gitattributes @@ -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 diff --git a/compiler/cgbase.pas b/compiler/cgbase.pas index abf4bc1a44..d00a311019 100644 --- a/compiler/cgbase.pas +++ b/compiler/cgbase.pas @@ -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 diff --git a/compiler/cgobj.pas b/compiler/cgobj.pas index ffcd678cc1..d7697853ce 100644 --- a/compiler/cgobj.pas +++ b/compiler/cgobj.pas @@ -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); diff --git a/compiler/cgutils.pas b/compiler/cgutils.pas index 861cefb202..2284af3e74 100644 --- a/compiler/cgutils.pas +++ b/compiler/cgutils.pas @@ -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} diff --git a/compiler/fpcdefs.inc b/compiler/fpcdefs.inc index 0c150e4979..028558dc1c 100644 --- a/compiler/fpcdefs.inc +++ b/compiler/fpcdefs.inc @@ -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} diff --git a/compiler/globals.pas b/compiler/globals.pas index fdf8847c24..29c944122d 100644 --- a/compiler/globals.pas +++ b/compiler/globals.pas @@ -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; diff --git a/compiler/mips/cgcpu.pas b/compiler/mips/cgcpu.pas new file mode 100644 index 0000000000..d7ee5cc7c2 --- /dev/null +++ b/compiler/mips/cgcpu.pas @@ -0,0 +1,1972 @@ +{ + Copyright (c) 1998-2009 by Florian Klaempfl and David Zhang + + This unit implements the code generator 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 cgcpu; + +{$i fpcdefs.inc} + +interface + +uses + globtype, parabase, + cgbase, cgutils, cgobj, cg64f32, + aasmbase, aasmtai, aasmcpu, aasmdata, + cpubase, cpuinfo, + node, symconst, SymType, symdef, + rgcpu; + +type + TCgMPSel = class(tcg) + public + procedure init_register_allocators; override; + procedure done_register_allocators; override; + function getfpuregister(list: tasmlist; size: Tcgsize): Tregister; override; +/// { needed by cg64 } + procedure make_simple_ref(list: tasmlist; var ref: treference); + procedure make_simple_ref_fpu(list: tasmlist; var ref: treference); + procedure handle_load_store(list: tasmlist; isstore: boolean; op: tasmop; reg: tregister; ref: treference); + procedure handle_load_store_fpu(list: tasmlist; isstore: boolean; op: tasmop; reg: tregister; ref: treference); + procedure handle_reg_const_reg(list: tasmlist; op: Tasmop; src: tregister; a: aint; dst: tregister); + + { parameter } + procedure a_param_const(list: tasmlist; size: tcgsize; a: aint; const paraloc: TCGPara); override; + procedure a_param_ref(list: tasmlist; sz: tcgsize; const r: TReference; const paraloc: TCGPara); override; + procedure a_paramaddr_ref(list: tasmlist; const r: TReference; const paraloc: TCGPara); override; + procedure a_paramfpu_reg(list: tasmlist; size: tcgsize; const r: tregister; const paraloc: TCGPara); override; + procedure a_paramfpu_ref(list: tasmlist; size: tcgsize; const ref: treference; const paraloc: TCGPara); override; + procedure a_call_name(list: tasmlist; const s: string; weak : boolean); override; + procedure a_call_reg(list: tasmlist; Reg: TRegister); override; + { General purpose instructions } + procedure a_op_const_reg(list: tasmlist; Op: TOpCG; size: tcgsize; a: aint; reg: TRegister); override; + procedure a_op_reg_reg(list: tasmlist; Op: TOpCG; size: TCGSize; src, dst: TRegister); override; + procedure a_op_const_reg_reg(list: tasmlist; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister); override; + procedure a_op_reg_reg_reg(list: tasmlist; op: TOpCg; size: tcgsize; src1, src2, dst: tregister); override; + procedure a_op_const_reg_reg_checkoverflow(list: tasmlist; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister; setflags: boolean; var ovloc: tlocation); override; + procedure a_op_reg_reg_reg_checkoverflow(list: tasmlist; op: TOpCg; size: tcgsize; src1, src2, dst: tregister; setflags: boolean; var ovloc: tlocation); override; + { move instructions } + procedure a_load_const_reg(list: tasmlist; size: tcgsize; a: aint; reg: tregister); override; + procedure a_load_const_ref(list: tasmlist; size: tcgsize; a: aint; const ref: TReference); override; + procedure a_load_reg_ref(list: tasmlist; FromSize, ToSize: TCgSize; reg: TRegister; const ref: TReference); override; + procedure a_load_ref_reg(list: tasmlist; FromSize, ToSize: TCgSize; const ref: TReference; reg: tregister); override; + procedure a_load_reg_reg(list: tasmlist; FromSize, ToSize: TCgSize; reg1, reg2: tregister); override; + procedure a_loadaddr_ref_reg(list: tasmlist; const ref: TReference; r: tregister); override; + { fpu move instructions } + procedure a_loadfpu_reg_reg(list: tasmlist; fromsize, tosize: tcgsize; reg1, reg2: tregister); override; + procedure a_loadfpu_ref_reg(list: tasmlist; fromsize, tosize: tcgsize; const ref: TReference; reg: tregister); override; + procedure a_loadfpu_reg_ref(list: tasmlist; fromsize, tosize: tcgsize; reg: tregister; const ref: TReference); override; + { comparison operations } + procedure a_cmp_const_reg_label(list: tasmlist; size: tcgsize; cmp_op: topcmp; a: aint; reg: tregister; l: tasmlabel); override; + procedure a_cmp_reg_reg_label(list: tasmlist; size: tcgsize; cmp_op: topcmp; reg1, reg2: tregister; l: tasmlabel); override; + procedure a_jmp_always(List: tasmlist; l: TAsmLabel); override; + procedure a_jmp_name(list: tasmlist; const s: string); override; + procedure a_jmp_cond(list: tasmlist; cond: TOpCmp; l: tasmlabel); { override;} + procedure g_overflowCheck(List: tasmlist; const Loc: TLocation; def: TDef); override; + procedure g_overflowCheck_loc(List: tasmlist; const Loc: TLocation; def: TDef; ovloc: tlocation); override; + procedure g_proc_entry(list: tasmlist; localsize: longint; nostackframe: boolean); override; + procedure g_proc_exit(list: tasmlist; parasize: longint; nostackframe: boolean); override; + procedure g_concatcopy(list: tasmlist; const Source, dest: treference; len: aint); override; + procedure g_concatcopy_unaligned(list: tasmlist; const Source, dest: treference; len: aint); override; + procedure g_concatcopy_move(list: tasmlist; const Source, dest: treference; len: aint); + procedure g_intf_wrapper(list: tasmlist; procdef: tprocdef; const labelname: string; ioffset: longint); override; + end; + + TCg64MPSel = class(tcg64f32) + public + procedure a_load64_reg_ref(list: tasmlist; reg: tregister64; const ref: treference); override; + procedure a_load64_ref_reg(list: tasmlist; const ref: treference; reg: tregister64); override; + procedure a_param64_ref(list: tasmlist; const r: treference; const paraloc: tcgpara); override; + procedure a_op64_reg_reg(list: tasmlist; op: TOpCG; size: tcgsize; regsrc, regdst: TRegister64); override; + procedure a_op64_const_reg(list: tasmlist; op: TOpCG; size: tcgsize; Value: int64; regdst: TRegister64); override; + procedure a_op64_const_reg_reg(list: tasmlist; op: TOpCG; size: tcgsize; Value: int64; regsrc, regdst: tregister64); override; + procedure a_op64_reg_reg_reg(list: tasmlist; op: TOpCG; size: tcgsize; regsrc1, regsrc2, regdst: tregister64); override; + procedure a_op64_const_reg_reg_checkoverflow(list: tasmlist; op: TOpCG; size: tcgsize; Value: int64; regsrc, regdst: tregister64; setflags: boolean; var ovloc: tlocation); override; + procedure a_op64_reg_reg_reg_checkoverflow(list: tasmlist; op: TOpCG; size: tcgsize; regsrc1, regsrc2, regdst: tregister64; setflags: boolean; var ovloc: tlocation); override; + end; + + + +implementation + +uses + globals, verbose, systems, cutils, + paramgr, fmodule, + tgobj, + procinfo, cpupi; + +var + cgcpu_calc_stackframe_size: aint; + + + function f_TOpCG2AsmOp(op: TOpCG; size: tcgsize): TAsmOp; + begin + if size = OS_32 then + case op of + OP_ADD: { simple addition } + f_TOpCG2AsmOp := A_ADDU; + OP_AND: { simple logical and } + f_TOpCG2AsmOp := A_AND; + OP_DIV: { simple unsigned division } + f_TOpCG2AsmOp := A_DIVU; + OP_IDIV: { simple signed division } + f_TOpCG2AsmOp := A_DIV; + OP_IMUL: { simple signed multiply } + f_TOpCG2AsmOp := A_MULT; + OP_MUL: { simple unsigned multiply } + f_TOpCG2AsmOp := A_MULTU; + OP_NEG: { simple negate } + f_TOpCG2AsmOp := A_NEGU; + OP_NOT: { simple logical not } + f_TOpCG2AsmOp := A_NOT; + OP_OR: { simple logical or } + f_TOpCG2AsmOp := A_OR; + OP_SAR: { arithmetic shift-right } + f_TOpCG2AsmOp := A_SRA; + OP_SHL: { logical shift left } + f_TOpCG2AsmOp := A_SLL; + OP_SHR: { logical shift right } + f_TOpCG2AsmOp := A_SRL; + OP_SUB: { simple subtraction } + f_TOpCG2AsmOp := A_SUBU; + OP_XOR: { simple exclusive or } + f_TOpCG2AsmOp := A_XOR; + else + InternalError(2007070401); + end{ case } + else + case op of + OP_ADD: { simple addition } + f_TOpCG2AsmOp := A_ADDU; + OP_AND: { simple logical and } + f_TOpCG2AsmOp := A_AND; + OP_DIV: { simple unsigned division } + f_TOpCG2AsmOp := A_DIVU; + OP_IDIV: { simple signed division } + f_TOpCG2AsmOp := A_DIV; + OP_IMUL: { simple signed multiply } + f_TOpCG2AsmOp := A_MULT; + OP_MUL: { simple unsigned multiply } + f_TOpCG2AsmOp := A_MULTU; + OP_NEG: { simple negate } + f_TOpCG2AsmOp := A_NEGU; + OP_NOT: { simple logical not } + f_TOpCG2AsmOp := A_NOT; + OP_OR: { simple logical or } + f_TOpCG2AsmOp := A_OR; + OP_SAR: { arithmetic shift-right } + f_TOpCG2AsmOp := A_SRA; + OP_SHL: { logical shift left } + f_TOpCG2AsmOp := A_SLL; + OP_SHR: { logical shift right } + f_TOpCG2AsmOp := A_SRL; + OP_SUB: { simple subtraction } + f_TOpCG2AsmOp := A_SUBU; + OP_XOR: { simple exclusive or } + f_TOpCG2AsmOp := A_XOR; + else + InternalError(2007010701); + end;{ case } + end; + + function f_TOpCG2AsmOp_ovf(op: TOpCG; size: tcgsize): TAsmOp; + begin + if size = OS_32 then + case op of + OP_ADD: { simple addition } + f_TOpCG2AsmOp_ovf := A_ADD; + OP_AND: { simple logical and } + f_TOpCG2AsmOp_ovf := A_AND; + OP_DIV: { simple unsigned division } + f_TOpCG2AsmOp_ovf := A_DIVU; + OP_IDIV: { simple signed division } + f_TOpCG2AsmOp_ovf := A_DIV; + OP_IMUL: { simple signed multiply } + f_TOpCG2AsmOp_ovf := A_MULO; + OP_MUL: { simple unsigned multiply } + f_TOpCG2AsmOp_ovf := A_MULOU; + OP_NEG: { simple negate } + f_TOpCG2AsmOp_ovf := A_NEG; + OP_NOT: { simple logical not } + f_TOpCG2AsmOp_ovf := A_NOT; + OP_OR: { simple logical or } + f_TOpCG2AsmOp_ovf := A_OR; + OP_SAR: { arithmetic shift-right } + f_TOpCG2AsmOp_ovf := A_SRA; + OP_SHL: { logical shift left } + f_TOpCG2AsmOp_ovf := A_SLL; + OP_SHR: { logical shift right } + f_TOpCG2AsmOp_ovf := A_SRL; + OP_SUB: { simple subtraction } + f_TOpCG2AsmOp_ovf := A_SUB; + OP_XOR: { simple exclusive or } + f_TOpCG2AsmOp_ovf := A_XOR; + else + InternalError(2007070403); + end{ case } + else + case op of + OP_ADD: { simple addition } + f_TOpCG2AsmOp_ovf := A_ADD; + OP_AND: { simple logical and } + f_TOpCG2AsmOp_ovf := A_AND; + OP_DIV: { simple unsigned division } + f_TOpCG2AsmOp_ovf := A_DIVU; + OP_IDIV: { simple signed division } + f_TOpCG2AsmOp_ovf := A_DIV; + OP_IMUL: { simple signed multiply } + f_TOpCG2AsmOp_ovf := A_MULO; + OP_MUL: { simple unsigned multiply } + f_TOpCG2AsmOp_ovf := A_MULOU; + OP_NEG: { simple negate } + f_TOpCG2AsmOp_ovf := A_NEG; + OP_NOT: { simple logical not } + f_TOpCG2AsmOp_ovf := A_NOT; + OP_OR: { simple logical or } + f_TOpCG2AsmOp_ovf := A_OR; + OP_SAR: { arithmetic shift-right } + f_TOpCG2AsmOp_ovf := A_SRA; + OP_SHL: { logical shift left } + f_TOpCG2AsmOp_ovf := A_SLL; + OP_SHR: { logical shift right } + f_TOpCG2AsmOp_ovf := A_SRL; + OP_SUB: { simple subtraction } + f_TOpCG2AsmOp_ovf := A_SUB; + OP_XOR: { simple exclusive or } + f_TOpCG2AsmOp_ovf := A_XOR; + else + InternalError(2007010703); + end;{ case } + end; + + function f_TOp64CG2AsmOp(op: TOpCG): TAsmOp; + begin + case op of + OP_ADD: { simple addition } + f_TOp64CG2AsmOp := A_DADDU; + OP_AND: { simple logical and } + f_TOp64CG2AsmOp := A_AND; + OP_DIV: { simple unsigned division } + f_TOp64CG2AsmOp := A_DDIVU; + OP_IDIV: { simple signed division } + f_TOp64CG2AsmOp := A_DDIV; + OP_IMUL: { simple signed multiply } + f_TOp64CG2AsmOp := A_DMULO; + OP_MUL: { simple unsigned multiply } + f_TOp64CG2AsmOp := A_DMULOU; + OP_NEG: { simple negate } + f_TOp64CG2AsmOp := A_DNEGU; + OP_NOT: { simple logical not } + f_TOp64CG2AsmOp := A_NOT; + OP_OR: { simple logical or } + f_TOp64CG2AsmOp := A_OR; + OP_SAR: { arithmetic shift-right } + f_TOp64CG2AsmOp := A_DSRA; + OP_SHL: { logical shift left } + f_TOp64CG2AsmOp := A_DSLL; + OP_SHR: { logical shift right } + f_TOp64CG2AsmOp := A_DSRL; + OP_SUB: { simple subtraction } + f_TOp64CG2AsmOp := A_DSUBU; + OP_XOR: { simple exclusive or } + f_TOp64CG2AsmOp := A_XOR; + else + InternalError(2007010702); + end;{ case } + end; + + + +procedure TCgMPSel.make_simple_ref(list: tasmlist; var ref: treference); +var + tmpreg, tmpreg1: tregister; + tmpref: treference; +begin + tmpreg := NR_NO; + { Be sure to have a base register } + if (ref.base = NR_NO) then + begin + ref.base := ref.index; + ref.index := NR_NO; + end; + if (cs_create_pic in current_settings.moduleswitches) and + assigned(ref.symbol) then + begin + tmpreg := GetIntRegister(list, OS_INT); + reference_reset(tmpref,sizeof(aint)); + tmpref.symbol := ref.symbol; + tmpref.refaddr := addr_pic; + if not (pi_needs_got in current_procinfo.flags) then + internalerror(200501161); + tmpref.index := current_procinfo.got; + list.concat(taicpu.op_reg_ref(A_LW, tmpreg, tmpref)); + ref.symbol := nil; + if (ref.index <> NR_NO) then + begin + list.concat(taicpu.op_reg_reg_reg(A_ADDU, tmpreg, ref.index, tmpreg)); + ref.index := tmpreg; + end + else + begin + if ref.base <> NR_NO then + ref.index := tmpreg + else + ref.base := tmpreg; + end; + end; + { When need to use LUI, do it first } + if assigned(ref.symbol) or + (ref.offset < simm16lo) or + (ref.offset > simm16hi) then + begin + tmpreg := GetIntRegister(list, OS_INT); + reference_reset(tmpref); + tmpref.symbol := ref.symbol; + tmpref.offset := ref.offset; + tmpref.refaddr := addr_hi; + list.concat(taicpu.op_reg_ref(A_LUI, tmpreg, tmpref)); + if (ref.offset = 0) and (ref.index = NR_NO) and + (ref.base = NR_NO) then + begin + ref.refaddr := addr_lo; + end + else + begin + { Load the low part is left } + tmpref.refaddr := addr_lo; + list.concat(taicpu.op_reg_reg_ref(A_ADDIU, tmpreg, tmpreg, tmpref)); + ref.offset := 0; + { symbol is loaded } + ref.symbol := nil; + end; + if (ref.index <> NR_NO) then + begin + list.concat(taicpu.op_reg_reg_reg(A_ADDU, tmpreg, ref.index, tmpreg)); + ref.index := tmpreg; + end + else + begin + if ref.base <> NR_NO then + ref.index := tmpreg + else + ref.base := tmpreg; + end; + end; + if (ref.base <> NR_NO) then + begin + if (ref.index <> NR_NO) and (ref.offset = 0) then + begin + tmpreg1 := GetIntRegister(list, OS_INT); + list.concat(taicpu.op_reg_reg_reg(A_ADDU, tmpreg1, ref.base, ref.index)); + ref.base := tmpreg1; + ref.index := NR_NO; + end + else if (ref.index <> NR_NO) and + ((ref.offset <> 0) or assigned(ref.symbol)) then + begin + if tmpreg = NR_NO then + tmpreg := GetIntRegister(list, OS_INT); + list.concat(taicpu.op_reg_reg_reg(A_ADDU, tmpreg, ref.base, ref.index)); + ref.base := tmpreg; + ref.index := NR_NO; + end; + end; +end; + +procedure TCgMPSel.make_simple_ref_fpu(list: tasmlist; var ref: treference); +var + tmpreg, tmpreg1: tregister; + tmpref: treference; +begin + tmpreg := NR_NO; + { Be sure to have a base register } + if (ref.base = NR_NO) then + begin + ref.base := ref.index; + ref.index := NR_NO; + end; + if (cs_create_pic in current_settings.moduleswitches) and + assigned(ref.symbol) then + begin + tmpreg := GetIntRegister(list, OS_INT); + reference_reset(tmpref); + tmpref.symbol := ref.symbol; + tmpref.refaddr := addr_pic; + if not (pi_needs_got in current_procinfo.flags) then + internalerror(200501161); + tmpref.index := current_procinfo.got; + list.concat(taicpu.op_reg_ref(A_LW, tmpreg, tmpref)); + ref.symbol := nil; + if (ref.index <> NR_NO) then + begin + list.concat(taicpu.op_reg_reg_reg(A_ADDU, tmpreg, ref.index, tmpreg)); + ref.index := tmpreg; + end + else + begin + if ref.base <> NR_NO then + ref.index := tmpreg + else + ref.base := tmpreg; + end; + end; + { When need to use LUI, do it first } + if (not assigned(ref.symbol)) and (ref.index = NR_NO) and + (ref.offset > simm16lo + 1000) and (ref.offset < simm16hi - 1000) + then + exit; + + tmpreg1 := GetIntRegister(list, OS_INT); + if assigned(ref.symbol) then + begin + reference_reset(tmpref); + tmpref.symbol := ref.symbol; + tmpref.offset := ref.offset; + tmpref.refaddr := addr_hi; + list.concat(taicpu.op_reg_ref(A_LUI, tmpreg1, tmpref)); + { Load the low part } + + tmpref.refaddr := addr_lo; + list.concat(taicpu.op_reg_reg_ref(A_ADDIU, tmpreg1, tmpreg1, tmpref)); + { symbol is loaded } + ref.symbol := nil; + end + else + list.concat(taicpu.op_reg_const(A_LI, tmpreg1, ref.offset)); + + if (ref.index <> NR_NO) then + begin + list.concat(taicpu.op_reg_reg_reg(A_ADDU, tmpreg1, ref.index, tmpreg1)); + ref.index := NR_NO + end; + if ref.base <> NR_NO then + list.concat(taicpu.op_reg_reg_reg(A_ADDU, tmpreg1, ref.base, tmpreg1)); + ref.base := tmpreg1; + ref.offset := 0; +end; + +procedure TCgMPSel.handle_load_store(list: tasmlist; isstore: boolean; op: tasmop; reg: tregister; ref: treference); +begin + make_simple_ref(list, ref); + list.concat(taicpu.op_reg_ref(op, reg, ref)); +end; + +procedure TCgMPSel.handle_load_store_fpu(list: tasmlist; isstore: boolean; op: tasmop; reg: tregister; ref: treference); +begin + make_simple_ref_fpu(list, ref); + list.concat(taicpu.op_reg_ref(op, reg, ref)); +end; + + +procedure TCgMPSel.handle_reg_const_reg(list: tasmlist; op: Tasmop; src: tregister; a: aint; dst: tregister); +var + tmpreg: tregister; +begin + if (a < simm16lo) or + (a > simm16hi) then + begin + tmpreg := GetIntRegister(list, OS_INT); + a_load_const_reg(list, OS_INT, a, tmpreg); + list.concat(taicpu.op_reg_reg_reg(op, dst, src, tmpreg)); + end + else + list.concat(taicpu.op_reg_reg_const(op, dst, src, a)); +end; + + +{**************************************************************************** + Assembler code +****************************************************************************} + +procedure TCgMPSel.init_register_allocators; +begin + inherited init_register_allocators; + + if (cs_create_pic in current_settings.moduleswitches) and + (pi_needs_got in current_procinfo.flags) then + begin + current_procinfo.got := NR_GP; + rg[R_INTREGISTER] := Trgcpu.Create(R_INTREGISTER, R_SUBD, + [RS_R4, RS_R5, RS_R6, RS_R7, RS_R8, RS_R9, RS_R10, RS_R11, + RS_R12, RS_R13, RS_R14 {, RS_R15 for tmp_const in ncpuadd.pas} {, RS_R24, RS_R25}], + first_int_imreg, []); + end + else + rg[R_INTREGISTER] := Trgcpu.Create(R_INTREGISTER, R_SUBD, + [RS_R4, RS_R5, RS_R6, RS_R7, RS_R8, RS_R9, RS_R10, RS_R11, + RS_R12, RS_R13, RS_R14 {, RS_R15 for tmp_const in ncpuadd.pas} {, RS_R24=VMT, RS_R25=PIC jump}], + first_int_imreg, []); + + rg[R_FPUREGISTER] := trgcpu.Create(R_FPUREGISTER, R_SUBFS{R_SUBFD}, + [RS_F0, RS_F2, RS_F4, RS_F6, + RS_F8, RS_F10, RS_F12, RS_F14, + RS_F16, RS_F18, RS_F20, RS_F22, + RS_F24, RS_F26, RS_F28, RS_F30], + first_fpu_imreg, []); +end; + + + +procedure TCgMPSel.done_register_allocators; +begin + rg[R_INTREGISTER].Free; + rg[R_FPUREGISTER].Free; + inherited done_register_allocators; +end; + + +function TCgMPSel.getfpuregister(list: tasmlist; size: Tcgsize): Tregister; +begin + if size = OS_F64 then + Result := rg[R_FPUREGISTER].getregister(list, R_SUBFD) + else + Result := rg[R_FPUREGISTER].getregister(list, R_SUBFS); +end; + + +procedure TCgMPSel.a_param_const(list: tasmlist; size: tcgsize; a: aint; const paraloc: TCGPara); +var + Ref: TReference; +begin + paraloc.check_simple_location; + case paraloc.location^.loc of + LOC_REGISTER, LOC_CREGISTER: + a_load_const_reg(list, size, a, paraloc.location^.Register); + LOC_REFERENCE: + begin + with paraloc.location^.Reference do + begin + if (Index = NR_SP) and (Offset < Target_info.first_parm_offset) then + InternalError(2002081104); + reference_reset_base(ref, index, offset); + end; + a_load_const_ref(list, size, a, ref); + end; + else + InternalError(2002122200); + end; +end; + + +procedure TCgMPSel.a_param_ref(list: tasmlist; sz: TCgSize; const r: TReference; const paraloc: TCGPara); +var + ref: treference; + tmpreg: TRegister; +begin + paraloc.check_simple_location; + with paraloc.location^ do + begin + case loc of + LOC_REGISTER, LOC_CREGISTER: + a_load_ref_reg(list, sz, sz, r, Register); + LOC_REFERENCE: + begin + with Reference do + begin + if (Index = NR_SP) and (Offset < Target_info.first_parm_offset) then + InternalError(2002081104); + reference_reset_base(ref, index, offset); + end; + tmpreg := GetIntRegister(list, OS_INT); + a_load_ref_reg(list, sz, sz, r, tmpreg); + a_load_reg_ref(list, sz, sz, tmpreg, ref); + end; + else + internalerror(2002081103); + end; + end; +end; + + +procedure TCgMPSel.a_paramaddr_ref(list: tasmlist; const r: TReference; const paraloc: TCGPara); +var + Ref: TReference; + TmpReg: TRegister; +begin + paraloc.check_simple_location; + with paraloc.location^ do + begin + case loc of + LOC_REGISTER, LOC_CREGISTER: + a_loadaddr_ref_reg(list, r, Register); + LOC_REFERENCE: + begin + reference_reset(ref); + ref.base := reference.index; + ref.offset := reference.offset; + tmpreg := GetAddressRegister(list); + a_loadaddr_ref_reg(list, r, tmpreg); + a_load_reg_ref(list, OS_ADDR, OS_ADDR, tmpreg, ref); + end; + else + internalerror(2002080701); + end; + end; +end; + + +procedure TCgMPSel.a_paramfpu_ref(list: tasmlist; size: tcgsize; const ref: treference; const paraloc: TCGPara); +var + href, href2: treference; + hloc: pcgparalocation; +begin + href := ref; + hloc := paraloc.location; + while assigned(hloc) do + begin + case hloc^.loc of + LOC_REGISTER: + a_load_ref_reg(list, hloc^.size, hloc^.size, href, hloc^.Register); + LOC_REFERENCE: + begin + reference_reset_base(href2, hloc^.reference.index, hloc^.reference.offset); + a_load_ref_ref(list, hloc^.size, hloc^.size, href, href2); + end; + else + internalerror(200408241); + end; + Inc(href.offset, tcgsize2size[hloc^.size]); + hloc := hloc^.Next; + end; +end; + + +procedure TCgMPSel.a_paramfpu_reg(list: tasmlist; size: tcgsize; const r: tregister; const paraloc: TCGPara); +var + href: treference; +begin + tg.GetTemp(list, TCGSize2Size[size], tt_normal, href); + a_loadfpu_reg_ref(list, size, r, href); + a_paramfpu_ref(list, size, href, paraloc); + tg.Ungettemp(list, href); +end; + + +procedure TCgMPSel.a_call_name(list: tasmlist; const s: string); +begin + list.concat(taicpu.op_sym(A_JAL, objectlibrary.newasmsymbol(s, AB_EXTERNAL, AT_FUNCTION))); + { Delay slot } + list.concat(taicpu.op_none(A_NOP)); +end; + + +procedure TCgMPSel.a_call_reg(list: tasmlist; Reg: TRegister); +begin + list.concat(taicpu.op_reg(A_JALR, reg)); + { Delay slot } + list.concat(taicpu.op_none(A_NOP)); +end; + + +{********************** load instructions ********************} + +procedure TCgMPSel.a_load_const_reg(list: tasmlist; size: TCGSize; a: aint; reg: TRegister); +begin + if (a = 0) then + list.concat(taicpu.op_reg_reg(A_MOVE, reg, NR_R0)) + { LUI allows to set the upper 16 bits, so we'll take full advantage of it } + else if (a and aint($ffff)) = 0 then + list.concat(taicpu.op_reg_const(A_LUI, reg, a shr 16)) + else if (a >= simm16lo) and (a <= simm16hi) then + list.concat(taicpu.op_reg_reg_const(A_ADDIU, reg, NR_R0, a)) + else if (a>=0) and (a <= 65535) then + list.concat(taicpu.op_reg_reg_const(A_ORI, reg, NR_R0, a)) + else + begin + list.concat(taicpu.op_reg_const(A_LI, reg, a )); + end; +end; + + +procedure TCgMPSel.a_load_const_ref(list: tasmlist; size: tcgsize; a: aint; const ref: TReference); +begin + if a = 0 then + a_load_reg_ref(list, size, size, NR_R0, ref) + else + inherited a_load_const_ref(list, size, a, ref); +end; + + +procedure TCgMPSel.a_load_reg_ref(list: tasmlist; FromSize, ToSize: TCGSize; reg: tregister; const Ref: TReference); +var + op: tasmop; +begin + + if (TCGSize2Size[fromsize] >= TCGSize2Size[tosize]) then + fromsize := tosize; + case fromsize of + { signed integer registers } + OS_8, + OS_S8: + Op := A_SB; + OS_16, + OS_S16: + Op := A_SH; + OS_32, + OS_S32: + Op := A_SW; + else + InternalError(2002122100); + end; + handle_load_store(list, True, op, reg, ref); +end; + + +procedure TCgMPSel.a_load_ref_reg(list: tasmlist; FromSize, ToSize: TCgSize; const ref: TReference; reg: tregister); +var + op: tasmop; +begin + if (TCGSize2Size[fromsize] >= TCGSize2Size[tosize]) then + fromsize := tosize; + case fromsize of + OS_S8: + Op := A_LB;{Load Signed Byte} + OS_8: + Op := A_LBU;{Load Unsigned Byte} + OS_S16: + Op := A_LH;{Load Signed Halfword} + OS_16: + Op := A_LHU;{Load Unsigned Halfword} + OS_S32: + Op := A_LW;{Load Word} + OS_32: + Op := A_LW;//A_LWU;{Load Unsigned Word} + OS_S64, + OS_64: + Op := A_LD;{Load a Long Word} + else + InternalError(2002122101); + end; + handle_load_store(list, False, op, reg, ref); +end; + + +procedure TCgMPSel.a_load_reg_reg(list: tasmlist; fromsize, tosize: tcgsize; reg1, reg2: tregister); +var + instr: taicpu; +begin + if (tcgsize2size[tosize] < tcgsize2size[fromsize]) or + ( + (tcgsize2size[tosize] = tcgsize2size[fromsize]) and + (tosize <> fromsize) and not (fromsize in [OS_32, OS_S32]) + ) then + begin + case tosize of + OS_8: + a_op_const_reg_reg(list, OP_AND, tosize, $ff, reg1, reg2); + OS_16: + a_op_const_reg_reg(list, OP_AND, tosize, $ffff, reg1, reg2); + OS_32, + OS_S32: + begin + instr := taicpu.op_reg_reg(A_MOVE, reg2, reg1); + list.Concat(instr); + { Notify the register allocator that we have written a move instruction so + it can try to eliminate it. } + add_move_instruction(instr); + end; + OS_S8: + begin + list.concat(taicpu.op_reg_reg_const(A_SLL, reg2, reg1, 24)); + list.concat(taicpu.op_reg_reg_const(A_SRA, reg2, reg2, 24)); + end; + OS_S16: + begin + list.concat(taicpu.op_reg_reg_const(A_SLL, reg2, reg1, 16)); + list.concat(taicpu.op_reg_reg_const(A_SRA, reg2, reg2, 16)); + end; + else + internalerror(2002090901); + end; + end + else + begin + if reg1 <> reg2 then + begin + { same size, only a register mov required } + instr := taicpu.op_reg_reg(A_MOVE, reg2, reg1); + list.Concat(instr); +// { Notify the register allocator that we have written a move instruction so +// it can try to eliminate it. } + + add_move_instruction(instr); + end; + end; +end; + + +procedure TCgMPSel.a_loadaddr_ref_reg(list: tasmlist; const ref: TReference; r: tregister); +var + tmpref, href: treference; + hreg, tmpreg: tregister; + r_used: boolean; +begin + r_used := false; + href := ref; + if (href.base = NR_NO) and (href.index <> NR_NO) then + internalerror(200306171); + + if (cs_create_pic in current_settings.moduleswitches) and + assigned(href.symbol) then + begin + tmpreg := r; //GetIntRegister(list, OS_ADDR); + r_used := true; + reference_reset(tmpref); + tmpref.symbol := href.symbol; + tmpref.refaddr := addr_pic; + if not (pi_needs_got in current_procinfo.flags) then + internalerror(200501161); + tmpref.base := current_procinfo.got; + list.concat(taicpu.op_reg_ref(A_LW, tmpreg, tmpref)); + href.symbol := nil; + if (href.index <> NR_NO) then + begin + list.concat(taicpu.op_reg_reg_reg(A_ADDU, tmpreg, href.index, tmpreg)); + href.index := tmpreg; + end + else + begin + if href.base <> NR_NO then + href.index := tmpreg + else + href.base := tmpreg; + end; + end; + + + if assigned(href.symbol) or + (href.offset < simm16lo) or + (href.offset > simm16hi) then + begin + if (href.base = NR_NO) and (href.index = NR_NO) then + hreg := r + else + hreg := GetAddressRegister(list); + reference_reset(tmpref); + tmpref.symbol := href.symbol; + tmpref.offset := href.offset; + tmpref.refaddr := addr_hi; + list.concat(taicpu.op_reg_ref(A_LUI, hreg, tmpref)); + { Only the low part is left } + tmpref.refaddr := addr_lo; + list.concat(taicpu.op_reg_reg_ref(A_ADDIU, hreg, hreg, tmpref)); + if href.base <> NR_NO then + begin + if href.index <> NR_NO then + begin + list.concat(taicpu.op_reg_reg_reg(A_ADDU, hreg, href.base, hreg)); + list.concat(taicpu.op_reg_reg_reg(A_ADDU, r, hreg, href.index)); + end + else + list.concat(taicpu.op_reg_reg_reg(A_ADDU, r, hreg, href.base)); + end; + end + else + { At least small offset, maybe base and maybe index } + if (href.offset >= simm16lo) and + (href.offset <= simm16hi) + then + begin + if href.index <> NR_NO then { Both base and index } + begin + if href.offset = 0 then + begin + list.concat(taicpu.op_reg_reg_reg(A_ADDU, r, href.base, href.index)); + end + else + begin + if r_used then + hreg := GetAddressRegister(list) + else + hreg := r; + list.concat(taicpu.op_reg_reg_const(A_ADDIU, hreg, href.base, href.offset)); + list.concat(taicpu.op_reg_reg_reg(A_ADDU, r, hreg, href.index)); + end + end + else if href.base <> NR_NO then { Only base } + begin + list.concat(taicpu.op_reg_reg_const(A_ADDIU, r, href.base, href.offset)); + end + else { only offset, can be generated by absolute } + + a_load_const_reg(list, OS_ADDR, href.offset, r); + end + else + internalerror(200703111); +end; + +procedure TCgMPSel.a_loadfpu_reg_reg(list: tasmlist; fromsize, tosize: tcgsize; reg1, reg2: tregister); +const + FpuMovInstr: array[OS_F32..OS_F64] of TAsmOp = + (A_MOV_S, A_MOV_D); +var + instr: taicpu; +begin + if reg1 <> reg2 then + begin + instr := taicpu.op_reg_reg(fpumovinstr[size], reg2, reg1); + list.Concat(instr); + { Notify the register allocator that we have written a move instruction so + it can try to eliminate it. } + add_move_instruction(instr); + end; +end; + + +procedure TCgMPSel.a_loadfpu_ref_reg(list: tasmlist; fromsize, tosize: tcgsize; const ref: TReference; reg: tregister); +var + tmpref: treference; + tmpreg: tregister; +begin + case size of + OS_F32: + begin + handle_load_store_fpu(list, False, A_LWC1, reg, ref); + end; + OS_F64: + begin + handle_load_store_fpu(list, False, A_LDC1, reg, ref); + end + else + InternalError(2007042701); + end; +end; + +procedure TCgMPSel.a_loadfpu_reg_ref(list: tasmlist; fromsize, tosize: tcgsize; reg: tregister; const ref: TReference); +var + tmpref: treference; + tmpreg: tregister; +begin + case size of + OS_F32: + begin + handle_load_store_fpu(list, True, A_SWC1, reg, ref); + end; + OS_F64: + begin + handle_load_store_fpu(list, True, A_SDC1, reg, ref); + end + else + InternalError(2007042702); + end; +end; + +procedure TCgMPSel.a_op_const_reg(list: tasmlist; Op: TOpCG; size: tcgsize; a: aint; reg: TRegister); +var + power: longint; + tmpreg1: tregister; +begin + if ((op = OP_MUL) or (op = OP_IMUL)) then + begin + if ispowerof2(a, power) then + begin + { can be done with a shift } + if power < 32 then + begin + list.concat(taicpu.op_reg_reg_const(A_SLL, reg, reg, power)); + exit; + end; + end; + end; + if ((op = OP_SUB) or (op = OP_ADD)) then + begin + if (a = 0) then + exit; + end; + + if Op in [OP_NEG, OP_NOT] then + internalerror(200306011); + if (a = 0) then + begin + if (Op = OP_IMUL) or (Op = OP_MUL) then + list.concat(taicpu.op_reg_reg(A_MOVE, reg, NR_R0)) + else + list.concat(taicpu.op_reg_reg_reg(f_TOpCG2AsmOp(op, size), reg, reg, NR_R0)) + end + else + begin + if op = OP_IMUL then + begin + tmpreg1 := GetIntRegister(list, OS_INT); + a_load_const_reg(list, OS_INT, a, tmpreg1); + list.concat(taicpu.op_reg_reg(A_MULT, reg, tmpreg1)); + list.concat(taicpu.op_reg(A_MFLO, reg)); + end + else if op = OP_MUL then + begin + tmpreg1 := GetIntRegister(list, OS_INT); + a_load_const_reg(list, OS_INT, a, tmpreg1); + list.concat(taicpu.op_reg_reg(A_MULTU, reg, tmpreg1)); + list.concat(taicpu.op_reg(A_MFLO, reg)); + end + else + handle_reg_const_reg(list, f_TOpCG2AsmOp(op, size), reg, a, reg); + end; +end; + + +procedure TCgMPSel.a_op_reg_reg(list: tasmlist; Op: TOpCG; size: TCGSize; src, dst: TRegister); +var + a: aint; +begin + case Op of + OP_NEG: + list.concat(taicpu.op_reg_reg(A_NEG, dst, src)); + OP_NOT: + begin + list.concat(taicpu.op_reg_reg(A_NOT, dst, src)); + end; + else + begin + if op = OP_IMUL then + begin + list.concat(taicpu.op_reg_reg(A_MULT, dst, src)); + list.concat(taicpu.op_reg(A_MFLO, dst)); + end + else if op = OP_MUL then + begin + list.concat(taicpu.op_reg_reg(A_MULTU, dst, src)); + list.concat(taicpu.op_reg(A_MFLO, dst)); + end + else + begin + list.concat(taicpu.op_reg_reg_reg(f_TOpCG2AsmOp(op, size), dst, dst, src)); + end; + end; + end; +end; + + +procedure TCgMPSel.a_op_const_reg_reg(list: tasmlist; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister); +var + power: longint; + tmpreg1: tregister; +begin + case op of + OP_MUL, + OP_IMUL: + begin + if ispowerof2(a, power) then + begin + { can be done with a shift } + if power < 32 then + list.concat(taicpu.op_reg_reg_const(A_SLL, dst, src, power)) + else + inherited a_op_const_reg_reg(list, op, size, a, src, dst); + exit; + end; + end; + OP_SUB, + OP_ADD: + begin + if (a = 0) then + begin + a_load_reg_reg(list, size, size, src, dst); + exit; + end; + end; + end; + if op = OP_IMUL then + begin + tmpreg1 := GetIntRegister(list, OS_INT); + a_load_const_reg(list, OS_INT, a, tmpreg1); + list.concat(taicpu.op_reg_reg(A_MULT, src, tmpreg1)); + list.concat(taicpu.op_reg(A_MFLO, dst)); + end + else if op = OP_MUL then + begin + tmpreg1 := GetIntRegister(list, OS_INT); + a_load_const_reg(list, OS_INT, a, tmpreg1); + list.concat(taicpu.op_reg_reg(A_MULTU, src, tmpreg1)); + list.concat(taicpu.op_reg(A_MFLO, dst)); + end + else + handle_reg_const_reg(list, f_TOpCG2AsmOp(op, size), src, a, dst); +end; + + +procedure TCgMPSel.a_op_reg_reg_reg(list: tasmlist; op: TOpCg; size: tcgsize; src1, src2, dst: tregister); +begin + + list.concat(taicpu.op_reg_reg_reg(f_TOpCG2AsmOp(op, size), dst, src2, src1)); +end; + + +procedure TCgMPSel.a_op_const_reg_reg_checkoverflow(list: tasmlist; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister; setflags: boolean; var ovloc: tlocation); +var + tmpreg1: tregister; +begin + ovloc.loc := LOC_VOID; + case op of + OP_SUB, + OP_ADD: + begin + if (a = 0) then + begin + a_load_reg_reg(list, size, size, src, dst); + exit; + end; + end; + end;{case} + + case op of + OP_ADD: + begin + if setflags then + handle_reg_const_reg(list, f_TOpCG2AsmOp_ovf(op, size), src, a, dst) + else + handle_reg_const_reg(list, f_TOpCG2AsmOp(op, size), src, a, dst); + end; + OP_SUB: + begin + if setflags then + handle_reg_const_reg(list, f_TOpCG2AsmOp_ovf(op, size), src, a, dst) + else + handle_reg_const_reg(list, f_TOpCG2AsmOp(op, size), src, a, dst); + end; + OP_MUL: + begin + if setflags then + handle_reg_const_reg(list, f_TOpCG2AsmOp_ovf(op, size), src, a, dst) + else + begin + tmpreg1 := GetIntRegister(list, OS_INT); + a_load_const_reg(list, OS_INT, a, tmpreg1); + list.concat(taicpu.op_reg_reg(f_TOpCG2AsmOp(op, size),src, tmpreg1)); + list.concat(taicpu.op_reg(A_MFLO, dst)); + end; + end; + OP_IMUL: + begin + if setflags then + handle_reg_const_reg(list, f_TOpCG2AsmOp_ovf(op, size), src, a, dst) + else + begin + tmpreg1 := GetIntRegister(list, OS_INT); + a_load_const_reg(list, OS_INT, a, tmpreg1); + list.concat(taicpu.op_reg_reg(f_TOpCG2AsmOp(op, size),src, tmpreg1)); + list.concat(taicpu.op_reg(A_MFLO, dst)); + end; + end; + OP_XOR, OP_OR, OP_AND: + begin + handle_reg_const_reg(list, f_TOpCG2AsmOp_ovf(op, size), src, a, dst); + end; + else + internalerror(2007012601); + end; +end; + + +procedure TCgMPSel.a_op_reg_reg_reg_checkoverflow(list: tasmlist; op: TOpCg; size: tcgsize; src1, src2, dst: tregister; setflags: boolean; var ovloc: tlocation); +begin + ovloc.loc := LOC_VOID; + case op of + OP_ADD: + begin + if setflags then + list.concat(taicpu.op_reg_reg_reg(f_TOpCG2AsmOp_ovf(op, size), dst, src2, src1)) + else + list.concat(taicpu.op_reg_reg_reg(f_TOpCG2AsmOp(op, size), dst, src2, src1)); + end; + OP_SUB: + begin + if setflags then + list.concat(taicpu.op_reg_reg_reg(f_TOpCG2AsmOp_ovf(op, size), dst, src2, src1)) + else + list.concat(taicpu.op_reg_reg_reg(f_TOpCG2AsmOp(op, size), dst, src2, src1)); + end; + OP_MUL: + begin + if setflags then + list.concat(taicpu.op_reg_reg_reg(f_TOpCG2AsmOp_ovf(op, size), dst, src2, src1)) + else + begin + list.concat(taicpu.op_reg_reg(f_TOpCG2AsmOp(op, size), src2, src1)); + list.concat(taicpu.op_reg(A_MFLO, dst)); + end; + end; + OP_IMUL: + begin + if setflags then + list.concat(taicpu.op_reg_reg_reg(f_TOpCG2AsmOp_ovf(op, size), dst, src2, src1)) + else + begin + list.concat(taicpu.op_reg_reg(f_TOpCG2AsmOp(op, size), src2, src1)); + list.concat(taicpu.op_reg(A_MFLO, dst)); + end; + end; + OP_XOR, OP_OR, OP_AND: + begin + list.concat(taicpu.op_reg_reg_reg(f_TOpCG2AsmOp_ovf(op, size), dst, src2, src1)); + end; + else + internalerror(2007012602); + end; +end; + + + +{*************** compare instructructions ****************} + +procedure TCgMPSel.a_cmp_const_reg_label(list: tasmlist; size: tcgsize; cmp_op: topcmp; a: aint; reg: tregister; l: tasmlabel); +var + tmpreg: tregister; +begin +if a = 0 then + tmpreg := NR_R0 +else +begin + tmpreg := GetIntRegister(list, OS_INT); + list.concat(taicpu.op_reg_const(A_LI, tmpreg, a)); +end; + case cmp_op of + OC_EQ: { equality comparison } + list.concat(taicpu.op_reg_reg_sym(A_BEQ, reg, tmpreg, l)); + OC_GT: { greater than (signed) } + list.concat(taicpu.op_reg_reg_sym(A_BGT, reg, tmpreg, l)); + OC_LT: { less than (signed) } + list.concat(taicpu.op_reg_reg_sym(A_BLT, reg, tmpreg, l)); + OC_GTE: { greater or equal than (signed) } + list.concat(taicpu.op_reg_reg_sym(A_BGE, reg, tmpreg, l)); + OC_LTE: { less or equal than (signed) } + list.concat(taicpu.op_reg_reg_sym(A_BLE, reg, tmpreg, l)); + OC_NE: { not equal } + list.concat(taicpu.op_reg_reg_sym(A_BNE, reg, tmpreg, l)); + OC_BE: { less or equal than (unsigned) } + list.concat(taicpu.op_reg_reg_sym(A_BLEU, reg, tmpreg, l)); + OC_B: { less than (unsigned) } + list.concat(taicpu.op_reg_reg_sym(A_BLTU, reg, tmpreg, l)); + OC_AE: { greater or equal than (unsigned) } + list.concat(taicpu.op_reg_reg_sym(A_BGEU, reg, tmpreg, l)); + OC_A: { greater than (unsigned) } + list.concat(taicpu.op_reg_reg_sym(A_BGTU, reg, tmpreg, l)); + else + internalerror(200701071); + end;{ case } + list.Concat(TAiCpu.Op_none(A_NOP)); + +end; + + +procedure TCgMPSel.a_cmp_reg_reg_label(list: tasmlist; size: tcgsize; cmp_op: topcmp; reg1, reg2: tregister; l: tasmlabel); +begin + case cmp_op of + OC_EQ: { equality comparison } + list.concat(taicpu.op_reg_reg_sym(A_BEQ, reg2, reg1, l)); + OC_GT: { greater than (signed) } + list.concat(taicpu.op_reg_reg_sym(A_BGT, reg2, reg1, l)); + OC_LT: { less than (signed) } + list.concat(taicpu.op_reg_reg_sym(A_BLT, reg2, reg1, l)); + OC_GTE: { greater or equal than (signed) } + list.concat(taicpu.op_reg_reg_sym(A_BGE, reg2, reg1, l)); + OC_LTE: { less or equal than (signed) } + list.concat(taicpu.op_reg_reg_sym(A_BLE, reg2, reg1, l)); + OC_NE: { not equal } + list.concat(taicpu.op_reg_reg_sym(A_BNE, reg2, reg1, l)); + OC_BE: { less or equal than (unsigned) } + list.concat(taicpu.op_reg_reg_sym(A_BLEU, reg2, reg1, l)); + OC_B: { less than (unsigned) } + list.concat(taicpu.op_reg_reg_sym(A_BLTU, reg2, reg1, l)); + OC_AE: { greater or equal than (unsigned) } + list.concat(taicpu.op_reg_reg_sym(A_BGEU, reg2, reg1, l)); + OC_A: { greater than (unsigned) } + list.concat(taicpu.op_reg_reg_sym(A_BGTU, reg2, reg1, l)); + else + internalerror(200701072); + end;{ case } + list.Concat(TAiCpu.Op_none(A_NOP)); +end; + + +procedure TCgMPSel.a_jmp_always(List: tasmlist; l: TAsmLabel); +begin + List.Concat(TAiCpu.op_sym(A_J, objectlibrary.newasmsymbol(l.Name, AB_EXTERNAL, AT_FUNCTION))); + { Delay slot } + list.Concat(TAiCpu.Op_none(A_NOP)); +end; + + +procedure TCgMPSel.a_jmp_name(list: tasmlist; const s: string); +begin + List.Concat(TAiCpu.op_sym(A_J, objectlibrary.newasmsymbol(s, AB_EXTERNAL, AT_FUNCTION))); + { Delay slot } + list.Concat(TAiCpu.Op_none(A_NOP)); +end; + + +procedure TCgMPSel.a_jmp_cond(list: tasmlist; cond: TOpCmp; l: TAsmLabel); +begin + internalerror(200701181); +end; + + +procedure TCgMPSel.g_overflowCheck(List: tasmlist; const Loc: TLocation; def: TDef); +begin +// this is an empty procedure +end; + +procedure TCgMPSel.g_overflowCheck_loc(List: tasmlist; const Loc: TLocation; def: TDef; ovloc: tlocation); +begin + +// this is an empty procedure + +end; + +{ *********** entry/exit code and address loading ************ } + +procedure TCgMPSel.g_proc_entry(list: tasmlist; localsize: longint; nostackframe: boolean); +var + regcounter, firstregfpu, firstreggpr: TSuperRegister; + href: treference; + usesfpr, usesgpr, gotgot: boolean; + regcounter2, firstfpureg: Tsuperregister; + cond: tasmcond; + instr: taicpu; + +begin + if STK2_dummy <> 0 then + begin + list.concat(Taicpu.Op_reg_reg_const(A_P_STK2, STK2_PTR, STK2_PTR, -STK2_dummy)); + end; + + if nostackframe then + exit; + + usesfpr := False; + if not (po_assembler in current_procinfo.procdef.procoptions) then + case target_info.abi of + abi_powerpc_aix: + firstfpureg := RS_F14; + abi_powerpc_sysv: + firstfpureg := RS_F14; + abi_default: + firstfpureg := RS_F14; + else + internalerror(2003122903); + end; + for regcounter := firstfpureg to RS_F31 do + begin + if regcounter in rg[R_FPUREGISTER].used_in_proc then + begin + usesfpr := True; + firstregfpu := regcounter; + break; + end; + end; + + usesgpr := False; + if not (po_assembler in current_procinfo.procdef.procoptions) then + for regcounter2 := RS_R13 to RS_R31 do + begin + if regcounter2 in rg[R_INTREGISTER].used_in_proc then + begin + usesgpr := True; + firstreggpr := regcounter2; + break; + end; + end; + + + LocalSize := align(LocalSize, 8); + + cgcpu_calc_stackframe_size := LocalSize; + list.concat(Taicpu.Op_reg_reg_const(A_P_FRAME, NR_FRAME_POINTER_REG, NR_R31, LocalSize)); + list.concat(Taicpu.op_none(A_P_SET_NOREORDER)); + list.concat(Taicpu.op_none(A_P_SET_NOMACRO)); + list.concat(Taicpu.Op_reg_reg_const(A_P_SW, NR_FRAME_POINTER_REG, NR_STACK_POINTER_REG, -LocalSize)); + list.concat(Taicpu.Op_reg_reg_const(A_P_SW, NR_R31, NR_STACK_POINTER_REG, -LocalSize + 4)); + list.concat(Taicpu.op_reg_reg(A_MOVE, NR_FRAME_POINTER_REG, NR_STACK_POINTER_REG)); + list.concat(Taicpu.Op_reg_reg_const(A_ADDIU, NR_STACK_POINTER_REG, NR_STACK_POINTER_REG, -LocalSize)); + if (cs_create_pic in current_settings.moduleswitches) and + (pi_needs_got in current_procinfo.flags) then + begin + current_procinfo.got := NR_GP; + end; +end; + + + + +procedure TCgMPSel.g_proc_exit(list: tasmlist; parasize: longint; nostackframe: boolean); +var + hr: treference; + localsize: aint; +begin + localsize := cgcpu_calc_stackframe_size; + if paramanager.ret_in_param(current_procinfo.procdef.rettype.def, current_procinfo.procdef.proccalloption) then + begin + reference_reset(hr); + hr.offset := 12; + hr.refaddr := addr_full; + if nostackframe then + begin + if STK2_dummy <> 0 then + list.concat(Taicpu.Op_reg_reg_const(A_P_STK2, STK2_PTR, STK2_PTR, STK2_dummy)); + list.concat(taicpu.op_reg(A_J, NR_R31)); + list.concat(Taicpu.op_none(A_NOP)); + end + else + begin + + list.concat(Taicpu.Op_reg_reg_const(A_P_LW, NR_FRAME_POINTER_REG, NR_STACK_POINTER_REG, 0)); + list.concat(Taicpu.Op_reg_reg_const(A_P_LW, NR_R31, NR_STACK_POINTER_REG, 4)); + list.concat(Taicpu.Op_reg_reg_const(A_ADDIU, NR_STACK_POINTER_REG, NR_STACK_POINTER_REG, localsize)); + if STK2_dummy <> 0 then + list.concat(Taicpu.Op_reg_reg_const(A_P_STK2, STK2_PTR, STK2_PTR, STK2_dummy)); + list.concat(taicpu.op_reg(A_J, NR_R31)); + list.concat(Taicpu.op_none(A_NOP)); + list.concat(Taicpu.op_none(A_P_SET_MACRO)); + list.concat(Taicpu.op_none(A_P_SET_REORDER)); + + end; + end + else + begin + if nostackframe then + begin + if STK2_dummy <> 0 then + list.concat(Taicpu.Op_reg_reg_const(A_P_STK2, STK2_PTR, STK2_PTR, STK2_dummy)); + list.concat(taicpu.op_reg(A_J, NR_R31)); + list.concat(Taicpu.op_none(A_NOP)); + list.concat(Taicpu.op_none(A_P_SET_MACRO)); + list.concat(Taicpu.op_none(A_P_SET_REORDER)); + end + else + begin + list.concat(Taicpu.Op_reg_reg_const(A_P_LW, NR_FRAME_POINTER_REG, NR_STACK_POINTER_REG, 0)); + list.concat(Taicpu.Op_reg_reg_const(A_P_LW, NR_R31, NR_STACK_POINTER_REG, 4)); + list.concat(Taicpu.Op_reg_reg_const(A_ADDIU, NR_STACK_POINTER_REG, NR_STACK_POINTER_REG, localsize)); + if STK2_dummy <> 0 then + list.concat(Taicpu.Op_reg_reg_const(A_P_STK2, STK2_PTR, STK2_PTR, STK2_dummy)); + list.concat(taicpu.op_reg(A_J, NR_R31)); + list.concat(Taicpu.op_none(A_NOP)); + list.concat(Taicpu.op_none(A_P_SET_MACRO)); + list.concat(Taicpu.op_none(A_P_SET_REORDER)); + end; + end; +end; + + + +{ ************* concatcopy ************ } + +procedure TCgMPSel.g_concatcopy_move(list: tasmlist; const Source, dest: treference; len: aint); +var + paraloc1, paraloc2, paraloc3: TCGPara; +begin + paraloc1.init; + paraloc2.init; + paraloc3.init; + paramanager.getintparaloc(pocall_default, 1, paraloc1); + paramanager.getintparaloc(pocall_default, 2, paraloc2); + paramanager.getintparaloc(pocall_default, 3, paraloc3); + paramanager.allocparaloc(list, paraloc3); + a_param_const(list, OS_INT, len, paraloc3); + paramanager.allocparaloc(list, paraloc2); + a_paramaddr_ref(list, dest, paraloc2); + paramanager.allocparaloc(list, paraloc2); + a_paramaddr_ref(list, Source, paraloc1); + paramanager.freeparaloc(list, paraloc3); + paramanager.freeparaloc(list, paraloc2); + paramanager.freeparaloc(list, paraloc1); + alloccpuregisters(list, R_INTREGISTER, paramanager.get_volatile_registers_int(pocall_default)); + alloccpuregisters(list, R_FPUREGISTER, paramanager.get_volatile_registers_fpu(pocall_default)); + a_call_name(list, 'FPC_MOVE'); + dealloccpuregisters(list, R_FPUREGISTER, paramanager.get_volatile_registers_fpu(pocall_default)); + dealloccpuregisters(list, R_INTREGISTER, paramanager.get_volatile_registers_int(pocall_default)); + paraloc3.done; + paraloc2.done; + paraloc1.done; +end; + + +procedure TCgMPSel.g_concatcopy(list: tasmlist; const Source, dest: treference; len: aint); +var + tmpreg1, hreg, countreg: TRegister; + src, dst: TReference; + lab: tasmlabel; + Count, count2: aint; +begin + if len > high(longint) then + internalerror(2002072704); + { anybody wants to determine a good value here :)? } + if len > 100 then + g_concatcopy_move(list, Source, dest, len) + else + begin + reference_reset(src); + reference_reset(dst); + { load the address of source into src.base } + src.base := GetAddressRegister(list); + a_loadaddr_ref_reg(list, Source, src.base); + { load the address of dest into dst.base } + dst.base := GetAddressRegister(list); + a_loadaddr_ref_reg(list, dest, dst.base); + { generate a loop } + Count := len div 4; + if Count > 4 then + begin + { the offsets are zero after the a_loadaddress_ref_reg and just } + { have to be set to 8. I put an Inc there so debugging may be } + { easier (should offset be different from zero here, it will be } + { easy to notice in the generated assembler } + countreg := GetIntRegister(list, OS_INT); + tmpreg1 := GetIntRegister(list, OS_INT); + a_load_const_reg(list, OS_INT, Count, countreg); + { explicitely allocate R_O0 since it can be used safely here } + { (for holding date that's being copied) } + objectlibrary.getlabel(lab); + a_label(list, lab); + list.concat(taicpu.op_reg_ref(A_LW, tmpreg1, src)); + list.concat(taicpu.op_reg_ref(A_SW, tmpreg1, dst)); + list.concat(taicpu.op_reg_reg_const(A_ADDIU, src.base, src.base, 4)); + list.concat(taicpu.op_reg_reg_const(A_ADDIU, dst.base, dst.base, 4)); + list.concat(taicpu.op_reg_reg_const(A_ADDIU, countreg, countreg, -1)); + list.concat(taicpu.op_reg_sym(A_BGTZ, countreg, lab)); + list.concat(taicpu.op_none(A_NOP)); + len := len mod 4; + end; + { unrolled loop } + Count := len div 4; + if Count > 0 then + begin + tmpreg1 := GetIntRegister(list, OS_INT); + for count2 := 1 to Count do + begin + list.concat(taicpu.op_reg_ref(A_LW, tmpreg1, src)); + list.concat(taicpu.op_reg_ref(A_SW, tmpreg1, dst)); + Inc(src.offset, 4); + Inc(dst.offset, 4); + end; + len := len mod 4; + end; + if (len and 4) <> 0 then + begin + hreg := GetIntRegister(list, OS_INT); + a_load_ref_reg(list, OS_32, OS_32, src, hreg); + a_load_reg_ref(list, OS_32, OS_32, hreg, dst); + Inc(src.offset, 4); + Inc(dst.offset, 4); + end; + { copy the leftovers } + if (len and 2) <> 0 then + begin + hreg := GetIntRegister(list, OS_INT); + a_load_ref_reg(list, OS_16, OS_16, src, hreg); + a_load_reg_ref(list, OS_16, OS_16, hreg, dst); + Inc(src.offset, 2); + Inc(dst.offset, 2); + end; + if (len and 1) <> 0 then + begin + hreg := GetIntRegister(list, OS_INT); + a_load_ref_reg(list, OS_8, OS_8, src, hreg); + a_load_reg_ref(list, OS_8, OS_8, hreg, dst); + end; + end; +end; + + +procedure TCgMPSel.g_concatcopy_unaligned(list: tasmlist; const Source, dest: treference; len: aint); +var + src, dst: TReference; + tmpreg1, countreg: TRegister; + i: aint; + lab: tasmlabel; +begin + if len > 31 then + g_concatcopy_move(list, Source, dest, len) + else + begin + reference_reset(src); + reference_reset(dst); + { load the address of source into src.base } + src.base := GetAddressRegister(list); + a_loadaddr_ref_reg(list, Source, src.base); + { load the address of dest into dst.base } + dst.base := GetAddressRegister(list); + a_loadaddr_ref_reg(list, dest, dst.base); + { generate a loop } + if len > 4 then + begin + { the offsets are zero after the a_loadaddress_ref_reg and just } + { have to be set to 8. I put an Inc there so debugging may be } + { easier (should offset be different from zero here, it will be } + { easy to notice in the generated assembler } + countreg := GetIntRegister(list, OS_INT); + tmpreg1 := GetIntRegister(list, OS_INT); + a_load_const_reg(list, OS_INT, len, countreg); + { explicitely allocate R_O0 since it can be used safely here } + { (for holding date that's being copied) } + objectlibrary.getlabel(lab); + a_label(list, lab); + list.concat(taicpu.op_reg_ref(A_LBU, tmpreg1, src)); + list.concat(taicpu.op_reg_ref(A_SB, tmpreg1, dst)); + list.concat(taicpu.op_reg_reg_const(A_ADDIU, src.base, src.base, 1)); + list.concat(taicpu.op_reg_reg_const(A_ADDIU, dst.base, dst.base, 1)); + list.concat(taicpu.op_reg_reg_const(A_ADDIU, countreg, countreg, -1)); + list.concat(taicpu.op_reg_sym(A_BGTZ, countreg, lab)); + list.concat(taicpu.op_none(A_NOP)); + end + else + begin + { unrolled loop } + tmpreg1 := GetIntRegister(list, OS_INT); + for i := 1 to len do + begin + list.concat(taicpu.op_reg_ref(A_LBU, tmpreg1, src)); + list.concat(taicpu.op_reg_ref(A_SB, tmpreg1, dst)); + Inc(src.offset); + Inc(dst.offset); + end; + end; + end; +end; + + +procedure TCgMPSel.g_intf_wrapper(list: tasmlist; procdef: tprocdef; const labelname: string; ioffset: longint); + procedure loadvmttor24; + var + href: treference; + begin + reference_reset_base(href, NR_R2, 0); { return value } + cg.a_load_ref_reg(list, OS_ADDR, OS_ADDR, href, NR_R24); + end; + + + procedure op_onr24methodaddr; + var + href : treference; + begin + if (procdef.extnumber=$ffff) then + Internalerror(200006139); + { call/jmp vmtoffs(%eax) ; method offs } + reference_reset_base(href, NR_R24, procdef._class.vmtmethodoffset(procdef.extnumber)); + cg.a_load_ref_reg(list, OS_ADDR, OS_ADDR, href, NR_R24); + list.concat(taicpu.op_reg(A_JR, NR_R24)); + end; +var + make_global: boolean; + href: treference; +begin + if procdef.proctypeoption <> potype_none then + Internalerror(200006137); + if not assigned(procdef._class) or + (procdef.procoptions * [po_classmethod, po_staticmethod, + po_methodpointer, po_interrupt, po_iocheck] <> []) then + Internalerror(200006138); + if procdef.owner.symtabletype <> objectsymtable then + Internalerror(200109191); + + make_global := False; + if (not current_module.is_unit) or + (procdef.owner.defowner.owner.symtabletype = globalsymtable) then + make_global := True; + + if make_global then + List.concat(Tai_symbol.Createname_global(labelname, AT_FUNCTION, 0)) + else + List.concat(Tai_symbol.Createname(labelname, AT_FUNCTION, 0)); + + { set param1 interface to self } + g_adjust_self_value(list, procdef, ioffset); + + if po_virtualmethod in procdef.procoptions then + begin + loadvmttor24; + op_onr24methodaddr; + end + else + list.concat(taicpu.op_sym(A_B, objectlibrary.newasmsymbol(procdef.mangledname, AB_EXTERNAL, AT_FUNCTION))); + { Delay slot } + list.Concat(TAiCpu.Op_none(A_NOP)); + + List.concat(Tai_symbol_end.Createname(labelname)); +end; + +{**************************************************************************** + TCG64_MIPSel +****************************************************************************} + + +procedure TCg64MPSel.a_load64_reg_ref(list: tasmlist; reg: tregister64; const ref: treference); +var + tmpref: treference; +begin + { Override this function to prevent loading the reference twice } + tmpref := ref; + cg.a_load_reg_ref(list, OS_S32, OS_S32, reg.reglo, tmpref); + Inc(tmpref.offset, 4); + cg.a_load_reg_ref(list, OS_S32, OS_S32, reg.reghi, tmpref); +end; + + +procedure TCg64MPSel.a_load64_ref_reg(list: tasmlist; const ref: treference; reg: tregister64); +var + tmpref: treference; +begin + { Override this function to prevent loading the reference twice } + tmpref := ref; + cg.a_load_ref_reg(list, OS_S32, OS_S32, tmpref, reg.reglo); + Inc(tmpref.offset, 4); + cg.a_load_ref_reg(list, OS_S32, OS_S32, tmpref, reg.reghi); +end; + + +procedure TCg64MPSel.a_param64_ref(list: tasmlist; const r: treference; const paraloc: tcgpara); +var + hreg64: tregister64; +begin + { Override this function to prevent loading the reference twice. + Use here some extra registers, but those are optimized away by the RA } + hreg64.reglo := cg.GetIntRegister(list, OS_S32); + hreg64.reghi := cg.GetIntRegister(list, OS_S32); + a_load64_ref_reg(list, r, hreg64); + a_param64_reg(list, hreg64, paraloc); +end; + + + + +procedure TCg64MPSel.a_op64_reg_reg(list: tasmlist; op: TOpCG; size: tcgsize; regsrc, regdst: TRegister64); +var + op1, op2, op_call64: TAsmOp; + tmpreg1, tmpreg2: TRegister; +begin + tmpreg1 := NR_TCR12; //GetIntRegister(list, OS_INT); + tmpreg2 := NR_TCR13; //GetIntRegister(list, OS_INT); + + case op of + OP_ADD: + begin + list.concat(taicpu.op_reg_reg_reg(A_ADDU, tmpreg1, regsrc.reglo, regdst.reglo)); + list.concat(taicpu.op_reg_reg_reg(A_SLTU, NR_TCR10, tmpreg1, regsrc.reglo)); + list.concat(taicpu.op_reg_reg_reg(A_ADDU, tmpreg2, regsrc.reghi, regdst.reghi)); + list.concat(taicpu.op_reg_reg_reg(A_ADDU, NR_TCR10, NR_TCR10, tmpreg2)); + list.concat(Taicpu.Op_reg_reg(A_MOVE, regdst.reglo, tmpreg1)); + list.concat(Taicpu.Op_reg_reg(A_MOVE, regdst.reghi, NR_TCR10)); + exit; + end; + OP_AND: + begin + list.concat(taicpu.op_reg_reg_reg(A_AND, regdst.reglo, regsrc.reglo, regdst.reglo)); + list.concat(taicpu.op_reg_reg_reg(A_AND, regdst.reghi, regsrc.reghi, regdst.reghi)); + exit; + end; + + OP_NEG: + begin + list.concat(taicpu.op_reg_reg_reg(A_SUBU, regdst.reglo, NR_R0, regsrc.reglo)); + list.concat(taicpu.op_reg_reg_reg(A_SLTU, NR_TCR10, NR_R0, regdst.reglo)); + list.concat(taicpu.op_reg_reg_reg(A_SUBU, regdst.reghi, NR_R0, regsrc.reghi)); + list.concat(taicpu.op_reg_reg_reg(A_SUBU, NR_TCR10, regdst.reghi, NR_TCR10)); + list.concat(Taicpu.Op_reg_reg(A_MOVE, regdst.reghi, NR_TCR10)); + exit; + end; + OP_NOT: + begin + list.concat(taicpu.op_reg_reg_reg(A_NOR, regdst.reglo, NR_R0, regsrc.reglo)); + list.concat(taicpu.op_reg_reg_reg(A_NOR, regdst.reghi, NR_R0, regsrc.reghi)); + exit; + end; + OP_OR: + begin + list.concat(taicpu.op_reg_reg_reg(A_OR, regdst.reglo, regsrc.reglo, regdst.reglo)); + list.concat(taicpu.op_reg_reg_reg(A_OR, regdst.reghi, regsrc.reghi, regdst.reghi)); + exit; + end; + OP_SUB: + begin + list.concat(taicpu.op_reg_reg_reg(A_SUBU, tmpreg1, regdst.reglo, regsrc.reglo)); + list.concat(taicpu.op_reg_reg_reg(A_SLTU, NR_TCR10, regdst.reglo, tmpreg1)); + list.concat(taicpu.op_reg_reg_reg(A_SUBU, tmpreg2, regdst.reghi, regsrc.reghi)); + list.concat(taicpu.op_reg_reg_reg(A_SUBU, tmpreg2, tmpreg2, NR_TCR10)); + list.concat(Taicpu.Op_reg_reg(A_MOVE, regdst.reglo, tmpreg1)); + list.concat(Taicpu.Op_reg_reg(A_MOVE, regdst.reghi, tmpreg2)); + exit; + end; + OP_XOR: + begin + list.concat(taicpu.op_reg_reg_reg(A_XOR, regdst.reglo, regdst.reglo, regsrc.reglo)); + list.concat(taicpu.op_reg_reg_reg(A_XOR, regdst.reghi, regsrc.reghi, regdst.reghi)); + exit; + end; + else + internalerror(200306017); + + end; {case} + + + +end; + + +procedure TCg64MPSel.a_op64_const_reg(list: tasmlist; op: TOpCG; size: tcgsize; Value: int64; regdst: TRegister64); +var + op1, op2: TAsmOp; +begin + case op of + OP_NEG, + OP_NOT: + internalerror(200306017); + end; + a_op64_const_reg_reg(list, op, size, value, regdst, regdst); + +end; + + +procedure TCg64MPSel.a_op64_const_reg_reg(list: tasmlist; op: TOpCG; size: tcgsize; Value: int64; regsrc, regdst: tregister64); +var + l: tlocation; +begin + a_op64_const_reg_reg_checkoverflow(list, op, size, Value, regsrc, regdst, False, l); +end; + + +procedure TCg64MPSel.a_op64_reg_reg_reg(list: tasmlist; op: TOpCG; size: tcgsize; regsrc1, regsrc2, regdst: tregister64); +var + l: tlocation; +begin + a_op64_reg_reg_reg_checkoverflow(list, op, size, regsrc1, regsrc2, regdst, False, l); +end; + + +procedure TCg64MPSel.a_op64_const_reg_reg_checkoverflow(list: tasmlist; op: TOpCG; size: tcgsize; Value: int64; regsrc, regdst: tregister64; setflags: boolean; var ovloc: tlocation); +var + op1, op2: TAsmOp; + tmpreg1: TRegister; +begin + tmpreg1 := NR_TCR12; + case op of + OP_NEG, + OP_NOT: + internalerror(200306017); + end; + + list.concat(taicpu.op_reg_const(A_LI, NR_TCR10, aint(hi(Value)))); + list.concat(taicpu.op_reg_const(A_LI, NR_TCR11, aint(lo(Value)))); + case op of + OP_ADD: + begin + list.concat(taicpu.op_reg_reg_reg(A_ADDU, regdst.reglo, regsrc.reglo, NR_TCR10)); + list.concat(taicpu.op_reg_reg_reg(A_SLTU, tmpreg1, regdst.reglo, regsrc.reglo)); + list.concat(taicpu.op_reg_reg_reg(A_ADDU, regdst.reghi, regsrc.reghi, NR_TCR11)); + list.concat(taicpu.op_reg_reg_reg(A_ADDU, tmpreg1, tmpreg1, regdst.reghi)); + list.concat(Taicpu.Op_reg_reg(A_MOVE, regdst.reghi, tmpreg1)); + exit; + end; + OP_AND: + begin + list.concat(taicpu.op_reg_reg_reg(A_AND, regdst.reglo, regsrc.reglo, NR_TCR10)); + list.concat(taicpu.op_reg_reg_reg(A_AND, regdst.reghi, regsrc.reghi, NR_TCR11)); + exit; + end; + + OP_OR: + begin + list.concat(taicpu.op_reg_reg_reg(A_OR, regdst.reglo, regsrc.reglo, NR_TCR10)); + list.concat(taicpu.op_reg_reg_reg(A_OR, regdst.reghi, regsrc.reghi, NR_TCR11)); + exit; + end; + OP_SUB: + begin + list.concat(taicpu.op_reg_reg_reg(A_SUBU, regdst.reglo, regsrc.reglo, NR_TCR10)); + list.concat(taicpu.op_reg_reg_reg(A_SLTU, tmpreg1, regsrc.reglo, regdst.reglo)); + list.concat(taicpu.op_reg_reg_reg(A_SUBU, regdst.reghi, regsrc.reghi, NR_TCR11)); + list.concat(taicpu.op_reg_reg_reg(A_SUBU, tmpreg1, regdst.reghi, tmpreg1)); + list.concat(Taicpu.Op_reg_reg(A_MOVE, regdst.reghi, tmpreg1)); + exit; + end; + OP_XOR: + begin + list.concat(taicpu.op_reg_reg_reg(A_XOR, regdst.reglo, regsrc.reglo, NR_TCR10)); + list.concat(taicpu.op_reg_reg_reg(A_XOR, regdst.reghi, regsrc.reghi, NR_TCR11)); + exit; + end; + else + internalerror(200306017); + end; + +end; + + +procedure TCg64MPSel.a_op64_reg_reg_reg_checkoverflow(list: tasmlist; op: TOpCG; size: tcgsize; regsrc1, regsrc2, regdst: tregister64; setflags: boolean; var ovloc: tlocation); +var + op1, op2: TAsmOp; + tmpreg1, tmpreg2: TRegister; + +begin + tmpreg1 := NR_TCR12; + tmpreg2 := NR_TCR13; + + case op of + OP_NEG, + OP_NOT: + internalerror(200306017); + end; + case op of + OP_ADD: + begin + list.concat(taicpu.op_reg_reg_reg(A_ADDU, tmpreg1, regsrc2.reglo, regsrc1.reglo)); + list.concat(taicpu.op_reg_reg_reg(A_SLTU, NR_TCR10, tmpreg1, regsrc2.reglo)); + list.concat(taicpu.op_reg_reg_reg(A_ADDU, tmpreg2, regsrc2.reghi, regsrc1.reghi)); + list.concat(taicpu.op_reg_reg_reg(A_ADDU, regdst.reghi, NR_TCR10, tmpreg2)); + list.concat(Taicpu.Op_reg_reg(A_MOVE, regdst.reglo, tmpreg1)); + exit; + end; + OP_AND: + begin + list.concat(taicpu.op_reg_reg_reg(A_AND, regdst.reglo, regsrc2.reglo, regsrc1.reglo)); + list.concat(taicpu.op_reg_reg_reg(A_AND, regdst.reghi, regsrc2.reghi, regsrc1.reghi)); + exit; + end; + OP_OR: + begin + list.concat(taicpu.op_reg_reg_reg(A_OR, regdst.reglo, regsrc2.reglo, regsrc1.reglo)); + list.concat(taicpu.op_reg_reg_reg(A_OR, regdst.reghi, regsrc2.reghi, regsrc1.reghi)); + exit; + end; + OP_SUB: + begin + list.concat(taicpu.op_reg_reg_reg(A_SUBU, tmpreg1, regsrc2.reglo, regsrc1.reglo)); + list.concat(taicpu.op_reg_reg_reg(A_SLTU, NR_TCR10, regsrc2.reglo, tmpreg1)); + list.concat(taicpu.op_reg_reg_reg(A_SUBU, tmpreg2, regsrc2.reghi, regsrc1.reghi)); + list.concat(taicpu.op_reg_reg_reg(A_SUBU, regdst.reghi, tmpreg2, NR_TCR10)); + list.concat(Taicpu.Op_reg_reg(A_MOVE, regdst.reglo, tmpreg1)); + exit; + end; + OP_XOR: + begin + list.concat(taicpu.op_reg_reg_reg(A_XOR, regdst.reglo, regsrc2.reglo, regsrc1.reglo)); + list.concat(taicpu.op_reg_reg_reg(A_XOR, regdst.reghi, regsrc2.reghi, regsrc1.reghi)); + exit; + end; + else + internalerror(200306017); + + end; {case} + +end; + + +begin + cg := TCgMPSel.Create; + cg64 := TCg64MPSel.Create; +end. diff --git a/compiler/mips/cpubase.pas b/compiler/mips/cpubase.pas index cfeeedc727..a3573ef140 100644 --- a/compiler/mips/cpubase.pas +++ b/compiler/mips/cpubase.pas @@ -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. diff --git a/compiler/mips/cpuinfo.pas b/compiler/mips/cpuinfo.pas index fd753666db..d1f2267378 100644 --- a/compiler/mips/cpuinfo.pas +++ b/compiler/mips/cpuinfo.pas @@ -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 } diff --git a/compiler/mips/cpupara.pas b/compiler/mips/cpupara.pas new file mode 100644 index 0000000000..9d13ab6fd0 --- /dev/null +++ b/compiler/mips/cpupara.pas @@ -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. diff --git a/compiler/mips/cpupi.pas b/compiler/mips/cpupi.pas new file mode 100644 index 0000000000..1c2dd53afd --- /dev/null +++ b/compiler/mips/cpupi.pas @@ -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 + + + + %sp+92 + \ + | included in first_parm_offset + / + %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. diff --git a/compiler/mips/opcode.inc b/compiler/mips/opcode.inc new file mode 100644 index 0000000000..f58fd3aa32 --- /dev/null +++ b/compiler/mips/opcode.inc @@ -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 diff --git a/compiler/mips/rgcpu.pas b/compiler/mips/rgcpu.pas new file mode 100644 index 0000000000..9708bc4e1b --- /dev/null +++ b/compiler/mips/rgcpu.pas @@ -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.