{
    $Id: aopt.pas,v 1.5 2002/07/01 18:46:21 peter Exp $
    Copyright (c) 1998-2002 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;

Interface

Uses Aasmbase,aasmtai,aasmcpu, cobjects, aoptobj, aoptcpud, aoptcpub {aoptcs, aoptpeep} ;

Type
  PAsmOptimizer = ^TAsmOptimizer;
  TAsmOptimizer = Object(TAoptObj)

    { _AsmL is the PAasmOutpout list that has to be optimized }
    Constructor Init(_AsmL: PAasmOutput);

    { call the necessary optimizer procedures }
    Procedure Optimize;
    Destructor Done;

    private

    Function FindLoHiLabels: Pai;
    Procedure BuildLabelTableAndFixRegAlloc;

  End;

procedure Optimize(AsmL:Paasmoutput);


Implementation

uses cpuinfo, globtype, globals;

Constructor TAsmOptimizer.Init(_AsmL: PAasmOutput);
Begin
  AsmL := _AsmL;
{setup labeltable, always necessary}
  New(LabelInfo);
  LabelInfo^.LowLabel := High(AWord);
  LabelInfo^.HighLabel := 0;
  LabelInfo^.LabelDif := 0;
End;

Function TAsmOptimizer.FindLoHiLabels: Pai;
{ 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: Pai;
Begin
  LabelFound := False;
  P := BlockStart;
  With LabelInfo^ Do
    Begin
      While Assigned(P) And
            ((P^.typ <> Ait_Marker) Or
             (Pai_Marker(P)^.Kind <> AsmBlockStart)) Do
        Begin
          If (Pai(p)^.typ = ait_label) Then
            If (Pai_Label(p)^.l^.is_used) Then
              Begin
                LabelFound := True;
                If (Pai_Label(p)^.l^.labelnr < LowLabel) Then
                  LowLabel := Pai_Label(p)^.l^.labelnr;
                If (Pai_Label(p)^.l^.labelnr > HighLabel) Then
                  HighLabel := Pai_Label(p)^.l^.labelnr
              End;
          GetNextInstruction(p, p)
        End;
      FindLoHiLabels := p;
      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 paasmoutput.       }
{ Also fixes some RegDeallocs like "# %eax released; push (%eax)"           }
Var p, hp1, hp2: Pai;
    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 Pai_Label(p)^.l^.is_used Then
                  LabelTable^[Pai_Label(p)^.l^.labelnr-LowLabel].PaiObj := p;
              ait_regAlloc:
                begin
                  if PairegAlloc(p)^.Allocation then
                    Begin
                      If Not(PaiRegAlloc(p)^.Reg in UsedRegs) Then
                        UsedRegs := UsedRegs + [PaiRegAlloc(p)^.Reg]
                      Else
                        Begin
                          hp1 := p;
                          hp2 := nil;
                          While GetLastInstruction(hp1, hp1) And
                                Not(RegInInstruction(PaiRegAlloc(p)^.Reg, hp1)) Do
                            hp2 := hp1;
                          If hp2 <> nil Then
                            Begin
                              hp1 := New(PaiRegAlloc, DeAlloc(PaiRegAlloc(p)^.Reg));
                              InsertLLItem(Pai(hp2^.previous), hp2, hp1);
                            End;
                        End;
                    End
                  else
                    Begin
                      UsedRegs := UsedRegs - [PaiRegAlloc(p)^.Reg];
                      hp1 := p;
                      hp2 := nil;
                      While Not(FindRegAlloc(PaiRegAlloc(p)^.Reg, Pai(hp1^.Next))) And
                            GetNextInstruction(hp1, hp1) And
                            RegInInstruction(PaiRegAlloc(p)^.Reg, hp1) Do
                        hp2 := hp1;
                      If hp2 <> nil Then
                        Begin
                          hp1 := Pai(p^.previous);
                          AsmL^.Remove(p);
                          InsertLLItem(hp2, Pai(hp2^.Next), p);
                          p := hp1;
                        End
                    End
                End
            End
          End;
        P := Pai(p^.Next);
        While Assigned(p) And
              (p^.typ in (SkipInstr - [ait_regalloc])) Do
          P := Pai(P^.Next)
      End
End;



Procedure TAsmOptimizer.Optimize;
Var HP: Pai;
    DFA: PAOptDFACpu;
Begin
  BlockStart := Pai(AsmL^.First);
  While Assigned(BlockStart) Do
    Begin
      { Initialize BlockEnd and the LabelInfo (low and high label) }
      BlockEnd := FindLoHiLabels;
      { initialize the LabelInfo (labeltable) and fix the regalloc info }
      BuildLabelTableAndFixRegAlloc;
      { peephole optimizations, twice because you can't do them all in one }
      { pass                                                               }
{      PeepHoleOptPass1;
      PeepHoleOptPass1;}
      If (cs_slowoptimize in aktglobalswitches) Then
        Begin
          New(DFA,Init(AsmL,BlockStart,BlockEnd,LabelInfo));
          { data flow analyzer }
          DFA^.DoDFA;
          { common subexpression elimination }
{          CSE;}
        End;
      { more peephole optimizations }
{      PeepHoleOptPass2;}
      {dispose labeltabel}
      If Assigned(LabelInfo^.LabelTable) Then
        Begin
          Dispose(LabelInfo^.LabelTable);
          LabelInfo := Nil
        End;
      { 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
            (Pai_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
                 (Pai_Marker(Blockstart)^.Kind <> AsmBlockEnd)) Do;
         { blockstart now contains a pai_marker(asmblockend) }
          If Not(GetNextInstruction(BlockStart, HP) And
                 ((HP^.typ <> ait_Marker) Or
                  (Pai_Marker(HP)^.Kind <> AsmBlockStart)
                 )
                ) Then
           {skip the next assembler block }
           BlockStart := HP;
         { otherwise there is no assembler block anymore after the current }
         { one, so optimize the next block of "normal" instructions        }
        End
    End;
End;

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


procedure Optimize(AsmL:Paasmoutput);
var
  p : PAsmOptimizer;
begin
  new(p,Init(AsmL));
  p^.Optimize;
  dispose(p,Done);
end;


End.

{Virtual methods, most have to be overridden by processor dependent methods}

{
 $Log: aopt.pas,v $
 Revision 1.5  2002/07/01 18:46:21  peter
   * internal linker
   * reorganized aasm layer

 Revision 1.4  2002/05/18 13:34:05  peter
   * readded missing revisions

 Revision 1.3  2002/05/16 19:46:34  carl
 + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
 + try to fix temp allocation (still in ifdef)
 + generic constructor calls
 + start of tassembler / tmodulebase class cleanup

}
