mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-11-04 11:24:16 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			218 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			218 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
{
 | 
						|
    Copyright (c) 1998-2004 by Jonas Maebe
 | 
						|
 | 
						|
    This unit calls the optimization procedures to optimize the assembler
 | 
						|
    code for sparc
 | 
						|
 | 
						|
    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 aoptcpu;
 | 
						|
 | 
						|
{$i fpcdefs.inc}
 | 
						|
 | 
						|
  Interface
 | 
						|
 | 
						|
    uses
 | 
						|
      cgbase, cpubase, aoptobj, aoptcpub, aopt, aasmtai;
 | 
						|
 | 
						|
    Type
 | 
						|
      TCpuAsmOptimizer = class(TAsmOptimizer)
 | 
						|
        function TryRemoveMov(var p: tai; opcode: TAsmOp): boolean;
 | 
						|
        function PeepHoleOptPass1Cpu(var p: tai): boolean; override;
 | 
						|
      End;
 | 
						|
 | 
						|
  Implementation
 | 
						|
 | 
						|
     uses
 | 
						|
       aasmcpu;
 | 
						|
 | 
						|
 | 
						|
  function MatchInstruction(const instr: tai; const op: TAsmOp): boolean;
 | 
						|
    begin
 | 
						|
      result :=
 | 
						|
        (instr.typ = ait_instruction) and
 | 
						|
        (taicpu(instr).opcode = op);
 | 
						|
    end;
 | 
						|
 | 
						|
 | 
						|
  function MatchOperand(const oper: TOper; reg: TRegister): boolean;
 | 
						|
    begin
 | 
						|
      result:=(oper.typ=top_reg) and (oper.reg=reg);
 | 
						|
    end;
 | 
						|
 | 
						|
 | 
						|
  function IsSameReg(this,next: taicpu): boolean;
 | 
						|
    begin
 | 
						|
      result:=(next.oper[0]^.typ=top_reg) and
 | 
						|
        (next.oper[1]^.typ=top_reg) and
 | 
						|
        (next.oper[0]^.reg=next.oper[1]^.reg) and
 | 
						|
        (next.oper[0]^.reg=this.oper[0]^.reg);
 | 
						|
    end;
 | 
						|
 | 
						|
 | 
						|
  function TCpuAsmOptimizer.TryRemoveMov(var p: tai; opcode: TAsmOp): boolean;
 | 
						|
    var
 | 
						|
      next,hp1: tai;
 | 
						|
      alloc,dealloc: tai_regalloc;
 | 
						|
    begin
 | 
						|
      { Fold
 | 
						|
          op      $reg1,...
 | 
						|
          opcode  $reg2,$reg1
 | 
						|
          dealloc $reg1
 | 
						|
        into
 | 
						|
          op   $reg2,...
 | 
						|
        opcode may be A_MOVE, A_MOV_s, A_MOV_d, etc.
 | 
						|
      }
 | 
						|
      result:=false;
 | 
						|
      if GetNextInstruction(p,next) and
 | 
						|
         MatchInstruction(next,opcode) and
 | 
						|
         MatchOperand(taicpu(next).oper[1]^,taicpu(p).oper[0]^.reg) then
 | 
						|
        begin
 | 
						|
          dealloc:=FindRegDealloc(taicpu(p).oper[0]^.reg,tai(next.Next));
 | 
						|
          if assigned(dealloc) then
 | 
						|
            begin
 | 
						|
              { taicpu(p).oper[0]^.reg is not used anymore, try to find its allocation
 | 
						|
                and remove it if possible }
 | 
						|
              GetLastInstruction(p,hp1);
 | 
						|
 | 
						|
              asml.Remove(dealloc);
 | 
						|
              alloc:=FindRegAlloc(taicpu(p).oper[0]^.reg,tai(hp1.Next));
 | 
						|
              if assigned(alloc) then
 | 
						|
                begin
 | 
						|
                  asml.Remove(alloc);
 | 
						|
                  alloc.free;
 | 
						|
                  dealloc.free;
 | 
						|
                end
 | 
						|
              else
 | 
						|
                asml.InsertAfter(dealloc,p);
 | 
						|
 | 
						|
              { try to move the allocation of the target register }
 | 
						|
              GetLastInstruction(next,hp1);
 | 
						|
              alloc:=FindRegAlloc(taicpu(next).oper[0]^.reg,tai(hp1.Next));
 | 
						|
              if assigned(alloc) then
 | 
						|
                begin
 | 
						|
                  asml.Remove(alloc);
 | 
						|
                  asml.InsertBefore(alloc,p);
 | 
						|
                  { adjust used regs }
 | 
						|
                  IncludeRegInUsedRegs(taicpu(next).oper[0]^.reg,UsedRegs);
 | 
						|
                end;
 | 
						|
 | 
						|
              { finally get rid of the mov }
 | 
						|
              taicpu(p).loadreg(0,taicpu(next).oper[0]^.reg);
 | 
						|
              asml.remove(next);
 | 
						|
              next.free;
 | 
						|
            end;
 | 
						|
        end;
 | 
						|
    end;
 | 
						|
 | 
						|
 | 
						|
  function TCpuAsmOptimizer.PeepHoleOptPass1Cpu(var p: tai): boolean;
 | 
						|
    var
 | 
						|
      next,next2: tai;
 | 
						|
    begin
 | 
						|
      result:=false;
 | 
						|
      case p.typ of
 | 
						|
        ait_instruction:
 | 
						|
          begin
 | 
						|
            case taicpu(p).opcode of
 | 
						|
              A_SRL:
 | 
						|
                begin
 | 
						|
                  { Remove 'andi' in sequences
 | 
						|
                      srl   Rx,Ry,16
 | 
						|
                      andi  Rx,Rx,65535
 | 
						|
 | 
						|
                      srl   Rx,Ry,24
 | 
						|
                      andi  Rx,Rx,255
 | 
						|
                    since 'srl' clears all relevant upper bits }
 | 
						|
                  if (taicpu(p).oper[2]^.typ=top_const) and
 | 
						|
                    GetNextInstruction(p,next) and
 | 
						|
                    MatchInstruction(next,A_ANDI) and
 | 
						|
                    IsSameReg(taicpu(p),taicpu(next)) and
 | 
						|
                    (taicpu(next).oper[2]^.typ=top_const) and
 | 
						|
                    ((
 | 
						|
                      (taicpu(p).oper[2]^.val>=16) and
 | 
						|
                      (taicpu(next).oper[2]^.val=65535)
 | 
						|
                    ) or (
 | 
						|
                      (taicpu(p).oper[2]^.val>=24) and
 | 
						|
                      (taicpu(next).oper[2]^.val=255)
 | 
						|
                    )) then
 | 
						|
                    begin
 | 
						|
                      asml.remove(next);
 | 
						|
                      next.free;
 | 
						|
                    end
 | 
						|
                  else
 | 
						|
                    TryRemoveMov(p,A_MOVE);
 | 
						|
                end;
 | 
						|
 | 
						|
              A_ANDI:
 | 
						|
                begin
 | 
						|
                  { Remove sign extension after 'andi' if bit 7/15 of const operand is clear }
 | 
						|
                  if (taicpu(p).oper[2]^.typ=top_const) and
 | 
						|
                    GetNextInstruction(p,next) and
 | 
						|
                    MatchInstruction(next,A_SLL) and
 | 
						|
                    GetNextInstruction(next,next2) and
 | 
						|
                    MatchInstruction(next2,A_SRA) and
 | 
						|
                    IsSameReg(taicpu(p),taicpu(next)) and
 | 
						|
                    IsSameReg(taicpu(p),taicpu(next2)) and
 | 
						|
                    (taicpu(next).oper[2]^.typ=top_const) and
 | 
						|
                    (taicpu(next2).oper[2]^.typ=top_const) and
 | 
						|
                    (taicpu(next).oper[2]^.val=taicpu(next2).oper[2]^.val) and
 | 
						|
                    ((
 | 
						|
                      (taicpu(p).oper[2]^.val<=$7fff) and
 | 
						|
                      (taicpu(next).oper[2]^.val=16)
 | 
						|
                    ) or (
 | 
						|
                      (taicpu(p).oper[2]^.val<=$7f) and
 | 
						|
                      (taicpu(next).oper[2]^.val=24)
 | 
						|
                    )) then
 | 
						|
                    begin
 | 
						|
                      asml.remove(next);
 | 
						|
                      asml.remove(next2);
 | 
						|
                      next.free;
 | 
						|
                      next2.free;
 | 
						|
                    end
 | 
						|
                  else
 | 
						|
                    TryRemoveMov(p,A_MOVE);
 | 
						|
                end;
 | 
						|
 | 
						|
              A_ADD,A_ADDU,
 | 
						|
              A_ADDI,A_ADDIU,
 | 
						|
              A_SUB,A_SUBU,
 | 
						|
              A_SRA,A_SRAV,
 | 
						|
              A_SRLV,
 | 
						|
              A_SLL,A_SLLV,
 | 
						|
              A_AND,A_OR,A_XOR,A_ORI,A_XORI:
 | 
						|
                TryRemoveMov(p,A_MOVE);
 | 
						|
 | 
						|
              A_ADD_s, A_SUB_s, A_MUL_s, A_DIV_s,
 | 
						|
              A_ABS_s, A_NEG_s, A_SQRT_s,
 | 
						|
              A_CVT_s_w, A_CVT_s_l, A_CVT_s_d:
 | 
						|
                TryRemoveMov(p,A_MOV_s);
 | 
						|
 | 
						|
              A_ADD_d, A_SUB_d, A_MUL_d, A_DIV_d,
 | 
						|
              A_ABS_d, A_NEG_d, A_SQRT_d,
 | 
						|
              A_CVT_d_w, A_CVT_d_l, A_CVT_d_s:
 | 
						|
                TryRemoveMov(p,A_MOV_d);
 | 
						|
            end;
 | 
						|
          end;
 | 
						|
      end;
 | 
						|
    end;
 | 
						|
 | 
						|
begin
 | 
						|
  casmoptimizer:=TCpuAsmOptimizer;
 | 
						|
end.
 |