|
@@ -1,2806 +0,0 @@
|
|
-{
|
|
|
|
- Copyright (c) 1998-2002 by Jonas Maebe, member of the Freepascal
|
|
|
|
- development team
|
|
|
|
-
|
|
|
|
- This unit contains the data flow analyzer and several helper procedures
|
|
|
|
- and functions.
|
|
|
|
-
|
|
|
|
- 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 daopt386;
|
|
|
|
-
|
|
|
|
-{$i fpcdefs.inc}
|
|
|
|
-
|
|
|
|
-interface
|
|
|
|
-
|
|
|
|
-uses
|
|
|
|
- globtype,
|
|
|
|
- cclasses,aasmbase,aasmtai,aasmdata,aasmcpu,cgbase,cgutils,
|
|
|
|
- cpubase;
|
|
|
|
-
|
|
|
|
-{******************************* Constants *******************************}
|
|
|
|
-
|
|
|
|
-const
|
|
|
|
-
|
|
|
|
-{ Possible register content types }
|
|
|
|
- con_Unknown = 0;
|
|
|
|
- con_ref = 1;
|
|
|
|
- con_const = 2;
|
|
|
|
- { The contents aren't usable anymore for CSE, but they may still be }
|
|
|
|
- { useful for detecting whether the result of a load is actually used }
|
|
|
|
- con_invalid = 3;
|
|
|
|
- { the reverse of the above (in case a (conditional) jump is encountered): }
|
|
|
|
- { CSE is still possible, but the original instruction can't be removed }
|
|
|
|
- con_noRemoveRef = 4;
|
|
|
|
- { same, but for constants }
|
|
|
|
- con_noRemoveConst = 5;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-const
|
|
|
|
- topsize2tcgsize: array[topsize] of tcgsize = (OS_NO,
|
|
|
|
- OS_8,OS_16,OS_32,OS_64,OS_16,OS_32,OS_32,
|
|
|
|
- OS_16,OS_32,OS_64,
|
|
|
|
- OS_F32,OS_F64,OS_F80,OS_C64,OS_F128,
|
|
|
|
- OS_M32,
|
|
|
|
- OS_ADDR,OS_NO,OS_NO,
|
|
|
|
- OS_NO,
|
|
|
|
- OS_NO,
|
|
|
|
- OS_NO);
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-{********************************* Types *********************************}
|
|
|
|
-
|
|
|
|
-type
|
|
|
|
- TRegEnum = RS_EAX..RS_ESP;
|
|
|
|
- TRegArray = Array[TRegEnum] of tsuperregister;
|
|
|
|
- TRegSet = Set of TRegEnum;
|
|
|
|
- toptreginfo = Record
|
|
|
|
- NewRegsEncountered, OldRegsEncountered: TRegSet;
|
|
|
|
- RegsLoadedForRef: TRegSet;
|
|
|
|
- lastReload: array[RS_EAX..RS_ESP] of tai;
|
|
|
|
- New2OldReg: TRegArray;
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
-{possible actions on an operand: read, write or modify (= read & write)}
|
|
|
|
- TOpAction = (OpAct_Read, OpAct_Write, OpAct_Modify, OpAct_Unknown);
|
|
|
|
-
|
|
|
|
-{the possible states of a flag}
|
|
|
|
- TFlagContents = (F_Unknown, F_notSet, F_Set);
|
|
|
|
-
|
|
|
|
- TContent = Packed Record
|
|
|
|
- {start and end of block instructions that defines the
|
|
|
|
- content of this register.}
|
|
|
|
- StartMod: tai;
|
|
|
|
- MemWrite: taicpu;
|
|
|
|
- {how many instructions starting with StarMod does the block consist of}
|
|
|
|
- NrOfMods: Word;
|
|
|
|
- {the type of the content of the register: unknown, memory, constant}
|
|
|
|
- Typ: Byte;
|
|
|
|
- case byte of
|
|
|
|
- {starts at 0, gets increased everytime the register is written to}
|
|
|
|
- 1: (WState: Byte;
|
|
|
|
- {starts at 0, gets increased everytime the register is read from}
|
|
|
|
- RState: Byte);
|
|
|
|
- { to compare both states in one operation }
|
|
|
|
- 2: (state: word);
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
-{Contents of the integer registers}
|
|
|
|
- TRegContent = Array[RS_EAX..RS_ESP] Of TContent;
|
|
|
|
-
|
|
|
|
-{contents of the FPU registers}
|
|
|
|
-// TRegFPUContent = Array[RS_ST..RS_ST7] Of TContent;
|
|
|
|
-
|
|
|
|
-{$ifdef tempOpts}
|
|
|
|
-{ linked list which allows searching/deleting based on value, no extra frills}
|
|
|
|
- PSearchLinkedListItem = ^TSearchLinkedListItem;
|
|
|
|
- TSearchLinkedListItem = object(TLinkedList_Item)
|
|
|
|
- constructor init;
|
|
|
|
- function equals(p: PSearchLinkedListItem): boolean; virtual;
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
- PSearchDoubleIntItem = ^TSearchDoubleInttem;
|
|
|
|
- TSearchDoubleIntItem = object(TLinkedList_Item)
|
|
|
|
- constructor init(_int1,_int2: longint);
|
|
|
|
- function equals(p: PSearchLinkedListItem): boolean; virtual;
|
|
|
|
- private
|
|
|
|
- int1, int2: longint;
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
- PSearchLinkedList = ^TSearchLinkedList;
|
|
|
|
- TSearchLinkedList = object(TLinkedList)
|
|
|
|
- function searchByValue(p: PSearchLinkedListItem): boolean;
|
|
|
|
- procedure removeByValue(p: PSearchLinkedListItem);
|
|
|
|
- end;
|
|
|
|
-{$endif tempOpts}
|
|
|
|
-
|
|
|
|
-{information record with the contents of every register. Every tai object
|
|
|
|
- gets one of these assigned: a pointer to it is stored in the OptInfo field}
|
|
|
|
- TtaiProp = Record
|
|
|
|
- Regs: TRegContent;
|
|
|
|
-{ FPURegs: TRegFPUContent;} {currently not yet used}
|
|
|
|
- { allocated Registers }
|
|
|
|
- UsedRegs: TRegSet;
|
|
|
|
- { status of the direction flag }
|
|
|
|
- DirFlag: TFlagContents;
|
|
|
|
-{$ifdef tempOpts}
|
|
|
|
- { currently used temps }
|
|
|
|
- tempAllocs: PSearchLinkedList;
|
|
|
|
-{$endif tempOpts}
|
|
|
|
- { can this instruction be removed? }
|
|
|
|
- CanBeRemoved: Boolean;
|
|
|
|
- { are the resultflags set by this instruction used? }
|
|
|
|
- FlagsUsed: Boolean;
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
- ptaiprop = ^TtaiProp;
|
|
|
|
-
|
|
|
|
- TtaiPropBlock = Array[1..250000] Of TtaiProp;
|
|
|
|
- PtaiPropBlock = ^TtaiPropBlock;
|
|
|
|
-
|
|
|
|
- TInstrSinceLastMod = Array[RS_EAX..RS_ESP] Of Word;
|
|
|
|
-
|
|
|
|
- TLabelTableItem = Record
|
|
|
|
- taiObj: tai;
|
|
|
|
-{$ifDef JumpAnal}
|
|
|
|
- InstrNr: Longint;
|
|
|
|
- RefsFound: Word;
|
|
|
|
- JmpsProcessed: Word
|
|
|
|
-{$endif JumpAnal}
|
|
|
|
- end;
|
|
|
|
- TLabelTable = Array[0..2500000] Of TLabelTableItem;
|
|
|
|
- PLabelTable = ^TLabelTable;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-{*********************** procedures and functions ************************}
|
|
|
|
-
|
|
|
|
-procedure InsertLLItem(AsmL: TAsmList; prev, foll, new_one: TLinkedListItem);
|
|
|
|
-
|
|
|
|
-function isgp32reg(supreg: tsuperregister): Boolean;
|
|
|
|
-function reginref(supreg: tsuperregister; const ref: treference): boolean;
|
|
|
|
-function RegReadByInstruction(supreg: tsuperregister; hp: tai): boolean;
|
|
|
|
-function RegModifiedByInstruction(supreg: tsuperregister; p1: tai): boolean;
|
|
|
|
-function RegInInstruction(supreg: tsuperregister; p1: tai): boolean;
|
|
|
|
-function reginop(supreg: tsuperregister; const o:toper): boolean;
|
|
|
|
-function instrWritesFlags(p: tai): boolean;
|
|
|
|
-function instrReadsFlags(p: tai): boolean;
|
|
|
|
-
|
|
|
|
-function writeToMemDestroysContents(regWritten: tsuperregister; const ref: treference;
|
|
|
|
- supreg: tsuperregister; size: tcgsize; const c: tcontent; var invalsmemwrite: boolean): boolean;
|
|
|
|
-function writeToRegDestroysContents(destReg, supreg: tsuperregister;
|
|
|
|
- const c: tcontent): boolean;
|
|
|
|
-function writeDestroysContents(const op: toper; supreg: tsuperregister; size: tcgsize;
|
|
|
|
- const c: tcontent; var memwritedestroyed: boolean): boolean;
|
|
|
|
-
|
|
|
|
-function sequenceDependsonReg(const Content: TContent; seqreg: tsuperregister; supreg: tsuperregister): Boolean;
|
|
|
|
-
|
|
|
|
-function GetNextInstruction(Current: tai; var Next: tai): Boolean;
|
|
|
|
-function GetLastInstruction(Current: tai; var Last: tai): Boolean;
|
|
|
|
-procedure SkipHead(var p: tai);
|
|
|
|
-function labelCanBeSkipped(p: tai_label): boolean;
|
|
|
|
-
|
|
|
|
-procedure RemoveLastDeallocForFuncRes(asmL: TAsmList; p: tai);
|
|
|
|
-function regLoadedWithNewValue(supreg: tsuperregister; canDependOnPrevValue: boolean;
|
|
|
|
- hp: tai): boolean;
|
|
|
|
-procedure UpdateUsedRegs(var UsedRegs: TRegSet; p: tai);
|
|
|
|
-procedure AllocRegBetween(asml: TAsmList; reg: tregister; p1, p2: tai; var initialusedregs: tregset);
|
|
|
|
-function FindRegDealloc(supreg: tsuperregister; p: tai): boolean;
|
|
|
|
-
|
|
|
|
-function InstructionsEquivalent(p1, p2: tai; var RegInfo: toptreginfo): Boolean;
|
|
|
|
-function sizescompatible(loadsize,newsize: topsize): boolean;
|
|
|
|
-function OpsEqual(const o1,o2:toper): Boolean;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-type
|
|
|
|
- tdfaobj = class
|
|
|
|
- constructor create(_list: TAsmList); virtual;
|
|
|
|
-
|
|
|
|
- function pass_1(_blockstart: tai): tai;
|
|
|
|
- function pass_generate_code: boolean;
|
|
|
|
- procedure clear;
|
|
|
|
-
|
|
|
|
- function getlabelwithsym(sym: tasmlabel): tai;
|
|
|
|
-
|
|
|
|
- private
|
|
|
|
- { asm list we're working on }
|
|
|
|
- list: TAsmList;
|
|
|
|
-
|
|
|
|
- { current part of the asm list }
|
|
|
|
- blockstart, blockend: tai;
|
|
|
|
-
|
|
|
|
- { the amount of taiObjects in the current part of the assembler list }
|
|
|
|
- nroftaiobjs: longint;
|
|
|
|
-
|
|
|
|
- { Array which holds all TtaiProps }
|
|
|
|
- taipropblock: ptaipropblock;
|
|
|
|
-
|
|
|
|
- { all labels in the current block: their value mapped to their location }
|
|
|
|
- lolab, hilab, labdif: longint;
|
|
|
|
- labeltable: plabeltable;
|
|
|
|
-
|
|
|
|
- { Walks through the list to find the lowest and highest label number, inits the }
|
|
|
|
- { labeltable and fixes/optimizes some regallocs }
|
|
|
|
- procedure initlabeltable;
|
|
|
|
-
|
|
|
|
- function initdfapass2: boolean;
|
|
|
|
- procedure dodfapass2;
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-function FindLabel(L: tasmlabel; var hp: tai): Boolean;
|
|
|
|
-
|
|
|
|
-procedure incState(var S: Byte; amount: longint);
|
|
|
|
-
|
|
|
|
-{******************************* Variables *******************************}
|
|
|
|
-
|
|
|
|
-var
|
|
|
|
- dfa: tdfaobj;
|
|
|
|
-
|
|
|
|
-{*********************** end of Interface section ************************}
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-Implementation
|
|
|
|
-
|
|
|
|
-Uses
|
|
|
|
-{$ifdef csdebug}
|
|
|
|
- cutils,
|
|
|
|
-{$else}
|
|
|
|
- {$ifdef statedebug}
|
|
|
|
- cutils,
|
|
|
|
- {$else}
|
|
|
|
- {$ifdef allocregdebug}
|
|
|
|
- cutils,
|
|
|
|
- {$endif}
|
|
|
|
- {$endif}
|
|
|
|
-{$endif}
|
|
|
|
- globals, systems, verbose, symconst, cgobj, procinfo,
|
|
|
|
- aoptx86;
|
|
|
|
-
|
|
|
|
-Type
|
|
|
|
- TRefCompare = function(const r1, r2: treference; size1, size2: tcgsize): boolean;
|
|
|
|
-
|
|
|
|
-var
|
|
|
|
- {How many instructions are between the current instruction and the last one
|
|
|
|
- that modified the register}
|
|
|
|
- NrOfInstrSinceLastMod: TInstrSinceLastMod;
|
|
|
|
-
|
|
|
|
-{$ifdef tempOpts}
|
|
|
|
- constructor TSearchLinkedListItem.init;
|
|
|
|
- begin
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
- function TSearchLinkedListItem.equals(p: PSearchLinkedListItem): boolean;
|
|
|
|
- begin
|
|
|
|
- equals := false;
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
- constructor TSearchDoubleIntItem.init(_int1,_int2: longint);
|
|
|
|
- begin
|
|
|
|
- int1 := _int1;
|
|
|
|
- int2 := _int2;
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
- function TSearchDoubleIntItem.equals(p: PSearchLinkedListItem): boolean;
|
|
|
|
- begin
|
|
|
|
- equals := (TSearchDoubleIntItem(p).int1 = int1) and
|
|
|
|
- (TSearchDoubleIntItem(p).int2 = int2);
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
- function TSearchLinkedList.FindByValue(p: PSearchLinkedListItem): boolean;
|
|
|
|
- var temp: PSearchLinkedListItem;
|
|
|
|
- begin
|
|
|
|
- temp := first;
|
|
|
|
- while (temp <> last.next) and
|
|
|
|
- not(temp.equals(p)) do
|
|
|
|
- temp := temp.next;
|
|
|
|
- searchByValue := temp <> last.next;
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
- procedure TSearchLinkedList.removeByValue(p: PSearchLinkedListItem);
|
|
|
|
- begin
|
|
|
|
- temp := first;
|
|
|
|
- while (temp <> last.next) and
|
|
|
|
- not(temp.equals(p)) do
|
|
|
|
- temp := temp.next;
|
|
|
|
- if temp <> last.next then
|
|
|
|
- begin
|
|
|
|
- remove(temp);
|
|
|
|
- dispose(temp,done);
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
-procedure updateTempAllocs(var UsedRegs: TRegSet; 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
|
|
|
|
- labelCanBeSkipped(tai_label(current)))) Do
|
|
|
|
- p := tai(p.next);
|
|
|
|
- while assigned(p) and
|
|
|
|
- (p.typ=ait_RegAlloc) Do
|
|
|
|
- begin
|
|
|
|
- case tai_regalloc(p).ratype of
|
|
|
|
- ra_alloc :
|
|
|
|
- Include(UsedRegs, TRegEnum(getsupreg(tai_regalloc(p).reg)));
|
|
|
|
- ra_dealloc :
|
|
|
|
- Exclude(UsedRegs, TRegEnum(getsupreg(tai_regalloc(p).reg)));
|
|
|
|
- end;
|
|
|
|
- p := tai(p.next);
|
|
|
|
- end;
|
|
|
|
- until not(assigned(p)) or
|
|
|
|
- (not(p.typ in SkipInstr) and
|
|
|
|
- not((p.typ = ait_label) and
|
|
|
|
- labelCanBeSkipped(tai_label(current))));
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-{$endif tempOpts}
|
|
|
|
-
|
|
|
|
-{************************ Create the Label table ************************}
|
|
|
|
-
|
|
|
|
-function findregalloc(supreg: tsuperregister; starttai: tai; ratyp: tregalloctype): boolean;
|
|
|
|
-{ Returns true if a ait_alloc object for reg is found in the block of tai's }
|
|
|
|
-{ starting with Starttai and ending with the next "real" instruction }
|
|
|
|
-begin
|
|
|
|
- findregalloc := false;
|
|
|
|
- repeat
|
|
|
|
- while assigned(starttai) and
|
|
|
|
- ((starttai.typ in (skipinstr - [ait_regalloc])) or
|
|
|
|
- ((starttai.typ = ait_label) and
|
|
|
|
- labelcanbeskipped(tai_label(starttai)))) do
|
|
|
|
- starttai := tai(starttai.next);
|
|
|
|
- if assigned(starttai) and
|
|
|
|
- (starttai.typ = ait_regalloc) then
|
|
|
|
- begin
|
|
|
|
- if (tai_regalloc(Starttai).ratype = ratyp) and
|
|
|
|
- (getsupreg(tai_regalloc(Starttai).reg) = supreg) then
|
|
|
|
- begin
|
|
|
|
- findregalloc:=true;
|
|
|
|
- break;
|
|
|
|
- end;
|
|
|
|
- starttai := tai(starttai.next);
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- break;
|
|
|
|
- until false;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-procedure RemoveLastDeallocForFuncRes(asml: TAsmList; p: tai);
|
|
|
|
-
|
|
|
|
- procedure DoRemoveLastDeallocForFuncRes(asml: TAsmList; supreg: tsuperregister);
|
|
|
|
- var
|
|
|
|
- hp2: tai;
|
|
|
|
- begin
|
|
|
|
- hp2 := p;
|
|
|
|
- repeat
|
|
|
|
- hp2 := tai(hp2.previous);
|
|
|
|
- if assigned(hp2) and
|
|
|
|
- (hp2.typ = ait_regalloc) and
|
|
|
|
- (tai_regalloc(hp2).ratype=ra_dealloc) and
|
|
|
|
- (getregtype(tai_regalloc(hp2).reg) = R_INTREGISTER) and
|
|
|
|
- (getsupreg(tai_regalloc(hp2).reg) = supreg) then
|
|
|
|
- begin
|
|
|
|
- asml.remove(hp2);
|
|
|
|
- hp2.free;
|
|
|
|
- break;
|
|
|
|
- end;
|
|
|
|
- until not(assigned(hp2)) or regInInstruction(supreg,hp2);
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
-begin
|
|
|
|
- case current_procinfo.procdef.returndef.typ of
|
|
|
|
- arraydef,recorddef,pointerdef,
|
|
|
|
- stringdef,enumdef,procdef,objectdef,errordef,
|
|
|
|
- filedef,setdef,procvardef,
|
|
|
|
- classrefdef,forwarddef:
|
|
|
|
- DoRemoveLastDeallocForFuncRes(asml,RS_EAX);
|
|
|
|
- orddef:
|
|
|
|
- if current_procinfo.procdef.returndef.size <> 0 then
|
|
|
|
- begin
|
|
|
|
- DoRemoveLastDeallocForFuncRes(asml,RS_EAX);
|
|
|
|
- { for int64/qword }
|
|
|
|
- if current_procinfo.procdef.returndef.size = 8 then
|
|
|
|
- DoRemoveLastDeallocForFuncRes(asml,RS_EDX);
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-procedure getNoDeallocRegs(var regs: tregset);
|
|
|
|
-var
|
|
|
|
- regCounter: TSuperRegister;
|
|
|
|
-begin
|
|
|
|
- regs := [];
|
|
|
|
- case current_procinfo.procdef.returndef.typ of
|
|
|
|
- arraydef,recorddef,pointerdef,
|
|
|
|
- stringdef,enumdef,procdef,objectdef,errordef,
|
|
|
|
- filedef,setdef,procvardef,
|
|
|
|
- classrefdef,forwarddef:
|
|
|
|
- regs := [RS_EAX];
|
|
|
|
- orddef:
|
|
|
|
- if current_procinfo.procdef.returndef.size <> 0 then
|
|
|
|
- begin
|
|
|
|
- regs := [RS_EAX];
|
|
|
|
- { for int64/qword }
|
|
|
|
- if current_procinfo.procdef.returndef.size = 8 then
|
|
|
|
- regs := regs + [RS_EDX];
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- for regCounter := RS_EAX to RS_EBX do
|
|
|
|
-{ if not(regCounter in rg.usableregsint) then}
|
|
|
|
- include(regs,regcounter);
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-procedure AddRegDeallocFor(asml: TAsmList; reg: tregister; p: tai);
|
|
|
|
-var
|
|
|
|
- hp1: tai;
|
|
|
|
- funcResRegs: tregset;
|
|
|
|
-{ funcResReg: boolean;}
|
|
|
|
-begin
|
|
|
|
-{ if not(supreg in rg.usableregsint) then
|
|
|
|
- exit;}
|
|
|
|
-{ if not(supreg in [RS_EDI]) then
|
|
|
|
- exit;}
|
|
|
|
- getNoDeallocRegs(funcresregs);
|
|
|
|
-{ funcResRegs := funcResRegs - rg.usableregsint;}
|
|
|
|
-{ funcResRegs := funcResRegs - [RS_EDI];}
|
|
|
|
-{ funcResRegs := funcResRegs - [RS_EAX,RS_EBX,RS_ECX,RS_EDX,RS_ESI]; }
|
|
|
|
-{ funcResReg := getsupreg(reg) in funcresregs;}
|
|
|
|
-
|
|
|
|
- hp1 := p;
|
|
|
|
-{
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- while not(funcResReg and
|
|
|
|
- (p.typ = ait_instruction) and
|
|
|
|
- (taicpu(p).opcode = A_JMP) and
|
|
|
|
- (tasmlabel(taicpu(p).oper[0]^.sym) = aktexit2label)) and
|
|
|
|
- getLastInstruction(p, p) and
|
|
|
|
- not(regInInstruction(supreg, p)) do
|
|
|
|
- hp1 := p;
|
|
|
|
-}
|
|
|
|
- { don't insert a dealloc for registers which contain the function result }
|
|
|
|
- { if they are followed by a jump to the exit label (for exit(...)) }
|
|
|
|
-{ if not(funcResReg) or
|
|
|
|
- not((hp1.typ = ait_instruction) and
|
|
|
|
- (taicpu(hp1).opcode = A_JMP) and
|
|
|
|
- (tasmlabel(taicpu(hp1).oper[0]^.sym) = aktexit2label)) then }
|
|
|
|
- begin
|
|
|
|
- p := tai_regalloc.deAlloc(reg,nil);
|
|
|
|
- insertLLItem(AsmL, hp1.previous, hp1, p);
|
|
|
|
- end;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-{************************ Search the Label table ************************}
|
|
|
|
-
|
|
|
|
-function findlabel(l: tasmlabel; var hp: tai): boolean;
|
|
|
|
-
|
|
|
|
-{searches for the specified label starting from hp as long as the
|
|
|
|
- encountered instructions are labels, to be able to optimize constructs like
|
|
|
|
-
|
|
|
|
- jne l2 jmp l2
|
|
|
|
- jmp l3 and l1:
|
|
|
|
- l1: l2:
|
|
|
|
- l2:}
|
|
|
|
-
|
|
|
|
-var
|
|
|
|
- p: tai;
|
|
|
|
-
|
|
|
|
-begin
|
|
|
|
- p := hp;
|
|
|
|
- while assigned(p) and
|
|
|
|
- (p.typ in SkipInstr + [ait_label,ait_align]) Do
|
|
|
|
- if (p.typ <> ait_Label) or
|
|
|
|
- (tai_label(p).labsym <> l) then
|
|
|
|
- GetNextInstruction(p, p)
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- hp := p;
|
|
|
|
- findlabel := true;
|
|
|
|
- exit
|
|
|
|
- end;
|
|
|
|
- findlabel := false;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-{************************ Some general functions ************************}
|
|
|
|
-
|
|
|
|
-function tch2reg(ch: tinschange): tsuperregister;
|
|
|
|
-{converts a TChange variable to a TRegister}
|
|
|
|
-const
|
|
|
|
- ch2reg: array[CH_REAX..CH_REDI] of tsuperregister = (RS_EAX,RS_ECX,RS_EDX,RS_EBX,RS_ESP,RS_EBP,RS_ESI,RS_EDI);
|
|
|
|
-begin
|
|
|
|
- if (ch <= CH_REDI) then
|
|
|
|
- tch2reg := ch2reg[ch]
|
|
|
|
- else if (ch <= CH_WEDI) then
|
|
|
|
- tch2reg := ch2reg[tinschange(ord(ch) - ord(CH_REDI))]
|
|
|
|
- else if (ch <= CH_RWEDI) then
|
|
|
|
- tch2reg := ch2reg[tinschange(ord(ch) - ord(CH_WEDI))]
|
|
|
|
- else if (ch <= CH_MEDI) then
|
|
|
|
- tch2reg := ch2reg[tinschange(ord(ch) - ord(CH_RWEDI))]
|
|
|
|
- else
|
|
|
|
- InternalError($db)
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-{ inserts new_one between prev and foll }
|
|
|
|
-
|
|
|
|
-procedure InsertLLItem(AsmL: TAsmList; 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;
|
|
|
|
- { shgould 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;
|
|
|
|
-
|
|
|
|
-{********************* Compare parts of tai objects *********************}
|
|
|
|
-
|
|
|
|
-function regssamesize(reg1, reg2: tregister): boolean;
|
|
|
|
-{returns true if Reg1 and Reg2 are of the same size (so if they're both
|
|
|
|
- 8bit, 16bit or 32bit)}
|
|
|
|
-begin
|
|
|
|
- if (reg1 = NR_NO) or (reg2 = NR_NO) then
|
|
|
|
- internalerror(2003111602);
|
|
|
|
- regssamesize := getsubreg(reg1) = getsubreg(reg2);
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-procedure AddReg2RegInfo(OldReg, NewReg: TRegister; var RegInfo: toptreginfo);
|
|
|
|
-{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 RS_INVALID}
|
|
|
|
-var
|
|
|
|
- newsupreg, oldsupreg: tsuperregister;
|
|
|
|
-begin
|
|
|
|
- if (newreg = NR_NO) or (oldreg = NR_NO) then
|
|
|
|
- internalerror(2003111601);
|
|
|
|
- newsupreg := getsupreg(newreg);
|
|
|
|
- oldsupreg := getsupreg(oldreg);
|
|
|
|
- with RegInfo Do
|
|
|
|
- begin
|
|
|
|
- NewRegsEncountered := NewRegsEncountered + [newsupreg];
|
|
|
|
- OldRegsEncountered := OldRegsEncountered + [oldsupreg];
|
|
|
|
- New2OldReg[newsupreg] := oldsupreg;
|
|
|
|
- end;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-procedure AddOp2RegInfo(const o:toper; var reginfo: toptreginfo);
|
|
|
|
-begin
|
|
|
|
- case o.typ Of
|
|
|
|
- top_reg:
|
|
|
|
- if (o.reg <> NR_NO) then
|
|
|
|
- AddReg2RegInfo(o.reg, o.reg, RegInfo);
|
|
|
|
- top_ref:
|
|
|
|
- begin
|
|
|
|
- if o.ref^.base <> NR_NO then
|
|
|
|
- AddReg2RegInfo(o.ref^.base, o.ref^.base, RegInfo);
|
|
|
|
- if o.ref^.index <> NR_NO then
|
|
|
|
- AddReg2RegInfo(o.ref^.index, o.ref^.index, RegInfo);
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-function RegsEquivalent(oldreg, newreg: tregister; const oldinst, newinst: taicpu; var reginfo: toptreginfo; opact: topaction): Boolean;
|
|
|
|
-begin
|
|
|
|
- if not((oldreg = NR_NO) or (newreg = NR_NO)) then
|
|
|
|
- if RegsSameSize(oldreg, newreg) then
|
|
|
|
- with reginfo do
|
|
|
|
-{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 RS_NO and the comparison in the else-part will fail}
|
|
|
|
- if (getsupreg(oldReg) in OldRegsEncountered) then
|
|
|
|
- if (getsupreg(NewReg) in NewRegsEncountered) then
|
|
|
|
- RegsEquivalent := (getsupreg(oldreg) = New2OldReg[getsupreg(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
|
|
|
|
- AddReg2RegInfo(oldreg, newreg, reginfo);
|
|
|
|
- RegsEquivalent := true
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- Regsequivalent := false
|
|
|
|
- else
|
|
|
|
- if not(getsupreg(newreg) in NewRegsEncountered) and
|
|
|
|
- ((opact = opact_write) or
|
|
|
|
- ((newreg = oldreg) and
|
|
|
|
- (ptaiprop(oldinst.optinfo)^.regs[getsupreg(oldreg)].wstate =
|
|
|
|
- ptaiprop(newinst.optinfo)^.regs[getsupreg(oldreg)].wstate) and
|
|
|
|
- not(regmodifiedbyinstruction(getsupreg(oldreg),oldinst)))) then
|
|
|
|
- begin
|
|
|
|
- AddReg2RegInfo(oldreg, newreg, reginfo);
|
|
|
|
- RegsEquivalent := true
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- RegsEquivalent := false
|
|
|
|
- else
|
|
|
|
- RegsEquivalent := false
|
|
|
|
- else
|
|
|
|
- RegsEquivalent := oldreg = newreg
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-function RefsEquivalent(const r1, r2: treference; const oldinst, newinst: taicpu; var regInfo: toptreginfo): boolean;
|
|
|
|
-begin
|
|
|
|
- RefsEquivalent :=
|
|
|
|
- (r1.offset = r2.offset) and
|
|
|
|
- RegsEquivalent(r1.base, r2.base, oldinst, newinst, reginfo, OpAct_Read) and
|
|
|
|
- RegsEquivalent(r1.index, r2.index, oldinst, newinst, reginfo, OpAct_Read) and
|
|
|
|
- (r1.segment = r2.segment) and (r1.scalefactor = r2.scalefactor) and
|
|
|
|
- (r1.symbol = r2.symbol) and (r1.refaddr = r2.refaddr) and
|
|
|
|
- (r1.relsymbol = r2.relsymbol);
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-{$push}
|
|
|
|
-{$q-}
|
|
|
|
-
|
|
|
|
-// checks whether a write to r2 of size "size" contains address r1
|
|
|
|
-function refsoverlapping(const r1, r2: treference; size1, size2: tcgsize): boolean;
|
|
|
|
-var
|
|
|
|
- realsize1, realsize2: aint;
|
|
|
|
-begin
|
|
|
|
- realsize1 := tcgsize2size[size1];
|
|
|
|
- realsize2 := tcgsize2size[size2];
|
|
|
|
- refsoverlapping :=
|
|
|
|
- (r2.offset <= r1.offset+realsize1) and
|
|
|
|
- (r1.offset <= r2.offset+realsize2) and
|
|
|
|
- (r1.segment = r2.segment) and (r1.base = r2.base) and
|
|
|
|
- (r1.index = r2.index) and (r1.scalefactor = r2.scalefactor) and
|
|
|
|
- (r1.symbol=r2.symbol) and (r1.refaddr = r2.refaddr) and
|
|
|
|
- (r1.relsymbol = r2.relsymbol);
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-{$pop}
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-function isgp32reg(supreg: tsuperregister): boolean;
|
|
|
|
-{Checks if the register is a 32 bit general purpose register}
|
|
|
|
-begin
|
|
|
|
- isgp32reg := false;
|
|
|
|
-{$push}{$warnings off}
|
|
|
|
- if (supreg >= RS_EAX) and (supreg <= RS_EBX) then
|
|
|
|
- isgp32reg := true
|
|
|
|
-{$pop}
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-function reginref(supreg: tsuperregister; const ref: treference): boolean;
|
|
|
|
-begin {checks whether ref contains a reference to reg}
|
|
|
|
- reginref :=
|
|
|
|
- ((ref.base <> NR_NO) and
|
|
|
|
- (getsupreg(ref.base) = supreg)) or
|
|
|
|
- ((ref.index <> NR_NO) and
|
|
|
|
- (getsupreg(ref.index) = supreg))
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-function RegReadByInstruction(supreg: tsuperregister; hp: tai): boolean;
|
|
|
|
-var
|
|
|
|
- p: taicpu;
|
|
|
|
- opcount: longint;
|
|
|
|
-begin
|
|
|
|
- RegReadByInstruction := false;
|
|
|
|
- if hp.typ <> ait_instruction then
|
|
|
|
- exit;
|
|
|
|
- p := taicpu(hp);
|
|
|
|
- case p.opcode of
|
|
|
|
- A_CALL:
|
|
|
|
- regreadbyinstruction := true;
|
|
|
|
- A_IMUL:
|
|
|
|
- case p.ops of
|
|
|
|
- 1:
|
|
|
|
- regReadByInstruction :=
|
|
|
|
- (supreg = RS_EAX) or reginop(supreg,p.oper[0]^);
|
|
|
|
- 2,3:
|
|
|
|
- regReadByInstruction :=
|
|
|
|
- reginop(supreg,p.oper[0]^) or
|
|
|
|
- reginop(supreg,p.oper[1]^);
|
|
|
|
- end;
|
|
|
|
- A_IDIV,A_DIV,A_MUL:
|
|
|
|
- begin
|
|
|
|
- regReadByInstruction :=
|
|
|
|
- reginop(supreg,p.oper[0]^) or (supreg in [RS_EAX,RS_EDX]);
|
|
|
|
- end;
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- for opcount := 0 to p.ops-1 do
|
|
|
|
- if (p.oper[opCount]^.typ = top_ref) and
|
|
|
|
- reginref(supreg,p.oper[opcount]^.ref^) then
|
|
|
|
- begin
|
|
|
|
- RegReadByInstruction := true;
|
|
|
|
- exit
|
|
|
|
- end;
|
|
|
|
- for opcount := 1 to maxinschanges do
|
|
|
|
- case insprop[p.opcode].ch[opcount] of
|
|
|
|
- CH_REAX..CH_REDI,CH_RWEAX..CH_MEDI:
|
|
|
|
- if supreg = tch2reg(insprop[p.opcode].ch[opcount]) then
|
|
|
|
- begin
|
|
|
|
- RegReadByInstruction := true;
|
|
|
|
- exit
|
|
|
|
- end;
|
|
|
|
- CH_RWOP1,CH_ROP1,CH_MOP1:
|
|
|
|
- if //(p.oper[0]^.typ = top_reg) and
|
|
|
|
- reginop(supreg,p.oper[0]^) then
|
|
|
|
- begin
|
|
|
|
- RegReadByInstruction := true;
|
|
|
|
- exit
|
|
|
|
- end;
|
|
|
|
- Ch_RWOP2,Ch_ROP2,Ch_MOP2:
|
|
|
|
- if //(p.oper[1]^.typ = top_reg) and
|
|
|
|
- reginop(supreg,p.oper[1]^) then
|
|
|
|
- begin
|
|
|
|
- RegReadByInstruction := true;
|
|
|
|
- exit
|
|
|
|
- end;
|
|
|
|
- Ch_RWOP3,Ch_ROP3,Ch_MOP3:
|
|
|
|
- if //(p.oper[2]^.typ = top_reg) and
|
|
|
|
- reginop(supreg,p.oper[2]^) then
|
|
|
|
- begin
|
|
|
|
- RegReadByInstruction := true;
|
|
|
|
- exit
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-function regInInstruction(supreg: tsuperregister; p1: tai): boolean;
|
|
|
|
-{ Checks if reg is used by the instruction p1 }
|
|
|
|
-{ Difference with "regReadBysinstruction() or regModifiedByInstruction()": }
|
|
|
|
-{ this one ignores CH_ALL opcodes, while regModifiedByInstruction doesn't }
|
|
|
|
-var
|
|
|
|
- p: taicpu;
|
|
|
|
- opcount: longint;
|
|
|
|
-begin
|
|
|
|
- regInInstruction := false;
|
|
|
|
- if p1.typ <> ait_instruction then
|
|
|
|
- exit;
|
|
|
|
- p := taicpu(p1);
|
|
|
|
- case p.opcode of
|
|
|
|
- A_CALL:
|
|
|
|
- regininstruction := true;
|
|
|
|
- A_IMUL:
|
|
|
|
- case p.ops of
|
|
|
|
- 1:
|
|
|
|
- regInInstruction :=
|
|
|
|
- (supreg = RS_EAX) or reginop(supreg,p.oper[0]^);
|
|
|
|
- 2,3:
|
|
|
|
- regInInstruction :=
|
|
|
|
- reginop(supreg,p.oper[0]^) or
|
|
|
|
- reginop(supreg,p.oper[1]^) or
|
|
|
|
- (assigned(p.oper[2]) and
|
|
|
|
- reginop(supreg,p.oper[2]^));
|
|
|
|
- end;
|
|
|
|
- A_IDIV,A_DIV,A_MUL:
|
|
|
|
- regInInstruction :=
|
|
|
|
- reginop(supreg,p.oper[0]^) or
|
|
|
|
- (supreg in [RS_EAX,RS_EDX])
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- for opcount := 0 to p.ops-1 do
|
|
|
|
- if (p.oper[opCount]^.typ = top_ref) and
|
|
|
|
- reginref(supreg,p.oper[opcount]^.ref^) then
|
|
|
|
- begin
|
|
|
|
- regInInstruction := true;
|
|
|
|
- exit
|
|
|
|
- end;
|
|
|
|
- for opcount := 1 to maxinschanges do
|
|
|
|
- case insprop[p.opcode].Ch[opCount] of
|
|
|
|
- CH_REAX..CH_MEDI:
|
|
|
|
- if tch2reg(InsProp[p.opcode].Ch[opCount]) = supreg then
|
|
|
|
- begin
|
|
|
|
- regInInstruction := true;
|
|
|
|
- exit;
|
|
|
|
- end;
|
|
|
|
- CH_ROp1..CH_MOp1:
|
|
|
|
- if reginop(supreg,p.oper[0]^) then
|
|
|
|
- begin
|
|
|
|
- regInInstruction := true;
|
|
|
|
- exit
|
|
|
|
- end;
|
|
|
|
- Ch_ROp2..Ch_MOp2:
|
|
|
|
- if reginop(supreg,p.oper[1]^) then
|
|
|
|
- begin
|
|
|
|
- regInInstruction := true;
|
|
|
|
- exit
|
|
|
|
- end;
|
|
|
|
- Ch_ROp3..Ch_MOp3:
|
|
|
|
- if reginop(supreg,p.oper[2]^) then
|
|
|
|
- begin
|
|
|
|
- regInInstruction := true;
|
|
|
|
- exit
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-function reginop(supreg: tsuperregister; const o:toper): boolean;
|
|
|
|
-begin
|
|
|
|
- reginop := false;
|
|
|
|
- case o.typ Of
|
|
|
|
- top_reg:
|
|
|
|
- reginop :=
|
|
|
|
- (getregtype(o.reg) = R_INTREGISTER) and
|
|
|
|
- (supreg = getsupreg(o.reg));
|
|
|
|
- top_ref:
|
|
|
|
- reginop :=
|
|
|
|
- ((o.ref^.base <> NR_NO) and
|
|
|
|
- (supreg = getsupreg(o.ref^.base))) or
|
|
|
|
- ((o.ref^.index <> NR_NO) and
|
|
|
|
- (supreg = getsupreg(o.ref^.index)));
|
|
|
|
- end;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-function RegModifiedByInstruction(supreg: tsuperregister; p1: tai): boolean;
|
|
|
|
-var
|
|
|
|
- InstrProp: TInsProp;
|
|
|
|
- TmpResult: Boolean;
|
|
|
|
- Cnt: Word;
|
|
|
|
-begin
|
|
|
|
- TmpResult := False;
|
|
|
|
- Result := False;
|
|
|
|
- if supreg = RS_INVALID then
|
|
|
|
- exit;
|
|
|
|
- if (p1.typ = ait_instruction) then
|
|
|
|
- case taicpu(p1).opcode of
|
|
|
|
- A_IMUL:
|
|
|
|
- With taicpu(p1) Do
|
|
|
|
- TmpResult :=
|
|
|
|
- ((ops = 1) and (supreg in [RS_EAX,RS_EDX])) or
|
|
|
|
- ((ops = 2) and (getsupreg(oper[1]^.reg) = supreg)) or
|
|
|
|
- ((ops = 3) and (getsupreg(oper[2]^.reg) = supreg));
|
|
|
|
- A_DIV, A_IDIV, A_MUL:
|
|
|
|
- With taicpu(p1) Do
|
|
|
|
- TmpResult :=
|
|
|
|
- (supreg in [RS_EAX,RS_EDX]);
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- Cnt := 1;
|
|
|
|
- InstrProp := InsProp[taicpu(p1).OpCode];
|
|
|
|
- while (Cnt <= maxinschanges) and
|
|
|
|
- (InstrProp.Ch[Cnt] <> Ch_None) and
|
|
|
|
- not(TmpResult) Do
|
|
|
|
- begin
|
|
|
|
- case InstrProp.Ch[Cnt] Of
|
|
|
|
- Ch_WEAX..Ch_MEDI:
|
|
|
|
- TmpResult := supreg = tch2reg(InstrProp.Ch[Cnt]);
|
|
|
|
- Ch_RWOp1,Ch_WOp1,Ch_Mop1:
|
|
|
|
- TmpResult := (taicpu(p1).oper[0]^.typ = top_reg) and
|
|
|
|
- reginop(supreg,taicpu(p1).oper[0]^);
|
|
|
|
- Ch_RWOp2,Ch_WOp2,Ch_Mop2:
|
|
|
|
- TmpResult := (taicpu(p1).oper[1]^.typ = top_reg) and
|
|
|
|
- reginop(supreg,taicpu(p1).oper[1]^);
|
|
|
|
- Ch_RWOp3,Ch_WOp3,Ch_Mop3:
|
|
|
|
- TmpResult := (taicpu(p1).oper[2]^.typ = top_reg) and
|
|
|
|
- reginop(supreg,taicpu(p1).oper[2]^);
|
|
|
|
- Ch_FPU: TmpResult := false; // supreg is supposed to be an intreg!! supreg in [RS_ST..RS_ST7,RS_MM0..RS_MM7];
|
|
|
|
- Ch_ALL: TmpResult := true;
|
|
|
|
- end;
|
|
|
|
- inc(Cnt)
|
|
|
|
- end
|
|
|
|
- end
|
|
|
|
- end;
|
|
|
|
- RegModifiedByInstruction := TmpResult
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-function instrWritesFlags(p: tai): boolean;
|
|
|
|
-var
|
|
|
|
- l: longint;
|
|
|
|
-begin
|
|
|
|
- instrWritesFlags := true;
|
|
|
|
- case p.typ of
|
|
|
|
- ait_instruction:
|
|
|
|
- begin
|
|
|
|
- for l := 1 to maxinschanges do
|
|
|
|
- if InsProp[taicpu(p).opcode].Ch[l] in [Ch_WFlags,Ch_RWFlags,Ch_All] then
|
|
|
|
- exit;
|
|
|
|
- end;
|
|
|
|
- ait_label:
|
|
|
|
- exit;
|
|
|
|
- end;
|
|
|
|
- instrWritesFlags := false;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-function instrReadsFlags(p: tai): boolean;
|
|
|
|
-var
|
|
|
|
- l: longint;
|
|
|
|
-begin
|
|
|
|
- instrReadsFlags := true;
|
|
|
|
- case p.typ of
|
|
|
|
- ait_instruction:
|
|
|
|
- begin
|
|
|
|
- for l := 1 to maxinschanges do
|
|
|
|
- if InsProp[taicpu(p).opcode].Ch[l] in [Ch_RFlags,Ch_RWFlags,Ch_All] then
|
|
|
|
- exit;
|
|
|
|
- end;
|
|
|
|
- ait_label:
|
|
|
|
- exit;
|
|
|
|
- end;
|
|
|
|
- instrReadsFlags := false;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-{********************* GetNext and GetLastInstruction *********************}
|
|
|
|
-function GetNextInstruction(Current: tai; var Next: tai): Boolean;
|
|
|
|
-{ skips ait_regalloc, ait_regdealloc and ait_stab* objects and puts the }
|
|
|
|
-{ next tai object in Next. Returns false if there isn't any }
|
|
|
|
-begin
|
|
|
|
- repeat
|
|
|
|
- if (Current.typ = ait_marker) and
|
|
|
|
- (tai_Marker(current).Kind = mark_AsmBlockStart) then
|
|
|
|
- begin
|
|
|
|
- GetNextInstruction := False;
|
|
|
|
- Next := Nil;
|
|
|
|
- Exit
|
|
|
|
- end;
|
|
|
|
- Current := tai(current.Next);
|
|
|
|
- while assigned(Current) and
|
|
|
|
- ((current.typ in skipInstr) or
|
|
|
|
- ((current.typ = ait_label) and
|
|
|
|
- labelCanBeSkipped(tai_label(current)))) do
|
|
|
|
- Current := tai(current.Next);
|
|
|
|
-{ if assigned(Current) and
|
|
|
|
- (current.typ = ait_Marker) and
|
|
|
|
- (tai_Marker(current).Kind = mark_NoPropInfoStart) then
|
|
|
|
- begin
|
|
|
|
- while assigned(Current) and
|
|
|
|
- ((current.typ <> ait_Marker) or
|
|
|
|
- (tai_Marker(current).Kind <> mark_NoPropInfoEnd)) Do
|
|
|
|
- Current := tai(current.Next);
|
|
|
|
- end;}
|
|
|
|
- until not(assigned(Current)) or
|
|
|
|
- (current.typ <> ait_Marker) or
|
|
|
|
- not(tai_Marker(current).Kind in [mark_NoPropInfoStart,mark_NoPropInfoEnd]);
|
|
|
|
- Next := Current;
|
|
|
|
- if assigned(Current) and
|
|
|
|
- not((current.typ in SkipInstr) or
|
|
|
|
- ((current.typ = ait_label) and
|
|
|
|
- labelCanBeSkipped(tai_label(current))))
|
|
|
|
- then
|
|
|
|
- GetNextInstruction :=
|
|
|
|
- not((current.typ = ait_marker) and
|
|
|
|
- (tai_marker(current).kind = mark_AsmBlockStart))
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- GetNextInstruction := False;
|
|
|
|
- Next := nil;
|
|
|
|
- end;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-function GetLastInstruction(Current: tai; var Last: tai): boolean;
|
|
|
|
-{skips the ait-types in SkipInstr puts the previous tai object in
|
|
|
|
- Last. Returns false if there isn't any}
|
|
|
|
-begin
|
|
|
|
- repeat
|
|
|
|
- Current := tai(current.previous);
|
|
|
|
- while assigned(Current) and
|
|
|
|
- (((current.typ = ait_Marker) and
|
|
|
|
- not(tai_Marker(current).Kind in [mark_AsmBlockEnd{,mark_NoPropInfoEnd}])) or
|
|
|
|
- (current.typ in SkipInstr) or
|
|
|
|
- ((current.typ = ait_label) and
|
|
|
|
- labelCanBeSkipped(tai_label(current)))) Do
|
|
|
|
- Current := tai(current.previous);
|
|
|
|
-{ if assigned(Current) and
|
|
|
|
- (current.typ = ait_Marker) and
|
|
|
|
- (tai_Marker(current).Kind = mark_NoPropInfoEnd) then
|
|
|
|
- begin
|
|
|
|
- while assigned(Current) and
|
|
|
|
- ((current.typ <> ait_Marker) or
|
|
|
|
- (tai_Marker(current).Kind <> mark_NoPropInfoStart)) Do
|
|
|
|
- Current := tai(current.previous);
|
|
|
|
- end;}
|
|
|
|
- until not(assigned(Current)) or
|
|
|
|
- (current.typ <> ait_Marker) or
|
|
|
|
- not(tai_Marker(current).Kind in [mark_NoPropInfoStart,mark_NoPropInfoEnd]);
|
|
|
|
- if not(assigned(Current)) or
|
|
|
|
- (current.typ in SkipInstr) or
|
|
|
|
- ((current.typ = ait_label) and
|
|
|
|
- labelCanBeSkipped(tai_label(current))) or
|
|
|
|
- ((current.typ = ait_Marker) and
|
|
|
|
- (tai_Marker(current).Kind = mark_AsmBlockEnd))
|
|
|
|
- then
|
|
|
|
- begin
|
|
|
|
- Last := nil;
|
|
|
|
- GetLastInstruction := False
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- Last := Current;
|
|
|
|
- GetLastInstruction := True;
|
|
|
|
- end;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-procedure SkipHead(var p: tai);
|
|
|
|
-var
|
|
|
|
- oldp: tai;
|
|
|
|
-begin
|
|
|
|
- repeat
|
|
|
|
- oldp := p;
|
|
|
|
- if (p.typ in SkipInstr) or
|
|
|
|
- ((p.typ = ait_marker) and
|
|
|
|
- (tai_Marker(p).Kind in [mark_AsmBlockEnd,mark_NoLineInfoStart,mark_NoLineInfoEnd])) then
|
|
|
|
- GetNextInstruction(p,p)
|
|
|
|
- else if ((p.Typ = Ait_Marker) and
|
|
|
|
- (tai_Marker(p).Kind = mark_NoPropInfoStart)) then
|
|
|
|
- {a marker of the mark_NoPropInfoStart can't be the first instruction of a
|
|
|
|
- TAsmList list}
|
|
|
|
- GetNextInstruction(tai(p.previous),p);
|
|
|
|
- until p = oldp
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-function labelCanBeSkipped(p: tai_label): boolean;
|
|
|
|
-begin
|
|
|
|
- labelCanBeSkipped := not(p.labsym.is_used) or (p.labsym.labeltype<>alt_jump);
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-{******************* The Data Flow Analyzer functions ********************}
|
|
|
|
-
|
|
|
|
-function regLoadedWithNewValue(supreg: tsuperregister; canDependOnPrevValue: boolean;
|
|
|
|
- hp: tai): boolean;
|
|
|
|
-{ assumes reg is a 32bit register }
|
|
|
|
-var
|
|
|
|
- p: taicpu;
|
|
|
|
-begin
|
|
|
|
- if not assigned(hp) or
|
|
|
|
- (hp.typ <> ait_instruction) then
|
|
|
|
- begin
|
|
|
|
- regLoadedWithNewValue := false;
|
|
|
|
- exit;
|
|
|
|
- end;
|
|
|
|
- p := taicpu(hp);
|
|
|
|
- regLoadedWithNewValue :=
|
|
|
|
- (((p.opcode = A_MOV) or
|
|
|
|
- (p.opcode = A_MOVZX) or
|
|
|
|
- (p.opcode = A_MOVSX) or
|
|
|
|
- (p.opcode = A_LEA)) and
|
|
|
|
- (p.oper[1]^.typ = top_reg) and
|
|
|
|
- (getsupreg(p.oper[1]^.reg) = supreg) and
|
|
|
|
- (canDependOnPrevValue or
|
|
|
|
- (p.oper[0]^.typ = top_const) or
|
|
|
|
- ((p.oper[0]^.typ = top_reg) and
|
|
|
|
- (getsupreg(p.oper[0]^.reg) <> supreg)) or
|
|
|
|
- ((p.oper[0]^.typ = top_ref) and
|
|
|
|
- not regInRef(supreg,p.oper[0]^.ref^)))) or
|
|
|
|
- ((p.opcode = A_POP) and
|
|
|
|
- (getsupreg(p.oper[0]^.reg) = supreg));
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-procedure UpdateUsedRegs(var UsedRegs: TRegSet; 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
|
|
|
|
- labelCanBeSkipped(tai_label(p))) or
|
|
|
|
- ((p.typ = ait_marker) and
|
|
|
|
- (tai_Marker(p).Kind in [mark_AsmBlockEnd,mark_NoLineInfoStart,mark_NoLineInfoEnd]))) do
|
|
|
|
- p := tai(p.next);
|
|
|
|
- while assigned(p) and
|
|
|
|
- (p.typ=ait_RegAlloc) Do
|
|
|
|
- begin
|
|
|
|
- if (getregtype(tai_regalloc(p).reg) = R_INTREGISTER) then
|
|
|
|
- begin
|
|
|
|
- case tai_regalloc(p).ratype of
|
|
|
|
- ra_alloc :
|
|
|
|
- Include(UsedRegs, TRegEnum(getsupreg(tai_regalloc(p).reg)));
|
|
|
|
- ra_dealloc :
|
|
|
|
- Exclude(UsedRegs, TRegEnum(getsupreg(tai_regalloc(p).reg)));
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- p := tai(p.next);
|
|
|
|
- end;
|
|
|
|
- until not(assigned(p)) or
|
|
|
|
- (not(p.typ in SkipInstr) and
|
|
|
|
- not((p.typ = ait_label) and
|
|
|
|
- labelCanBeSkipped(tai_label(p))));
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-procedure AllocRegBetween(asml: TAsmList; reg: tregister; p1, p2: tai; var initialusedregs: tregset);
|
|
|
|
-{ allocates register reg between (and including) instructions p1 and p2 }
|
|
|
|
-{ the type of p1 and p2 must not be in SkipInstr }
|
|
|
|
-{ note that this routine is both called from the peephole optimizer }
|
|
|
|
-{ where optinfo is not yet initialised) and from the cse (where it is) }
|
|
|
|
-var
|
|
|
|
- hp, start: tai;
|
|
|
|
- removedsomething,
|
|
|
|
- firstRemovedWasAlloc,
|
|
|
|
- lastRemovedWasDealloc: boolean;
|
|
|
|
- supreg: tsuperregister;
|
|
|
|
-begin
|
|
|
|
-{$ifdef EXTDEBUG}
|
|
|
|
- if assigned(p1.optinfo) and
|
|
|
|
- (ptaiprop(p1.optinfo)^.usedregs <> initialusedregs) then
|
|
|
|
- internalerror(2004101010);
|
|
|
|
-{$endif EXTDEBUG}
|
|
|
|
- start := p1;
|
|
|
|
- if (reg = NR_ESP) or
|
|
|
|
- (reg = current_procinfo.framepointer) or
|
|
|
|
- not(assigned(p1)) then
|
|
|
|
- { this happens with registers which are loaded implicitely, outside the }
|
|
|
|
- { current block (e.g. esi with self) }
|
|
|
|
- exit;
|
|
|
|
- supreg := getsupreg(reg);
|
|
|
|
- { make sure we allocate it for this instruction }
|
|
|
|
- getnextinstruction(p2,p2);
|
|
|
|
- lastRemovedWasDealloc := false;
|
|
|
|
- removedSomething := false;
|
|
|
|
- firstRemovedWasAlloc := false;
|
|
|
|
-{$ifdef allocregdebug}
|
|
|
|
- hp := tai_comment.Create(strpnew('allocating '+std_regname(newreg(R_INTREGISTER,supreg,R_SUBWHOLE))+
|
|
|
|
- ' from here...'));
|
|
|
|
- insertllitem(asml,p1.previous,p1,hp);
|
|
|
|
- hp := tai_comment.Create(strpnew('allocated '+std_regname(newreg(R_INTREGISTER,supreg,R_SUBWHOLE))+
|
|
|
|
- ' till here...'));
|
|
|
|
- insertllitem(asml,p2,p2.next,hp);
|
|
|
|
-{$endif allocregdebug}
|
|
|
|
- if not(supreg in initialusedregs) then
|
|
|
|
- begin
|
|
|
|
- hp := tai_regalloc.alloc(reg,nil);
|
|
|
|
- insertllItem(asmL,p1.previous,p1,hp);
|
|
|
|
- include(initialusedregs,supreg);
|
|
|
|
- end;
|
|
|
|
- while assigned(p1) and
|
|
|
|
- (p1 <> p2) do
|
|
|
|
- begin
|
|
|
|
- if assigned(p1.optinfo) then
|
|
|
|
- include(ptaiprop(p1.optinfo)^.usedregs,supreg);
|
|
|
|
- p1 := tai(p1.next);
|
|
|
|
- repeat
|
|
|
|
- while assigned(p1) and
|
|
|
|
- (p1.typ in (SkipInstr-[ait_regalloc])) Do
|
|
|
|
- p1 := tai(p1.next);
|
|
|
|
-{ remove all allocation/deallocation info about the register in between }
|
|
|
|
- if assigned(p1) and
|
|
|
|
- (p1.typ = ait_regalloc) then
|
|
|
|
- if (getsupreg(tai_regalloc(p1).reg) = supreg) then
|
|
|
|
- begin
|
|
|
|
- if not removedSomething then
|
|
|
|
- begin
|
|
|
|
- firstRemovedWasAlloc := tai_regalloc(p1).ratype=ra_alloc;
|
|
|
|
- removedSomething := true;
|
|
|
|
- end;
|
|
|
|
- lastRemovedWasDealloc := (tai_regalloc(p1).ratype=ra_dealloc);
|
|
|
|
- hp := tai(p1.Next);
|
|
|
|
- asml.Remove(p1);
|
|
|
|
- p1.free;
|
|
|
|
- p1 := hp;
|
|
|
|
- end
|
|
|
|
- else p1 := tai(p1.next);
|
|
|
|
- until not(assigned(p1)) or
|
|
|
|
- not(p1.typ in SkipInstr);
|
|
|
|
- end;
|
|
|
|
- if assigned(p1) then
|
|
|
|
- begin
|
|
|
|
- if firstRemovedWasAlloc then
|
|
|
|
- begin
|
|
|
|
- hp := tai_regalloc.Alloc(reg,nil);
|
|
|
|
- insertLLItem(asmL,start.previous,start,hp);
|
|
|
|
- end;
|
|
|
|
- if lastRemovedWasDealloc then
|
|
|
|
- begin
|
|
|
|
- hp := tai_regalloc.DeAlloc(reg,nil);
|
|
|
|
- insertLLItem(asmL,p1.previous,p1,hp);
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-function FindRegDealloc(supreg: tsuperregister; p: tai): boolean;
|
|
|
|
-var
|
|
|
|
- hp: tai;
|
|
|
|
- first: boolean;
|
|
|
|
-begin
|
|
|
|
- findregdealloc := false;
|
|
|
|
- first := true;
|
|
|
|
- while assigned(p.previous) and
|
|
|
|
- ((tai(p.previous).typ in (skipinstr+[ait_align])) or
|
|
|
|
- ((tai(p.previous).typ = ait_label) and
|
|
|
|
- labelCanBeSkipped(tai_label(p.previous)))) do
|
|
|
|
- begin
|
|
|
|
- p := tai(p.previous);
|
|
|
|
- if (p.typ = ait_regalloc) and
|
|
|
|
- (getregtype(tai_regalloc(p).reg) = R_INTREGISTER) and
|
|
|
|
- (getsupreg(tai_regalloc(p).reg) = supreg) then
|
|
|
|
- if (tai_regalloc(p).ratype=ra_dealloc) then
|
|
|
|
- if first then
|
|
|
|
- begin
|
|
|
|
- findregdealloc := true;
|
|
|
|
- break;
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- findRegDealloc :=
|
|
|
|
- getNextInstruction(p,hp) and
|
|
|
|
- regLoadedWithNewValue(supreg,false,hp);
|
|
|
|
- break
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- first := false;
|
|
|
|
- end
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-procedure incState(var S: Byte; amount: longint);
|
|
|
|
-{increases S by 1, wraps around at $ffff to 0 (so we won't get overflow
|
|
|
|
- errors}
|
|
|
|
-begin
|
|
|
|
- if (s <= $ff - amount) then
|
|
|
|
- inc(s, amount)
|
|
|
|
- else s := longint(s) + amount - $ff;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-function sequenceDependsonReg(const Content: TContent; seqreg: tsuperregister; supreg: tsuperregister): Boolean;
|
|
|
|
-{ Content is the sequence of instructions that describes the contents of }
|
|
|
|
-{ seqReg. reg is being overwritten by the current instruction. if the }
|
|
|
|
-{ content of seqReg depends on reg (ie. because of a }
|
|
|
|
-{ "movl (seqreg,reg), seqReg" instruction), this function returns true }
|
|
|
|
-var
|
|
|
|
- p: tai;
|
|
|
|
- Counter: Word;
|
|
|
|
- TmpResult: Boolean;
|
|
|
|
- RegsChecked: TRegSet;
|
|
|
|
-begin
|
|
|
|
- RegsChecked := [];
|
|
|
|
- p := Content.StartMod;
|
|
|
|
- TmpResult := False;
|
|
|
|
- Counter := 1;
|
|
|
|
- while not(TmpResult) and
|
|
|
|
- (Counter <= Content.NrOfMods) Do
|
|
|
|
- begin
|
|
|
|
- if (p.typ = ait_instruction) and
|
|
|
|
- ((taicpu(p).opcode = A_MOV) or
|
|
|
|
- (taicpu(p).opcode = A_MOVZX) or
|
|
|
|
- (taicpu(p).opcode = A_MOVSX) or
|
|
|
|
- (taicpu(p).opcode = A_LEA)) and
|
|
|
|
- (taicpu(p).oper[0]^.typ = top_ref) then
|
|
|
|
- With taicpu(p).oper[0]^.ref^ Do
|
|
|
|
- if ((base = current_procinfo.FramePointer) or
|
|
|
|
- (assigned(symbol) and (base = NR_NO))) and
|
|
|
|
- (index = NR_NO) then
|
|
|
|
- begin
|
|
|
|
- RegsChecked := RegsChecked + [getsupreg(taicpu(p).oper[1]^.reg)];
|
|
|
|
- if supreg = getsupreg(taicpu(p).oper[1]^.reg) then
|
|
|
|
- break;
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- tmpResult :=
|
|
|
|
- regReadByInstruction(supreg,p) and
|
|
|
|
- regModifiedByInstruction(seqReg,p)
|
|
|
|
- else
|
|
|
|
- tmpResult :=
|
|
|
|
- regReadByInstruction(supreg,p) and
|
|
|
|
- regModifiedByInstruction(seqReg,p);
|
|
|
|
- inc(Counter);
|
|
|
|
- GetNextInstruction(p,p)
|
|
|
|
- end;
|
|
|
|
- sequenceDependsonReg := TmpResult
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-procedure invalidateDependingRegs(p1: ptaiprop; supreg: tsuperregister);
|
|
|
|
-var
|
|
|
|
- counter: tsuperregister;
|
|
|
|
-begin
|
|
|
|
- for counter := RS_EAX to RS_EDI do
|
|
|
|
- if counter <> supreg then
|
|
|
|
- with p1^.regs[counter] Do
|
|
|
|
- begin
|
|
|
|
- if (typ in [con_ref,con_noRemoveRef]) and
|
|
|
|
- sequenceDependsOnReg(p1^.Regs[counter],counter,supreg) then
|
|
|
|
- if typ in [con_ref, con_invalid] then
|
|
|
|
- typ := con_invalid
|
|
|
|
- { con_noRemoveRef = con_unknown }
|
|
|
|
- else
|
|
|
|
- typ := con_unknown;
|
|
|
|
- if assigned(memwrite) and
|
|
|
|
- regInRef(counter,memwrite.oper[1]^.ref^) then
|
|
|
|
- memwrite := nil;
|
|
|
|
- end;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-procedure DestroyReg(p1: ptaiprop; supreg: tsuperregister; doincState:Boolean);
|
|
|
|
-{Destroys the contents of the register reg in the ptaiprop p1, as well as the
|
|
|
|
- contents of registers are loaded with a memory location based on reg.
|
|
|
|
- doincState is false when this register has to be destroyed not because
|
|
|
|
- it's contents are directly modified/overwritten, but because of an indirect
|
|
|
|
- action (e.g. this register holds the contents of a variable and the value
|
|
|
|
- of the variable in memory is changed) }
|
|
|
|
-begin
|
|
|
|
-{$push}{$warnings off}
|
|
|
|
- { the following happens for fpu registers }
|
|
|
|
- if (supreg < low(NrOfInstrSinceLastMod)) or
|
|
|
|
- (supreg > high(NrOfInstrSinceLastMod)) then
|
|
|
|
- exit;
|
|
|
|
-{$pop}
|
|
|
|
- NrOfInstrSinceLastMod[supreg] := 0;
|
|
|
|
- with p1^.regs[supreg] do
|
|
|
|
- begin
|
|
|
|
- if doincState then
|
|
|
|
- begin
|
|
|
|
- incState(wstate,1);
|
|
|
|
- typ := con_unknown;
|
|
|
|
- startmod := nil;
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- if typ in [con_ref,con_const,con_invalid] then
|
|
|
|
- typ := con_invalid
|
|
|
|
- { con_noRemoveRef = con_unknown }
|
|
|
|
- else
|
|
|
|
- typ := con_unknown;
|
|
|
|
- memwrite := nil;
|
|
|
|
- end;
|
|
|
|
- invalidateDependingRegs(p1,supreg);
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-{procedure AddRegsToSet(p: tai; var RegSet: TRegSet);
|
|
|
|
-begin
|
|
|
|
- if (p.typ = ait_instruction) then
|
|
|
|
- begin
|
|
|
|
- case taicpu(p).oper[0]^.typ Of
|
|
|
|
- top_reg:
|
|
|
|
- if not(taicpu(p).oper[0]^.reg in [RS_NO,RS_ESP,current_procinfo.FramePointer]) then
|
|
|
|
- RegSet := RegSet + [taicpu(p).oper[0]^.reg];
|
|
|
|
- top_ref:
|
|
|
|
- With TReference(taicpu(p).oper[0]^) Do
|
|
|
|
- begin
|
|
|
|
- if not(base in [current_procinfo.FramePointer,RS_NO,RS_ESP])
|
|
|
|
- then RegSet := RegSet + [base];
|
|
|
|
- if not(index in [current_procinfo.FramePointer,RS_NO,RS_ESP])
|
|
|
|
- then RegSet := RegSet + [index];
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- case taicpu(p).oper[1]^.typ Of
|
|
|
|
- top_reg:
|
|
|
|
- if not(taicpu(p).oper[1]^.reg in [RS_NO,RS_ESP,current_procinfo.FramePointer]) then
|
|
|
|
- if RegSet := RegSet + [TRegister(TwoWords(taicpu(p).oper[1]^).Word1];
|
|
|
|
- top_ref:
|
|
|
|
- With TReference(taicpu(p).oper[1]^) Do
|
|
|
|
- begin
|
|
|
|
- if not(base in [current_procinfo.FramePointer,RS_NO,RS_ESP])
|
|
|
|
- then RegSet := RegSet + [base];
|
|
|
|
- if not(index in [current_procinfo.FramePointer,RS_NO,RS_ESP])
|
|
|
|
- then RegSet := RegSet + [index];
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
-end;}
|
|
|
|
-
|
|
|
|
-function OpsEquivalent(const o1, o2: toper; const oldinst, newinst: taicpu; var RegInfo: toptreginfo; OpAct: TopAction): Boolean;
|
|
|
|
-begin {checks whether the two ops are equivalent}
|
|
|
|
- OpsEquivalent := False;
|
|
|
|
- if o1.typ=o2.typ then
|
|
|
|
- case o1.typ Of
|
|
|
|
- top_reg:
|
|
|
|
- OpsEquivalent :=RegsEquivalent(o1.reg,o2.reg, oldinst, newinst, RegInfo, OpAct);
|
|
|
|
- top_ref:
|
|
|
|
- OpsEquivalent := RefsEquivalent(o1.ref^, o2.ref^, oldinst, newinst, RegInfo);
|
|
|
|
- Top_Const:
|
|
|
|
- OpsEquivalent := o1.val = o2.val;
|
|
|
|
- Top_None:
|
|
|
|
- OpsEquivalent := True
|
|
|
|
- end;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-function OpsEqual(const o1,o2:toper): Boolean;
|
|
|
|
-begin {checks whether the two ops are equal}
|
|
|
|
- OpsEqual := False;
|
|
|
|
- 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_None :
|
|
|
|
- OpsEqual := True
|
|
|
|
- end;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-function sizescompatible(loadsize,newsize: topsize): boolean;
|
|
|
|
- begin
|
|
|
|
- case loadsize of
|
|
|
|
- S_B,S_BW,S_BL:
|
|
|
|
- sizescompatible := (newsize = loadsize) or (newsize = S_B);
|
|
|
|
- S_W,S_WL:
|
|
|
|
- sizescompatible := (newsize = loadsize) or (newsize = S_W);
|
|
|
|
- else
|
|
|
|
- sizescompatible := newsize = S_L;
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-function opscompatible(p1,p2: taicpu): boolean;
|
|
|
|
-begin
|
|
|
|
- case p1.opcode of
|
|
|
|
- A_MOVZX,A_MOVSX:
|
|
|
|
- opscompatible :=
|
|
|
|
- ((p2.opcode = p1.opcode) or (p2.opcode = A_MOV)) and
|
|
|
|
- sizescompatible(p1.opsize,p2.opsize);
|
|
|
|
- else
|
|
|
|
- opscompatible :=
|
|
|
|
- (p1.opcode = p2.opcode) and
|
|
|
|
- (p1.ops = p2.ops) and
|
|
|
|
- (p1.opsize = p2.opsize);
|
|
|
|
- end;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-function InstructionsEquivalent(p1, p2: tai; var RegInfo: toptreginfo): Boolean;
|
|
|
|
-{$ifdef csdebug}
|
|
|
|
-var
|
|
|
|
- hp: tai;
|
|
|
|
-{$endif csdebug}
|
|
|
|
-begin {checks whether two taicpu instructions are equal}
|
|
|
|
- if assigned(p1) and assigned(p2) and
|
|
|
|
- (tai(p1).typ = ait_instruction) and
|
|
|
|
- (tai(p2).typ = ait_instruction) and
|
|
|
|
- opscompatible(taicpu(p1),taicpu(p2)) and
|
|
|
|
- (not(assigned(taicpu(p1).oper[0])) or
|
|
|
|
- (taicpu(p1).oper[0]^.typ = taicpu(p2).oper[0]^.typ)) and
|
|
|
|
- (not(assigned(taicpu(p1).oper[1])) or
|
|
|
|
- (taicpu(p1).oper[1]^.typ = taicpu(p2).oper[1]^.typ)) and
|
|
|
|
- (not(assigned(taicpu(p1).oper[2])) or
|
|
|
|
- (taicpu(p1).oper[2]^.typ = taicpu(p2).oper[2]^.typ)) then
|
|
|
|
- {both instructions have the same structure:
|
|
|
|
- "<operator> <operand of type1>, <operand of type 2>"}
|
|
|
|
- if ((taicpu(p1).opcode = A_MOV) or
|
|
|
|
- (taicpu(p1).opcode = A_MOVZX) or
|
|
|
|
- (taicpu(p1).opcode = A_MOVSX) or
|
|
|
|
- (taicpu(p1).opcode = A_LEA)) and
|
|
|
|
- (taicpu(p1).oper[0]^.typ = top_ref) {then .oper[1]^t = top_reg} then
|
|
|
|
- if not(RegInRef(getsupreg(taicpu(p1).oper[1]^.reg), taicpu(p1).oper[0]^.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(getsupreg(taicpu(p2).oper[1]^.reg), taicpu(p2).oper[0]^.ref^)) and
|
|
|
|
- RefsEquivalent(taicpu(p1).oper[0]^.ref^, taicpu(p2).oper[0]^.ref^,taicpu(p1), taicpu(p2), reginfo) 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 taicpu(p2).oper[0]^.ref^ Do
|
|
|
|
- begin
|
|
|
|
- if (base <> NR_NO) and
|
|
|
|
- (not(getsupreg(base) in [getsupreg(current_procinfo.FramePointer), RS_ESP])) then
|
|
|
|
- include(RegInfo.RegsLoadedForRef, getsupreg(base));
|
|
|
|
- if (index <> NR_NO) and
|
|
|
|
- (not(getsupreg(index) in [getsupreg(current_procinfo.FramePointer), RS_ESP])) then
|
|
|
|
- include(RegInfo.RegsLoadedForRef, getsupreg(index));
|
|
|
|
- end;
|
|
|
|
- {add the registers from the reference (.oper[0]^) to the RegInfo, all registers
|
|
|
|
- from the reference are the same in the old and in the new instruction
|
|
|
|
- sequence}
|
|
|
|
- AddOp2RegInfo(taicpu(p1).oper[0]^, RegInfo);
|
|
|
|
- {the registers from .oper[1]^ have to be equivalent, but not necessarily equal}
|
|
|
|
- InstructionsEquivalent :=
|
|
|
|
- RegsEquivalent(taicpu(p1).oper[1]^.reg,
|
|
|
|
- taicpu(p2).oper[1]^.reg, taicpu(p1), taicpu(p2), RegInfo, OpAct_Write);
|
|
|
|
- end
|
|
|
|
- {the registers are loaded with values from different memory locations. if
|
|
|
|
- this was 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 taicpu(p2).oper[0]^.ref^ Do
|
|
|
|
- begin
|
|
|
|
- if (base <> NR_NO) and
|
|
|
|
- (not(getsupreg(base) in [getsupreg(current_procinfo.FramePointer),
|
|
|
|
- getsupreg(taicpu(p2).oper[1]^.reg),RS_ESP])) then
|
|
|
|
- {it won't do any harm if the register is already in RegsLoadedForRef}
|
|
|
|
- begin
|
|
|
|
- include(RegInfo.RegsLoadedForRef, getsupreg(base));
|
|
|
|
-{$ifdef csdebug}
|
|
|
|
- Writeln(std_regname(base), ' added');
|
|
|
|
-{$endif csdebug}
|
|
|
|
- end;
|
|
|
|
- if (index <> NR_NO) and
|
|
|
|
- (not(getsupreg(index) in [getsupreg(current_procinfo.FramePointer),
|
|
|
|
- getsupreg(taicpu(p2).oper[1]^.reg),RS_ESP])) then
|
|
|
|
- begin
|
|
|
|
- include(RegInfo.RegsLoadedForRef, getsupreg(index));
|
|
|
|
-{$ifdef csdebug}
|
|
|
|
- Writeln(std_regname(index), ' added');
|
|
|
|
-{$endif csdebug}
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
- end;
|
|
|
|
- if (taicpu(p2).oper[1]^.reg <> NR_NO) and
|
|
|
|
- (not(getsupreg(taicpu(p2).oper[1]^.reg) in [getsupreg(current_procinfo.FramePointer),RS_ESP])) then
|
|
|
|
- begin
|
|
|
|
- RegInfo.RegsLoadedForRef := RegInfo.RegsLoadedForRef -
|
|
|
|
- [getsupreg(taicpu(p2).oper[1]^.reg)];
|
|
|
|
-{$ifdef csdebug}
|
|
|
|
- Writeln(std_regname(newreg(R_INTREGISTER,getsupreg(taicpu(p2).oper[1]^.reg),R_SUBWHOLE)), ' removed');
|
|
|
|
-{$endif csdebug}
|
|
|
|
- end;
|
|
|
|
- InstructionsEquivalent :=
|
|
|
|
- OpsEquivalent(taicpu(p1).oper[0]^, taicpu(p2).oper[0]^, taicpu(p1), taicpu(p2), RegInfo, OpAct_Read) and
|
|
|
|
- OpsEquivalent(taicpu(p1).oper[1]^, taicpu(p2).oper[1]^, taicpu(p1), taicpu(p2), RegInfo, OpAct_Write)
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- {an instruction <> mov, movzx, movsx}
|
|
|
|
- begin
|
|
|
|
- {$ifdef csdebug}
|
|
|
|
- hp := tai_comment.Create(strpnew('checking if equivalent'));
|
|
|
|
- hp.previous := p2;
|
|
|
|
- hp.next := p2.next;
|
|
|
|
- p2.next.previous := hp;
|
|
|
|
- p2.next := hp;
|
|
|
|
- {$endif csdebug}
|
|
|
|
- InstructionsEquivalent :=
|
|
|
|
- (not(assigned(taicpu(p1).oper[0])) or
|
|
|
|
- OpsEquivalent(taicpu(p1).oper[0]^, taicpu(p2).oper[0]^, taicpu(p1), taicpu(p2), RegInfo, OpAct_Unknown)) and
|
|
|
|
- (not(assigned(taicpu(p1).oper[1])) or
|
|
|
|
- OpsEquivalent(taicpu(p1).oper[1]^, taicpu(p2).oper[1]^, taicpu(p1), taicpu(p2), RegInfo, OpAct_Unknown)) and
|
|
|
|
- (not(assigned(taicpu(p1).oper[2])) or
|
|
|
|
- OpsEquivalent(taicpu(p1).oper[2]^, taicpu(p2).oper[2]^, taicpu(p1), taicpu(p2), RegInfo, OpAct_Unknown))
|
|
|
|
- end
|
|
|
|
- {the instructions haven't even got the same structure, so they're certainly
|
|
|
|
- not equivalent}
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- {$ifdef csdebug}
|
|
|
|
- hp := tai_comment.Create(strpnew('different opcodes/format'));
|
|
|
|
- hp.previous := p2;
|
|
|
|
- hp.next := p2.next;
|
|
|
|
- p2.next.previous := hp;
|
|
|
|
- p2.next := hp;
|
|
|
|
- {$endif csdebug}
|
|
|
|
- InstructionsEquivalent := False;
|
|
|
|
- end;
|
|
|
|
- {$ifdef csdebug}
|
|
|
|
- hp := tai_comment.Create(strpnew('instreq: '+tostr(byte(instructionsequivalent))));
|
|
|
|
- hp.previous := p2;
|
|
|
|
- hp.next := p2.next;
|
|
|
|
- p2.next.previous := hp;
|
|
|
|
- p2.next := hp;
|
|
|
|
- {$endif csdebug}
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-(*
|
|
|
|
-function InstructionsEqual(p1, p2: tai): Boolean;
|
|
|
|
-begin {checks whether two taicpu instructions are equal}
|
|
|
|
- InstructionsEqual :=
|
|
|
|
- assigned(p1) and assigned(p2) and
|
|
|
|
- ((tai(p1).typ = ait_instruction) and
|
|
|
|
- (tai(p1).typ = ait_instruction) and
|
|
|
|
- (taicpu(p1).opcode = taicpu(p2).opcode) and
|
|
|
|
- (taicpu(p1).oper[0]^.typ = taicpu(p2).oper[0]^.typ) and
|
|
|
|
- (taicpu(p1).oper[1]^.typ = taicpu(p2).oper[1]^.typ) and
|
|
|
|
- OpsEqual(taicpu(p1).oper[0]^.typ, taicpu(p1).oper[0]^, taicpu(p2).oper[0]^) and
|
|
|
|
- OpsEqual(taicpu(p1).oper[1]^.typ, taicpu(p1).oper[1]^, taicpu(p2).oper[1]^))
|
|
|
|
-end;
|
|
|
|
-*)
|
|
|
|
-
|
|
|
|
-procedure readreg(p: ptaiprop; supreg: tsuperregister);
|
|
|
|
-begin
|
|
|
|
- if supreg in [RS_EAX..RS_EDI] then
|
|
|
|
- incState(p^.regs[supreg].rstate,1)
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-procedure readref(p: ptaiprop; const ref: preference);
|
|
|
|
-begin
|
|
|
|
- if ref^.base <> NR_NO then
|
|
|
|
- readreg(p, getsupreg(ref^.base));
|
|
|
|
- if ref^.index <> NR_NO then
|
|
|
|
- readreg(p, getsupreg(ref^.index));
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-procedure ReadOp(p: ptaiprop;const o:toper);
|
|
|
|
-begin
|
|
|
|
- case o.typ Of
|
|
|
|
- top_reg: readreg(p, getsupreg(o.reg));
|
|
|
|
- top_ref: readref(p, o.ref);
|
|
|
|
- end;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-function RefInInstruction(const ref: TReference; p: tai;
|
|
|
|
- RefsEq: TRefCompare; size: tcgsize): Boolean;
|
|
|
|
-{checks whehter ref is used in p}
|
|
|
|
-var
|
|
|
|
- mysize: tcgsize;
|
|
|
|
- TmpResult: Boolean;
|
|
|
|
-begin
|
|
|
|
- TmpResult := False;
|
|
|
|
- if (p.typ = ait_instruction) then
|
|
|
|
- begin
|
|
|
|
- mysize := topsize2tcgsize[taicpu(p).opsize];
|
|
|
|
- if (taicpu(p).ops >= 1) and
|
|
|
|
- (taicpu(p).oper[0]^.typ = top_ref) then
|
|
|
|
- TmpResult := RefsEq(taicpu(p).oper[0]^.ref^,ref,mysize,size);
|
|
|
|
- if not(TmpResult) and
|
|
|
|
- (taicpu(p).ops >= 2) and
|
|
|
|
- (taicpu(p).oper[1]^.typ = top_ref) then
|
|
|
|
- TmpResult := RefsEq(taicpu(p).oper[1]^.ref^,ref,mysize,size);
|
|
|
|
- if not(TmpResult) and
|
|
|
|
- (taicpu(p).ops >= 3) and
|
|
|
|
- (taicpu(p).oper[2]^.typ = top_ref) then
|
|
|
|
- TmpResult := RefsEq(taicpu(p).oper[2]^.ref^,ref,mysize,size);
|
|
|
|
- end;
|
|
|
|
- RefInInstruction := TmpResult;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-function RefInSequence(const ref: TReference; Content: TContent;
|
|
|
|
- RefsEq: TRefCompare; size: tcgsize): Boolean;
|
|
|
|
-{checks the whole sequence of Content (so StartMod and and the next NrOfMods
|
|
|
|
- tai objects) to see whether ref is used somewhere}
|
|
|
|
-var p: tai;
|
|
|
|
- Counter: Word;
|
|
|
|
- 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, RefsEq, size)
|
|
|
|
- then TmpResult := True;
|
|
|
|
- inc(Counter);
|
|
|
|
- GetNextInstruction(p,p)
|
|
|
|
- end;
|
|
|
|
- RefInSequence := TmpResult
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-{$push}
|
|
|
|
-{$q-}
|
|
|
|
-// checks whether a write to r2 of size "size" contains address r1
|
|
|
|
-function arrayrefsoverlapping(const r1, r2: treference; size1, size2: tcgsize): Boolean;
|
|
|
|
-var
|
|
|
|
- realsize1, realsize2: aint;
|
|
|
|
-begin
|
|
|
|
- realsize1 := tcgsize2size[size1];
|
|
|
|
- realsize2 := tcgsize2size[size2];
|
|
|
|
- arrayrefsoverlapping :=
|
|
|
|
- (r2.offset <= r1.offset+realsize1) and
|
|
|
|
- (r1.offset <= r2.offset+realsize2) and
|
|
|
|
- (r1.segment = r2.segment) and
|
|
|
|
- (r1.symbol=r2.symbol) and
|
|
|
|
- (r1.base = r2.base)
|
|
|
|
-end;
|
|
|
|
-{$pop}
|
|
|
|
-
|
|
|
|
-function isSimpleRef(const ref: treference): boolean;
|
|
|
|
-{ returns true if ref is reference to a local or global variable, to a }
|
|
|
|
-{ parameter or to an object field (this includes arrays). Returns false }
|
|
|
|
-{ otherwise. }
|
|
|
|
-begin
|
|
|
|
- isSimpleRef :=
|
|
|
|
- assigned(ref.symbol) or
|
|
|
|
- (ref.base = current_procinfo.framepointer);
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-function containsPointerRef(p: tai): boolean;
|
|
|
|
-{ checks if an instruction contains a reference which is a pointer location }
|
|
|
|
-var
|
|
|
|
- hp: taicpu;
|
|
|
|
- count: longint;
|
|
|
|
-begin
|
|
|
|
- containsPointerRef := false;
|
|
|
|
- if p.typ <> ait_instruction then
|
|
|
|
- exit;
|
|
|
|
- hp := taicpu(p);
|
|
|
|
- for count := 0 to hp.ops-1 do
|
|
|
|
- begin
|
|
|
|
- case hp.oper[count]^.typ of
|
|
|
|
- top_ref:
|
|
|
|
- if not isSimpleRef(hp.oper[count]^.ref^) then
|
|
|
|
- begin
|
|
|
|
- containsPointerRef := true;
|
|
|
|
- exit;
|
|
|
|
- end;
|
|
|
|
- top_none:
|
|
|
|
- exit;
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-function containsPointerLoad(c: tcontent): boolean;
|
|
|
|
-{ checks whether the contents of a register contain a pointer reference }
|
|
|
|
-var
|
|
|
|
- p: tai;
|
|
|
|
- count: longint;
|
|
|
|
-begin
|
|
|
|
- containsPointerLoad := false;
|
|
|
|
- p := c.startmod;
|
|
|
|
- for count := c.nrOfMods downto 1 do
|
|
|
|
- begin
|
|
|
|
- if containsPointerRef(p) then
|
|
|
|
- begin
|
|
|
|
- containsPointerLoad := true;
|
|
|
|
- exit;
|
|
|
|
- end;
|
|
|
|
- getnextinstruction(p,p);
|
|
|
|
- end;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-function writeToMemDestroysContents(regWritten: tsuperregister; const ref: treference;
|
|
|
|
- supreg: tsuperregister; size: tcgsize; const c: tcontent; var invalsmemwrite: boolean): boolean;
|
|
|
|
-{ returns whether the contents c of reg are invalid after regWritten is }
|
|
|
|
-{ is written to ref }
|
|
|
|
-var
|
|
|
|
- refsEq: trefCompare;
|
|
|
|
-begin
|
|
|
|
- if isSimpleRef(ref) then
|
|
|
|
- begin
|
|
|
|
- if (ref.index <> NR_NO) or
|
|
|
|
- (assigned(ref.symbol) and
|
|
|
|
- (ref.base <> NR_NO)) then
|
|
|
|
- { local/global variable or parameter which is an array }
|
|
|
|
- refsEq := @arrayRefsOverlapping
|
|
|
|
- else
|
|
|
|
- { local/global variable or parameter which is not an array }
|
|
|
|
- refsEq := @refsOverlapping;
|
|
|
|
- invalsmemwrite :=
|
|
|
|
- assigned(c.memwrite) and
|
|
|
|
- ((not(cs_opt_size in current_settings.optimizerswitches) and
|
|
|
|
- containsPointerRef(c.memwrite)) or
|
|
|
|
- refsEq(c.memwrite.oper[1]^.ref^,ref,topsize2tcgsize[c.memwrite.opsize],size));
|
|
|
|
- if not(c.typ in [con_ref,con_noRemoveRef,con_invalid]) then
|
|
|
|
- begin
|
|
|
|
- writeToMemDestroysContents := false;
|
|
|
|
- exit;
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
- { 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 }
|
|
|
|
- { expression based on ref) }
|
|
|
|
- { * with uncertain optimizations off: }
|
|
|
|
- { - also destroy registers that contain any pointer }
|
|
|
|
- with c do
|
|
|
|
- writeToMemDestroysContents :=
|
|
|
|
- (typ in [con_ref,con_noRemoveRef]) and
|
|
|
|
- ((not(cs_opt_size in current_settings.optimizerswitches) and
|
|
|
|
- containsPointerLoad(c)
|
|
|
|
- ) or
|
|
|
|
- (refInSequence(ref,c,refsEq,size) and
|
|
|
|
- ((supreg <> regWritten) or
|
|
|
|
- not((nrOfMods = 1) and
|
|
|
|
- {StarMod is always of the type ait_instruction}
|
|
|
|
- (taicpu(StartMod).oper[0]^.typ = top_ref) and
|
|
|
|
- refsEq(taicpu(StartMod).oper[0]^.ref^, ref, topsize2tcgsize[taicpu(StartMod).opsize],size)
|
|
|
|
- )
|
|
|
|
- )
|
|
|
|
- )
|
|
|
|
- );
|
|
|
|
- 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 }
|
|
|
|
- begin
|
|
|
|
- invalsmemwrite :=
|
|
|
|
- assigned(c.memwrite) and
|
|
|
|
- (not(cs_opt_size in current_settings.optimizerswitches) or
|
|
|
|
- containsPointerRef(c.memwrite));
|
|
|
|
- if not(c.typ in [con_ref,con_noRemoveRef,con_invalid]) then
|
|
|
|
- begin
|
|
|
|
- writeToMemDestroysContents := false;
|
|
|
|
- exit;
|
|
|
|
- end;
|
|
|
|
- with c do
|
|
|
|
- writeToMemDestroysContents :=
|
|
|
|
- (typ in [con_ref,con_noRemoveRef]) and
|
|
|
|
- (not(cs_opt_size in current_settings.optimizerswitches) or
|
|
|
|
- { for movsl }
|
|
|
|
- ((ref.base = NR_EDI) and (ref.index = NR_EDI)) or
|
|
|
|
- { don't destroy if reg contains a parameter, local or global variable }
|
|
|
|
- containsPointerLoad(c)
|
|
|
|
- );
|
|
|
|
- end;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-function writeToRegDestroysContents(destReg, supreg: tsuperregister;
|
|
|
|
- const c: tcontent): boolean;
|
|
|
|
-{ returns whether the contents c of reg are invalid after destReg is }
|
|
|
|
-{ modified }
|
|
|
|
-begin
|
|
|
|
- writeToRegDestroysContents :=
|
|
|
|
- (c.typ in [con_ref,con_noRemoveRef,con_invalid]) and
|
|
|
|
- sequenceDependsOnReg(c,supreg,destReg);
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-function writeDestroysContents(const op: toper; supreg: tsuperregister; size: tcgsize;
|
|
|
|
- const c: tcontent; var memwritedestroyed: boolean): boolean;
|
|
|
|
-{ returns whether the contents c of reg are invalid after regWritten is }
|
|
|
|
-{ is written to op }
|
|
|
|
-begin
|
|
|
|
- memwritedestroyed := false;
|
|
|
|
- case op.typ of
|
|
|
|
- top_reg:
|
|
|
|
- writeDestroysContents :=
|
|
|
|
- (getregtype(op.reg) = R_INTREGISTER) and
|
|
|
|
- writeToRegDestroysContents(getsupreg(op.reg),supreg,c);
|
|
|
|
- top_ref:
|
|
|
|
- writeDestroysContents :=
|
|
|
|
- writeToMemDestroysContents(RS_INVALID,op.ref^,supreg,size,c,memwritedestroyed);
|
|
|
|
- else
|
|
|
|
- writeDestroysContents := false;
|
|
|
|
- end;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-procedure destroyRefs(p: tai; const ref: treference; regwritten: tsuperregister; size: tcgsize);
|
|
|
|
-{ destroys all registers which possibly contain a reference to ref, regWritten }
|
|
|
|
-{ is the register whose contents are being written to memory (if this proc }
|
|
|
|
-{ is called because of a "mov?? %reg, (mem)" instruction) }
|
|
|
|
-var
|
|
|
|
- counter: tsuperregister;
|
|
|
|
- destroymemwrite: boolean;
|
|
|
|
-begin
|
|
|
|
- for counter := RS_EAX to RS_EDI Do
|
|
|
|
- begin
|
|
|
|
- if writeToMemDestroysContents(regwritten,ref,counter,size,
|
|
|
|
- ptaiprop(p.optInfo)^.regs[counter],destroymemwrite) then
|
|
|
|
- destroyReg(ptaiprop(p.optInfo), counter, false)
|
|
|
|
- else if destroymemwrite then
|
|
|
|
- ptaiprop(p.optinfo)^.regs[counter].MemWrite := nil;
|
|
|
|
- end;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-procedure DestroyAllRegs(p: ptaiprop; read, written: boolean);
|
|
|
|
-var Counter: tsuperregister;
|
|
|
|
-begin {initializes/desrtoys all registers}
|
|
|
|
- For Counter := RS_EAX To RS_EDI Do
|
|
|
|
- begin
|
|
|
|
- if read then
|
|
|
|
- readreg(p, Counter);
|
|
|
|
- DestroyReg(p, Counter, written);
|
|
|
|
- p^.regs[counter].MemWrite := nil;
|
|
|
|
- end;
|
|
|
|
- p^.DirFlag := F_Unknown;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-procedure DestroyOp(taiObj: tai; const o:Toper);
|
|
|
|
-{$ifdef statedebug}
|
|
|
|
-var
|
|
|
|
- hp: tai;
|
|
|
|
-{$endif statedebug}
|
|
|
|
-begin
|
|
|
|
- case o.typ Of
|
|
|
|
- top_reg:
|
|
|
|
- begin
|
|
|
|
-{$ifdef statedebug}
|
|
|
|
- hp := tai_comment.Create(strpnew('destroying '+std_regname(o.reg)));
|
|
|
|
- hp.next := taiobj.next;
|
|
|
|
- hp.previous := taiobj;
|
|
|
|
- taiobj.next := hp;
|
|
|
|
- if assigned(hp.next) then
|
|
|
|
- hp.next.previous := hp;
|
|
|
|
-{$endif statedebug}
|
|
|
|
- DestroyReg(ptaiprop(taiObj.OptInfo), getsupreg(o.reg), true);
|
|
|
|
- end;
|
|
|
|
- top_ref:
|
|
|
|
- begin
|
|
|
|
- readref(ptaiprop(taiObj.OptInfo), o.ref);
|
|
|
|
- DestroyRefs(taiObj, o.ref^, RS_INVALID,topsize2tcgsize[(taiobj as taicpu).opsize]);
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-procedure AddInstr2RegContents({$ifdef statedebug} asml: TAsmList; {$endif}
|
|
|
|
-p: taicpu; supreg: tsuperregister);
|
|
|
|
-{$ifdef statedebug}
|
|
|
|
-var
|
|
|
|
- hp: tai;
|
|
|
|
-{$endif statedebug}
|
|
|
|
-begin
|
|
|
|
- With ptaiprop(p.optinfo)^.regs[supreg] Do
|
|
|
|
- if (typ in [con_ref,con_noRemoveRef]) then
|
|
|
|
- begin
|
|
|
|
- incState(wstate,1);
|
|
|
|
- { also store how many instructions are part of the sequence in the first }
|
|
|
|
- { instructions ptaiprop, so it can be easily accessed from within }
|
|
|
|
- { CheckSequence}
|
|
|
|
- inc(NrOfMods, NrOfInstrSinceLastMod[supreg]);
|
|
|
|
- ptaiprop(tai(StartMod).OptInfo)^.Regs[supreg].NrOfMods := NrOfMods;
|
|
|
|
- NrOfInstrSinceLastMod[supreg] := 0;
|
|
|
|
- invalidateDependingRegs(p.optinfo,supreg);
|
|
|
|
- ptaiprop(p.optinfo)^.regs[supreg].memwrite := nil;
|
|
|
|
-{$ifdef StateDebug}
|
|
|
|
- hp := tai_comment.Create(strpnew(std_regname(newreg(R_INTREGISTER,supreg,R_SUBWHOLE))+': '+tostr(ptaiprop(p.optinfo)^.Regs[supreg].WState)
|
|
|
|
- + ' -- ' + tostr(ptaiprop(p.optinfo)^.Regs[supreg].nrofmods)));
|
|
|
|
- InsertLLItem(AsmL, p, p.next, hp);
|
|
|
|
-{$endif StateDebug}
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
-{$ifdef statedebug}
|
|
|
|
- hp := tai_comment.Create(strpnew('destroying '+std_regname(newreg(R_INTREGISTER,supreg,R_SUBWHOLE))));
|
|
|
|
- insertllitem(asml,p,p.next,hp);
|
|
|
|
-{$endif statedebug}
|
|
|
|
- DestroyReg(ptaiprop(p.optinfo), supreg, true);
|
|
|
|
-{$ifdef StateDebug}
|
|
|
|
- hp := tai_comment.Create(strpnew(std_regname(newreg(R_INTREGISTER,supreg,R_SUBWHOLE))+': '+tostr(ptaiprop(p.optinfo)^.Regs[supreg].WState)));
|
|
|
|
- InsertLLItem(AsmL, p, p.next, hp);
|
|
|
|
-{$endif StateDebug}
|
|
|
|
- end
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-procedure AddInstr2OpContents({$ifdef statedebug} asml: TAsmList; {$endif}
|
|
|
|
-p: taicpu; const oper: TOper);
|
|
|
|
-begin
|
|
|
|
- if oper.typ = top_reg then
|
|
|
|
- AddInstr2RegContents({$ifdef statedebug} asml, {$endif}p, getsupreg(oper.reg))
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- ReadOp(ptaiprop(p.optinfo), oper);
|
|
|
|
- DestroyOp(p, oper);
|
|
|
|
- end
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-{*************************************************************************************}
|
|
|
|
-{************************************** TDFAOBJ **************************************}
|
|
|
|
-{*************************************************************************************}
|
|
|
|
-
|
|
|
|
-constructor tdfaobj.create(_list: TAsmList);
|
|
|
|
-begin
|
|
|
|
- list := _list;
|
|
|
|
- blockstart := nil;
|
|
|
|
- blockend := nil;
|
|
|
|
- nroftaiobjs := 0;
|
|
|
|
- taipropblock := nil;
|
|
|
|
- lolab := 0;
|
|
|
|
- hilab := 0;
|
|
|
|
- labdif := 0;
|
|
|
|
- labeltable := nil;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-procedure tdfaobj.initlabeltable;
|
|
|
|
-var
|
|
|
|
- labelfound: boolean;
|
|
|
|
- p, prev: tai;
|
|
|
|
- hp1, hp2: tai;
|
|
|
|
-{$ifdef i386}
|
|
|
|
- regcounter,
|
|
|
|
- supreg : tsuperregister;
|
|
|
|
-{$endif i386}
|
|
|
|
- usedregs, nodeallocregs: tregset;
|
|
|
|
-begin
|
|
|
|
- labelfound := false;
|
|
|
|
- lolab := maxlongint;
|
|
|
|
- hilab := 0;
|
|
|
|
- p := blockstart;
|
|
|
|
- prev := p;
|
|
|
|
- while assigned(p) do
|
|
|
|
- begin
|
|
|
|
- if (tai(p).typ = ait_label) then
|
|
|
|
- if not labelcanbeskipped(tai_label(p)) then
|
|
|
|
- begin
|
|
|
|
- labelfound := true;
|
|
|
|
- if (tai_Label(p).labsym.labelnr < lolab) then
|
|
|
|
- lolab := tai_label(p).labsym.labelnr;
|
|
|
|
- if (tai_Label(p).labsym.labelnr > hilab) then
|
|
|
|
- hilab := tai_label(p).labsym.labelnr;
|
|
|
|
- end;
|
|
|
|
- prev := p;
|
|
|
|
- getnextinstruction(p, p);
|
|
|
|
- end;
|
|
|
|
- if (prev.typ = ait_marker) and
|
|
|
|
- (tai_marker(prev).kind = mark_AsmBlockStart) then
|
|
|
|
- blockend := prev
|
|
|
|
- else blockend := nil;
|
|
|
|
- if labelfound then
|
|
|
|
- labdif := hilab+1-lolab
|
|
|
|
- else labdif := 0;
|
|
|
|
-
|
|
|
|
- usedregs := [];
|
|
|
|
- if (labdif <> 0) then
|
|
|
|
- begin
|
|
|
|
- getmem(labeltable, labdif*sizeof(tlabeltableitem));
|
|
|
|
- fillchar(labeltable^, labdif*sizeof(tlabeltableitem), 0);
|
|
|
|
- end;
|
|
|
|
- p := blockstart;
|
|
|
|
- prev := p;
|
|
|
|
- while (p <> blockend) do
|
|
|
|
- begin
|
|
|
|
- case p.typ of
|
|
|
|
- ait_label:
|
|
|
|
- if not labelcanbeskipped(tai_label(p)) then
|
|
|
|
- labeltable^[tai_label(p).labsym.labelnr-lolab].taiobj := p;
|
|
|
|
-{$ifdef i386}
|
|
|
|
- ait_regalloc:
|
|
|
|
- if (getregtype(tai_regalloc(p).reg) = R_INTREGISTER) then
|
|
|
|
- begin
|
|
|
|
- supreg:=getsupreg(tai_regalloc(p).reg);
|
|
|
|
- case tai_regalloc(p).ratype of
|
|
|
|
- ra_alloc :
|
|
|
|
- begin
|
|
|
|
- if not(supreg in usedregs) then
|
|
|
|
- include(usedregs, supreg)
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- //addregdeallocfor(list, tai_regalloc(p).reg, p);
|
|
|
|
- hp1 := tai(p.previous);
|
|
|
|
- list.remove(p);
|
|
|
|
- p.free;
|
|
|
|
- p := hp1;
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- ra_dealloc :
|
|
|
|
- begin
|
|
|
|
- exclude(usedregs, supreg);
|
|
|
|
- hp1 := p;
|
|
|
|
- hp2 := nil;
|
|
|
|
- while not(findregalloc(supreg,tai(hp1.next),ra_alloc)) and
|
|
|
|
- getnextinstruction(hp1, hp1) and
|
|
|
|
- regininstruction(getsupreg(tai_regalloc(p).reg), hp1) Do
|
|
|
|
- hp2 := hp1;
|
|
|
|
- if hp2 <> nil then
|
|
|
|
- begin
|
|
|
|
- hp1 := tai(p.previous);
|
|
|
|
- list.remove(p);
|
|
|
|
- insertllitem(list, hp2, tai(hp2.next), p);
|
|
|
|
- p := hp1;
|
|
|
|
- end
|
|
|
|
- else if findregalloc(getsupreg(tai_regalloc(p).reg), tai(p.next),ra_alloc)
|
|
|
|
- and getnextinstruction(p,hp1) then
|
|
|
|
- begin
|
|
|
|
- hp1 := tai(p.previous);
|
|
|
|
- list.remove(p);
|
|
|
|
- p.free;
|
|
|
|
- p := hp1;
|
|
|
|
-// don't include here, since then the allocation will be removed when it's processed
|
|
|
|
-// include(usedregs,supreg);
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
-{$endif i386}
|
|
|
|
- end;
|
|
|
|
- repeat
|
|
|
|
- prev := p;
|
|
|
|
- p := tai(p.next);
|
|
|
|
- until not(assigned(p)) or
|
|
|
|
- (p = blockend) or
|
|
|
|
- not(p.typ in (skipinstr - [ait_regalloc]));
|
|
|
|
- end;
|
|
|
|
-{$ifdef i386}
|
|
|
|
- { don't add deallocation for function result variable or for regvars}
|
|
|
|
- getNoDeallocRegs(noDeallocRegs);
|
|
|
|
- usedRegs := usedRegs - noDeallocRegs;
|
|
|
|
- for regCounter := RS_EAX to RS_EDI do
|
|
|
|
- if regCounter in usedRegs then
|
|
|
|
- addRegDeallocFor(list,newreg(R_INTREGISTER,regCounter,R_SUBWHOLE),prev);
|
|
|
|
-{$endif i386}
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-function tdfaobj.pass_1(_blockstart: tai): tai;
|
|
|
|
-begin
|
|
|
|
- blockstart := _blockstart;
|
|
|
|
- initlabeltable;
|
|
|
|
- pass_1 := blockend;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-function tdfaobj.initdfapass2: boolean;
|
|
|
|
-{reserves memory for the PtaiProps in one big memory block when not using
|
|
|
|
- TP, returns False if not enough memory is available for the optimizer in all
|
|
|
|
- cases}
|
|
|
|
-var
|
|
|
|
- p: tai;
|
|
|
|
- count: Longint;
|
|
|
|
-{ TmpStr: String; }
|
|
|
|
-begin
|
|
|
|
- p := blockstart;
|
|
|
|
- skiphead(p);
|
|
|
|
- nroftaiobjs := 0;
|
|
|
|
- while (p <> blockend) do
|
|
|
|
- begin
|
|
|
|
-{$ifDef JumpAnal}
|
|
|
|
- case p.typ of
|
|
|
|
- ait_label:
|
|
|
|
- begin
|
|
|
|
- if not labelcanbeskipped(tai_label(p)) then
|
|
|
|
- labeltable^[tai_label(p).labsym.labelnr-lolab].instrnr := nroftaiobjs
|
|
|
|
- end;
|
|
|
|
- ait_instruction:
|
|
|
|
- begin
|
|
|
|
- if taicpu(p).is_jmp then
|
|
|
|
- begin
|
|
|
|
- if (tasmlabel(taicpu(p).oper[0]^.sym).labsymabelnr >= lolab) and
|
|
|
|
- (tasmlabel(taicpu(p).oper[0]^.sym).labsymabelnr <= hilab) then
|
|
|
|
- inc(labeltable^[tasmlabel(taicpu(p).oper[0]^.sym).labsymabelnr-lolab].refsfound);
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
-{ ait_instruction:
|
|
|
|
- begin
|
|
|
|
- if (taicpu(p).opcode = A_PUSH) and
|
|
|
|
- (taicpu(p).oper[0]^.typ = top_symbol) and
|
|
|
|
- (PCSymbol(taicpu(p).oper[0]^)^.offset = 0) then
|
|
|
|
- begin
|
|
|
|
- TmpStr := StrPas(PCSymbol(taicpu(p).oper[0]^)^.symbol);
|
|
|
|
- if}
|
|
|
|
- end;
|
|
|
|
-{$endif JumpAnal}
|
|
|
|
- inc(NrOftaiObjs);
|
|
|
|
- getnextinstruction(p,p);
|
|
|
|
- end;
|
|
|
|
- if nroftaiobjs <> 0 then
|
|
|
|
- begin
|
|
|
|
- initdfapass2 := True;
|
|
|
|
- getmem(taipropblock, nroftaiobjs*sizeof(ttaiprop));
|
|
|
|
- fillchar(taiPropblock^,nroftaiobjs*sizeof(ttaiprop),0);
|
|
|
|
- p := blockstart;
|
|
|
|
- skiphead(p);
|
|
|
|
- for count := 1 To nroftaiobjs do
|
|
|
|
- begin
|
|
|
|
- ptaiprop(p.optinfo) := @taipropblock^[count];
|
|
|
|
- getnextinstruction(p, p);
|
|
|
|
- end;
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- initdfapass2 := false;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-procedure tdfaobj.dodfapass2;
|
|
|
|
-{Analyzes the Data Flow of an assembler list. Starts creating the reg
|
|
|
|
- contents for the instructions starting with p. Returns the last tai which has
|
|
|
|
- been processed}
|
|
|
|
-var
|
|
|
|
- curprop, LastFlagsChangeProp: ptaiprop;
|
|
|
|
- Cnt, InstrCnt : Longint;
|
|
|
|
- InstrProp: TInsProp;
|
|
|
|
- UsedRegs: TRegSet;
|
|
|
|
- prev,p : tai;
|
|
|
|
- tmpref: TReference;
|
|
|
|
- tmpsupreg: tsuperregister;
|
|
|
|
-{$ifdef statedebug}
|
|
|
|
- hp : tai;
|
|
|
|
-{$endif}
|
|
|
|
-{$ifdef AnalyzeLoops}
|
|
|
|
- hp : tai;
|
|
|
|
- TmpState: Byte;
|
|
|
|
-{$endif AnalyzeLoops}
|
|
|
|
-begin
|
|
|
|
- p := BlockStart;
|
|
|
|
- LastFlagsChangeProp := nil;
|
|
|
|
- prev := nil;
|
|
|
|
- UsedRegs := [];
|
|
|
|
- UpdateUsedregs(UsedRegs, p);
|
|
|
|
- SkipHead(p);
|
|
|
|
- BlockStart := p;
|
|
|
|
- InstrCnt := 1;
|
|
|
|
- fillchar(NrOfInstrSinceLastMod, SizeOf(NrOfInstrSinceLastMod), 0);
|
|
|
|
- while (p <> Blockend) Do
|
|
|
|
- begin
|
|
|
|
- curprop := @taiPropBlock^[InstrCnt];
|
|
|
|
- if assigned(prev)
|
|
|
|
- then
|
|
|
|
- begin
|
|
|
|
-{$ifdef JumpAnal}
|
|
|
|
- if (p.Typ <> ait_label) then
|
|
|
|
-{$endif JumpAnal}
|
|
|
|
- begin
|
|
|
|
- curprop^.regs := ptaiprop(prev.OptInfo)^.Regs;
|
|
|
|
- curprop^.DirFlag := ptaiprop(prev.OptInfo)^.DirFlag;
|
|
|
|
- curprop^.FlagsUsed := false;
|
|
|
|
- end
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- fillchar(curprop^, SizeOf(curprop^), 0);
|
|
|
|
-{ For tmpreg := RS_EAX to RS_EDI Do
|
|
|
|
- curprop^.regs[tmpreg].WState := 1;}
|
|
|
|
- end;
|
|
|
|
- curprop^.UsedRegs := UsedRegs;
|
|
|
|
- curprop^.CanBeRemoved := False;
|
|
|
|
- UpdateUsedRegs(UsedRegs, tai(p.Next));
|
|
|
|
- For tmpsupreg := RS_EAX To RS_EDI Do
|
|
|
|
- if NrOfInstrSinceLastMod[tmpsupreg] < 255 then
|
|
|
|
- inc(NrOfInstrSinceLastMod[tmpsupreg])
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- NrOfInstrSinceLastMod[tmpsupreg] := 0;
|
|
|
|
- curprop^.regs[tmpsupreg].typ := con_unknown;
|
|
|
|
- end;
|
|
|
|
- case p.typ Of
|
|
|
|
- ait_marker:;
|
|
|
|
- ait_label:
|
|
|
|
-{$ifndef JumpAnal}
|
|
|
|
- if not labelCanBeSkipped(tai_label(p)) then
|
|
|
|
- DestroyAllRegs(curprop,false,false);
|
|
|
|
-{$else JumpAnal}
|
|
|
|
- begin
|
|
|
|
- if not labelCanBeSkipped(tai_label(p)) then
|
|
|
|
- With LTable^[tai_Label(p).labsym^.labelnr-LoLab] Do
|
|
|
|
-{$ifDef AnalyzeLoops}
|
|
|
|
- if (RefsFound = tai_Label(p).labsym^.RefCount)
|
|
|
|
-{$else AnalyzeLoops}
|
|
|
|
- if (JmpsProcessed = tai_Label(p).labsym^.RefCount)
|
|
|
|
-{$endif AnalyzeLoops}
|
|
|
|
- then
|
|
|
|
-{all jumps to this label have been found}
|
|
|
|
-{$ifDef AnalyzeLoops}
|
|
|
|
- if (JmpsProcessed > 0)
|
|
|
|
- then
|
|
|
|
-{$endif AnalyzeLoops}
|
|
|
|
- {we've processed at least one jump to this label}
|
|
|
|
- begin
|
|
|
|
- if (GetLastInstruction(p, hp) and
|
|
|
|
- not(((hp.typ = ait_instruction)) and
|
|
|
|
- (taicpu_labeled(hp).is_jmp))
|
|
|
|
- then
|
|
|
|
- {previous instruction not a JMP -> the contents of the registers after the
|
|
|
|
- previous intruction has been executed have to be taken into account as well}
|
|
|
|
- For tmpsupreg := RS_EAX to RS_EDI Do
|
|
|
|
- begin
|
|
|
|
- if (curprop^.regs[tmpsupreg].WState <>
|
|
|
|
- ptaiprop(hp.OptInfo)^.Regs[tmpsupreg].WState)
|
|
|
|
- then DestroyReg(curprop, tmpsupreg, true)
|
|
|
|
- end
|
|
|
|
- end
|
|
|
|
-{$ifDef AnalyzeLoops}
|
|
|
|
- else
|
|
|
|
- {a label from a backward jump (e.g. a loop), no jump to this label has
|
|
|
|
- already been processed}
|
|
|
|
- if GetLastInstruction(p, hp) and
|
|
|
|
- not(hp.typ = ait_instruction) and
|
|
|
|
- (taicpu_labeled(hp).opcode = A_JMP))
|
|
|
|
- then
|
|
|
|
- {previous instruction not a jmp, so keep all the registers' contents from the
|
|
|
|
- previous instruction}
|
|
|
|
- begin
|
|
|
|
- curprop^.regs := ptaiprop(hp.OptInfo)^.Regs;
|
|
|
|
- curprop.DirFlag := ptaiprop(hp.OptInfo)^.DirFlag;
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- {previous instruction a jmp and no jump to this label processed yet}
|
|
|
|
- begin
|
|
|
|
- hp := p;
|
|
|
|
- Cnt := InstrCnt;
|
|
|
|
- {continue until we find a jump to the label or a label which has already
|
|
|
|
- been processed}
|
|
|
|
- while GetNextInstruction(hp, hp) and
|
|
|
|
- not((hp.typ = ait_instruction) and
|
|
|
|
- (taicpu(hp).is_jmp) and
|
|
|
|
- (tasmlabel(taicpu(hp).oper[0]^.sym).labsymabelnr = tai_Label(p).labsym^.labelnr)) and
|
|
|
|
- not((hp.typ = ait_label) and
|
|
|
|
- (LTable^[tai_Label(hp).labsym^.labelnr-LoLab].RefsFound
|
|
|
|
- = tai_Label(hp).labsym^.RefCount) and
|
|
|
|
- (LTable^[tai_Label(hp).labsym^.labelnr-LoLab].JmpsProcessed > 0)) Do
|
|
|
|
- inc(Cnt);
|
|
|
|
- if (hp.typ = ait_label)
|
|
|
|
- then
|
|
|
|
- {there's a processed label after the current one}
|
|
|
|
- begin
|
|
|
|
- curprop^.regs := taiPropBlock^[Cnt].Regs;
|
|
|
|
- curprop.DirFlag := taiPropBlock^[Cnt].DirFlag;
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- {there's no label anymore after the current one, or they haven't been
|
|
|
|
- processed yet}
|
|
|
|
- begin
|
|
|
|
- GetLastInstruction(p, hp);
|
|
|
|
- curprop^.regs := ptaiprop(hp.OptInfo)^.Regs;
|
|
|
|
- curprop.DirFlag := ptaiprop(hp.OptInfo)^.DirFlag;
|
|
|
|
- DestroyAllRegs(ptaiprop(hp.OptInfo),true,true)
|
|
|
|
- end
|
|
|
|
- end
|
|
|
|
-{$endif AnalyzeLoops}
|
|
|
|
- else
|
|
|
|
-{not all references to this label have been found, so destroy all registers}
|
|
|
|
- begin
|
|
|
|
- GetLastInstruction(p, hp);
|
|
|
|
- curprop^.regs := ptaiprop(hp.OptInfo)^.Regs;
|
|
|
|
- curprop.DirFlag := ptaiprop(hp.OptInfo)^.DirFlag;
|
|
|
|
- DestroyAllRegs(curprop,true,true)
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
-{$endif JumpAnal}
|
|
|
|
-
|
|
|
|
- ait_stab, ait_force_line, ait_function_name:;
|
|
|
|
- ait_align: ; { may destroy flags !!! }
|
|
|
|
- ait_instruction:
|
|
|
|
- begin
|
|
|
|
- if taicpu(p).is_jmp or
|
|
|
|
- (taicpu(p).opcode = A_JMP) then
|
|
|
|
- begin
|
|
|
|
-{$ifNDef JumpAnal}
|
|
|
|
- for tmpsupreg := RS_EAX to RS_EDI do
|
|
|
|
- with curprop^.regs[tmpsupreg] do
|
|
|
|
- case typ of
|
|
|
|
- con_ref: typ := con_noRemoveRef;
|
|
|
|
- con_const: typ := con_noRemoveConst;
|
|
|
|
- con_invalid: typ := con_unknown;
|
|
|
|
- end;
|
|
|
|
-{$else JumpAnal}
|
|
|
|
- With LTable^[tasmlabel(taicpu(p).oper[0]^.sym).labsymabelnr-LoLab] Do
|
|
|
|
- if (RefsFound = tasmlabel(taicpu(p).oper[0]^.sym).RefCount) then
|
|
|
|
- begin
|
|
|
|
- if (InstrCnt < InstrNr)
|
|
|
|
- then
|
|
|
|
- {forward jump}
|
|
|
|
- if (JmpsProcessed = 0) then
|
|
|
|
- {no jump to this label has been processed yet}
|
|
|
|
- begin
|
|
|
|
- taiPropBlock^[InstrNr].Regs := curprop^.regs;
|
|
|
|
- taiPropBlock^[InstrNr].DirFlag := curprop.DirFlag;
|
|
|
|
- inc(JmpsProcessed);
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- For tmpreg := RS_EAX to RS_EDI Do
|
|
|
|
- if (taiPropBlock^[InstrNr].Regs[tmpreg].WState <>
|
|
|
|
- curprop^.regs[tmpreg].WState) then
|
|
|
|
- DestroyReg(@taiPropBlock^[InstrNr], tmpreg, true);
|
|
|
|
- inc(JmpsProcessed);
|
|
|
|
- end
|
|
|
|
-{$ifdef AnalyzeLoops}
|
|
|
|
- else
|
|
|
|
-{ backward jump, a loop for example}
|
|
|
|
-{ if (JmpsProcessed > 0) or
|
|
|
|
- not(GetLastInstruction(taiObj, hp) and
|
|
|
|
- (hp.typ = ait_labeled_instruction) and
|
|
|
|
- (taicpu_labeled(hp).opcode = A_JMP))
|
|
|
|
- then}
|
|
|
|
-{instruction prior to label is not a jmp, or at least one jump to the label
|
|
|
|
- has yet been processed}
|
|
|
|
- begin
|
|
|
|
- inc(JmpsProcessed);
|
|
|
|
- For tmpreg := RS_EAX to RS_EDI Do
|
|
|
|
- if (taiPropBlock^[InstrNr].Regs[tmpreg].WState <>
|
|
|
|
- curprop^.regs[tmpreg].WState)
|
|
|
|
- then
|
|
|
|
- begin
|
|
|
|
- TmpState := taiPropBlock^[InstrNr].Regs[tmpreg].WState;
|
|
|
|
- Cnt := InstrNr;
|
|
|
|
- while (TmpState = taiPropBlock^[Cnt].Regs[tmpreg].WState) Do
|
|
|
|
- begin
|
|
|
|
- DestroyReg(@taiPropBlock^[Cnt], tmpreg, true);
|
|
|
|
- inc(Cnt);
|
|
|
|
- end;
|
|
|
|
- while (Cnt <= InstrCnt) Do
|
|
|
|
- begin
|
|
|
|
- inc(taiPropBlock^[Cnt].Regs[tmpreg].WState);
|
|
|
|
- inc(Cnt)
|
|
|
|
- end
|
|
|
|
- end;
|
|
|
|
- end
|
|
|
|
-{ else }
|
|
|
|
-{instruction prior to label is a jmp and no jumps to the label have yet been
|
|
|
|
- processed}
|
|
|
|
-{ begin
|
|
|
|
- inc(JmpsProcessed);
|
|
|
|
- For tmpreg := RS_EAX to RS_EDI Do
|
|
|
|
- begin
|
|
|
|
- TmpState := taiPropBlock^[InstrNr].Regs[tmpreg].WState;
|
|
|
|
- Cnt := InstrNr;
|
|
|
|
- while (TmpState = taiPropBlock^[Cnt].Regs[tmpreg].WState) Do
|
|
|
|
- begin
|
|
|
|
- taiPropBlock^[Cnt].Regs[tmpreg] := curprop^.regs[tmpreg];
|
|
|
|
- inc(Cnt);
|
|
|
|
- end;
|
|
|
|
- TmpState := taiPropBlock^[InstrNr].Regs[tmpreg].WState;
|
|
|
|
- while (TmpState = taiPropBlock^[Cnt].Regs[tmpreg].WState) Do
|
|
|
|
- begin
|
|
|
|
- DestroyReg(@taiPropBlock^[Cnt], tmpreg, true);
|
|
|
|
- inc(Cnt);
|
|
|
|
- end;
|
|
|
|
- while (Cnt <= InstrCnt) Do
|
|
|
|
- begin
|
|
|
|
- inc(taiPropBlock^[Cnt].Regs[tmpreg].WState);
|
|
|
|
- inc(Cnt)
|
|
|
|
- end
|
|
|
|
- end
|
|
|
|
- end}
|
|
|
|
-{$endif AnalyzeLoops}
|
|
|
|
- end;
|
|
|
|
-{$endif JumpAnal}
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- InstrProp := InsProp[taicpu(p).opcode];
|
|
|
|
- case taicpu(p).opcode Of
|
|
|
|
- A_MOV, A_MOVZX, A_MOVSX:
|
|
|
|
- begin
|
|
|
|
- case taicpu(p).oper[0]^.typ Of
|
|
|
|
- top_ref, top_reg:
|
|
|
|
- case taicpu(p).oper[1]^.typ Of
|
|
|
|
- top_reg:
|
|
|
|
- begin
|
|
|
|
-{$ifdef statedebug}
|
|
|
|
- hp := tai_comment.Create(strpnew('destroying '+std_regname(taicpu(p).oper[1]^.reg)));
|
|
|
|
- insertllitem(list,p,p.next,hp);
|
|
|
|
-{$endif statedebug}
|
|
|
|
-
|
|
|
|
- readOp(curprop, taicpu(p).oper[0]^);
|
|
|
|
- tmpsupreg := getsupreg(taicpu(p).oper[1]^.reg);
|
|
|
|
- if reginop(tmpsupreg, taicpu(p).oper[0]^) and
|
|
|
|
- (curprop^.regs[tmpsupreg].typ in [con_ref,con_noRemoveRef]) then
|
|
|
|
- begin
|
|
|
|
- with curprop^.regs[tmpsupreg] Do
|
|
|
|
- begin
|
|
|
|
- incState(wstate,1);
|
|
|
|
- { also store how many instructions are part of the sequence in the first }
|
|
|
|
- { instruction's ptaiprop, so it can be easily accessed from within }
|
|
|
|
- { CheckSequence }
|
|
|
|
- inc(nrOfMods, nrOfInstrSinceLastMod[tmpsupreg]);
|
|
|
|
- ptaiprop(startmod.optinfo)^.regs[tmpsupreg].nrOfMods := nrOfMods;
|
|
|
|
- nrOfInstrSinceLastMod[tmpsupreg] := 0;
|
|
|
|
- { Destroy the contents of the registers }
|
|
|
|
- { that depended on the previous value of }
|
|
|
|
- { this register }
|
|
|
|
- invalidateDependingRegs(curprop,tmpsupreg);
|
|
|
|
- curprop^.regs[tmpsupreg].memwrite := nil;
|
|
|
|
- end;
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
-{$ifdef statedebug}
|
|
|
|
- hp := tai_comment.Create(strpnew('destroying & initing '+std_regname(newreg(R_INTREGISTER,tmpsupreg,R_SUBWHOLE))));
|
|
|
|
- insertllitem(list,p,p.next,hp);
|
|
|
|
-{$endif statedebug}
|
|
|
|
- destroyReg(curprop, tmpsupreg, true);
|
|
|
|
- if not(reginop(tmpsupreg, taicpu(p).oper[0]^)) then
|
|
|
|
- with curprop^.regs[tmpsupreg] Do
|
|
|
|
- begin
|
|
|
|
- typ := con_ref;
|
|
|
|
- startmod := p;
|
|
|
|
- nrOfMods := 1;
|
|
|
|
- end
|
|
|
|
- end;
|
|
|
|
-{$ifdef StateDebug}
|
|
|
|
- hp := tai_comment.Create(strpnew(std_regname(newreg(R_INTREGISTER,tmpsupreg,R_SUBWHOLE))+': '+tostr(curprop^.regs[tmpsupreg].WState)));
|
|
|
|
- insertllitem(list,p,p.next,hp);
|
|
|
|
-{$endif StateDebug}
|
|
|
|
- end;
|
|
|
|
- top_ref:
|
|
|
|
- begin
|
|
|
|
- readref(curprop, taicpu(p).oper[1]^.ref);
|
|
|
|
- if taicpu(p).oper[0]^.typ = top_reg then
|
|
|
|
- begin
|
|
|
|
- readreg(curprop, getsupreg(taicpu(p).oper[0]^.reg));
|
|
|
|
- DestroyRefs(p, taicpu(p).oper[1]^.ref^, getsupreg(taicpu(p).oper[0]^.reg),topsize2tcgsize[taicpu(p).opsize]);
|
|
|
|
- ptaiprop(p.optinfo)^.regs[getsupreg(taicpu(p).oper[0]^.reg)].memwrite :=
|
|
|
|
- taicpu(p);
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- DestroyRefs(p, taicpu(p).oper[1]^.ref^, RS_INVALID,topsize2tcgsize[taicpu(p).opsize]);
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- top_Const:
|
|
|
|
- begin
|
|
|
|
- case taicpu(p).oper[1]^.typ Of
|
|
|
|
- top_reg:
|
|
|
|
- begin
|
|
|
|
- tmpsupreg := getsupreg(taicpu(p).oper[1]^.reg);
|
|
|
|
-{$ifdef statedebug}
|
|
|
|
- hp := tai_comment.Create(strpnew('destroying '+std_regname(newreg(R_INTREGISTER,tmpsupreg,R_SUBWHOLE))));
|
|
|
|
- insertllitem(list,p,p.next,hp);
|
|
|
|
-{$endif statedebug}
|
|
|
|
- With curprop^.regs[tmpsupreg] Do
|
|
|
|
- begin
|
|
|
|
- DestroyReg(curprop, tmpsupreg, true);
|
|
|
|
- typ := Con_Const;
|
|
|
|
- StartMod := p;
|
|
|
|
- nrOfMods := 1;
|
|
|
|
- end
|
|
|
|
- end;
|
|
|
|
- top_ref:
|
|
|
|
- begin
|
|
|
|
- readref(curprop, taicpu(p).oper[1]^.ref);
|
|
|
|
- DestroyRefs(p, taicpu(p).oper[1]^.ref^, RS_INVALID,topsize2tcgsize[taicpu(p).opsize]);
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- A_DIV, A_IDIV, A_MUL:
|
|
|
|
- begin
|
|
|
|
- ReadOp(curprop, taicpu(p).oper[0]^);
|
|
|
|
- readreg(curprop,RS_EAX);
|
|
|
|
- if (taicpu(p).OpCode = A_IDIV) or
|
|
|
|
- (taicpu(p).OpCode = A_DIV) then
|
|
|
|
- begin
|
|
|
|
- readreg(curprop,RS_EDX);
|
|
|
|
- end;
|
|
|
|
-{$ifdef statedebug}
|
|
|
|
- hp := tai_comment.Create(strpnew('destroying eax and edx'));
|
|
|
|
- insertllitem(list,p,p.next,hp);
|
|
|
|
-{$endif statedebug}
|
|
|
|
-{ DestroyReg(curprop, RS_EAX, true);}
|
|
|
|
- AddInstr2RegContents({$ifdef statedebug}list,{$endif}
|
|
|
|
- taicpu(p), RS_EAX);
|
|
|
|
- DestroyReg(curprop, RS_EDX, true);
|
|
|
|
- LastFlagsChangeProp := curprop;
|
|
|
|
- end;
|
|
|
|
- A_IMUL:
|
|
|
|
- begin
|
|
|
|
- ReadOp(curprop,taicpu(p).oper[0]^);
|
|
|
|
- if (taicpu(p).ops >= 2) then
|
|
|
|
- ReadOp(curprop,taicpu(p).oper[1]^);
|
|
|
|
- if (taicpu(p).ops <= 2) then
|
|
|
|
- if (taicpu(p).ops=1) then
|
|
|
|
- begin
|
|
|
|
- readreg(curprop,RS_EAX);
|
|
|
|
-{$ifdef statedebug}
|
|
|
|
- hp := tai_comment.Create(strpnew('destroying eax and edx'));
|
|
|
|
- insertllitem(list,p,p.next,hp);
|
|
|
|
-{$endif statedebug}
|
|
|
|
-{ DestroyReg(curprop, RS_EAX, true); }
|
|
|
|
- AddInstr2RegContents({$ifdef statedebug}list,{$endif}
|
|
|
|
- taicpu(p), RS_EAX);
|
|
|
|
- DestroyReg(curprop,RS_EDX, true)
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- AddInstr2OpContents(
|
|
|
|
- {$ifdef statedebug}list,{$endif}
|
|
|
|
- taicpu(p), taicpu(p).oper[1]^)
|
|
|
|
- else
|
|
|
|
- AddInstr2OpContents({$ifdef statedebug}list,{$endif}
|
|
|
|
- taicpu(p), taicpu(p).oper[2]^);
|
|
|
|
- LastFlagsChangeProp := curprop;
|
|
|
|
- end;
|
|
|
|
- A_LEA:
|
|
|
|
- begin
|
|
|
|
- readop(curprop,taicpu(p).oper[0]^);
|
|
|
|
- if reginref(getsupreg(taicpu(p).oper[1]^.reg),taicpu(p).oper[0]^.ref^) then
|
|
|
|
- AddInstr2RegContents({$ifdef statedebug}list,{$endif}
|
|
|
|
- taicpu(p), getsupreg(taicpu(p).oper[1]^.reg))
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
-{$ifdef statedebug}
|
|
|
|
- hp := tai_comment.Create(strpnew('destroying & initing'+
|
|
|
|
- std_regname(taicpu(p).oper[1]^.reg)));
|
|
|
|
- insertllitem(list,p,p.next,hp);
|
|
|
|
-{$endif statedebug}
|
|
|
|
- destroyreg(curprop,getsupreg(taicpu(p).oper[1]^.reg),true);
|
|
|
|
- with curprop^.regs[getsupreg(taicpu(p).oper[1]^.reg)] Do
|
|
|
|
- begin
|
|
|
|
- typ := con_ref;
|
|
|
|
- startmod := p;
|
|
|
|
- nrOfMods := 1;
|
|
|
|
- end
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- Cnt := 1;
|
|
|
|
- while (Cnt <= maxinschanges) and
|
|
|
|
- (InstrProp.Ch[Cnt] <> Ch_None) Do
|
|
|
|
- begin
|
|
|
|
- case InstrProp.Ch[Cnt] Of
|
|
|
|
- Ch_REAX..Ch_REDI:
|
|
|
|
- begin
|
|
|
|
- tmpsupreg:=tch2reg(InstrProp.Ch[Cnt]);
|
|
|
|
- readreg(curprop,tmpsupreg);
|
|
|
|
- end;
|
|
|
|
- Ch_WEAX..Ch_RWEDI:
|
|
|
|
- begin
|
|
|
|
- if (InstrProp.Ch[Cnt] >= Ch_RWEAX) then
|
|
|
|
- begin
|
|
|
|
- tmpsupreg:=tch2reg(InstrProp.Ch[Cnt]);
|
|
|
|
- readreg(curprop,tmpsupreg);
|
|
|
|
- end;
|
|
|
|
-{$ifdef statedebug}
|
|
|
|
- hp := tai_comment.Create(strpnew('destroying '+
|
|
|
|
- std_regname(tch2reg(InstrProp.Ch[Cnt]))));
|
|
|
|
- insertllitem(list,p,p.next,hp);
|
|
|
|
-{$endif statedebug}
|
|
|
|
- tmpsupreg:=tch2reg(InstrProp.Ch[Cnt]);
|
|
|
|
- DestroyReg(curprop,tmpsupreg, true);
|
|
|
|
- end;
|
|
|
|
- Ch_MEAX..Ch_MEDI:
|
|
|
|
- begin
|
|
|
|
- tmpsupreg:=tch2reg(InstrProp.Ch[Cnt]);
|
|
|
|
- AddInstr2RegContents({$ifdef statedebug} list,{$endif}
|
|
|
|
- taicpu(p),tmpsupreg);
|
|
|
|
- end;
|
|
|
|
- Ch_CDirFlag: curprop^.DirFlag := F_notSet;
|
|
|
|
- Ch_SDirFlag: curprop^.DirFlag := F_Set;
|
|
|
|
- Ch_Rop1: ReadOp(curprop, taicpu(p).oper[0]^);
|
|
|
|
- Ch_Rop2: ReadOp(curprop, taicpu(p).oper[1]^);
|
|
|
|
- Ch_ROp3: ReadOp(curprop, taicpu(p).oper[2]^);
|
|
|
|
- Ch_Wop1..Ch_RWop1:
|
|
|
|
- begin
|
|
|
|
- if (InstrProp.Ch[Cnt] in [Ch_RWop1]) then
|
|
|
|
- ReadOp(curprop, taicpu(p).oper[0]^);
|
|
|
|
- DestroyOp(p, taicpu(p).oper[0]^);
|
|
|
|
- end;
|
|
|
|
- Ch_Mop1:
|
|
|
|
- AddInstr2OpContents({$ifdef statedebug} list, {$endif}
|
|
|
|
- taicpu(p), taicpu(p).oper[0]^);
|
|
|
|
- Ch_Wop2..Ch_RWop2:
|
|
|
|
- begin
|
|
|
|
- if (InstrProp.Ch[Cnt] = Ch_RWop2) then
|
|
|
|
- ReadOp(curprop, taicpu(p).oper[1]^);
|
|
|
|
- DestroyOp(p, taicpu(p).oper[1]^);
|
|
|
|
- end;
|
|
|
|
- Ch_Mop2:
|
|
|
|
- AddInstr2OpContents({$ifdef statedebug} list, {$endif}
|
|
|
|
- taicpu(p), taicpu(p).oper[1]^);
|
|
|
|
- Ch_WOp3..Ch_RWOp3:
|
|
|
|
- begin
|
|
|
|
- if (InstrProp.Ch[Cnt] = Ch_RWOp3) then
|
|
|
|
- ReadOp(curprop, taicpu(p).oper[2]^);
|
|
|
|
- DestroyOp(p, taicpu(p).oper[2]^);
|
|
|
|
- end;
|
|
|
|
- Ch_Mop3:
|
|
|
|
- AddInstr2OpContents({$ifdef statedebug} list, {$endif}
|
|
|
|
- taicpu(p), taicpu(p).oper[2]^);
|
|
|
|
- Ch_WMemEDI:
|
|
|
|
- begin
|
|
|
|
- readreg(curprop, RS_EDI);
|
|
|
|
- fillchar(tmpref, SizeOf(tmpref), 0);
|
|
|
|
- tmpref.base := NR_EDI;
|
|
|
|
- tmpref.index := NR_EDI;
|
|
|
|
- DestroyRefs(p, tmpref,RS_INVALID,OS_32)
|
|
|
|
- end;
|
|
|
|
- Ch_RFlags:
|
|
|
|
- if assigned(LastFlagsChangeProp) then
|
|
|
|
- LastFlagsChangeProp^.FlagsUsed := true;
|
|
|
|
- Ch_WFlags:
|
|
|
|
- LastFlagsChangeProp := curprop;
|
|
|
|
- Ch_RWFlags:
|
|
|
|
- begin
|
|
|
|
- if assigned(LastFlagsChangeProp) then
|
|
|
|
- LastFlagsChangeProp^.FlagsUsed := true;
|
|
|
|
- LastFlagsChangeProp := curprop;
|
|
|
|
- end;
|
|
|
|
- Ch_FPU:;
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
-{$ifdef statedebug}
|
|
|
|
- hp := tai_comment.Create(strpnew(
|
|
|
|
- 'destroying all regs for prev instruction'));
|
|
|
|
- insertllitem(list,p, p.next,hp);
|
|
|
|
-{$endif statedebug}
|
|
|
|
- DestroyAllRegs(curprop,true,true);
|
|
|
|
- LastFlagsChangeProp := curprop;
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- inc(Cnt);
|
|
|
|
- end
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
-{$ifdef statedebug}
|
|
|
|
- hp := tai_comment.Create(strpnew(
|
|
|
|
- 'destroying all regs: unknown tai: '+tostr(ord(p.typ))));
|
|
|
|
- insertllitem(list,p, p.next,hp);
|
|
|
|
-{$endif statedebug}
|
|
|
|
- DestroyAllRegs(curprop,true,true);
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- inc(InstrCnt);
|
|
|
|
- prev := p;
|
|
|
|
- GetNextInstruction(p, p);
|
|
|
|
- end;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-function tdfaobj.pass_generate_code: boolean;
|
|
|
|
-begin
|
|
|
|
- if initdfapass2 then
|
|
|
|
- begin
|
|
|
|
- dodfapass2;
|
|
|
|
- pass_generate_code := true
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- pass_generate_code := false;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-{$push}
|
|
|
|
-{$r-}
|
|
|
|
-function tdfaobj.getlabelwithsym(sym: tasmlabel): tai;
|
|
|
|
-begin
|
|
|
|
- if (sym.labelnr >= lolab) and
|
|
|
|
- (sym.labelnr <= hilab) then { range check, a jump can go past an assembler block! }
|
|
|
|
- getlabelwithsym := labeltable^[sym.labelnr-lolab].taiobj
|
|
|
|
- else
|
|
|
|
- getlabelwithsym := nil;
|
|
|
|
-end;
|
|
|
|
-{$pop}
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-procedure tdfaobj.clear;
|
|
|
|
-begin
|
|
|
|
- if labdif <> 0 then
|
|
|
|
- begin
|
|
|
|
- freemem(labeltable);
|
|
|
|
- labeltable := nil;
|
|
|
|
- end;
|
|
|
|
- if assigned(taipropblock) then
|
|
|
|
- begin
|
|
|
|
- freemem(taipropblock, nroftaiobjs*sizeof(ttaiprop));
|
|
|
|
- taipropblock := nil;
|
|
|
|
- end;
|
|
|
|
-end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-end.
|
|
|