diff options
Diffstat (limited to 'closures/compiler/i386/daopt386.pas')
-rw-r--r-- | closures/compiler/i386/daopt386.pas | 2816 |
1 files changed, 2816 insertions, 0 deletions
diff --git a/closures/compiler/i386/daopt386.pas b/closures/compiler/i386/daopt386.pas new file mode 100644 index 0000000000..bdcaea11a2 --- /dev/null +++ b/closures/compiler/i386/daopt386.pas @@ -0,0 +1,2816 @@ +{ + 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); + + + +{********************************* 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 RefsEqual(const R1, R2: TReference): Boolean; +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; + +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; + + +function refsequal(const r1, r2: treference): boolean; +begin + refsequal := + (r1.offset = r2.offset) 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; + + +{$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; + 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. |