diff options
author | fpc <fpc@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2005-05-16 18:37:41 +0000 |
---|---|---|
committer | fpc <fpc@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2005-05-16 18:37:41 +0000 |
commit | f206a9c2b1ae1d8727ca27a96d448b61fdb4c766 (patch) | |
tree | f28256ff9964c1fc7c0f7fb00891268a117b745d /compiler/aoptobj.pas | |
download | fpc-f206a9c2b1ae1d8727ca27a96d448b61fdb4c766.tar.gz |
initial import
git-svn-id: http://svn.freepascal.org/svn/fpc/trunk@1 3ad0048d-3df7-0310-abae-a5850022a9f2
Diffstat (limited to 'compiler/aoptobj.pas')
-rw-r--r-- | compiler/aoptobj.pas | 1105 |
1 files changed, 1105 insertions, 0 deletions
diff --git a/compiler/aoptobj.pas b/compiler/aoptobj.pas new file mode 100644 index 0000000000..ff75dd00d3 --- /dev/null +++ b/compiler/aoptobj.pas @@ -0,0 +1,1105 @@ +{ + $Id: aoptobj.pas,v 1.17 2005/02/26 01:26:59 jonas Exp $ + Copyright (c) 1998-2004 by Jonas Maebe, member of the Free Pascal + Development Team + + This unit contains the processor independent assembler optimizer + object, base for the dataflow analyzer, peepholeoptimizer and + common subexpression elimination objects. + + 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 AoptObj; + + {$i fpcdefs.inc} + + { general, processor independent objects for use by the assembler optimizer } + + Interface + + uses + globtype, + aasmbase,aasmcpu,aasmtai, + cclasses, + cgbase,cgutils, + cpubase, + aoptbase,aoptcpub,aoptda; + + { ************************************************************************* } + { ********************************* Constants ***************************** } + { ************************************************************************* } + + Const + + {Possible register content types} + con_Unknown = 0; + con_ref = 1; + con_const = 2; + + {***************** Types ****************} + + Type + + { ************************************************************************* } + { ************************* Some general type definitions ***************** } + { ************************************************************************* } + TRefCompare = Function(r1, r2: TReference): Boolean; + //!!! FIXME + TRegArray = Array[byte] of tsuperregister; + TRegSet = Set of byte; + { possible actions on an operand: read, write or modify (= read & write) } + TOpAction = (OpAct_Read, OpAct_Write, OpAct_Modify, OpAct_Unknown); + + { ************************************************************************* } + { * Object to hold information on which regiters are in use and which not * } + { ************************************************************************* } + TUsedRegs = class + Constructor create; + Constructor create_regset(Const _RegSet: TRegSet); + + Destructor Destroy;override; + { update the info with the pairegalloc objects coming after } + { p } + Procedure Update(p: Tai); + { is Reg currently in use } + Function IsUsed(Reg: TRegister): Boolean; + { get all the currently used registers } + Function GetUsedRegs: TRegSet; + + Private + + UsedRegs: TRegSet; + End; + + { ************************************************************************* } + { ******************* Contents of the integer registers ******************* } + { ************************************************************************* } + + { size of the integer that holds the state number of a register. Can be any } + { integer type, so it can be changed to reduce the size of the TContent } + { structure or to improve alignment } + TStateInt = Byte; + + TContent = Record + { start and end of block instructions that defines the } + { content of this register. If Typ = con_const, then } + { Longint(StartMod) = value of the constant) } + StartMod: Tai; + { starts at 0, gets increased everytime the register is } + { written to } + WState: TStateInt; + { starts at 0, gets increased everytime the register is read } + { from } + RState: TStateInt; + { how many instructions starting with StarMod does the block } + { consist of } + NrOfMods: Byte; + { the type of the content of the register: unknown, memory } + { (variable) or constant } + Typ: Byte; + End; + + //!!! FIXME + TRegContent = Array[byte] Of TContent; + + { ************************************************************************** } + { information object with the contents of every register. Every Tai object } + { gets one of these assigned: a pointer to it is stored in the OptInfo field } + { ************************************************************************** } + + TPaiProp = class(TAoptBaseCpu) + Regs: TRegContent; + { info about allocation of general purpose integer registers } + UsedRegs: TUsedRegs; + { can this instruction be removed? } + CanBeRemoved: Boolean; + + Constructor create; + + { checks the whole sequence of which (so regs[which].StartMod and and } + { the next NrOfMods Tai objects) to see whether Reg is used somewhere, } + { without it being loaded with something else first } + Function RegInSequence(Reg, which: TRegister): Boolean; + { destroy the contents of a register, as well as those whose contents } + { are based on those of that register } + Procedure DestroyReg(Reg: TRegister; var InstrSinceLastMod: + TInstrSinceLastMod); + { if the contents of WhichReg (can be R_NO in case of a constant) are } + { written to memory at the location Ref, the contents of the registers } + { that depend on Ref have to be destroyed } + Procedure DestroyRefs(Const Ref: TReference; WhichReg: TRegister; var + InstrSinceLastMod: TInstrSinceLastMod); + + { an instruction reads from operand o } + Procedure ReadOp(const o:toper); + { an instruction reads from reference Ref } + Procedure ReadRef(Ref: PReference); + { an instruction reads from register Reg } + Procedure ReadReg(Reg: TRegister); + + { an instruction writes/modifies operand o and this has special } + { side-effects or modifies the contents in such a way that we can't } + { simply add this instruction to the sequence of instructions that } + { describe the contents of the operand, so destroy it } + Procedure DestroyOp(const o:Toper; var InstrSinceLastMod: + TInstrSinceLastMod); + { destroy the contents of all registers } + Procedure DestroyAllRegs(var InstrSinceLastMod: TInstrSinceLastMod); + { a register's contents are modified, but not destroyed (the new value } + { depends on the old one) } + Procedure ModifyReg(reg: TRegister; var InstrSinceLastMod: + TInstrSinceLastMod); + { an operand's contents are modified, but not destroyed (the new value } + { depends on the old one) } + Procedure ModifyOp(const oper: TOper; var InstrSinceLastMod: + TInstrSinceLastMod); + + { increase the write state of a register (call every time a register is } + { written to) } + Procedure IncWState(Reg: TRegister); + { increase the read state of a register (call every time a register is } + { read from) } + Procedure IncRState(Reg: TRegister); + { get the write state of a register } + Function GetWState(Reg: TRegister): TStateInt; + { get the read state of a register } + Function GetRState(Reg: TRegister): TStateInt; + + { get the type of contents of a register } + Function GetRegContentType(Reg: TRegister): Byte; + + Destructor Done; + + Private + + Procedure IncState(var s: TStateInt); + + { returns whether the reference Ref is used somewhere in the loading } + { sequence Content } + Function RefInSequence(Const Ref: TReference; Content: TContent; + RefsEq: TRefCompare): Boolean; + + { returns whether the instruction P reads from and/or writes } + { to Reg } + Function RefInInstruction(Const Ref: TReference; p: Tai; + RefsEq: TRefCompare): Boolean; + + { returns whether two references with at least one pointing to an array } + { may point to the same memory location } + + End; + + + { ************************************************************************* } + { ************************ Label information ****************************** } + { ************************************************************************* } + TLabelTableItem = Record + PaiObj: Tai; + End; + + {$ifndef TP} + TLabelTable = Array[0..2500000] Of TLabelTableItem; + {$else TP} + TLabelTable = Array[0..(65520 div sizeof(TLabelTableItem))] Of TLabelTableItem; + {$endif TP} + PLabelTable = ^TLabelTable; + PLabelInfo = ^TLabelInfo; + TLabelInfo = Record + { the highest and lowest label number occurring in the current code } + { fragment } + LowLabel, HighLabel: AWord; + LabelDif: AWord; + { table that contains the addresses of the Pai_Label objects associated + with each label number } + LabelTable: PLabelTable; + End; + + { ************************************************************************* } + { ********** General optimizer object, used to derive others from ********* } + { ************************************************************************* } + + TAOptObj = class(TAoptBaseCpu) + { the PAasmOutput list this optimizer instance works on } + AsmL: TAasmOutput; + + { The labelinfo record contains the addresses of the Tai objects } + { that are labels, how many labels there are and the min and max } + { label numbers } + LabelInfo: PLabelInfo; + + { Start and end of the block that is currently being optimized } + BlockStart, BlockEnd: Tai; + + DFA: TAOptDFA; + { _AsmL is the PAasmOutpout list that has to be optimized, } + { _BlockStart and _BlockEnd the start and the end of the block } + { that has to be optimized and _LabelInfo a pointer to a } + { TLabelInfo record } + Constructor create(_AsmL: TAasmOutput; _BlockStart, _BlockEnd: Tai; + _LabelInfo: PLabelInfo); + + { processor independent methods } + + { returns true if the label L is found between hp and the next } + { instruction } + Function FindLabel(L: TasmLabel; Var hp: Tai): Boolean; + + { inserts new_one between prev and foll in AsmL } + Procedure InsertLLItem(prev, foll, new_one: TLinkedListItem); + + + { If P is a Tai object releveant to the optimizer, P is returned + If it is not relevant tot he optimizer, the first object after P + that is relevant is returned } + Function SkipHead(P: Tai): Tai; + + { returns true if the operands o1 and o2 are completely equal } + Function OpsEqual(const o1,o2:toper): Boolean; + + { Returns true if a ait_alloc object for Reg is found in the block + of Tai's starting with StartPai and ending with the next "real" + instruction } + Function FindRegAlloc(Reg: TRegister; StartPai: Tai): Boolean; + + { traces sucessive jumps to their final destination and sets it, e.g. + je l1 je l3 + <code> <code> + l1: becomes l1: + je l2 je l3 + <code> <code> + l2: l2: + jmp l3 jmp l3 + + the level parameter denotes how deeep we have already followed the jump, + to avoid endless loops with constructs such as "l5: ; jmp l5" } + function GetFinalDestination(hp: taicpu; level: longint): boolean; + + function getlabelwithsym(sym: tasmlabel): tai; + + { peephole optimizer } + procedure PrePeepHoleOpts;virtual; + procedure PeepHoleOptPass1;virtual; + procedure PeepHoleOptPass2;virtual; + procedure PostPeepHoleOpts;virtual; + + { processor dependent methods } + End; + + Function ArrayRefsEq(const r1, r2: TReference): Boolean; + + { ***************************** Implementation **************************** } + + Implementation + + uses + globals, + verbose, + procinfo; + + { ************************************************************************* } + { ******************************** TUsedRegs ****************************** } + { ************************************************************************* } + + Constructor TUsedRegs.create; + Begin + UsedRegs := []; + End; + + Constructor TUsedRegs.create_regset(Const _RegSet: TRegSet); + Begin + UsedRegs := _RegSet; + End; + + Procedure TUsedRegs.Update(p: Tai); + {updates UsedRegs with the RegAlloc Information coming after P} + Begin + Repeat + While Assigned(p) And + ((p.typ in (SkipInstr - [ait_RegAlloc])) or + ((p.typ = ait_label) And + Not(Tai_Label(p).l.is_used))) Do + p := Tai(p.next); + While Assigned(p) And + (p.typ=ait_RegAlloc) Do + Begin + {!!!!!!!! FIXME + if tai_regalloc(p).ratype=ra_alloc then + UsedRegs := UsedRegs + [tai_regalloc(p).Reg] + else + UsedRegs := UsedRegs - [tai_regalloc(p).Reg]; + p := Tai(p.next); + } + End; + Until Not(Assigned(p)) Or + (Not(p.typ in SkipInstr) And + Not((p.typ = ait_label) And + Not(Tai_Label(p).l.is_used))); + End; + + Function TUsedRegs.IsUsed(Reg: TRegister): Boolean; + Begin + //!!!!!!!!!!! IsUsed := Reg in UsedRegs + End; + + Function TUsedRegs.GetUsedRegs: TRegSet; + Begin + GetUsedRegs := UsedRegs; + End; + + Destructor TUsedRegs.Destroy; + Begin + inherited destroy; + end; + + { ************************************************************************* } + { **************************** TPaiProp *********************************** } + { ************************************************************************* } + + Constructor TPaiProp.Create; + Begin + {!!!!!! + UsedRegs.Init; + CondRegs.init; + } + { DirFlag: TFlagContents; I386 specific} + End; + + Function TPaiProp.RegInSequence(Reg, which: TRegister): Boolean; + Var p: Tai; + RegsChecked: TRegSet; + content: TContent; + Counter: Byte; + TmpResult: Boolean; + Begin + {!!!!!!!!!!1 + RegsChecked := []; + content := regs[which]; + p := content.StartMod; + TmpResult := False; + Counter := 1; + While Not(TmpResult) And + (Counter <= Content.NrOfMods) Do + Begin + If IsLoadMemReg(p) Then + With PInstr(p)^.oper[LoadSrc]^.ref^ Do + If (Base = ProcInfo.FramePointer) + {$ifdef RefsHaveIndexReg} + And (Index = R_NO) + {$endif RefsHaveIndexReg} Then + Begin + RegsChecked := RegsChecked + + [RegMaxSize(PInstr(p)^.oper[LoadDst]^.reg)]; + If Reg = RegMaxSize(PInstr(p)^.oper[LoadDst]^.reg) Then + Break; + End + Else + Begin + If (Base = Reg) And + Not(Base In RegsChecked) + Then TmpResult := True; + {$ifdef RefsHaveIndexReg} + If Not(TmpResult) And + (Index = Reg) And + Not(Index In RegsChecked) + Then TmpResult := True; + {$Endif RefsHaveIndexReg} + End + Else TmpResult := RegInInstruction(Reg, p); + Inc(Counter); + GetNextInstruction(p,p) + End; + RegInSequence := TmpResult + } + End; + + + Procedure TPaiProp.DestroyReg(Reg: TRegister; var InstrSinceLastMod: + TInstrSinceLastMod); + { Destroys the contents of the register Reg in the PPaiProp p1, as well as } + { the contents of registers are loaded with a memory location based on Reg } + Var TmpWState, TmpRState: Byte; + Counter: TRegister; + Begin + {!!!!!!! + Reg := RegMaxSize(Reg); + If (Reg in [LoGPReg..HiGPReg]) Then + For Counter := LoGPReg to HiGPReg Do + With Regs[Counter] Do + If (Counter = reg) Or + ((Typ = Con_Ref) And + RegInSequence(Reg, Counter)) Then + Begin + InstrSinceLastMod[Counter] := 0; + IncWState(Counter); + TmpWState := GetWState(Counter); + TmpRState := GetRState(Counter); + FillChar(Regs[Counter], SizeOf(TContent), 0); + WState := TmpWState; + RState := TmpRState + End + } + End; + + Function ArrayRefsEq(const r1, r2: TReference): Boolean; + Begin + {!!!!!!!!!! + ArrayRefsEq := (R1.Offset+R1.OffsetFixup = R2.Offset+R2.OffsetFixup) And + {$ifdef refsHaveSegmentReg} + (R1.Segment = R2.Segment) And + {$endif} + (R1.Base = R2.Base) And + (R1.Symbol=R2.Symbol); + } + End; + + Procedure TPaiProp.DestroyRefs(Const Ref: TReference; WhichReg: TRegister; + var InstrSinceLastMod: TInstrSinceLastMod); + { destroys all registers which possibly contain a reference to Ref, WhichReg } + { is the register whose contents are being written to memory (if this proc } + { is called because of a "mov?? %reg, (mem)" instruction) } + Var RefsEq: TRefCompare; + Counter: TRegister; + Begin + {!!!!!!!!!!! + WhichReg := RegMaxSize(WhichReg); + If (Ref.base = procinfo.FramePointer) or + Assigned(Ref.Symbol) Then + Begin + If + {$ifdef refsHaveIndexReg} + (Ref.Index = R_NO) And + {$endif refsHaveIndexReg} + (Not(Assigned(Ref.Symbol)) or + (Ref.base = R_NO)) Then + { local variable which is not an array } + RefsEq := {$ifdef fpc}@{$endif}RefsEqual + Else + { local variable which is an array } + RefsEq := {$ifdef fpc}@{$endif}ArrayRefsEq; + {write something to a parameter, a local or global variable, so + * with uncertain optimizations on: + - destroy the contents of registers whose contents have somewhere a + "mov?? (Ref), %reg". WhichReg (this is the register whose contents + are being written to memory) is not destroyed if it's StartMod is + of that form and NrOfMods = 1 (so if it holds ref, but is not a + pointer or value based on Ref) + * with uncertain optimizations off: + - also destroy registers that contain any pointer} + For Counter := LoGPReg to HiGPReg Do + With Regs[Counter] Do + Begin + If (typ = Con_Ref) And + ((Not(cs_UncertainOpts in aktglobalswitches) And + (NrOfMods <> 1) + ) Or + (RefInSequence(Ref,Regs[Counter], RefsEq) And + ((Counter <> WhichReg) Or + ((NrOfMods <> 1) And + {StarMod is always of the type ait_instruction} + (PInstr(StartMod)^.oper[0].typ = top_ref) And + RefsEq(PInstr(StartMod)^.oper[0].ref^, Ref) + ) + ) + ) + ) + Then + DestroyReg(Counter, InstrSinceLastMod) + End + End + Else + {write something to a pointer location, so + * with uncertain optimzations on: + - do not destroy registers which contain a local/global variable or a + parameter, except if DestroyRefs is called because of a "movsl" + * with uncertain optimzations off: + - destroy every register which contains a memory location + } + For Counter := LoGPReg to HiGPReg Do + With Regs[Counter] Do + If (typ = Con_Ref) And + (Not(cs_UncertainOpts in aktglobalswitches) Or + {$ifdef x86} + {for movsl} + (Ref.Base = R_EDI) Or + {$endif} + {don't destroy if reg contains a parameter, local or global variable} + Not((NrOfMods = 1) And + (PInstr(StartMod)^.oper[0].typ = top_ref) And + ((PInstr(StartMod)^.oper[0].ref^.base = ProcInfo.FramePointer) Or + Assigned(PInstr(StartMod)^.oper[0].ref^.Symbol) + ) + ) + ) + Then DestroyReg(Counter, InstrSinceLastMod) + } + End; + + Procedure TPaiProp.DestroyAllRegs(var InstrSinceLastMod: TInstrSinceLastMod); + Var Counter: TRegister; + Begin {initializes/desrtoys all registers} + {!!!!!!!!! + For Counter := LoGPReg To HiGPReg Do + Begin + ReadReg(Counter); + DestroyReg(Counter, InstrSinceLastMod); + End; + CondRegs.Init; + { FPURegs.Init; } + } + End; + + Procedure TPaiProp.DestroyOp(const o:Toper; var InstrSinceLastMod: + TInstrSinceLastMod); + Begin + {!!!!!!! + Case o.typ Of + top_reg: DestroyReg(o.reg, InstrSinceLastMod); + top_ref: + Begin + ReadRef(o.ref); + DestroyRefs(o.ref^, R_NO, InstrSinceLastMod); + End; + top_symbol:; + End; + } + End; + + Procedure TPaiProp.ReadReg(Reg: TRegister); + Begin + {!!!!!!! + Reg := RegMaxSize(Reg); + If Reg in General_Registers Then + IncRState(RegMaxSize(Reg)) + } + End; + + Procedure TPaiProp.ReadRef(Ref: PReference); + Begin + {!!!!!!! + If Ref^.Base <> R_NO Then + ReadReg(Ref^.Base); + {$ifdef refsHaveIndexReg} + If Ref^.Index <> R_NO Then + ReadReg(Ref^.Index); + {$endif} + } + End; + + Procedure TPaiProp.ReadOp(const o:toper); + Begin + Case o.typ Of + top_reg: ReadReg(o.reg); + top_ref: ReadRef(o.ref); + else + internalerror(200410241); + End; + End; + + Procedure TPaiProp.ModifyReg(reg: TRegister; Var InstrSinceLastMod: + TInstrSinceLastMod); + Begin + {!!!!!!! + With Regs[reg] Do + If (Typ = Con_Ref) + Then + Begin + IncState(WState); + {also store how many instructions are part of the sequence in the first + instructions PPaiProp, so it can be easily accessed from within + CheckSequence} + Inc(NrOfMods, InstrSinceLastMod[Reg]); + PPaiProp(StartMod.OptInfo)^.Regs[Reg].NrOfMods := NrOfMods; + InstrSinceLastMod[Reg] := 0; + End + Else + DestroyReg(Reg, InstrSinceLastMod); + } + End; + + Procedure TPaiProp.ModifyOp(const oper: TOper; var InstrSinceLastMod: + TInstrSinceLastMod); + Begin + If oper.typ = top_reg Then + ModifyReg(RegMaxSize(oper.reg),InstrSinceLastMod) + Else + Begin + ReadOp(oper); + DestroyOp(oper, InstrSinceLastMod); + End + End; + + Procedure TPaiProp.IncWState(Reg: TRegister);{$ifdef inl} inline;{$endif inl} + Begin + //!!!! IncState(Regs[Reg].WState); + End; + + Procedure TPaiProp.IncRState(Reg: TRegister);{$ifdef inl} inline;{$endif inl} + Begin + //!!!! IncState(Regs[Reg].RState); + End; + + Function TPaiProp.GetWState(Reg: TRegister): TStateInt; {$ifdef inl} inline;{$endif inl} + Begin + //!!!! GetWState := Regs[Reg].WState + End; + + Function TPaiProp.GetRState(Reg: TRegister): TStateInt; {$ifdef inl} inline;{$endif inl} + Begin + //!!!! GetRState := Regs[Reg].RState + End; + + Function TPaiProp.GetRegContentType(Reg: TRegister): Byte; {$ifdef inl} inline;{$endif inl} + Begin + //!!!! GetRegContentType := Regs[Reg].typ + End; + + Destructor TPaiProp.Done; + Begin + //!!!! UsedRegs.Done; + //!!!! CondRegs.Done; + { DirFlag: TFlagContents; I386 specific} + End; + { ************************ private TPaiProp stuff ************************* } + + Procedure TPaiProp.IncState(Var s: TStateInt); {$ifdef inl} inline;{$endif inl} + Begin + If s <> High(TStateInt) Then Inc(s) + Else s := 0 + End; + + Function TPaiProp.RefInInstruction(Const Ref: TReference; p: Tai; + RefsEq: TRefCompare): Boolean; + Var Count: AWord; + TmpResult: Boolean; + Begin + TmpResult := False; + If (p.typ = ait_instruction) Then + Begin + Count := 0; + Repeat + If (TInstr(p).oper[Count]^.typ = Top_Ref) Then + TmpResult := RefsEq(Ref, PInstr(p)^.oper[Count]^.ref^); + Inc(Count); + Until (Count = MaxOps) or TmpResult; + End; + RefInInstruction := TmpResult; + End; + + Function TPaiProp.RefInSequence(Const Ref: TReference; Content: TContent; + RefsEq: TRefCompare): Boolean; + Var p: Tai; + Counter: Byte; + TmpResult: Boolean; + Begin + p := Content.StartMod; + TmpResult := False; + Counter := 1; + While Not(TmpResult) And + (Counter <= Content.NrOfMods) Do + Begin + If (p.typ = ait_instruction) And + RefInInstruction(Ref, p, {$ifdef fpc}@{$endif}references_equal) + Then TmpResult := True; + Inc(Counter); + GetNextInstruction(p,p) + End; + RefInSequence := TmpResult + End; + + { ************************************************************************* } + { ***************************** TAoptObj ********************************** } + { ************************************************************************* } + + Constructor TAoptObj.create(_AsmL: TAasmOutput; _BlockStart, _BlockEnd: Tai; + _LabelInfo: PLabelInfo); + Begin + AsmL := _AsmL; + BlockStart := _BlockStart; + BlockEnd := _BlockEnd; + LabelInfo := _LabelInfo + End; + + Function TAOptObj.FindLabel(L: TasmLabel; Var hp: Tai): Boolean; + Var TempP: Tai; + Begin + TempP := hp; + While Assigned(TempP) and + (TempP.typ In SkipInstr + [ait_label]) Do + If (TempP.typ <> ait_Label) Or + (Tai_label(TempP).l <> L) + Then GetNextInstruction(TempP, TempP) + Else + Begin + hp := TempP; + FindLabel := True; + exit + End; + FindLabel := False; + End; + + Procedure TAOptObj.InsertLLItem(prev, foll, new_one : TLinkedListItem); + Begin + If Assigned(prev) Then + If Assigned(foll) Then + Begin + If Assigned(new_one) Then + Begin + new_one.previous := prev; + new_one.next := foll; + prev.next := new_one; + foll.previous := new_one; + { should we update line information? } + if (not (tai(new_one).typ in SkipLineInfo)) and + (not (tai(foll).typ in SkipLineInfo)) then + Tailineinfo(new_one).fileinfo := Tailineinfo(foll).fileinfo + End + End + Else AsmL.Concat(new_one) + Else If Assigned(Foll) Then AsmL.Insert(new_one) + End; + + + Function TAOptObj.SkipHead(P: Tai): Tai; + Var OldP: Tai; + Begin + Repeat + OldP := P; + If (P.typ in SkipInstr) Or + ((P.typ = ait_marker) And + (Tai_Marker(P).Kind = AsmBlockEnd)) Then + GetNextInstruction(P, P) + Else If ((P.Typ = Ait_Marker) And + (Tai_Marker(P).Kind = NoPropInfoStart)) Then + { a marker of the type NoPropInfoStart can't be the first instruction of a } + { paasmoutput list } + GetNextInstruction(Tai(P.Previous),P); + If (P.Typ = Ait_Marker) And + (Tai_Marker(P).Kind = AsmBlockStart) Then + Begin + P := Tai(P.Next); + While (P.typ <> Ait_Marker) Or + (Tai_Marker(P).Kind <> AsmBlockEnd) Do + P := Tai(P.Next) + End; + Until P = OldP; + SkipHead := P; + End; + + Function TAOptObj.OpsEqual(const o1,o2:toper): Boolean; + Begin + if o1.typ=o2.typ then + Case o1.typ Of + Top_Reg : + OpsEqual:=o1.reg=o2.reg; + Top_Ref : + OpsEqual := references_equal(o1.ref^, o2.ref^); + Top_Const : + OpsEqual:=o1.val=o2.val; + Top_None : + OpsEqual := True + else OpsEqual := False + End; + End; + + Function TAOptObj.FindRegAlloc(Reg: TRegister; StartPai: Tai): Boolean; + Begin + FindRegAlloc:=False; + Repeat + While Assigned(StartPai) And + ((StartPai.typ in (SkipInstr - [ait_regAlloc])) Or + ((StartPai.typ = ait_label) and + Not(Tai_Label(StartPai).l.Is_Used))) Do + StartPai := Tai(StartPai.Next); + If Assigned(StartPai) And + (StartPai.typ = ait_regAlloc) and (tai_regalloc(StartPai).ratype=ra_alloc) Then + Begin + if tai_regalloc(StartPai).Reg = Reg then + begin + FindRegAlloc:=true; + exit; + end; + StartPai := Tai(StartPai.Next); + End + else + exit; + Until false; + End; + + + function SkipLabels(hp: tai; var hp2: tai): boolean; + {skips all labels and returns the next "real" instruction} + begin + while assigned(hp.next) and + (tai(hp.next).typ in SkipInstr + [ait_label,ait_align]) Do + hp := tai(hp.next); + if assigned(hp.next) then + begin + SkipLabels := True; + hp2 := tai(hp.next) + end + else + begin + hp2 := hp; + SkipLabels := False + end; + end; + + + function FindAnyLabel(hp: tai; var l: tasmlabel): Boolean; + begin + FindAnyLabel := false; + while assigned(hp.next) and + (tai(hp.next).typ in (SkipInstr+[ait_align])) Do + hp := tai(hp.next); + if assigned(hp.next) and + (tai(hp.next).typ = ait_label) then + begin + FindAnyLabel := true; + l := tai_label(hp.next).l; + end + end; + + +{$ifopt r+} +{$define rangewason} +{$r-} +{$endif} + function tAOptObj.getlabelwithsym(sym: tasmlabel): tai; + begin + if (sym.labelnr >= labelinfo^.lowlabel) and + (sym.labelnr <= labelinfo^.highlabel) then { range check, a jump can go past an assembler block! } + getlabelwithsym := labelinfo^.labeltable^[sym.labelnr-labelinfo^.lowlabel].paiobj + else + getlabelwithsym := nil; + end; +{$ifdef rangewason} +{$r+} +{$undef rangewason} +{$endif} + + function TAOptObj.GetFinalDestination(hp: taicpu; level: longint): boolean; + {traces sucessive jumps to their final destination and sets it, e.g. + je l1 je l3 + <code> <code> + l1: becomes l1: + je l2 je l3 + <code> <code> + l2: l2: + jmp l3 jmp l3 + + the level parameter denotes how deeep we have already followed the jump, + to avoid endless loops with constructs such as "l5: ; jmp l5" } + + var p1, p2: tai; + l: tasmlabel; + + begin + GetfinalDestination := false; + if level > 20 then + exit; + p1 := getlabelwithsym(tasmlabel(hp.oper[0]^.ref^.symbol)); + if assigned(p1) then + begin + SkipLabels(p1,p1); + if (tai(p1).typ = ait_instruction) and + (taicpu(p1).is_jmp) then + if { the next instruction after the label where the jump hp arrives} + { is unconditional or of the same type as hp, so continue } + ((taicpu(p1).opcode = aopt_uncondjmp) or + conditions_equal(taicpu(p1).condition,hp.condition)) or + { the next instruction after the label where the jump hp arrives} + { is the opposite of hp (so this one is never taken), but after } + { that one there is a branch that will be taken, so perform a } + { little hack: set p1 equal to this instruction (that's what the} + { last SkipLabels is for, only works with short bool evaluation)} + (conditions_equal(taicpu(p1).condition,inverse_cond(hp.condition)) and + SkipLabels(p1,p2) and + (p2.typ = ait_instruction) and + (taicpu(p2).is_jmp) and + ((taicpu(p2).opcode = aopt_uncondjmp) or + (conditions_equal(taicpu(p2).condition,hp.condition))) and + SkipLabels(p1,p1)) then + begin + { quick check for loops of the form "l5: ; jmp l5 } + if (tasmlabel(taicpu(p1).oper[0]^.ref^.symbol).labelnr = + tasmlabel(hp.oper[0]^.ref^.symbol).labelnr) then + exit; + if not GetFinalDestination(taicpu(p1),succ(level)) then + exit; + tasmlabel(hp.oper[0]^.ref^.symbol).decrefs; + hp.oper[0]^.ref^.symbol:=taicpu(p1).oper[0]^.ref^.symbol; + tasmlabel(hp.oper[0]^.ref^.symbol).increfs; + end + else + if conditions_equal(taicpu(p1).condition,inverse_cond(hp.condition)) then + if not FindAnyLabel(p1,l) then + begin + {$ifdef finaldestdebug} + insertllitem(asml,p1,p1.next,tai_comment.Create( + strpnew('previous label inserted')))); + {$endif finaldestdebug} + objectlibrary.getlabel(l); + insertllitem(p1,p1.next,tai_label.Create(l)); + tasmlabel(taicpu(hp).oper[0]^.ref^.symbol).decrefs; + hp.oper[0]^.ref^.symbol := l; + l.increfs; + { this won't work, since the new label isn't in the labeltable } + { so it will fail the rangecheck. Labeltable should become a } + { hashtable to support this: } + { GetFinalDestination(asml, hp); } + end + else + begin + {$ifdef finaldestdebug} + insertllitem(asml,p1,p1.next,tai_comment.Create( + strpnew('next label reused')))); + {$endif finaldestdebug} + l.increfs; + hp.oper[0]^.ref^.symbol := l; + if not GetFinalDestination(hp,succ(level)) then + exit; + end; + end; + GetFinalDestination := true; + end; + + + procedure TAOptObj.PrePeepHoleOpts; + begin + end; + + + procedure TAOptObj.PeepHoleOptPass1; + var + p,hp1,hp2 : tai; + begin + p := BlockStart; + //!!!! UsedRegs := []; + while (p <> BlockEnd) Do + begin + //!!!! UpDateUsedRegs(UsedRegs, tai(p.next)); + case p.Typ Of + ait_instruction: + begin + { Handle Jmp Optimizations } + if taicpu(p).is_jmp then + begin + { the following if-block removes all code between a jmp and the next label, + because it can never be executed + } + if (taicpu(p).opcode = aopt_uncondjmp) then + begin + while GetNextInstruction(p, hp1) and + (hp1.typ <> ait_label) do + if not(hp1.typ in ([ait_label,ait_align]+skipinstr)) then + begin + asml.remove(hp1); + hp1.free; + end + else break; + end; + { remove jumps to a label coming right after them } + if GetNextInstruction(p, hp1) then + begin + if FindLabel(tasmlabel(taicpu(p).oper[0]^.ref^.symbol), hp1) and + {$warning FIXME removing the first instruction fails} + (p<>blockstart) then + begin + hp2:=tai(hp1.next); + asml.remove(p); + p.free; + p:=hp2; + continue; + end + else + begin + if hp1.typ = ait_label then + SkipLabels(hp1,hp1); + if (tai(hp1).typ=ait_instruction) and + (taicpu(hp1).opcode=aopt_uncondjmp) and + GetNextInstruction(hp1, hp2) and + FindLabel(tasmlabel(taicpu(p).oper[0]^.ref^.symbol), hp2) then + begin + if taicpu(p).opcode=aopt_condjmp then + begin + taicpu(p).condition:=inverse_cond(taicpu(p).condition); + tai_label(hp2).l.decrefs; + taicpu(p).oper[0]^.ref^.symbol:=taicpu(hp1).oper[0]^.ref^.symbol; + taicpu(p).oper[0]^.ref^.symbol.increfs; +{$ifdef SPARC} + hp2:=tai(hp1.next); + asml.remove(hp2); + hp2.free; +{$endif SPARC} + asml.remove(hp1); + hp1.free; + GetFinalDestination(taicpu(p),0); + end + else + begin + GetFinalDestination(taicpu(p),0); + p:=tai(p.next); + continue; + end; + end + else + GetFinalDestination(taicpu(p),0); + end; + end; + end + else + { All other optimizes } + begin + end; { if is_jmp } + end; + end; + //!!!!!!!! updateUsedRegs(UsedRegs,p); + p:=tai(p.next); + end; + end; + + + procedure TAOptObj.PeepHoleOptPass2; + begin + end; + + + procedure TAOptObj.PostPeepHoleOpts; + begin + end; + + +End. + +{ + $Log: aoptobj.pas,v $ + Revision 1.17 2005/02/26 01:26:59 jonas + * fixed generic jumps optimizer and enabled it for ppc (the label table + was not being initialised -> getfinaldestination always failed, which + caused wrong optimizations in some cases) + * changed the inverse_cond into a function, because tasmcond is a record + on ppc + + added a compare_conditions() function for the same reason + + Revision 1.16 2005/02/25 20:50:53 jonas + * fixed uninitialised function result in getfinaldestination() when + maximum recursion reached + + Revision 1.15 2005/02/14 17:13:06 peter + * truncate log + +} |