mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-11-04 03:39:40 +01:00 
			
		
		
		
	so that they can still be freed after the reference has been changed
    (e.g. in case of array indexing or record field accesses) (mantis #33628)
git-svn-id: trunk@38814 -
		
	
			
		
			
				
	
	
		
			178 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			178 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
{
 | 
						|
    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.
 | 
						|
 | 
						|
 ****************************************************************************
 | 
						|
}
 | 
						|
 | 
						|
unit rgcpu;
 | 
						|
 | 
						|
{$i fpcdefs.inc}
 | 
						|
 | 
						|
  interface
 | 
						|
 | 
						|
     uses
 | 
						|
       aasmbase,aasmtai,aasmdata,aasmsym,aasmcpu,
 | 
						|
       cgbase,cgutils,cpubase,
 | 
						|
       rgobj;
 | 
						|
 | 
						|
     type
 | 
						|
       trgcpu = class(trgobj)
 | 
						|
         procedure do_spill_read(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister); override;
 | 
						|
         procedure do_spill_written(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister); override;
 | 
						|
         function do_spill_replace(list : TAsmList;instr : tai_cpu_abstract_sym; orgreg : tsuperregister;const spilltemp : treference) : boolean; override;
 | 
						|
       end;
 | 
						|
 | 
						|
  implementation
 | 
						|
 | 
						|
    uses
 | 
						|
      cutils,cgobj,verbose,globtype,globals,cpuinfo;
 | 
						|
 | 
						|
    { returns True if source operand of MOVE can be replaced with spilltemp when its destination is ref^. }
 | 
						|
    function isvalidmovedest(ref: preference): boolean; inline;
 | 
						|
      begin
 | 
						|
        { The following is for Coldfire, for other CPUs it maybe can be relaxed. }
 | 
						|
        result:=(ref^.symbol=nil) and (ref^.scalefactor<=1) and
 | 
						|
          (ref^.index=NR_NO) and (ref^.base<>NR_NO) and (ref^.offset>=low(smallint)) and
 | 
						|
          (ref^.offset<=high(smallint));
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure trgcpu.do_spill_read(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister);
 | 
						|
      var
 | 
						|
        helpins  : tai;
 | 
						|
        tmpref   : treference;
 | 
						|
        helplist : tasmlist;
 | 
						|
        hreg     : tregister;
 | 
						|
      begin
 | 
						|
        if (abs(spilltemp.offset)>32767) and (current_settings.cputype in (cpu_coldfire + [cpu_mc68000])) then
 | 
						|
          begin
 | 
						|
            helplist:=tasmlist.create;
 | 
						|
 | 
						|
            if getregtype(tempreg)=R_INTREGISTER then
 | 
						|
              hreg:=tempreg
 | 
						|
            else
 | 
						|
              hreg:=cg.getintregister(helplist,OS_ADDR);
 | 
						|
{$ifdef DEBUG_SPILLING}
 | 
						|
            helplist.concat(tai_comment.Create(strpnew('Spilling: Read, large offset')));
 | 
						|
{$endif}
 | 
						|
 | 
						|
            helplist.concat(taicpu.op_const_reg(A_MOVE,S_L,spilltemp.offset,hreg));
 | 
						|
            reference_reset_base(tmpref,spilltemp.base,0,spilltemp.temppos,sizeof(aint),[]);
 | 
						|
            tmpref.index:=hreg;
 | 
						|
 | 
						|
            helpins:=spilling_create_load(tmpref,tempreg);
 | 
						|
            helplist.concat(helpins);
 | 
						|
            list.insertlistafter(pos,helplist);
 | 
						|
            helplist.free;
 | 
						|
          end
 | 
						|
        else
 | 
						|
          inherited;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure trgcpu.do_spill_written(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister);
 | 
						|
      var
 | 
						|
        tmpref   : treference;
 | 
						|
        helplist : tasmlist;
 | 
						|
        hreg     : tregister;
 | 
						|
      begin
 | 
						|
        if (abs(spilltemp.offset)>32767) and (current_settings.cputype in (cpu_coldfire + [cpu_mc68000])) then
 | 
						|
          begin
 | 
						|
            helplist:=tasmlist.create;
 | 
						|
 | 
						|
            if getregtype(tempreg)=R_INTREGISTER then
 | 
						|
              hreg:=getregisterinline(helplist,[R_SUBWHOLE])
 | 
						|
            else
 | 
						|
              hreg:=cg.getintregister(helplist,OS_ADDR);
 | 
						|
{$ifdef DEBUG_SPILLING}
 | 
						|
            helplist.concat(tai_comment.Create(strpnew('Spilling: Write, large offset')));
 | 
						|
{$endif}
 | 
						|
 | 
						|
            helplist.concat(taicpu.op_const_reg(A_MOVE,S_L,spilltemp.offset,hreg));
 | 
						|
            reference_reset_base(tmpref,spilltemp.base,0,spilltemp.temppos,sizeof(aint),[]);
 | 
						|
            tmpref.index:=hreg;
 | 
						|
 | 
						|
            helplist.concat(spilling_create_store(tempreg,tmpref));
 | 
						|
            if getregtype(tempreg)=R_INTREGISTER then
 | 
						|
              ungetregisterinline(helplist,hreg);
 | 
						|
 | 
						|
            list.insertlistafter(pos,helplist);
 | 
						|
            helplist.free;
 | 
						|
          end
 | 
						|
        else
 | 
						|
          inherited;
 | 
						|
    end;
 | 
						|
 | 
						|
 | 
						|
    function trgcpu.do_spill_replace(list : TAsmList;instr : tai_cpu_abstract_sym; orgreg : tsuperregister;const spilltemp : treference) : boolean;
 | 
						|
      var
 | 
						|
        opidx: longint;
 | 
						|
      begin
 | 
						|
        result:=false;
 | 
						|
        opidx:=-1;
 | 
						|
        if (abs(spilltemp.offset)>32767) and (current_settings.cputype in cpu_coldfire) then
 | 
						|
          exit;
 | 
						|
        case instr.ops of
 | 
						|
          1:
 | 
						|
            begin
 | 
						|
              if (instr.oper[0]^.typ=top_reg) and (getregtype(instr.oper[0]^.reg)=regtype) and
 | 
						|
                ((instr.opcode=A_TST) or (instr.opcode=A_CLR)) then
 | 
						|
                begin
 | 
						|
                  if get_alias(getsupreg(instr.oper[0]^.reg))<>orgreg then
 | 
						|
                    InternalError(2014080101);
 | 
						|
                  opidx:=0;
 | 
						|
                end;
 | 
						|
            end;
 | 
						|
          2:
 | 
						|
            begin
 | 
						|
              if (instr.oper[0]^.typ=top_reg) and (getregtype(instr.oper[0]^.reg)=regtype) and
 | 
						|
                (get_alias(getsupreg(instr.oper[0]^.reg))=orgreg) then
 | 
						|
                begin
 | 
						|
                  { source can be replaced if dest is register... }
 | 
						|
                  if ((instr.oper[1]^.typ=top_reg) and (instr.opcode in [A_MOVE,A_ADD,A_SUB,A_AND,A_OR,A_CMP])) or
 | 
						|
                    {... or a "simple" reference in case of MOVE }
 | 
						|
                    ((instr.opcode=A_MOVE) and (instr.oper[1]^.typ=top_ref) and isvalidmovedest(instr.oper[1]^.ref)) then
 | 
						|
                    opidx:=0;
 | 
						|
                end
 | 
						|
              else if (instr.oper[1]^.typ=top_reg) and (getregtype(instr.oper[1]^.reg)=regtype) and
 | 
						|
                (get_alias(getsupreg(instr.oper[1]^.reg))=orgreg) and
 | 
						|
                ((
 | 
						|
                  (instr.opcode in [A_MOVE,A_ADD,A_SUB,A_AND,A_OR]) and
 | 
						|
                  (instr.oper[0]^.typ=top_reg) and not
 | 
						|
                  (isaddressregister(instr.oper[0]^.reg))
 | 
						|
                ) or
 | 
						|
                (instr.opcode in [A_ADDQ,A_SUBQ,A_MOV3Q])) then
 | 
						|
                opidx:=1;
 | 
						|
            end;
 | 
						|
        end;
 | 
						|
 | 
						|
        if (opidx<0) then
 | 
						|
          exit;
 | 
						|
        instr.oper[opidx]^.typ:=top_ref;
 | 
						|
        new(instr.oper[opidx]^.ref);
 | 
						|
        instr.oper[opidx]^.ref^:=spilltemp;
 | 
						|
        case taicpu(instr).opsize of
 | 
						|
          S_B: inc(instr.oper[opidx]^.ref^.offset,3);
 | 
						|
          S_W: inc(instr.oper[opidx]^.ref^.offset,2);
 | 
						|
        end;
 | 
						|
        result:=true;
 | 
						|
      end;
 | 
						|
 | 
						|
end.
 |