Переглянути джерело

* 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/ra68kmot.pas svneol=native#text/plain
 compiler/m68k/rgcpu.pas svneol=native#text/plain
 compiler/m68k/rgcpu.pas svneol=native#text/plain
 compiler/mips/aasmcpu.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/cpubase.pas svneol=native#text/plain
 compiler/mips/cpuinfo.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/itcpugas.pas svneol=native#text/plain
 compiler/mips/mipsreg.dat 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/rmipscon.inc svneol=native#text/plain
 compiler/mips/rmipsdwf.inc svneol=native#text/plain
 compiler/mips/rmipsdwf.inc svneol=native#text/plain
 compiler/mips/rmipsgas.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_full,
          addr_pic,
          addr_pic,
          addr_pic_no_got
          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_low,         // bits 48-63
          addr_high,        // bits 32-47
          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_name(list : TAsmList;const s : string); virtual; abstract;
           procedure a_jmp_always(list : TAsmList;l: tasmlabel); 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;
           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)
           {# 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_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;
           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
              This routine tries to optimize the op_const_reg/ref opcode, and should be
@@ -3463,6 +3465,7 @@ implementation
       end;
       end;
 
 
 
 
+{$ifdef cpuflags}
     procedure tcg.g_flags2ref(list: TAsmList; size: TCgSize; const f: tresflags; const ref:TReference);
     procedure tcg.g_flags2ref(list: TAsmList; size: TCgSize; const f: tresflags; const ref:TReference);
 
 
       var
       var
@@ -3472,6 +3475,7 @@ implementation
         g_flags2reg(list,size,f,tmpreg);
         g_flags2reg(list,size,f,tmpreg);
         a_load_reg_ref(list,size,size,tmpreg,ref);
         a_load_reg_ref(list,size,size,tmpreg,ref);
       end;
       end;
+{$endif cpuflags}
 
 
 
 
     procedure tcg.g_maybe_testself(list : TAsmList;reg:tregister);
     procedure tcg.g_maybe_testself(list : TAsmList;reg:tregister);

+ 2 - 0
compiler/cgutils.pas

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

+ 9 - 0
compiler/fpcdefs.inc

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

+ 5 - 0
compiler/globals.pas

@@ -401,6 +401,11 @@ interface
         optimizecputype : cpuinfo.cpu_avr;
         optimizecputype : cpuinfo.cpu_avr;
         fputype : fpu_none;
         fputype : fpu_none;
 {$endif avr}
 {$endif avr}
+{$ifdef mips}
+        cputype : cpu_mips32;
+        optimizecputype : cpu_mips32;
+        fputype : fpu_mips2;
+{$endif mips}
         asmmode : asmmode_standard;
         asmmode : asmmode_standard;
         interfacetype : it_interfacecom;
         interfacetype : it_interfacecom;
         defproccall : pocall_default;
         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
     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
     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
     it under the terms of the GNU General Public License as published by
@@ -43,28 +43,7 @@ unit cpubase;
 *****************************************************************************}
 *****************************************************************************}
 
 
     type
     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 }
       { This should define the array of instructions as string }
       op2strtable=array[tasmop] of string[11];
       op2strtable=array[tasmop] of string[11];
@@ -126,94 +105,28 @@ unit cpubase;
     type
     type
       totherregisterset = set of tregisterindex;
       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
                                 Conditions
 *****************************************************************************}
 *****************************************************************************}
 
 
     type
     type
       TAsmCond=(C_None,
       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
                                  Constants
 *****************************************************************************}
 *****************************************************************************}
