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

    This unit contains the interface routines between the code generator
    and the optimizer.

    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 aopt;

{$i fpcdefs.inc}

  Interface

    Uses
      aasmbase,aasmtai,aasmcpu,
      aoptobj;

    Type
      TAsmOptimizer = class(TAoptObj)

        { _AsmL is the PAasmOutpout list that has to be optimized }
        Constructor create(_AsmL: taasmoutput); virtual;

        { call the necessary optimizer procedures }
        Procedure Optimize;
        Destructor destroy;override;

      private
        procedure FindLoHiLabels;
        Procedure BuildLabelTableAndFixRegAlloc;
        procedure clear;
        procedure pass_1;
      End;

    var
      casmoptimizer : class of tasmoptimizer;

    procedure Optimize(AsmL:taasmoutput);

  Implementation

    uses
      globtype, globals,
      aoptda,aoptcpu,aoptcpud;

    Constructor TAsmOptimizer.create(_AsmL: taasmoutput);
      Begin
        inherited create(_asml,nil,nil,nil);
      {setup labeltable, always necessary}
        New(LabelInfo);
      End;

    procedure TAsmOptimizer.FindLoHiLabels;
      { Walks through the paasmlist to find the lowest and highest label number.  }
      { Returns the last Pai object of the current block                          }
      Var LabelFound: Boolean;
          p, prev: tai;
      Begin
        LabelInfo^.LowLabel := High(AWord);
        LabelInfo^.HighLabel := 0;
        LabelInfo^.LabelDif := 0;
        LabelInfo^.LabelTable:=nil;
        LabelFound := False;
        P := BlockStart;
        prev := p;
        With LabelInfo^ Do
          Begin
            While Assigned(P) And
                  ((P.typ <> Ait_Marker) Or
                   (tai_Marker(P).Kind <> AsmBlockStart)) Do
              Begin
                If (p.typ = ait_label) Then
                  If (tai_Label(p).l.is_used) Then
                    Begin
                      LabelFound := True;
                      If (tai_Label(p).l.labelnr < LowLabel) Then
                        LowLabel := tai_Label(p).l.labelnr;
                      If (tai_Label(p).l.labelnr > HighLabel) Then
                        HighLabel := tai_Label(p).l.labelnr
                    End;
                prev := p;
                GetNextInstruction(p, p)
              End;
            if (prev.typ = ait_marker) and
               (tai_marker(prev).kind = asmblockstart) then
              blockend := prev
            else blockend := nil;
            If LabelFound
              Then LabelDif := HighLabel-LowLabel+1
              Else LabelDif := 0
          End
      End;

    Procedure TAsmOptimizer.BuildLabelTableAndFixRegAlloc;
    { Builds a table with the locations of the labels in the taasmoutput.       }
    { Also fixes some RegDeallocs like "# %eax released; push (%eax)"           }
    Var p, hp1, hp2: tai;
        UsedRegs: TRegSet;
    Begin
      UsedRegs := [];
      With LabelInfo^ Do
        If (LabelDif <> 0) Then
          Begin
            GetMem(LabelTable, LabelDif*SizeOf(TLabelTableItem));
            FillChar(LabelTable^, LabelDif*SizeOf(TLabelTableItem), 0);
            p := BlockStart;
            While (P <> BlockEnd) Do
              Begin
                Case p.typ Of
                  ait_Label:
                    If tai_label(p).l.is_used Then
                      LabelTable^[tai_label(p).l.labelnr-LowLabel].PaiObj := p;
                  ait_regAlloc:
                    begin
                    {!!!!!!!!!
                      if tai_regalloc(p).ratype=ra_alloc then
                        Begin
                          If Not(tai_regalloc(p).Reg in UsedRegs) Then
                            UsedRegs := UsedRegs + [tai_regalloc(p).Reg]
                          Else
                            Begin
                              hp1 := p;
                              hp2 := nil;
                              While GetLastInstruction(hp1, hp1) And
                                    Not(RegInInstruction(tai_regalloc(p).Reg, hp1)) Do
                                hp2:=hp1;
                              If hp2<>nil Then
                                Begin
                                  hp1:=tai_regalloc.DeAlloc(tai_regalloc(p).Reg,hp2);
                                  InsertLLItem(tai(hp2.previous), hp2, hp1);
                                End;
                            End;
                        End
                      else
                        Begin
                          UsedRegs := UsedRegs - [tai_regalloc(p).Reg];
                          hp1 := p;
                          hp2 := nil;
                          While Not(FindRegAlloc(tai_regalloc(p).Reg, tai(hp1.Next))) And
                                GetNextInstruction(hp1, hp1) And
                                RegInInstruction(tai_regalloc(p).Reg, hp1) Do
                            hp2 := hp1;
                          If hp2 <> nil Then
                            Begin
                              hp1 := tai(p.previous);
                              AsmL.Remove(p);
                              InsertLLItem(hp2, tai(hp2.Next), p);
                              p := hp1;
                            End
                        End
                    };
                    End
                End;
                P := tai(p.Next);
                While Assigned(p) and
                      (p <> blockend) and
                      (p.typ in (SkipInstr - [ait_regalloc])) Do
                  P := tai(P.Next)
              End;
          End
    End;

    procedure tasmoptimizer.clear;
      begin
        if LabelInfo^.labeldif <> 0 then
          begin
            freemem(LabelInfo^.labeltable);
            LabelInfo^.labeltable := nil;
          end;
      end;

    procedure tasmoptimizer.pass_1;
      begin
        findlohilabels;
        BuildLabelTableAndFixRegAlloc;
      end;


    Procedure TAsmOptimizer.Optimize;
      Var
        HP: tai;
        pass: longint;
      Begin
        pass:=0;
        BlockStart := tai(AsmL.First);
        pass_1;
        While Assigned(BlockStart) Do
          Begin
             if pass = 0 then
               PrePeepHoleOpts;
            { Peephole optimizations }
             PeepHoleOptPass1;
            { Only perform them twice in the first pass }
             if pass = 0 then
               PeepHoleOptPass1;
            If (cs_slowoptimize in aktglobalswitches) Then
              Begin
