Преглед изворни кода

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

git-svn-id: trunk@14219 -
florian пре 15 година
родитељ
комит
e5ebb2a26e

+ 5 - 0
.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

+ 1 - 1
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

+ 4 - 0
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);

+ 2 - 0
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}

+ 9 - 0
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}

+ 5 - 0
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;

+ 1972 - 0
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.

+ 88 - 176
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'
       );
 
-      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
+    const
+      cond2str : array[TAsmCond] of string[3]=('',
+        'eq','ne','lt','le','gt','ge','ltu','leu','gtu','geu',
+        'feq','fne','fgt','flt','fge','fle'
       );
 
-{*****************************************************************************
-                                   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);
-      const
-        inv_flags: array[TResFlags] of TResFlags =
-          (F_NE,F_EQ,F_CC,F_CS,F_PL,F_MI,F_VC,F_VS,F_LS,F_HI,
-          F_LT,F_GE,F_LE,F_GT);
-      begin
-        f:=inv_flags[f];
-      end;
-
-
-    function flags_to_cond(const f: TResFlags) : TAsmCond;
+    function inverse_cond(const c: TAsmCond): TAsmCond; {$ifdef USEINLINE}inline;{$endif USEINLINE}
       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);
+        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
-        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.

+ 4 - 6
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 }

+ 342 - 0
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.

+ 76 - 0
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
+            <locals>
+            <temp>
+            <arguments 6-n for calling>
+          %sp+92
+            <space for arguments 0-5>                \
+            <return pointer for calling>              | included in first_parm_offset
+            <register window save area for calling>  /
+          %sp
+
+          Alignment must be the max available, as doubles require
+          8 byte alignment
+        }
+        result:=Align(tg.direction*tg.lasttemp+maxpushedparasize+target_info.first_parm_offset,current_settings.alignment.localalignmax);
+      end;
+
+
+begin
+  cprocinfo:=TMIPSProcInfo;
+end.

+ 241 - 0
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

+ 165 - 0
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.