{
    $Id: rgcpu.pas,v 1.9 2003/04/23 13:40:33 peter Exp $
    Copyright (c) 1998-2002 by Florian Klaempfl

    This unit implements the register allocator for m68k

    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.

 ****************************************************************************
}

{$i fpcdefs.inc}
unit rgcpu;

{$i fpcdefs.inc}

  interface

     uses
       aasmbase,aasmtai,
       cpubase,
       rgobj;

     type
       trgcpu = class(trgobj)
          procedure saveStateForInline(var state: pointer);override;
          procedure restoreStateAfterInline(var state: pointer);override;
          procedure saveUnusedState(var state: pointer);override;
          procedure restoreUnusedState(var state: pointer);override;
          function isaddressregister(reg: tregister): boolean; override;
          function getaddressregister(list: taasmoutput): tregister; override;
          procedure ungetaddressregister(list: taasmoutput; r: tregister); override;
          procedure resetusableregisters;override;
          procedure restoreusedintregisters(list:Taasmoutput;
                                            const saved:Tpushedsavedint);override;
          procedure saveusedintregisters(list:Taasmoutput;
                                         var saved:Tpushedsavedint;
                                         const s:Tsupregset);override;
          procedure cleartempgen;override;

       end;

  implementation

    uses
      cgobj,tgobj,cpuinfo;

     procedure trgcpu.ungetaddressregister(list: taasmoutput; r: tregister);
       begin
         ungetregistergenint(list,r,usableregsaddr,unusedregsaddr,
           countunusedregsaddr);
       end;


    function trgcpu.getaddressregister(list: taasmoutput): tregister;

    begin
      result:=getregistergenint(list,
                                R_SUBWHOLE,
                                firstsaveaddrreg,
                                lastsaveaddrreg,
                                usedintbyproc,
                                usedintinproc,
                                unusedregsint,
                                countunusedregsint);

    end;

    function trgcpu.isaddressregister(reg: tregister): boolean;

    begin
      isaddressregister := reg.enum in addrregs;
    end;


    procedure trgcpu.resetusableregisters;

      begin
        inherited resetusableregisters;
        { initialize fields with constant values from cpubase }
        countusableregsaddr := cpubase.c_countusableregsaddr;
        usableregsaddr := cpubase.usableregsaddr;
      end;


    procedure Trgcpu.restoreusedintregisters(list:Taasmoutput;
                                             const saved:Tpushedsavedint);
    var r:Tsuperregister;
        r2,r3:Tregister;
        hr:Treference;

    begin
      inherited restoreusedintregisters(list, saved);

      for r:=lastsaveaddrreg downto firstsaveaddrreg do
        begin
          if saved[r].ofs<>reg_not_saved then
            begin
              r2.enum:=R_INTREGISTER;
              r2.number:=NR_FRAME_POINTER_REG;
              reference_reset_base(hr,r2,saved[r].ofs);
              r3.enum:=R_INTREGISTER;
              r3.number:=r shl 8 or R_SUBWHOLE;
              cg.a_reg_alloc(list,r3);
              cg.a_load_ref_reg(list,OS_ADDR,hr,r3);
              if not (r in unusedregsaddr) then
                { internalerror(10)
                  in n386cal we always save/restore the reg *state*
                  using save/restoreunusedstate -> the current state
                  may not be real (JM) }
              else
                begin
                  dec(countunusedregsaddr);
                  exclude(unusedregsaddr,r);
                end;
              tg.ungettemp(list,hr);
            end;
        end;
    end;


    procedure Trgcpu.saveusedintregisters(list:Taasmoutput;
                                          var saved:Tpushedsavedint;
                                          const s:Tsupregset);
    var r:Tsuperregister;
        r2:Tregister;
        hr:Treference;

    begin
      inherited saveusedintregisters(list,saved,s);
      for r:=firstsaveaddrreg to lastsaveaddrreg do
        begin
          saved[r].ofs:=reg_not_saved;
          { if the register is used by the calling subroutine and if }
          { it's not a regvar (those are handled separately)         }
          if not(r in is_reg_var_int) and (r in s) and
               { and is present in use }
               not(r in unusedregsaddr) then
            begin
              { then save it }
              tg.gettemp(list,pointer_size,tt_persistant,hr);
              saved[r].ofs:=hr.offset;
              r2.enum:=R_INTREGISTER;
              r2.number:=r shl 8 or R_SUBWHOLE;
              cg.a_load_reg_ref(list,OS_ADDR,r2,hr);
              cg.a_reg_dealloc(list,r2);
              include(unusedregsaddr,r);
              inc(countunusedregsaddr);
            end;
        end;
    end;



    procedure trgcpu.saveStateForInline(var state: pointer);
      begin
        inherited savestateforinline(state);
        psavedstate(state)^.unusedregsaddr := unusedregsaddr;
        psavedstate(state)^.usableregsaddr := usableregsaddr;
        psavedstate(state)^.countunusedregsaddr := countunusedregsaddr;
      end;


    procedure trgcpu.restoreStateAfterInline(var state: pointer);
      begin
        unusedregsaddr := psavedstate(state)^.unusedregsaddr;
        usableregsaddr := psavedstate(state)^.usableregsaddr;
        countunusedregsaddr := psavedstate(state)^.countunusedregsaddr;
        inherited restoreStateAfterInline(state);
      end;


    procedure trgcpu.saveUnusedState(var state: pointer);
      begin
        inherited saveUnusedState(state);
        punusedstate(state)^.unusedregsaddr := unusedregsaddr;
        punusedstate(state)^.countunusedregsaddr := countunusedregsaddr;
      end;


    procedure trgcpu.restoreUnusedState(var state: pointer);
      begin
        unusedregsaddr := punusedstate(state)^.unusedregsaddr;
        countunusedregsaddr := punusedstate(state)^.countunusedregsaddr;
        inherited restoreUnusedState(state);
      end;

    procedure trgcpu.cleartempgen;

      begin
         inherited cleartempgen;
         countunusedregsaddr:=countusableregsaddr;
         unusedregsaddr:=usableregsaddr;
      end;


initialization
  rg := trgcpu.create(16);
end.

{
  $Log: rgcpu.pas,v $
  Revision 1.9  2003/04/23 13:40:33  peter
    * fix m68k compile

  Revision 1.8  2003/04/22 10:09:35  daniel
    + Implemented the actual register allocator
    + Scratch registers unavailable when new register allocator used
    + maybe_save/maybe_restore unavailable when new register allocator used

  Revision 1.7  2003/02/19 22:00:16  daniel
    * Code generator converted to new register notation
    - Horribily outdated todo.txt removed

  Revision 1.6  2003/02/02 19:25:54  carl
    * Several bugfixes for m68k target (register alloc., opcode emission)
    + VIS target
    + Generic add more complete (still not verified)

  Revision 1.5  2003/01/08 18:43:57  daniel
   * Tregister changed into a record

  Revision 1.4  2002/09/07 15:25:14  peter
    * old logs removed and tabs fixed

  Revision 1.3  2002/08/23 16:14:50  peter
    * tempgen cleanup
    * tt_noreuse temp type added that will be used in genentrycode

  Revision 1.2  2002/08/12 15:08:44  carl
    + stab register indexes for powerpc (moved from gdb to cpubase)
    + tprocessor enumeration moved to cpuinfo
    + linker in target_info is now a class
    * many many updates for m68k (will soon start to compile)
    - removed some ifdef or correct them for correct cpu

  Revision 1.1  2002/08/05 17:26:09  carl
    + updated m68k

}