//                DFA:=TAOptDFACpu.Create(AsmL,BlockStart,BlockEnd,LabelInfo);
                { data flow analyzer }
//                DFA.DoDFA;
                { common subexpression elimination }
      {          CSE;}
              End;
            { more peephole optimizations }
      {      PeepHoleOptPass2;}
            { if pass = last_pass then }
            PostPeepHoleOpts;
            { free memory }
            clear;
            { continue where we left off, BlockEnd is either the start of an }
            { assembler block or nil}
            BlockStart := BlockEnd;
            While Assigned(BlockStart) And
                  (BlockStart.typ = ait_Marker) And
                  (tai_Marker(BlockStart).Kind = AsmBlockStart) Do
              Begin
               { we stopped at an assembler block, so skip it    }
               While GetNextInstruction(BlockStart, BlockStart) And
                     ((BlockStart.Typ <> Ait_Marker) Or
                      (tai_Marker(Blockstart).Kind <> AsmBlockEnd)) Do;
               { blockstart now contains a tai_marker(asmblockend) }
               If GetNextInstruction(BlockStart, HP) And
                  ((HP.typ <> ait_Marker) Or
                   (Tai_Marker(HP).Kind <> AsmBlockStart)) Then
               { There is no assembler block anymore after the current one, so }
               { optimize the next block of "normal" instructions              }
                 pass_1
               { Otherwise, skip the next assembler block }
               else
                 blockStart := hp;
              End
          End;
      End;

    Destructor TAsmOptimizer.Destroy;
      Begin
        Dispose(LabelInfo)
      End;


    procedure Optimize(AsmL:taasmoutput);
      var
        p : TAsmOptimizer;
      begin
        p:=casmoptimizer.Create(AsmL);
        p.Optimize;
        p.free
      end;


end.
