123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170 |
- {
- $Id$
- Copyright (c) 1999 by Jonas Maebe, member of the Free Pascal
- Development Team
- This unit contains the processor independent assembler 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 AoptObj;
- { general, processor independent objects for use by the assembler optimizer }
- Interface
- uses Cobjects, cpubase, aoptcpu;
- {***************** Constants *****************}
- Const
- { ait_* types which don't result in executable code or which don't influence }
- { the way the program runs/behaves }
- SkipInstr = [ait_comment, ait_align, ait_symbol
- {$ifdef GDB}
- ,ait_stabs, ait_stabn, ait_stab_function_name
- {$endif GDB}
- ,ait_regalloc, ait_tempalloc
- ];
- {Possible register content types}
- con_Unknown = 0;
- con_ref = 1;
- con_const = 2;
- {***************** Types ****************}
- Type
- TRegArray = Array[LoReg..HiReg] of TRegister;
- TRegSet = Set of LoReg..HiReg;
- PRegInfo = ^TReginfo;
- { info about the equivalence of registers when comparing two code sequences}
- TRegInfo = Object
- { registers encountered in the new and old sequence }
- NewRegsEncountered, OldRegsEncountered,
- { registers which only have been loaded for use as base or }
- { index in a reference later on }
- RegsLoadedForRef: TRegSet;
- { to which register in the old sequence corresponds every }
- { register in the new sequence }
- New2OldReg: TRegArray;
- Constructor init;
- { clear all information store in the object }
- Procedure Clear;
- { the contents of OldReg in the old sequence are now being }
- { loaded into NewReg in the new sequence }
- Procedure AddReg(OldReg, NewReg: TRegister); Virtual;
- { the contents of OldOp in the old sequence are now being }
- { loaded into NewOp in the new sequence. It is assumed that }
- { OldOp and NewOp are equivalent }
- Procedure AddOp(const OldOp, NewOp:Toper);
- { check if a register in the old sequence (OldReg) can be }
- { equivalent to a register in the new sequence (NewReg) if }
- { the operation OpAct is performed on it. The RegInfo is }
- { updated (not necessary to call AddReg afterwards }
- Function RegsEquivalent(OldReg, NewReg: TRegister;
- OpAct: TopAction): Boolean;
- { check if a reference in the old sequence (OldRef) can be }
- { equivalent to a reference in the new sequence (NewRef) if }
- { the operation OpAct is performed on it. The RegInfo is }
- { updated (not necessary to call AddOp afterwards }
- Function RefsEquivalent(Const OldRef, NewRef: TReference;
- OpAct: TOpAction): Boolean;
- { check if an operand in the old sequence (OldOp) can be }
- { equivalent to an operand in the new sequence (NewOp) if }
- { the operation OpAct is performed on it. The RegInfo is }
- { updated (not necessary to call AddOp afterwards }
- Function OpsEquivalent(const OldOp, NewOp: toper;
- OpAct: TopAction): Boolean;
- { check if an instruction in the old sequence (OldP) can be }
- { equivalent to an instruction in the new sequence (Newp) }
- { The RegInfo is updated }
- Function InstructionsEquivalent(OldP, NewP: Pai): Boolean;
- End;
- { possible actions on an operand: read, write or modify (= read & write) }
- TOpAction = (OpAct_Read, OpAct_Write, OpAct_Modify, OpAct_Unknown);
- { the properties of a cpu instruction }
- TAsmInstrucProp = Record
- { what it changes }
- Ch: Array[1..MaxCh] of TChange;
- End;
- { Object to hold on information on which regiters are in use and which not }
- TUsedRegs = Object
- Constructor init;
- Constructor InitWithValue(_RegSet: TRegSet);
- { update the info with the pairegalloc objects coming after }
- { p }
- Procedure Update(p: Pai);
- { is Reg currently in use }
- Function IsUsed(Reg: TRegister): Boolean;
- { get all the currently used registers }
- Function GetUsedRegs: TRegSet;
- Destructor Done;
- Private
- UsedRegs: TRegSet;
- End;
- { 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 = Packed 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: pai;
- { 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;
- { Contents of the integer registers }
- TRegContent = Array[LoGPReg..HiGPReg] Of TContent;
- PPaiProp = ^TPaiProp;
- { information object with the contents of every register. Every Pai object }
- { gets one of these assigned: a pointer to it is stored in the OptInfo field }
- TPaiProp = Object
- Regs: TRegContent;
- { info about allocation of general purpose integer registers }
- UsedRegs: TUsedRegs;
- { info about the conditional registers }
- CondRegs: TCondRegs;
- { can this instruction be removed? }
- CanBeRemoved: Boolean;
- Constructor init;
- { destroy the contents of a register }
- Procedure DestroyReg(Reg: TRegister);
- { 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);
- { 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);
- { destroy the contetns of all registers }
- Procedure DestroyAllRegs;
- {$ifdef arithopt}
- { a register's contents are modified, but not destroyed }
- { (the new value depends on the old one) }
- Procedure ModifyReg(reg: TRegister);
- { an operand's contents are modified, but not destroyed }
- { (the new value depends on the old one) }
- Procedure ModifyOp(const oper: TOper);
- {$endif arithopt}
- { 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 GetRegContentKind(Reg: TRegister): Byte;
- Destructor Done;
- Private
- Procedure IncState(Reg: TRegister);
- End;
- { the number of instructions that we have encountered since the last }
- { modification of a register }
- TInstrSinceLastMod = Array[LoGPReg..HiGPReg] Of Byte;
- TLabelTableItem = Record
- PaiObj: Pai;
- {$IfDef JumpAnal}
- InstrNr: Longint;
- RefsFound: Word;
- JmpsProcessed: Word
- {$EndIf JumpAnal}
- End;
- TLabelTable = Array[0..2500000] Of TLabelTableItem;
- PLabelTable = ^TLabelTable;
- 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: PLableTable;
- End;
- {***** General optimizer object, used to derive others from *****}
- Type TAOptObj = Object
- { processor independent methods }
- { returns true if the label L is found between hp and the next }
- { instruction }
- Function FindLabel(L: PasmLabel; Var hp: Pai): Boolean;
- { inserts new_one between prev and foll in AsmL }
- Procedure InsertLLItem(AsmL: PAasmOutput; prev, foll, new_one:
- PLinkedList_Item);
- { returns true if register Reg is used by instruction p1 }
- Function RegInInstruction(Reg: TRegister; p1: Pai): Boolean;
- { returns true if register Reg is used in the reference Ref }
- Function RegInRef(Reg: TRegister; Const Ref: TReference): Boolean;
- { returns whether the reference Ref is used somewhere in the loading }
- { sequence Constent }
- Function TAOptObj.RefInSequence(Const Ref: TReference;
- Content: TContent): Boolean;
- { returns whether the instruction P reads from and/or writes to Reg }
- Function TAOptObj.RefInInstruction(Const Ref: TReference; p: Pai): Boolean;
- { returns true if the instruction p1 modifies the register Reg }
- Function RegModifiedByInstruction(Reg: TRegister; p1: Pai): Boolean;
- { gets the next Pai object after current that contains info relevant }
- { to the optimizer in p1. If there is none, it returns false and }
- { sets p1 to nil }
- Function GetNextInstruction(Current: Pai; Var Next: Pai): Boolean;
- { gets the previous Pai object after current that contains info }
- { relevant to the optimizer in last. If there is none, it retuns }
- { false and sets last to nil }
- Function GetLastInstruction(Current: Pai; Var Last: Pai): Boolean;
- { If P is a Pai object releveant to the optimizer, it is left }
- { unchanged. If it is not relevant tot he optimizer, the first }
- { object after P that is relevant is stored in P }
- Procedure SkipHead(var P: Pai);
- { 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 Pai's starting with StartPai and ending with the next "real" }
- { instruction }
- Function FindRegAlloc(Reg: TRegister; StartPai: Pai): Boolean;
- { processor dependent methods }
- { returns the maximum width component of Reg. Only has to be }
- { overridden for the 80x86 (afaik) }
- Function RegMaxSize(Reg: TRegister): TRegister; Virtual;
- { returns true if Reg1 and Reg2 are of the samae width. Only has to }
- { overridden for the 80x86 (afaik) }
- Function RegsSameSize(Reg1, Reg2: TRegister): Boolean; Virtual;
- { returns whether P is a load instruction (load contents from a }
- { memory location or (register) variable into a register) }
- Function IsLoadInstr(p: pai): Boolean; Virtual;
- { returns whether P is a store instruction (store contents from a }
- { register to a memory location or to a (register) variable) }
- Function IsStoreInstr(p: pai): Boolean; Virtual;
- { returns whether the instruction P reads from register Reg }
- Function RegReadByInstr(Reg: TRegister; p: Pai); Virtual;
- { convert a TChange value into the corresponding register }
- Function TCh2Reg(Ch: TChange): TRegister; Virtual;
- End;
- {***************** Implementation *****************}
- Implementation
- {*********************** TReginfo ***********************}
- Constructor TRegInfo.Init;
- Begin
- Clear;
- End;
- Constructor TRegInfo.Init;
- Begin
- RegsLoadedForRef := [];
- NewRegsEncountered := [ProcInfo.FramePointer, R_ESP];
- OldRegsEncountered := [ProcInfo.FramePointer, R_ESP];
- New2OldReg[ProcInfo.FramePointer] := ProcInfo.FramePointer;
- New2OldReg[R_ESP] := R_ESP;
- End;
- Procedure TRegInfo.AddReg(OldReg, NewReg: TRegister);
- { updates the ???RegsEncountered and ???2???Reg fields of RegInfo. Assumes }
- { that OldReg and NewReg have the same size (has to be chcked in advance }
- { with RegsSameSize) and that neither equals R_NO }
- { has to be overridden for architectures like the 80x86 when not all GP }
- { regs are of the same size }
- Begin
- NewRegsEncountered := NewRegsEncountered + [NewReg];
- OldRegsEncountered := OldRegsEncountered + [OldReg];
- New2OldReg[NewReg] := OldReg;
- End;
- Procedure TRegInfo.AddOp(const OldOp, NewOp:Toper);
- Begin
- Case OldOp.typ Of
- Top_Reg:
- If (OldOp.reg <> R_NO) Then
- AddReg(OldOp.reg, NewOp.reg);
- Top_Ref:
- Begin
- If OldOp.ref^.base <> R_NO Then
- AddReg(OldOp.ref^.base, NewOp.ref^.base);
- {$ifdef RefsHaveIndexReg}
- If OldOp.ref^.index <> R_NO Then
- AddReg(OldOp.ref^.index, NewOp.ref^.index);
- {$endif RefsHaveIndexReg}
- End;
- End;
- End;
- Function TRegInfo.RegsEquivalent(OldReg, NewReg: TRegister;
- OPAct: TOpAction): Boolean;
- Begin
- If Not((OldReg = R_NO) Or (NewReg = R_NO)) Then
- If RegsSameSize(OldReg, NewReg) Then
- {here we always check for the 32 bit component, because it is possible that
- the 8 bit component has not been set, event though NewReg already has been
- processed. This happens if it has been compared with a register that doesn't
- have an 8 bit component (such as EDI). In that case the 8 bit component is
- still set to R_NO and the comparison in the Else-part will fail}
- If (RegMaxSize(OldReg) in OldRegsEncountered) Then
- If (RegMaxSize(NewReg) in NewRegsEncountered) Then
- RegsEquivalent := (OldReg = New2OldReg[NewReg])
- { If we haven't encountered the new register yet, but we have encountered the
- old one already, the new one can only be correct if it's being written to
- (and consequently the old one is also being written to), otherwise
- movl -8(%ebp), %eax and movl -8(%ebp), %eax
- movl (%eax), %eax movl (%edx), %edx
- are considered equivalent}
- Else
- If (OpAct = OpAct_Write) Then
- Begin
- AddReg(OldReg, NewReg);
- RegsEquivalent := True
- End
- Else Regsequivalent := False
- Else
- If Not(RegMaxSize(NewReg) in NewRegsEncountered) Then
- Begin
- AddReg(OldReg, NewReg);
- RegsEquivalent := True
- End
- Else RegsEquivalent := False
- Else RegsEquivalent := False
- Else RegsEquivalent := OldReg = NewReg
- End;
- Function TRegInfo.RefsEquivalent(Const OldRef, NewRef: TReference;
- OpAct: TOpAction): Boolean;
- Begin
- If OldRef.is_immediate Then
- RefsEquivalent := NewRef.is_immediate and (OldRef.Offset = NewRef.Offset)
- Else
- RefsEquivalent := (OldRef.Offset+OldRef.OffsetFixup =
- NewRef.Offset+NewRef.OffsetFixup) And
- RegsEquivalent(OldRef.Base, NewRef.Base, OpAct)
- {$ifdef RefsHaveindex}
- And RegsEquivalent(OldRef.Index, NewRef.Index, OpAct)
- {$endif RefsHaveIndex}
- {$ifdef RefsHaveScale}
- And (OldRef.ScaleFactor = NewRef.ScaleFactor)
- {$endif RefsHaveScale}
- And (OldRef.Symbol = NewRef.Symbol)
- {$ifdef RefsHaveSegment}
- And (OldRef.Segment = NewRef.Segment)
- {$endif RefsHaveSegment}
- ;
- End;
- Function TRegInfo.OpsEquivalent(const OldOp, NewOp: toper; OpAct: TopAction):
- Boolean;
- Begin {checks whether the two ops are equivalent}
- OpsEquivalent := False;
- if OldOp.typ=NewOp.typ then
- Case OldOp.typ Of
- Top_Const: OpsEquivalent := OldOp.value = NewOp.value;
- Top_Reg:
- OpsEquivalent := RegsEquivalent(OldOp.reg,NewOp.reg, OpAct);
- Top_Ref:
- OpsEquivalent := RefsEquivalent(OldOp.ref^, NewOp.ref^, OpAct);
- Top_None:
- OpsEquivalent := True
- End;
- End;
- Function TRegInfo.InstructionsEquivalent(OldP, NewP: Pai): Boolean;
- { checks whether two PInstr instructions are equal }
- Var Count: TNatInt;
- TmpResult: Boolean;
- Begin
- If Assigned(OldP) And Assigned(NewP) And
- (Pai(OldP)^.typ = ait_instruction) And
- (Pai(NewP)^.typ = ait_instruction) And
- (PInstr(OldP)^.opcode = PInstr(NewP)^.opcode) And
- (PInstr(OldP)^.oper[0].typ = PInstr(NewP)^.oper[0].typ) And
- (PInstr(OldP)^.oper[1].typ = PInstr(NewP)^.oper[1].typ) And
- (PInstr(OldP)^.oper[2].typ = PInstr(NewP)^.oper[2].typ)
- Then
- { both instructions have the same structure: }
- { "<operator> <operand of type1>, <operand of type 2>" }
- If IsLoadInstr(OldP) {then also NewP = loadinstr} Then
- If Not(RegInRef(PInstr(OldP)^.oper[LoadDst].reg,
- PInstr(OldP)^.oper[LoadSrc].ref^)) Then
- { the "old" instruction is a load of a register with a new value, not with }
- { a value based on the contents of this register (so no "mov (reg), reg") }
- If Not(RegInRef(PInstr(NewP)^.oper[LoadDst].reg,
- PInstr(NewP)^.oper[LoadSrc].ref^)) And
- RefsEqual(PInstr(OldP)^.oper[LoadSrc].ref^,
- PInstr(NewP)^.oper[LoadSrc].ref^)
- Then
- { the "new" instruction is also a load of a register with a new value, and }
- { this value is fetched from the same memory location }
- Begin
- With PInstr(NewP)^.oper[LoadSrc].ref^ Do
- Begin
- If Not(Base in [ProcInfo.FramePointer, R_NO, StackPtr])
- { it won't do any harm if the register is already in RegsLoadedForRef }
- Then RegsLoadedForRef := RegsLoadedForRef + [Base];
- {$ifdef RefsHaveIndex}
- If Not(Index in [ProcInfo.FramePointer, R_NO, R_StackPtr])
- Then RegsLoadedForRef := RegsLoadedForRef + [Index];
- {$endif RefsHaveIndex}
- End;
- { add the registers from the reference (.oper[Src]) to the RegInfo, all }
- { registers from the reference are the same in the old and in the new }
- { instruction sequence }
- AddOp(PInstr(OldP)^.oper[Src], PInstr(OldP)^.oper[Src]);
- { the registers from .oper[Dest] have to be equivalent, but not necessarily }
- { equal }
- InstructionsEquivalent :=
- RegsEquivalent(PInstr(OldP)^.oper[Dest].reg,
- PInstr(NewP)^.oper[Dest].reg, OpAct_Write);
- End
- { the registers are loaded with values from different memory locations. If }
- { this were allowed, the instructions "mov -4(%esi),%eax" and }
- { "mov -4(%ebp),%eax" would be considered equivalent }
- Else InstructionsEquivalent := False
- Else
- { load register with a value based on the current value of this register }
- Begin
- With PInstr(NewP)^.oper[0].ref^ Do
- { Assume the registers occurring in the reference have only been loaded with }
- { the value they contain now to calculate an address (so the value they have }
- { now, won't be stored to memory later on)}
- Begin
- If Not(Base in [ProcInfo.FramePointer,
- RegMaxSize(PInstr(NewP)^.oper[LoadDst].reg),
- R_NO,StackPtr])
- { It won't do any harm if the register is already in RegsLoadedForRef }
- Then
- Begin
- RegsLoadedForRef := RegsLoadedForRef + [Base];
- {$ifdef csdebug}
- Writeln(att_reg2str[base], ' added');
- {$endif csdebug}
- end;
- {$Ifdef RefsHaveIndex}
- If Not(Index in [ProcInfo.FramePointer,
- RegMaxSize(PInstr(NewP)^.oper[LoadDst].reg),
- R_NO,StackPtr])
- Then
- Begin
- RegsLoadedForRef := RegsLoadedForRef + [Index];
- {$ifdef csdebug}
- Writeln(att_reg2str[index], ' added');
- {$endif csdebug}
- end;
- {$endif RefsHaveIndex}
- End;
- { now, remove the destination register of the load from the }
- { RegsLoadedForReg, since if it's loaded with a new value, it certainly }
- { will still be used later on }
- If Not(RegMaxSize(PInstr(NewP)^.oper[LoadDst].reg) In
- [ProcInfo.FramePointer,R_NO,StackPtr])
- Then
- Begin
- RegsLoadedForRef := RegsLoadedForRef -
- [RegMaxSize(PInstr(NewP)^.oper[LoadDst].reg)];
- {$ifdef csdebug}
- Writeln(att_reg2str[Reg32(Pai386(NewP)^.oper[1].reg)], ' removed');
- {$endif csdebug}
- end;
- InstructionsEquivalent :=
- OpsEquivalent(PInstr(OldP)^.oper[LoadSrc],
- PInstr(NewP)^.oper[LoadSrc], OpAct_Read) And
- OpsEquivalent(PInstr(OldP)^.oper[LoadDst],
- PInstr(NewP)^.oper[LoadDst], OpAct_Write)
- End
- Else
- {an instruction that's not a load instruction}
- Begin
- Count := 0;
- TmpResult := true;
- Repeat
- TmpResult :=
- OpsEquivalent(PInstr(OldP)^.oper[Count], PInstr(NewP)^.oper[Count],
- OpAct_Unknown);
- Inc(Count)
- Until (Count = MaxOps) or not(TmpResult);
- InstructionsEquivalent := TmpResult
- End
- { the instructions haven't even got the same structure, so they're certainly }
- { not equivalent }
- Else InstructionsEquivalent := False;
- End;
- {*************************** TUsedRegs ***************************}
- Constructor TUsedRegs.init;
- Begin
- UsedRegs := [];
- End;
- Constructor TUsedRegisters.InitWithValue(Const _RegSet: TRegSet);
- Begin
- RegSet := _RegSet;
- End;
- Procedure TUsedRegs.Update(p: Pai);
- {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(Pai_Label(p)^.l^.is_used))) Do
- p := Pai(p^.next);
- While Assigned(p) And
- (p^.typ=ait_RegAlloc) Do
- Begin
- if pairegalloc(p)^.allocation then
- UsedRegs := UsedRegs + [PaiRegAlloc(p)^.Reg]
- else
- UsedRegs := UsedRegs - [PaiRegAlloc(p)^.Reg];
- p := pai(p^.next);
- End;
- Until Not(Assigned(p)) Or
- (Not(p^.typ in SkipInstr) And
- Not((p^.typ = ait_label) And
- Not(Pai_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;
- {*************************** TPaiProp ***************************}
- Constructor TPaiProp.Init;
- Begin
- UsedRegs.Init;
- CondRegs.init;
- { DirFlag: TFlagContents; I386 specific}
- End;
- Procedure TPaiProp.DestroyReg(Reg: TRegister);
- {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 := Reg32(Reg);
- NrOfInstrSinceLastMod[Reg] := 0;
- If (Reg >= R_EAX) And (Reg <= R_EDI)
- Then
- Begin
- With Regs[Reg] Do
- Begin
- IncState(WState);
- TmpWState := WState;
- TmpRState := RState;
- FillChar(Regs[Reg], SizeOf(TContent), 0);
- WState := TmpWState;
- RState := TmpRState;
- End;
- For Counter := R_EAX to R_EDI Do
- With Regs[Counter] Do
- If (Typ = Con_Ref) And
- RegInSequence(Reg, Regs[Counter])
- Then
- Begin
- IncState(WState);
- TmpWState := WState;
- TmpRState := RState;
- FillChar(Regs[Counter], SizeOf(TContent), 0);
- WState := TmpWState;
- RState := TmpRState;
- End;
- End;
- End;
- Procedure TPaiProp.DestroyRefs(Const Ref: TReference; WhichReg: TRegister);
- {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 Counter: TRegister;
- Begin
- WhichReg := RegMaxSize(WhichReg);
- If ((Ref.base = ProcInfo.FramePointer) And
- {$ifdef refsHaveIndex}
- (Ref.Index = R_NO)
- {$endif refsHaveIndex}
- ) Or
- Assigned(Ref.Symbol)
- Then
- {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]) And
- ((Counter <> WhichReg) Or
- ((NrOfMods <> 1) And
- {StarMod is always of the type ait_instruction}
- (PInstr(StartMod)^.oper[0].typ = top_ref) And
- RefsEqual(PInstr(StartMod)^.oper[0].ref^, Ref)
- )
- )
- )
- )
- Then
- DestroyReg(Counter)
- 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 i386}
- {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)
- End;
- Procedure TPaiProp.DestroyAllRegs;
- Var Counter: TRegister;
- Begin {initializes/desrtoys all registers}
- For Counter := R_EAX To R_EDI Do
- DestroyReg(Counter);
- CondRegs.Init;
- { FPURegs.Init; }
- End;
- Procedure TPaiProp.DestroyOp(const o:Toper);
- Begin
- Case o.typ Of
- top_reg: DestroyReg(o.reg);
- top_ref: DestroyRefs(o.ref^, R_NO);
- 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);
- If Ref^.Index <> R_NO Then
- ReadReg(Ref^.Index);
- End;
- Procedure TPaiProp.ReadOp(const o:toper);
- Begin
- Case o.typ Of
- top_reg: ReadReg(o.reg);
- top_ref: ReadRef(o.ref);
- top_symbol : ;
- End;
- End;
- {$ifdef arithopt}
- Procedure TPaiProp.ModifyReg(reg: TRegister);
- 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, NrOfInstrSinceLastMod[Reg]);
- PPaiProp(StartMod^.OptInfo)^.Regs[Reg].NrOfMods := NrOfMods;
- NrOfInstrSinceLastMod[Reg] := 0;
- End
- Else
- DestroyReg(Reg);
- End;
- Procedure TPaiProp.ModifyOp(const oper: TOper);
- Begin
- If oper.typ = top_reg Then
- ModifyReg(RegMaxSize(oper.reg))
- Else
- Begin
- ReadOp(oper);
- DestroyOp(oper);
- End
- End;
- {$endif arithopt}
- Procedure TPaiProp.IncWState(Reg: TRegister);{$ifdef fpc} inline;{$endif fpc}
- Begin
- IncState(Regs[Reg].WState);
- End;
- Procedure TPaiProp.IncRState(Reg: TRegister);{$ifdef fpc} inline;{$endif fpc}
- Begin
- IncState(Regs[Reg].RState);
- End;
- Procedure TPaiProp.IncState(Var s: TStateInt); {$ifdef fpc} inline;{$endif fpc}
- Begin
- If s <> $ff Then Inc(s)
- Else s := 0
- End;
- Function TPaiProp.GetWState(Reg: TRegister): TStateInt;
- Begin
- GetWState := Regs[Reg].WState
- End;
- Function TPaiProp.GetRState(Reg: TRegister): TStateInt;
- Begin
- GetRState := Regs[Reg].RState
- End;
- Function TPaiProp.GetRegContentKind(Reg: TRegister): Byte;
- Begin
- GetRegContentKind := Regs[Reg].ty
- End;
- {******************* TAOptObj *******************}
- Function TAOptObj.FindLabel(L: PasmLabel; Var hp: Pai): Boolean;
- Var TempP: Pai;
- Begin
- TempP := hp;
- While Assigned(TempP) and
- (TempP^.typ In SkipInstr + [ait_label]) Do
- If (TempP^.typ <> ait_Label) Or
- (pai_label(TempP)^.l <> L)
- Then GetNextInstruction(TempP, TempP)
- Else
- Begin
- hp := TempP;
- FindLabel := True;
- exit
- End;
- FindLabel := False;
- End;
- Procedure TAOptObj.InsertLLItem(AsmL: PAasmOutput; prev, foll, new_one:
- PLinkedList_Item);
- 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;
- new_one^.fileinfo := foll^.fileinfo
- End
- End
- Else AsmL^.Concat(new_one)
- Else If Assigned(Foll) Then AsmL^.Insert(new_one)
- End;
- Function TAOptObj.RegInInstruction(Reg: TRegister; p1: Pai): Boolean;
- Var Count: TNatInt;
- TmpResult: Boolean;
- Begin
- TmpResult := False;
- Count := 0;
- If (p1^.typ = ait_instruction) Then
- Repeat
- TmpResult := RegInOp(Reg, PInstr(p1)^.oper[Count]);
- Inc(Count)
- Until (Count = MaxOps) or TmpResult;
- RegInInstruction := TmpResult
- End;
- Function TAOptObj.RegInOp(Reg: TRegister; const op: toper): Boolean;
- Begin
- Case op.typ Of
- Top_Reg: RegInOp := Reg = op.reg;
- Top_Ref: RegInOp := RegInRef(Reg, op.ref^)
- Else RegInOp := False
- End
- End;
- Function TAOptObj.RegModifiedByInstruction(Reg: TRegister; p1: Pai): Boolean;
- Var hp: Pai;
- Begin
- If GetLastInstruction(p1, hp)
- Then
- RegModifiedByInstruction :=
- PPAiProp(p1^.OptInfo)^.Regs[Reg].WState <>
- PPAiProp(hp^.OptInfo)^.Regs[Reg].WState
- Else RegModifiedByInstruction := True;
- End;
- Function TAOptObj.GetNextInstruction(Current: Pai; Var Next: Pai): Boolean;
- Begin
- Repeat
- Current := Pai(Current^.Next);
- While Assigned(Current) And
- ((Current^.typ In SkipInstr) or
- ((Current^.typ = ait_label) And
- Not(Pai_Label(Current)^.l^.is_used))) Do
- Current := Pai(Current^.Next);
- If Assigned(Current) And
- (Current^.typ = ait_Marker) And
- (Pai_Marker(Current)^.Kind = NoPropInfoStart) Then
- Begin
- While Assigned(Current) And
- ((Current^.typ <> ait_Marker) Or
- (Pai_Marker(Current)^.Kind <> NoPropInfoEnd)) Do
- Current := Pai(Current^.Next);
- End;
- Until Not(Assigned(Current)) Or
- (Current^.typ <> ait_Marker) Or
- (Pai_Marker(Current)^.Kind <> NoPropInfoEnd);
- Next := Current;
- If Assigned(Current) And
- Not((Current^.typ In SkipInstr) or
- ((Current^.typ = ait_label) And
- Not(Pai_Label(Current)^.l^.is_used)))
- Then GetNextInstruction := True
- Else
- Begin
- Next := Nil;
- GetNextInstruction := False;
- End;
- End;
- Function TAOptObj.GetLastInstruction(Current: Pai; Var Last: Pai): Boolean;
- Begin
- Repeat
- Current := Pai(Current^.previous);
- While Assigned(Current) And
- (((Current^.typ = ait_Marker) And
- Not(Pai_Marker(Current)^.Kind in [AsmBlockEnd,NoPropInfoEnd])) or
- (Current^.typ In SkipInstr) or
- ((Current^.typ = ait_label) And
- Not(Pai_Label(Current)^.l^.is_used))) Do
- Current := Pai(Current^.previous);
- If Assigned(Current) And
- (Current^.typ = ait_Marker) And
- (Pai_Marker(Current)^.Kind = NoPropInfoEnd) Then
- Begin
- While Assigned(Current) And
- ((Current^.typ <> ait_Marker) Or
- (Pai_Marker(Current)^.Kind <> NoPropInfoStart)) Do
- Current := Pai(Current^.previous);
- End;
- Until Not(Assigned(Current)) Or
- (Current^.typ <> ait_Marker) Or
- (Pai_Marker(Current)^.Kind <> NoPropInfoStart);
- If Not(Assigned(Current)) or
- (Current^.typ In SkipInstr) or
- ((Current^.typ = ait_label) And
- Not(Pai_Label(Current)^.l^.is_used)) or
- ((Current^.typ = ait_Marker) And
- (Pai_Marker(Current)^.Kind = AsmBlockEnd))
- Then
- Begin
- Last := Nil;
- GetLastInstruction := False
- End
- Else
- Begin
- Last := Current;
- GetLastInstruction := True;
- End;
- End;
- Procedure TAOptObj.SkipHead(var P: Pai);
- { skips Pai objects at the start of a block that don't do anything }
- Var OldP: Pai;
- Begin
- Repeat
- OldP := P;
- If (P^.typ in SkipInstr) Or
- ((P^.typ = ait_marker) And
- (Pai_Marker(P)^.Kind = AsmBlockEnd)) Then
- GetNextInstruction(P, P)
- Else If ((P^.Typ = Ait_Marker) And
- (Pai_Marker(P)^.Kind = NoPropInfoStart)) Then
- { a marker of the type NoPropInfoStart can't be the first instruction of a }
- { paasmoutput list }
- GetNextInstruction(Pai(P^.Previous),P);
- If (P^.Typ = Ait_Marker) And
- (Pai_Marker(P)^.Kind = AsmBlockStart) Then
- Begin
- P := Pai(P^.Next);
- While (P^.typ <> Ait_Marker) Or
- (Pai_Marker(P)^.Kind <> AsmBlockEnd) Do
- P := Pai(P^.Next)
- End;
- Until P = OldP
- 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 := RefsEqual(o1.ref^, o2.ref^);
- Top_Const :
- OpsEqual:=o1.val=o2.val;
- Top_Symbol :
- OpsEqual:=(o1.sym=o2.sym) and (o1.symofs=o2.symofs);
- Top_None :
- OpsEqual := True
- else OpsEqual := False
- End;
- End;
- Function TAOptObj.FindRegAlloc(Reg: TRegister; StartPai: Pai): Boolean;
- Begin
- FindRegAlloc:=False;
- Repeat
- While Assigned(StartPai) And
- ((StartPai^.typ in (SkipInstr - [ait_regAlloc])) Or
- ((StartPai^.typ = ait_label) and
- Not(Pai_Label(StartPai)^.l^.Is_Used))) Do
- StartPai := Pai(StartPai^.Next);
- If Assigned(StartPai) And
- (StartPai^.typ = ait_regAlloc) and (PairegAlloc(StartPai)^.allocation) Then
- Begin
- if PairegAlloc(StartPai)^.Reg = Reg then
- begin
- FindRegAlloc:=true;
- exit;
- end;
- StartPai := Pai(StartPai^.Next);
- End
- else
- exit;
- Until false;
- End;
- Function TAOptObj.RefsEqual(Const R1, R2: TReference): Boolean;
- Begin
- If R1.is_immediate Then
- RefsEqual := R2.is_immediate and (R1.Offset = R2.Offset)
- Else
- RefsEqual := (R1.Offset+R1.OffsetFixup = R2.Offset+R2.OffsetFixup)
- And (R1.Base = R2.Base)
- {$ifdef RefsHaveindex}
- And (R1.Index = R2.Index)
- {$endif RefsHaveindex}
- {$ifdef RefsHaveScale}
- And (R1.ScaleFactor = R2.ScaleFactor)
- {$endif RefsHaveScale}
- And (R1.Symbol = R2.Symbol)
- {$ifdef RefsHaveSegment}
- And (R1.Segment = R2.Segment)
- {$endif RefsHaveSegment}
- ;
- Function TAOptObj.RegInRef(Reg: TRegister; Const Ref: TReference): Boolean;
- Begin
- Reg := RegMaxSize(Reg);
- RegInRef := (Ref.Base = Reg)
- {$ifdef RefsHaveIndexReg}
- Or (Ref.Index = Reg)
- {$endif RefsHaveIndexReg}
- End;
- Function TAOptObj.RegModifiedByInstruction(Reg: TRegister; p1: Pai): Boolean;
- Var hp: Pai;
- Begin
- If GetLastInstruction(p1, hp)
- Then
- RegModifiedByInstruction :=
- PPAiProp(p1^.OptInfo)^.GetWState <>
- PPAiProp(hp^.OptInfo)^.GetWState
- Else RegModifiedByInstruction := True;
- End;
- Function TAOptObj.RefInInstruction(Const Ref: TReference; p: Pai): Boolean;
- Var Count: TNatInt;
- TmpResult: Boolean;
- Begin
- TmpResult := False;
- If (p^.typ = ait_instruction) Then
- Begin
- Count := 0;
- Repeat
- If (PInstr(p)^.oper[Count].typ = Top_Ref) Then
- TmpResult := RefsEqual(Ref, PInstr(p)^.oper[Count].ref^);
- Inc(Count);
- Until (Count = MaxOps) or TmpResult;
- End;
- RefInInstruction := TmpResult;
- End;
- Function TAOptObj.RefInSequence(Const Ref: TReference; Content: TContent):
- Boolean;
- Var p: Pai;
- 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)
- Then TmpResult := True;
- Inc(Counter);
- GetNextInstruction(p,p)
- End;
- RefInSequence := TmpResult
- End;
- Function TAOptObj.RegMaxSize(Reg: TRegister): TRegister;
- Begin
- RegMaxSize := Reg
- End;
- Function TAOptObj.RegsSameSize(Reg1, Reg2: TRegister): Boolean;
- Begin
- RegsSameSize := True
- End;
- Function TAOptObj.IsLoadInstr(p: pai): Boolean;
- Begin
- Abstract
- End;
- Function TAOptObj.RegReadByInstr(Reg: TRegister; p: Pai);
- Begin
- Abstract
- End;
- Function TAOptObj.IsStoreInstr(p: pai): Boolean;
- Begin
- Abstract
- End;
- Function TAOptObj.TCh2Reg(Ch: TChange): TRegister;
- Begin
- Abstract
- End;
- End.
- {
- $Log$
- 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
- }
|