{
    Copyright (c) 2015 by Jonas Maebe, member of the Free Pascal
    Development Team

    This unit implements the JVM optimizer object

    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 cpubase, aasmtai, aopt, aoptcpub;

Type
  TCpuAsmOptimizer = class(TAsmOptimizer)
   protected
    function RemoveDoubleSwap(var p: tai): boolean;
    function RemoveCommutativeSwap(var p: tai): boolean;
    function RemoveLoadLoadSwap(var p: tai): boolean;
   public
    { uses the same constructor as TAopObj }
    function PeepHoleOptPass1Cpu(var p: tai): boolean; override;
    procedure PeepHoleOptPass2;override;
    function PostPeepHoleOptsCpu(var p: tai): boolean; override;
  End;

Implementation

  uses
    aasmbase,aasmcpu,cgbase;


  function TCpuAsmOptimizer.RemoveDoubleSwap(var p: tai): boolean;
    var
      next, next2: tai;
    begin
      result:=false;
      { remove two successive "swap" instructions }
      if (taicpu(p).opcode=a_swap) and
         GetNextInstruction(p,next) and
         (next.typ=ait_instruction) and
         (taicpu(next).opcode=a_swap) then
        begin
          { can't be the instruction, must end in a return or so }
          next2:=tai(next.next);
          asml.remove(p);
          asml.remove(next);
          p.free;
          next.free;
          p:=next2;
          result:=true;
        end;
    end;


  { returns whether p is an instruction that does not consume any stack slots,
    and adds a new item on the stack that is one stack slot wide }
  function OpCreatesSingleStackSlot(p: tai): boolean;
    begin
      result:=
        (p.typ=ait_instruction) and
        (taicpu(p).opcode in
          [a_aload, a_aload_0, a_aload_1, a_aload_2, a_aload_3,
           a_bipush,
           a_fconst_0, a_fconst_1, a_fconst_2,
           a_fload, a_fload_0, a_fload_1, a_fload_2, a_fload_3,
           a_getstatic,
           a_iconst_m1, a_iconst_0, a_iconst_1, a_iconst_2, a_iconst_3,
           a_iconst_4, a_iconst_5,
           a_iload, a_iload_0, a_iload_1, a_iload_2, a_iload_3,
           a_new,
           a_sipush]);
    end;


  function OpIsCommutativeSingleSlots(p: tai): boolean;
    begin
      result:=
        (p.typ=ait_instruction) and
        (taicpu(p).opcode in
          [a_fadd, a_fmul,
           a_iadd, a_iand, a_imul, a_ior, a_ixor,
           a_pop2])
    end;


  function TCpuAsmOptimizer.RemoveCommutativeSwap(var p: tai): boolean;
    var
      next: tai;
    begin
      result:=false;
      if (taicpu(p).opcode<>a_swap) then
        exit;
      { if the next opcode is commutative operation, we can remove the swap }
      if GetNextInstruction(p,next) and
         OpIsCommutativeSingleSlots(next) then
        begin
          asml.remove(p);
          p.free;
          p:=next;
          result:=true;
          exit;
        end;
    end;


  function TCpuAsmOptimizer.PeepHoleOptPass1Cpu(var p: tai): boolean;
    var
      next, next2: tai;
    begin
      result:=false;
      case p.typ of
        ait_instruction:
          begin
            if RemoveDoubleSwap(p) or
               RemoveCommutativeSwap(p) then
              exit(true)
          end;
      end;
    end;


  procedure TCpuAsmOptimizer.PeepHoleOptPass2;
    begin
    end;


  function TCpuAsmOptimizer.RemoveLoadLoadSwap(var p: tai): boolean;
    var
      next, prev1, prev2: tai;
    begin
      result:=false;
      if (taicpu(p).opcode<>a_swap) then
        exit;
      { if we can swap the previous two instructions that put the items on the
        stack, we can remove the swap -- only do this in PostPeepholeOpts,
        because this may make the temp alloc information invalid. Ideally, we
        should move the tempallocs around too }
      if GetLastInstruction(p,prev1) and
         OpCreatesSingleStackSlot(prev1) and
         GetLastInstruction(prev1,prev2) and
         OpCreatesSingleStackSlot(prev2) then
        begin
          next:=tai(p.next);
          asml.remove(prev2);
          asml.InsertAfter(prev2,prev1);
          asml.remove(p);
          p.free;
          p:=next;
          result:=true;
        end;
    end;


  function TCpuAsmOptimizer.PostPeepHoleOptsCpu(var p: tai): boolean;
    begin
      result:=
        (p.typ=ait_instruction) and
        RemoveLoadLoadSwap(p);
    end;

begin
  casmoptimizer:=TCpuAsmOptimizer;
End.

