{ $Id$ Copyright (c) 1999 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 Aasm, cobjects, aoptobj, aoptda, aoptcs, aoptpeep, aoptcpu; Type TAsmOptimizer = Object { the PAasmOutput list this optimizer instance works on } AsmL: PAasmOutput; { The labeltable contains the addresses of the Pai objects that are } { labels } LabelInfo: PLabelInfo; { Start and end of the block that is currently being optimized, } { initialized by InitDFA } BlockStart, BlockEnd: Pai; { _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; End; Implementation Constructor TAsmOptimizer.Init(_AsmL: PAasmOutput); Begin AsmL := _AsmL; 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; 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; 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(AsmL, 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(AsmL, hp2, Pai(hp2^.Next), p); p := hp1; 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; AsmDFA: TAsmDFA; Begin {setup labeltable, always necessary} BlockStart := Pai(AsmL^.First); {Blockend now either contains an ait_marker with Kind = AsmBlockStart, or nil} 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 } BuilLabelTableAndFixRegAlloc; { peephole optimizations, twice because you can't do them all in one } { pass } PeepHoleOptPass1; PeepHoleOptPass1; If (cs_slowoptimize in aktglobalswitches) Then Begin { data flow analyzer } DFAPass2; { 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 End; {Virtual methods, most have to be overridden by processor dependent methods} { $Log$ Revision 1.2 1999-08-09 14:07:22 jonas commit.msg Revision 1.1 1999/08/08 13:24:50 jonas + added copyright header/GNU license info * made the assembler optimizer almost completely OOP * some code style clean up and extra comments * moved from the new/aopt to the /new and /new/i386 dirs }