@@ -224,7 +137,7 @@ unit cpubase;
       { Constant defining possibly all registers which might require saving }
       { Constant defining possibly all registers which might require saving }
       ALL_OTHERREGISTERS = [];
       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
       { Table of registers which can be allocated by the code generator
         internally, when generating the code.
         internally, when generating the code.
@@ -238,7 +151,7 @@ unit cpubase;
       {           passing on ABI's that define this)                           }
       {           passing on ABI's that define this)                           }
       { c_countusableregsxxx = amount of registers in the usableregsxxx set    }
       { c_countusableregsxxx = amount of registers in the usableregsxxx set    }
 
 
-      maxintregs = 15;
+      maxintregs = 31;
       { to determine how many registers to use for regvars }
       { to determine how many registers to use for regvars }
       maxintscratchregs = 3;
       maxintscratchregs = 3;
       usableregsint = [RS_R4..RS_R10];
       usableregsint = [RS_R4..RS_R10];
@@ -300,44 +213,61 @@ unit cpubase;
                           Generic Register names
                           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) }
       { 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 }
       { 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 }
       { 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 }
       { 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 }
       { 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 }
       { 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_FPU_RESULT_REG = NR_F0;
-
       NR_MM_RESULT_REG  = NR_NO;
       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
                        GCC /ABI linking information
@@ -351,12 +281,12 @@ unit cpubase;
         This value can be deduced from the CALLED_USED_REGISTERS array in the
         This value can be deduced from the CALLED_USED_REGISTERS array in the
         GCC source.
         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 }
       { this is only for the generic code which is not used for this architecture }
       saved_mm_registers : array[0..0] of tsuperregister = (RS_NO);
       saved_mm_registers : array[0..0] of tsuperregister = (RS_NO);
-      
+
       { Required parameter alignment when calling a routine declared as
       { Required parameter alignment when calling a routine declared as
         stdcall and cdecl. The alignment value should be the one defined
         stdcall and cdecl. The alignment value should be the one defined
         by GCC or the target ABI.
         by GCC or the target ABI.
@@ -373,17 +303,12 @@ unit cpubase;
 
 
     { Returns the tcgsize corresponding with the size of reg.}
     { Returns the tcgsize corresponding with the size of reg.}
     function reg_cgsize(const reg: tregister) : tcgsize;
     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;
     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 findreg_by_number(r:Tregister):tregisterindex;
     function std_regnum_search(const s:string):Tregister;
     function std_regnum_search(const s:string):Tregister;
     function std_regname(r:Tregister):string;
     function std_regname(r:Tregister):string;
 
 
-    procedure shifterop_reset(var so : tshifterop);
-    function is_pc(const r : tregister) : boolean;
-
   implementation
   implementation
 
 
     uses
     uses
@@ -404,21 +329,27 @@ unit cpubase;
       );
       );
 
 
 
 
-    function cgsize2subreg(s:Tcgsize):Tsubregister;
+    function cgsize2subreg(regtype: tregistertype; s:tcgsize):tsubregister;
       begin
       begin
-        cgsize2subreg:=R_SUBWHOLE;
+        if s in [OS_64,OS_S64] then
+          cgsize2subreg:=R_SUBQ
+        else
+          cgsize2subreg:=R_SUBWHOLE;
       end;
       end;
 
 
 
 
     function reg_cgsize(const reg: tregister): tcgsize;
     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
       begin
         case getregtype(reg) of
         case getregtype(reg) of
           R_INTREGISTER :
           R_INTREGISTER :
             reg_cgsize:=OS_32;
             reg_cgsize:=OS_32;
           R_FPUREGISTER :
           R_FPUREGISTER :
-            reg_cgsize:=OS_F80;
+            begin
+              if getsubreg(reg)=R_SUBFD then
+                result:=OS_F64
+              else
+                result:=OS_F32;
+            end;
           else
           else
             internalerror(200303181);
             internalerror(200303181);
           end;
           end;
@@ -435,29 +366,21 @@ unit cpubase;
       end;
       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
       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
       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
       begin
         result:=rgBase.findreg_by_number_table(r,regnumber_index);
         result:=rgBase.findreg_by_number_table(r,regnumber_index);
       end;
       end;
@@ -481,15 +404,4 @@ unit cpubase;
       end;
       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.
 end.

+ 4 - 6
compiler/mips/cpuinfo.pas

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