|
@@ -1,2265 +0,0 @@
|
|
|
-{
|
|
|
- Copyright (c) 1998-2002 by Jonas Maebe, member of the Free Pascal
|
|
|
- development team
|
|
|
-
|
|
|
- This unit contains the common subexpression elimination procedure.
|
|
|
-
|
|
|
- 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 CSOpt386;
|
|
|
-
|
|
|
-{$i fpcdefs.inc}
|
|
|
-
|
|
|
-interface
|
|
|
-
|
|
|
-uses aasmbase,aasmtai,aasmdata,aasmcpu, cpuinfo, cpubase, cgbase;
|
|
|
-
|
|
|
-function CSE(asml: TAsmList; first, last: tai; pass: longint): boolean;
|
|
|
-
|
|
|
-function doReplaceReg(hp: taicpu; newReg, orgReg: tsuperregister): boolean;
|
|
|
-function changeOp(var o: toper; newReg, orgReg: tsuperregister): boolean;
|
|
|
-function storeBack(start, current: tai; orgReg, newReg: tsuperregister): boolean;
|
|
|
-function NoHardCodedRegs(p: taicpu; orgReg, newReg: tsuperregister): boolean;
|
|
|
-function RegSizesOK(oldReg,newReg: tsuperregister; p: taicpu): boolean;
|
|
|
-
|
|
|
-implementation
|
|
|
-
|
|
|
-uses
|
|
|
-{$ifdef csdebug}
|
|
|
- cutils,
|
|
|
-{$else}
|
|
|
- {$ifdef replaceregdebug}cutils,{$endif}
|
|
|
-{$endif}
|
|
|
- globtype, verbose, procinfo, globals, daopt386, rgobj, rropt386,cgutils;
|
|
|
-
|
|
|
-{
|
|
|
-function TaiInSequence(P: tai; Const Seq: TContent): Boolean;
|
|
|
-var P1: tai;
|
|
|
- Counter: Byte;
|
|
|
- TmpResult: Boolean;
|
|
|
-begin
|
|
|
- TmpResult := False;
|
|
|
- P1 := Seq.StartMod;
|
|
|
- Counter := 1;
|
|
|
- while not(TmpResult) and
|
|
|
- (Counter <= Seq.NrofMods) do
|
|
|
- begin
|
|
|
- if (P = P1) then TmpResult := True;
|
|
|
- inc(Counter);
|
|
|
- p1 := tai(p1.Next);
|
|
|
- end;
|
|
|
- TaiInSequence := TmpResult;
|
|
|
-end;
|
|
|
-}
|
|
|
-
|
|
|
-function modifiesConflictingMemLocation(p1: tai; supreg: tsuperregister; c: tregContent;
|
|
|
- var regsStillValid: tregset; onlymem: boolean; var invalsmemwrite: boolean): boolean;
|
|
|
-var
|
|
|
- p: taicpu;
|
|
|
- tmpRef: treference;
|
|
|
- regCounter: tsuperregister;
|
|
|
- opCount: longint;
|
|
|
- dummy: boolean;
|
|
|
-begin
|
|
|
- modifiesConflictingMemLocation := false;
|
|
|
- invalsmemwrite := false;
|
|
|
- if p1.typ <> ait_instruction then
|
|
|
- exit;
|
|
|
- p := taicpu(p1);
|
|
|
- case p.opcode of
|
|
|
- A_MOV,A_MOVSX,A_MOVZX:
|
|
|
- if p.oper[1]^.typ = top_ref then
|
|
|
- for regCounter := RS_EAX to RS_EDI do
|
|
|
- begin
|
|
|
- if (p.oper[0]^.typ<>top_reg) or
|
|
|
- (getregtype(p.oper[0]^.reg) <> R_INTREGISTER) then
|
|
|
- break;
|
|
|
- if writeToMemDestroysContents(getsupreg(p.oper[0]^.reg),p.oper[1]^.ref^,
|
|
|
- regCounter,topsize2tcgsize[p.opsize],c[regCounter],dummy) then
|
|
|
- begin
|
|
|
- exclude(regsStillValid,regCounter);
|
|
|
- modifiesConflictingMemLocation := not(supreg in regsStillValid);
|
|
|
- end;
|
|
|
- if (regcounter = supreg) then
|
|
|
- invalsmemwrite := invalsmemwrite or dummy;
|
|
|
- end
|
|
|
- else
|
|
|
-{ if is_reg_var[getsupreg(p.oper[1]^.reg)] then }
|
|
|
- if not onlymem then
|
|
|
- for regCounter := RS_EAX to RS_EDI do
|
|
|
- begin
|
|
|
- if writeDestroysContents(p.oper[1]^,regCounter,topsize2tcgsize[p.opsize],c[regCounter],dummy) then
|
|
|
- begin
|
|
|
- exclude(regsStillValid,regCounter);
|
|
|
- modifiesConflictingMemLocation := not(supreg in regsStillValid);
|
|
|
- end
|
|
|
- end;
|
|
|
- A_DIV, A_IDIV, A_MUL, A_IMUL:
|
|
|
- begin
|
|
|
- if not onlymem then
|
|
|
- if (p.ops = 1) then
|
|
|
- begin
|
|
|
- for regCounter := RS_EAX to RS_EDI do
|
|
|
- begin
|
|
|
- if writeToRegDestroysContents(RS_EDX,regCounter,c[regCounter]) then
|
|
|
- begin
|
|
|
- exclude(regsStillValid,RS_EDX);
|
|
|
- modifiesConflictingMemLocation := not(supreg in regsStillValid);
|
|
|
- end;
|
|
|
- if writeToRegDestroysContents(RS_EAX,regCounter,c[regCounter]) then
|
|
|
- begin
|
|
|
- exclude(regsStillValid,RS_EAX);
|
|
|
- modifiesConflictingMemLocation := not(supreg in regsStillValid);
|
|
|
- end;
|
|
|
- end
|
|
|
- end
|
|
|
- else
|
|
|
- { only possible for imul }
|
|
|
- { last operand is always destination }
|
|
|
- for regCounter := RS_EAX to RS_EDI do
|
|
|
- begin
|
|
|
- if writeDestroysContents(p.oper[p.ops-1]^,regCounter,topsize2tcgsize[p.opsize],c[regCounter],dummy) then
|
|
|
- begin
|
|
|
- exclude(regsStillValid,regCounter);
|
|
|
- modifiesConflictingMemLocation := not(supreg in regsStillValid);
|
|
|
- end
|
|
|
- end
|
|
|
- end;
|
|
|
- else
|
|
|
- for opCount := 1 to maxinschanges do
|
|
|
- case InsProp[p.opcode].Ch[opCount] of
|
|
|
- Ch_MOp1,CH_WOp1,CH_RWOp1:
|
|
|
- if not(onlymem) or
|
|
|
- (p.oper[0]^.typ = top_ref) then
|
|
|
-{ or ((p.oper[0]^.typ = top_reg) and }
|
|
|
-{ is_reg_var[getsupreg(p.oper[0]^.reg)]) then }
|
|
|
- for regCounter := RS_EAX to RS_EDI do
|
|
|
- begin
|
|
|
- if writeDestroysContents(p.oper[0]^,regCounter,topsize2tcgsize[p.opsize],c[regCounter],dummy) then
|
|
|
- begin
|
|
|
- exclude(regsStillValid,regCounter);
|
|
|
- modifiesConflictingMemLocation := not(supreg in regsStillValid);
|
|
|
- end;
|
|
|
- if (regcounter = supreg) then
|
|
|
- invalsmemwrite := invalsmemwrite or dummy;
|
|
|
- end;
|
|
|
- Ch_MOp2,CH_WOp2,CH_RWOp2:
|
|
|
- if not(onlymem) or
|
|
|
- (p.oper[1]^.typ = top_ref) then
|
|
|
-{ or ((p.oper[1]^.typ = top_reg) and }
|
|
|
-{ is_reg_var[getsupreg(p.oper[1]^.reg)]) then }
|
|
|
- for regCounter := RS_EAX to RS_EDI do
|
|
|
- begin
|
|
|
- if writeDestroysContents(p.oper[1]^,regCounter,topsize2tcgsize[p.opsize],c[regCounter],dummy) then
|
|
|
- begin
|
|
|
- exclude(regsStillValid,regCounter);
|
|
|
- modifiesConflictingMemLocation := not(supreg in regsStillValid);
|
|
|
- end;
|
|
|
- if (regcounter = supreg) then
|
|
|
- invalsmemwrite := invalsmemwrite or dummy;
|
|
|
- end;
|
|
|
- Ch_MOp3,CH_WOp3,CH_RWOp3:
|
|
|
- if not(onlymem) or
|
|
|
- (p.oper[2]^.typ = top_ref) then
|
|
|
-{ or ((p.oper[2]^.typ = top_reg) and }
|
|
|
-{ is_reg_var[getsupreg(p.oper[2]^.reg)]) then }
|
|
|
- for regCounter := RS_EAX to RS_EDI do
|
|
|
- begin
|
|
|
- if writeDestroysContents(p.oper[2]^,regCounter,topsize2tcgsize[p.opsize],c[regCounter],dummy) then
|
|
|
- begin
|
|
|
- exclude(regsStillValid,regCounter);
|
|
|
- modifiesConflictingMemLocation := not(supreg in regsStillValid);
|
|
|
- end;
|
|
|
- if (regcounter = supreg) then
|
|
|
- invalsmemwrite := invalsmemwrite or dummy;
|
|
|
- end;
|
|
|
- Ch_WMemEDI:
|
|
|
- begin
|
|
|
- fillchar(tmpref,sizeof(tmpref),0);
|
|
|
- tmpRef.base := NR_EDI;
|
|
|
- tmpRef.index := NR_EDI;
|
|
|
- for regCounter := RS_EAX to RS_EDI do
|
|
|
- begin
|
|
|
- if writeToMemDestroysContents(RS_INVALID,tmpRef,regCounter,OS_32,c[regCounter],dummy) then
|
|
|
- begin
|
|
|
- exclude(regsStillValid,regCounter);
|
|
|
- modifiesConflictingMemLocation := not(supreg in regsStillValid);
|
|
|
- end;
|
|
|
- if (regcounter = supreg) then
|
|
|
- invalsmemwrite := invalsmemwrite or dummy;
|
|
|
- end;
|
|
|
- end;
|
|
|
- end;
|
|
|
- end;
|
|
|
-end;
|
|
|
-
|
|
|
-
|
|
|
-function isSimpleMemLoc(const ref: treference): boolean;
|
|
|
-begin
|
|
|
-{ isSimpleMemLoc :=
|
|
|
- (ref.index = RS_NO) and
|
|
|
- not(ref.base in (rg.usableregsint+[RS_EDI]));}
|
|
|
- isSimpleMemLoc :=
|
|
|
- (ref.index = NR_NO) and
|
|
|
- ((ref.base = NR_NO) or
|
|
|
- not(getsupreg(ref.base) in [RS_EAX,RS_EBX,RS_ECX,RS_EDX,RS_ESI,RS_EDI]));
|
|
|
-end;
|
|
|
-
|
|
|
-
|
|
|
-{checks whether the current instruction sequence (starting with p) and the
|
|
|
- one between StartMod and EndMod of Reg are the same. if so, the number of
|
|
|
- instructions that match is stored in Found and true is returned, otherwise
|
|
|
- Found holds the number of instructions between StartMod and EndMod and false
|
|
|
- is returned}
|
|
|
-function CheckSequence(p: tai; var prev: tai; supreg: tsuperregister; var Found: Longint;
|
|
|
- var reginfo: toptreginfo; findPrevSeqs: boolean): Boolean;
|
|
|
-
|
|
|
-var
|
|
|
- regsNotRead, regsStillValid : tregset;
|
|
|
- checkingPrevSequences,
|
|
|
- passedFlagsModifyingInstr : boolean;
|
|
|
-
|
|
|
- function getPrevSequence(p: tai; supreg: tsuperregister; currentPrev: tai; var newPrev: tai): tsuperregister;
|
|
|
-
|
|
|
- const
|
|
|
- current_reg: tsuperregister = RS_INVALID;
|
|
|
-
|
|
|
- function stillValid(p: tai): boolean;
|
|
|
- var
|
|
|
- hp: tai;
|
|
|
- begin
|
|
|
- { only regvars are still used at jump instructions }
|
|
|
- if (cs_opt_regvar in current_settings.optimizerswitches) and
|
|
|
- (p.typ = ait_instruction) and
|
|
|
- taicpu(p).is_jmp then
|
|
|
- regsstillvalid := regsstillvalid - ptaiprop(p.optinfo)^.usedregs;
|
|
|
-
|
|
|
- stillValid :=
|
|
|
- (p.typ = ait_instruction) and
|
|
|
- (taicpu(p).opcode <> a_jmp) and
|
|
|
- (ptaiprop(p.optinfo)^.regs[supreg].wstate =
|
|
|
- ptaiprop(currentPrev.optinfo)^.regs[supreg].wstate) and
|
|
|
- { in case destroyreg is called with doIncState = false }
|
|
|
- (ptaiprop(p.optinfo)^.regs[supreg].typ =
|
|
|
- ptaiprop(currentPrev.optinfo)^.regs[supreg].typ) and
|
|
|
- (supreg in (regsNotRead * regsStillValid));
|
|
|
- { stop if the register was still used right before a (conditional) }
|
|
|
- { jump, since in that case its current contents could still be }
|
|
|
- { used in the other path of the jump) }
|
|
|
- if (p.typ = ait_instruction) and
|
|
|
- (taicpu(p).is_jmp) and
|
|
|
- getlastinstruction(p,hp) then
|
|
|
- stillValid := stillValid and
|
|
|
- not(supreg in ptaiprop(hp.optinfo)^.usedregs);
|
|
|
- passedFlagsModifyingInstr := passedFlagsModifyingInstr or
|
|
|
- instrWritesFlags(currentPrev);
|
|
|
- end;
|
|
|
-
|
|
|
-
|
|
|
- function findChangedRegister(p: tai): tsuperregister;
|
|
|
- var
|
|
|
- regCounter, loopstart: tsuperregister;
|
|
|
- begin
|
|
|
- if (current_reg <> RS_INVALID) then
|
|
|
- loopstart := succ(current_reg)
|
|
|
- else
|
|
|
- loopstart := RS_EAX;
|
|
|
- for regCounter := loopstart to RS_EDI do
|
|
|
- with ptaiprop(p.optinfo)^.regs[regCounter] do
|
|
|
- if ((startmod <>
|
|
|
- ptaiprop(currentPrev.optinfo)^.regs[regCounter].startmod) or
|
|
|
- (nrofMods <>
|
|
|
- ptaiprop(currentPrev.optinfo)^.regs[regCounter].nrofMods)) and
|
|
|
- (ptaiprop(p.optinfo)^.regs[regCounter].typ in [con_ref,con_noRemoveRef]) then
|
|
|
- begin
|
|
|
- findChangedRegister := regCounter;
|
|
|
- current_reg := regCounter;
|
|
|
- exit;
|
|
|
- end;
|
|
|
- current_reg := RS_INVALID;
|
|
|
- findChangedRegister := RS_INVALID;
|
|
|
- end;
|
|
|
-
|
|
|
-
|
|
|
- var
|
|
|
- hp, prevFound: tai;
|
|
|
- tmpResult, regCounter: tsuperregister;
|
|
|
- invalsmemwrite: boolean;
|
|
|
- begin
|
|
|
- if (current_reg <> RS_EDI) and
|
|
|
- (current_reg <> RS_INVALID) then
|
|
|
- begin
|
|
|
- tmpResult := findChangedRegister(currentPrev);
|
|
|
- if tmpResult <> RS_INVALID then
|
|
|
- begin
|
|
|
- getPrevSequence := tmpResult;
|
|
|
- exit;
|
|
|
- end;
|
|
|
- end;
|
|
|
-
|
|
|
- getPrevSequence := RS_INVALID;
|
|
|
- passedFlagsModifyingInstr := passedFlagsModifyingInstr or
|
|
|
- instrWritesFlags(currentPrev);
|
|
|
- if (cs_opt_regvar in current_settings.optimizerswitches) and
|
|
|
- (currentprev.typ = ait_instruction) and
|
|
|
- taicpu(currentprev).is_jmp then
|
|
|
- regsstillvalid := regsstillvalid - ptaiprop(currentprev.optinfo)^.usedregs;
|
|
|
-
|
|
|
- if not getLastInstruction(currentPrev,hp) then
|
|
|
- exit;
|
|
|
-
|
|
|
- prevFound := currentPrev;
|
|
|
- tmpResult := RS_INVALID;
|
|
|
-
|
|
|
- while (tmpResult = RS_INVALID) and
|
|
|
- stillValid(hp) and
|
|
|
- (ptaiprop(prevFound.optinfo)^.canBeRemoved or
|
|
|
- not(modifiesConflictingMemLocation(prevFound,supreg,
|
|
|
- ptaiprop(p.optinfo)^.regs,regsStillValid,false, invalsmemwrite))) do
|
|
|
- begin
|
|
|
- { only update the regsread for the instructions we already passed }
|
|
|
- if not(ptaiprop(prevFound.optinfo)^.canBeRemoved) then
|
|
|
- for regCounter := RS_EAX to RS_EDI do
|
|
|
- if regReadByInstruction(regCounter,prevFound) then
|
|
|
- exclude(regsNotRead,regCounter);
|
|
|
-
|
|
|
- { in case getPreviousInstruction fails and sets hp to nil in the }
|
|
|
- { next iteration }
|
|
|
- prevFound := hp;
|
|
|
- if not(ptaiprop(hp.optinfo)^.canBeRemoved) then
|
|
|
- tmpResult := findChangedRegister(hp);
|
|
|
- if not getLastInstruction(hp,hp) then
|
|
|
- break;
|
|
|
- end;
|
|
|
- getPrevSequence := tmpResult;
|
|
|
- if tmpResult <> RS_INVALID then
|
|
|
- newPrev := prevFound;
|
|
|
- end;
|
|
|
-
|
|
|
-
|
|
|
- function getNextRegToTest(var prev: tai; currentReg: tsuperregister): tsuperregister;
|
|
|
- begin
|
|
|
- getNextRegToTest := RS_INVALID;
|
|
|
- if not checkingPrevSequences then
|
|
|
- begin
|
|
|
- if (currentreg = RS_INVALID) then
|
|
|
- currentreg := RS_EAX
|
|
|
- else
|
|
|
- inc(currentreg);
|
|
|
- while (currentReg <= RS_EDI) and
|
|
|
- not(ptaiprop(prev.optinfo)^.regs[currentReg].typ in [con_ref,con_noRemoveRef]) do
|
|
|
- inc(currentReg);
|
|
|
- if currentReg > RS_EDI then
|
|
|
- begin
|
|
|
- if (taicpu(p).oper[0]^.typ <> top_ref) or
|
|
|
- isSimpleMemLoc(taicpu(p).oper[0]^.ref^) then
|
|
|
- begin
|
|
|
- checkingPrevSequences := true;
|
|
|
- end
|
|
|
- else
|
|
|
- getNextRegToTest := RS_INVALID;
|
|
|
- end
|
|
|
- else
|
|
|
- getNextRegToTest := currentReg;
|
|
|
- end;
|
|
|
- if checkingPrevSequences then
|
|
|
- if findPrevSeqs then
|
|
|
- getNextRegToTest :=
|
|
|
- getPrevSequence(p,supreg,prev,prev)
|
|
|
- else
|
|
|
- getNextRegToTest := RS_INVALID;
|
|
|
- end;
|
|
|
-
|
|
|
-
|
|
|
- function changedreginvalidatedbetween(const oldreginfo: toptreginfo; var newreginfo: toptreginfo; startp,endp,current: tai): boolean;
|
|
|
- var
|
|
|
- orgdiffregs,diffregs: tregset;
|
|
|
- runner: tai;
|
|
|
- invalsmemwrite: boolean;
|
|
|
- begin
|
|
|
- diffregs := newreginfo.newregsencountered - oldreginfo.newregsencountered;
|
|
|
- orgdiffregs := diffregs;
|
|
|
- if diffregs <> [] then
|
|
|
- begin
|
|
|
- runner := startp;
|
|
|
- repeat
|
|
|
- modifiesConflictingMemLocation(runner,RS_EAX { dummy },ptaiprop(current.optinfo)^.regs,diffregs,true,invalsmemwrite);
|
|
|
- if orgdiffregs <> diffregs then
|
|
|
- begin
|
|
|
- changedreginvalidatedbetween := true;
|
|
|
- newreginfo := oldreginfo;
|
|
|
- exit;
|
|
|
- end;
|
|
|
- getnextinstruction(runner,runner);
|
|
|
- until (runner = endp);
|
|
|
- end;
|
|
|
- changedreginvalidatedbetween := false;
|
|
|
- end;
|
|
|
-
|
|
|
-var
|
|
|
- prevreginfo: toptreginfo;
|
|
|
- hp2, hp3{, EndMod}, prevhp3, highPrev, orgPrev, pprev: tai;
|
|
|
- {Cnt,} OldNrofMods: Longint;
|
|
|
- startRegInfo, OrgRegInfo, HighRegInfo: toptreginfo;
|
|
|
- regModified, lastregloadremoved: array[RS_EAX..RS_ESP] of boolean;
|
|
|
- HighFound, OrgRegFound: longint;
|
|
|
- regcounter, regCounter2, tmpreg, base, index: tsuperregister;
|
|
|
- OrgRegResult: Boolean;
|
|
|
- TmpResult, flagResultsNeeded: Boolean;
|
|
|
-begin {CheckSequence}
|
|
|
- TmpResult := False;
|
|
|
- FillChar(OrgRegInfo, Sizeof(OrgRegInfo), 0);
|
|
|
- FillChar(startRegInfo, sizeof(startRegInfo), 0);
|
|
|
- FillChar(HighRegInfo, sizeof(HighRegInfo), 0);
|
|
|
- FillChar(prevreginfo, sizeof(prevreginfo), 0);
|
|
|
- OrgRegFound := 0;
|
|
|
- HighFound := 0;
|
|
|
- OrgRegResult := False;
|
|
|
- highPrev := nil;
|
|
|
- orgPrev := nil;
|
|
|
- with startRegInfo do
|
|
|
- begin
|
|
|
- newRegsEncountered := [RS_EBP, RS_ESP];
|
|
|
- fillword(new2oldreg,sizeof(new2oldreg),RS_INVALID);
|
|
|
- new2OldReg[RS_EBP] := RS_EBP;
|
|
|
- new2OldReg[RS_ESP] := RS_ESP;
|
|
|
- oldRegsEncountered := newRegsEncountered;
|
|
|
- end;
|
|
|
-
|
|
|
- checkingPrevSequences := false;
|
|
|
- passedFlagsModifyingInstr := false;
|
|
|
- flagResultsNeeded := false;
|
|
|
- regsNotRead := [RS_EAX,RS_EBX,RS_ECX,RS_EDX,RS_ESP,RS_EBP,RS_EDI,RS_ESI];
|
|
|
- regsStillValid := regsNotRead;
|
|
|
- GetLastInstruction(p, prev);
|
|
|
- pprev := prev;
|
|
|
- tmpreg:=RS_INVALID;
|
|
|
- regCounter := getNextRegToTest(prev,tmpreg);
|
|
|
- while (regcounter <> RS_INVALID) do
|
|
|
- begin
|
|
|
- fillchar(regModified,sizeof(regModified),0);
|
|
|
- fillchar(lastregloadremoved,sizeof(lastregloadremoved),0);
|
|
|
- reginfo := startRegInfo;
|
|
|
- Found := 0;
|
|
|
- hp2 := ptaiprop(prev.optinfo)^.Regs[regcounter].StartMod;
|
|
|
- if (prev <> ptaiprop(prev.optinfo)^.Regs[regcounter].StartMod) then
|
|
|
- OldNrofMods := ptaiprop(prev.optinfo)^.Regs[regcounter].NrofMods
|
|
|
- else
|
|
|
- OldNrofMods := 1;
|
|
|
- hp3 := p;
|
|
|
- if checkingprevsequences then
|
|
|
- prevreginfo := reginfo;
|
|
|
- while (Found <> OldNrofMods) and
|
|
|
- { old new }
|
|
|
- InstructionsEquivalent(hp2, hp3, reginfo) and
|
|
|
- (not(checkingprevsequences) or
|
|
|
- not(changedreginvalidatedbetween(prevreginfo,reginfo,prev,p,hp3))) do
|
|
|
- begin
|
|
|
- if checkingprevsequences then
|
|
|
- begin
|
|
|
- prevreginfo := reginfo;
|
|
|
- end;
|
|
|
- if (hp3.typ = ait_instruction) and
|
|
|
- ((taicpu(hp3).opcode = A_MOV) or
|
|
|
- (taicpu(hp3).opcode = A_MOVZX) or
|
|
|
- (taicpu(hp3).opcode = A_LEA) or
|
|
|
- (taicpu(hp3).opcode = A_MOVSX)) and
|
|
|
- (taicpu(hp3).oper[1]^.typ = top_reg) and
|
|
|
- not(regInOp(getsupreg(taicpu(hp3).oper[1]^.reg),taicpu(hp3).oper[0]^)) then
|
|
|
- begin
|
|
|
- tmpreg := getsupreg(taicpu(hp3).oper[1]^.reg);
|
|
|
- lastregloadremoved[tmpreg] := ptaiprop(hp2.optinfo)^.canberemoved;
|
|
|
- reginfo.lastReload[tmpreg] := hp3;
|
|
|
- case taicpu(hp3).oper[0]^.typ of
|
|
|
- top_ref:
|
|
|
- begin
|
|
|
- base := getsupreg(taicpu(hp3).oper[0]^.ref^.base);
|
|
|
- index := getsupreg(taicpu(hp3).oper[0]^.ref^.index);
|
|
|
- if (found <> 0) and
|
|
|
- ((taicpu(hp3).oper[0]^.ref^.base = NR_NO) or
|
|
|
- regModified[base] or
|
|
|
- (base = getsupreg(current_procinfo.framepointer))) and
|
|
|
- ((taicpu(hp3).oper[0]^.ref^.index = NR_NO) or
|
|
|
- regModified[index]) and
|
|
|
- not(regInRef(tmpReg,taicpu(hp3).oper[0]^.ref^)) then
|
|
|
- begin
|
|
|
- with ptaiprop(hp3.optinfo)^.regs[tmpreg] do
|
|
|
- if nrofMods > (oldNrofMods - found) then
|
|
|
- oldNrofMods := found + nrofMods;
|
|
|
- { next is safe because instructions are equivalent }
|
|
|
- with ptaiprop(hp2.optinfo)^.regs[getsupreg(taicpu(hp2).oper[1]^.reg)] do
|
|
|
- if nrofMods > (oldNrofMods - found) then
|
|
|
- oldNrofMods := found + nrofMods;
|
|
|
- end;
|
|
|
- end;
|
|
|
- top_reg:
|
|
|
- if regModified[getsupreg(taicpu(hp3).oper[0]^.reg)] then
|
|
|
- begin
|
|
|
- with ptaiprop(hp3.optinfo)^.regs[tmpreg] do
|
|
|
- if nrofMods > (oldNrofMods - found) then
|
|
|
- oldNrofMods := found + nrofMods;
|
|
|
- with ptaiprop(hp2.optinfo)^.regs[getsupreg(taicpu(hp2).oper[1]^.reg)] do
|
|
|
- if nrofMods > (oldNrofMods - found) then
|
|
|
- oldNrofMods := found + nrofMods;
|
|
|
- end;
|
|
|
- end;
|
|
|
- end;
|
|
|
- for regCounter2 := RS_EAX to RS_EDI do
|
|
|
- regModified[regCounter2] := regModified[regCounter2] or
|
|
|
- regModifiedByInstruction(regCounter2,hp3);
|
|
|
- if flagResultsNeeded then
|
|
|
- flagResultsNeeded := not instrReadsFlags(hp3);
|
|
|
- if not flagResultsNeeded then
|
|
|
- flagResultsNeeded := ptaiprop(hp3.optinfo)^.FlagsUsed;
|
|
|
- inc(Found);
|
|
|
- prevhp3 := hp3;
|
|
|
- if (Found <> OldNrofMods) then
|
|
|
- if not GetNextInstruction(hp2, hp2) or
|
|
|
- not GetNextInstruction(hp3, hp3) then
|
|
|
- break;
|
|
|
- end;
|
|
|
-
|
|
|
- if assigned(hp3) then
|
|
|
- begin
|
|
|
- prevhp3 := hp3;
|
|
|
- getnextinstruction(hp3,hp3);
|
|
|
- end;
|
|
|
- if not assigned(hp3) or
|
|
|
- { a marker has no optinfo, which is used below }
|
|
|
- (hp3.typ = ait_marker) then
|
|
|
- hp3 := prevhp3;
|
|
|
-{
|
|
|
-a) movl -4(%ebp),%edx
|
|
|
- movl -12(%ebp),%ecx
|
|
|
- ...
|
|
|
- movl -8(%ebp),%eax
|
|
|
- movl -12(%ebp),%edx (marked as removable)
|
|
|
- movl (%eax,%edx),%eax (replaced by "movl (%eax,%ecx),%eax")
|
|
|
- ...
|
|
|
- movl -8(%ebp),%eax
|
|
|
- movl -12(%ebp),%edx
|
|
|
- movl (%eax,%edx),%eax
|
|
|
- movl (%edx),%edx
|
|
|
-
|
|
|
--> the "movl -12(ebp),%edx" can't be removed in the last sequence, because
|
|
|
- edx has not been replaced with ecx there, and edx is still used after the
|
|
|
- sequence
|
|
|
-
|
|
|
-b) tests/webtbs/tw4266.pp
|
|
|
-}
|
|
|
-
|
|
|
- { hp2 = instruction after previous sequence, pprev = instruction before }
|
|
|
- { current sequence, prev = instruction where the loads of the registers }
|
|
|
- { will be inserted }
|
|
|
- for regCounter2 := RS_EAX to RS_EDI do
|
|
|
- if (reginfo.new2OldReg[regCounter2] <> RS_INVALID) and
|
|
|
- { case a) above }
|
|
|
- (((regCounter2 in ptaiprop(hp3.optinfo)^.usedRegs) and
|
|
|
- (not regLoadedWithNewValue(regCounter2,false,hp3) and
|
|
|
- lastregloadremoved[regcounter2])) or
|
|
|
- { case b) above }
|
|
|
- ((ptaiprop(hp2.optinfo)^.regs[regCounter2].wstate <>
|
|
|
- ptaiprop(pprev.optinfo)^.regs[regcounter2].wstate)) or
|
|
|
- ((ptaiprop(hp2.optinfo)^.regs[reginfo.new2OldReg[regCounter2]].wstate <>
|
|
|
- ptaiprop(prev.optinfo)^.regs[reginfo.new2OldReg[regCounter2]].wstate))) then
|
|
|
- begin
|
|
|
- found := 0;
|
|
|
- break;
|
|
|
- end;
|
|
|
-
|
|
|
- if checkingPrevSequences then
|
|
|
- begin
|
|
|
- for regCounter2 := RS_EAX to RS_EDI do
|
|
|
- if (reginfo.new2OldReg[regCounter2] <> RS_INVALID) and
|
|
|
- (reginfo.new2OldReg[regCounter2] <> regCounter2) and
|
|
|
- (not(regCounter2 in (regsNotRead * regsStillValid)) or
|
|
|
- not(reginfo.new2OldReg[regCounter2] in regsStillValid)) then
|
|
|
- begin
|
|
|
- found := 0;
|
|
|
- break;
|
|
|
- end;
|
|
|
- if passedFlagsModifyingInstr and flagResultsNeeded then
|
|
|
- found := 0;
|
|
|
- end;
|
|
|
-
|
|
|
- TmpResult := true;
|
|
|
- if (found <> OldNrofMods) then
|
|
|
- TmpResult := false
|
|
|
- else if assigned(hp3) then
|
|
|
- for regcounter2 := RS_EAX to RS_EDI do
|
|
|
- if (regcounter2 in reginfo.regsLoadedforRef) and
|
|
|
- regModified[regcounter2] and
|
|
|
- (regcounter2 in ptaiprop(hp3.optinfo)^.usedRegs) and
|
|
|
- not regLoadedWithNewValue(regcounter2,false,hp3) then
|
|
|
- begin
|
|
|
- TmpResult := False;
|
|
|
- if (found > 0) then
|
|
|
- {this is correct because we only need to turn off the CanBeRemoved flag
|
|
|
- when an instruction has already been processed by CheckSequence
|
|
|
- (otherwise CanBeRemoved can't be true and thus can't have to be turned off).
|
|
|
- if it has already been processed by CheckSequence and flagged to be
|
|
|
- removed, it means that it has been checked against a previous sequence
|
|
|
- and that it was equal (otherwise CheckSequence would have returned false
|
|
|
- and the instruction wouldn't have been removed). if this "if found > 0"
|
|
|
- check is left out, incorrect optimizations are performed.}
|
|
|
- Found := ptaiprop(tai(p).optinfo)^.Regs[supreg].NrofMods;
|
|
|
- break;
|
|
|
- end;
|
|
|
-
|
|
|
- if TmpResult and
|
|
|
- (Found > HighFound) then
|
|
|
- begin
|
|
|
- highPrev := prev;
|
|
|
- HighFound := Found;
|
|
|
- HighRegInfo := reginfo;
|
|
|
- end;
|
|
|
- if (regcounter = supreg) then
|
|
|
- begin
|
|
|
- orgPrev := prev;
|
|
|
- OrgRegFound := Found;
|
|
|
- OrgRegResult := TmpResult;
|
|
|
- OrgRegInfo := reginfo
|
|
|
- end;
|
|
|
- regCounter := getNextRegToTest(prev,regCounter);
|
|
|
- end;
|
|
|
- if (HighFound > 0) and
|
|
|
- (not(OrgRegResult) Or
|
|
|
- (HighFound > OrgRegFound))
|
|
|
- then
|
|
|
- begin
|
|
|
- CheckSequence := True;
|
|
|
- prev := highPrev;
|
|
|
- reginfo := HighRegInfo;
|
|
|
- Found := HighFound
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- CheckSequence := OrgRegResult;
|
|
|
- prev := orgPrev;
|
|
|
- Found := OrgRegFound;
|
|
|
- reginfo := OrgRegInfo;
|
|
|
- end;
|
|
|
-end; {CheckSequence}
|
|
|
-
|
|
|
-
|
|
|
-procedure SetAlignReg(p: tai);
|
|
|
-Const alignSearch = 12;
|
|
|
-var regsUsable: TRegSet;
|
|
|
- prevInstrCount, nextInstrCount: Longint;
|
|
|
- prevState, nextWState,nextRState: Array[RS_EAX..RS_EDI] of byte;
|
|
|
- regCounter, lastRemoved: tsuperregister;
|
|
|
- prev, next: tai;
|
|
|
-{$ifdef alignregdebug}
|
|
|
- temp: tai;
|
|
|
-{$endif alignregdebug}
|
|
|
-begin
|
|
|
- regsUsable := [RS_EAX,RS_ECX,RS_EDX,RS_EBX,{R_ESP,RS_EBP,}RS_ESI,RS_EDI];
|
|
|
- for regCounter := RS_EAX to RS_EDI do
|
|
|
- begin
|
|
|
- prevState[regCounter] := ptaiprop(p.optinfo)^.Regs[regCounter].wState;
|
|
|
- nextWState[regCounter] := ptaiprop(p.optinfo)^.Regs[regCounter].wState;
|
|
|
- nextRState[regCounter] := ptaiprop(p.optinfo)^.Regs[regCounter].rState;
|
|
|
- end;
|
|
|
- getLastInstruction(p,prev);
|
|
|
- getNextInstruction(p,next);
|
|
|
- lastRemoved := getsupreg(tai_align(p).reg);
|
|
|
- nextInstrCount := 0;
|
|
|
- prevInstrCount := 0;
|
|
|
- while ((assigned(prev) and
|
|
|
- assigned(prev.optinfo) and
|
|
|
- (prevInstrCount < alignSearch)) or
|
|
|
- (assigned(next) and
|
|
|
- assigned(next.optinfo) and
|
|
|
- (nextInstrCount < alignSearch))) and
|
|
|
- (regsUsable <> []) do
|
|
|
- begin
|
|
|
-{$ifdef alignregdebug}
|
|
|
- if assigned(prev) then
|
|
|
- begin
|
|
|
- temp := tai_comment.Create(strpnew('got here'));
|
|
|
- temp.next := prev.next;
|
|
|
- temp.previous := prev;
|
|
|
- prev.next := temp;
|
|
|
- if assigned(temp.next) then
|
|
|
- temp.next.previous := temp;
|
|
|
- end;
|
|
|
-{$endif alignregdebug}
|
|
|
- if assigned(prev) and assigned(prev.optinfo) and
|
|
|
- (prevInstrCount < alignSearch) then
|
|
|
- begin
|
|
|
- if (prev.typ = ait_instruction) and
|
|
|
- (insProp[taicpu(prev).opcode].ch[1] <> Ch_ALL) and
|
|
|
- (taicpu(prev).opcode <> A_JMP) then
|
|
|
- begin
|
|
|
- inc(prevInstrCount);
|
|
|
- for regCounter := RS_EAX to RS_EDI do
|
|
|
- begin
|
|
|
- if (regCounter in regsUsable) and
|
|
|
- (ptaiprop(prev.optinfo)^.Regs[regCounter].wState <>
|
|
|
- prevState[regCounter]) then
|
|
|
- begin
|
|
|
- lastRemoved := regCounter;
|
|
|
- exclude(regsUsable,regCounter);
|
|
|
-{$ifdef alignregdebug}
|
|
|
- temp := tai_comment.Create(strpnew(
|
|
|
- std_regname(newreg(R_INTREGISTER,regCounter,R_SUBWHOLE))+' removed')));
|
|
|
- temp.next := prev.next;
|
|
|
- temp.previous := prev;
|
|
|
- prev.next := temp;
|
|
|
- if assigned(temp.next) then
|
|
|
- temp.next.previous := temp;
|
|
|
- if regsUsable = [] then
|
|
|
- begin
|
|
|
- temp := tai_comment.Create(strpnew(
|
|
|
- 'regsUsable empty here')));
|
|
|
- temp.next := prev.next;
|
|
|
- temp.previous := prev;
|
|
|
- prev.next := temp;
|
|
|
- if assigned(temp.next) then
|
|
|
- temp.next.previous := temp;
|
|
|
- end;
|
|
|
-{$endif alignregdebug}
|
|
|
- end;
|
|
|
- prevState[regCounter] :=
|
|
|
- ptaiprop(prev.optinfo)^.Regs[regCounter].wState;
|
|
|
- end;
|
|
|
- getLastInstruction(prev,prev);
|
|
|
- end
|
|
|
- else
|
|
|
- if GetLastInstruction(prev,prev) and
|
|
|
- assigned(prev.optinfo) then
|
|
|
- for regCounter := RS_EAX to RS_EDI do
|
|
|
- prevState[regCounter] :=
|
|
|
- ptaiprop(prev.optinfo)^.Regs[regCounter].wState
|
|
|
- end;
|
|
|
- if assigned(next) and assigned(next.optinfo) and
|
|
|
- (nextInstrCount < alignSearch) then
|
|
|
- begin
|
|
|
- if (next.typ = ait_instruction) and
|
|
|
- (insProp[taicpu(next).opcode].ch[1] <> Ch_ALL) and
|
|
|
- (taicpu(next).opcode <> A_JMP) then
|
|
|
- begin
|
|
|
- inc(nextInstrCount);
|
|
|
- for regCounter := RS_EAX to RS_EDI do
|
|
|
- begin
|
|
|
- if (regCounter in regsUsable) and
|
|
|
- ((ptaiprop(next.optinfo)^.Regs[regCounter].wState <>
|
|
|
- nextWState[regCounter]) or
|
|
|
- (ptaiprop(next.optinfo)^.Regs[regCounter].rState <>
|
|
|
- nextRState[regCounter])) then
|
|
|
- begin
|
|
|
- lastRemoved := regCounter;
|
|
|
- exclude(regsUsable,regCounter);
|
|
|
-{$ifdef alignregdebug}
|
|
|
- temp := tai_comment.Create(strpnew(
|
|
|
- std_regname(newreg(R_INTREGISTER,regCounter,R_SUBWHOLE))+' removed')));
|
|
|
- temp.next := next.next;
|
|
|
- temp.previous := next;
|
|
|
- next.next := temp;
|
|
|
- if assigned(temp.next) then
|
|
|
- temp.next.previous := temp;
|
|
|
- if regsUsable = [] then
|
|
|
- begin
|
|
|
- temp := tai_comment.Create(strpnew(
|
|
|
- 'regsUsable empty here')));
|
|
|
- temp.next := next.next;
|
|
|
- temp.previous := next;
|
|
|
- next.next := temp;
|
|
|
- if assigned(temp.next) then
|
|
|
- temp.next.previous := temp;
|
|
|
- end;
|
|
|
-{$endif alignregdebug}
|
|
|
- end;
|
|
|
- nextWState[regCounter] :=
|
|
|
- ptaiprop(next.optinfo)^.Regs[regCounter].wState;
|
|
|
- nextRState[regCounter] :=
|
|
|
- ptaiprop(next.optinfo)^.Regs[regCounter].rState;
|
|
|
- end
|
|
|
- end
|
|
|
- else
|
|
|
- for regCounter := RS_EAX to RS_EDI do
|
|
|
- begin
|
|
|
- nextWState[regCounter] :=
|
|
|
- ptaiprop(next.optinfo)^.Regs[regCounter].wState;
|
|
|
- nextRState[regCounter] :=
|
|
|
- ptaiprop(next.optinfo)^.Regs[regCounter].rState;
|
|
|
- end;
|
|
|
- getNextInstruction(next,next);
|
|
|
- end;
|
|
|
- end;
|
|
|
- if regsUsable <> [] then
|
|
|
- for regCounter := RS_EAX to RS_EDI do
|
|
|
- if regCounter in regsUsable then
|
|
|
- begin
|
|
|
- lastRemoved := regCounter;
|
|
|
- break
|
|
|
- end;
|
|
|
-{$ifdef alignregdebug}
|
|
|
- next := tai_comment.Create(strpnew(std_regname(newreg(R_INTREGISTER,lastremoved,R_SUBWHOLE))+
|
|
|
- ' chosen as alignment register')));
|
|
|
- next.next := p.next;
|
|
|
- next.previous := p;
|
|
|
- p.next := next;
|
|
|
- if assigned(next.next) then
|
|
|
- next.next.previous := next;
|
|
|
-{$endif alignregdebug}
|
|
|
- tai_align(p).reg := newreg(R_INTREGISTER,lastRemoved,R_SUBWHOLE);
|
|
|
-end;
|
|
|
-
|
|
|
-
|
|
|
-procedure clearmemwrites(p: tai; supreg: tsuperregister);
|
|
|
-var
|
|
|
- beginmemwrite: tai;
|
|
|
-begin
|
|
|
- beginmemwrite := ptaiprop(p.optinfo)^.regs[supreg].memwrite;
|
|
|
- repeat
|
|
|
- ptaiprop(p.optinfo)^.regs[supreg].memwrite := nil;
|
|
|
- until not getnextinstruction(p,p) or
|
|
|
- (ptaiprop(p.optinfo)^.regs[supreg].memwrite <> beginmemwrite);
|
|
|
-end;
|
|
|
-
|
|
|
-
|
|
|
-procedure ClearRegContentsFrom(asml: TAsmList; supreg: tsuperregister; p, endP: tai);
|
|
|
-{ first clears the contents of reg from p till endP. then the contents are }
|
|
|
-{ cleared until the first instruction that changes reg }
|
|
|
-var
|
|
|
-{$ifdef replaceregdebug}
|
|
|
- hp: tai;
|
|
|
- l: longint;
|
|
|
-{$endif replaceregdebug}
|
|
|
- regcounter: tsuperregister;
|
|
|
- oldStartmod: tai;
|
|
|
- regstoclear: tregset;
|
|
|
-begin
|
|
|
-{$ifdef replaceregdebug}
|
|
|
- l := random(1000);
|
|
|
- hp := tai_comment.Create(strpnew(
|
|
|
- 'cleared '+std_regname(newreg(R_INTREGISTER,supreg,R_SUBWHOLE))+' from here... '+tostr(l)));
|
|
|
- insertllitem(asml,p.previous,p,hp);
|
|
|
-{$endif replaceregdebug}
|
|
|
- ptaiprop(p.optinfo)^.Regs[supreg].typ := con_unknown;
|
|
|
- regstoclear := [supreg];
|
|
|
- while (p <> endP) do
|
|
|
- begin
|
|
|
- for regcounter := RS_EAX to RS_EDI do
|
|
|
- begin
|
|
|
- if (regcounter <> supreg) and
|
|
|
- assigned(ptaiprop(p.optinfo)^.regs[supreg].memwrite) and
|
|
|
- reginref(regcounter,ptaiprop(p.optinfo)^.regs[supreg].memwrite.oper[1]^.ref^) then
|
|
|
- clearmemwrites(p,regcounter);
|
|
|
- { needs double loop to cheack for each dependency combination? }
|
|
|
- if assigned(ptaiprop(p.optinfo)^.regs[regcounter].startmod) and
|
|
|
- sequencedependsonreg(ptaiprop(p.optinfo)^.regs[regcounter],regcounter,supreg) then
|
|
|
- include(regstoclear,regcounter);
|
|
|
-
|
|
|
- if regcounter in regstoclear then
|
|
|
- with ptaiprop(p.optinfo)^.Regs[regcounter] do
|
|
|
- begin
|
|
|
- typ := con_unknown;
|
|
|
- memwrite := nil;
|
|
|
- startmod := nil;
|
|
|
- nrofmods := 0;
|
|
|
- end;
|
|
|
- end;
|
|
|
- getNextInstruction(p,p);
|
|
|
- end;
|
|
|
- oldStartmod := ptaiprop(p.optinfo)^.Regs[supreg].startmod;
|
|
|
- repeat
|
|
|
- for regcounter := RS_EAX to RS_EDI do
|
|
|
- begin
|
|
|
- { needs double loop to cheack for each dependency combination? }
|
|
|
- if assigned(ptaiprop(p.optinfo)^.regs[regcounter].startmod) and
|
|
|
- sequencedependsonreg(ptaiprop(p.optinfo)^.regs[regcounter],regcounter,supreg) then
|
|
|
- include(regstoclear,regcounter);
|
|
|
- with ptaiprop(p.optinfo)^.Regs[supreg] do
|
|
|
- if regcounter in regstoclear then
|
|
|
- begin
|
|
|
- typ := con_unknown;
|
|
|
- memwrite := nil;
|
|
|
- end;
|
|
|
- end;
|
|
|
- until not getNextInstruction(p,p) or
|
|
|
- (ptaiprop(p.optinfo)^.Regs[supreg].startmod <> oldStartmod);
|
|
|
-{$ifdef replaceregdebug}
|
|
|
- if assigned(p) then
|
|
|
- begin
|
|
|
- hp := tai_comment.Create(strpnew(
|
|
|
- 'cleared '+std_regname(newreg(R_INTREGISTER,supreg,R_SUBWHOLE))+' till here... '+tostr(l)));
|
|
|
- insertllitem(asml,p.previous,p,hp);
|
|
|
- end;
|
|
|
-{$endif replaceregdebug}
|
|
|
-end;
|
|
|
-
|
|
|
-procedure RestoreRegContentsTo(asml: TAsmList; supreg: tsuperregister; const c: TContent; p, endP: tai);
|
|
|
-var
|
|
|
-{$ifdef replaceregdebug}
|
|
|
- l: longint;
|
|
|
-{$endif replaceregdebug}
|
|
|
- hp: tai;
|
|
|
- validregs, prevvalidregs: tregset;
|
|
|
- regcounter: tsuperregister;
|
|
|
- tmpState, newrstate: byte;
|
|
|
- prevcontenttyp: byte;
|
|
|
- memconflict: boolean;
|
|
|
- invalsmemwrite: boolean;
|
|
|
-begin
|
|
|
-{$ifdef replaceregdebug}
|
|
|
- l := random(1000);
|
|
|
- hp := tai_comment.Create(strpnew(
|
|
|
- 'restored '+std_regname(newreg(R_INTREGISTER,supreg,R_SUBWHOLE))+' with data from here... '+tostr(l)));
|
|
|
- insertllitem(asml,p.previous,p,hp);
|
|
|
-{$endif replaceregdebug}
|
|
|
-{ ptaiprop(p.optinfo)^.Regs[reg] := c;}
|
|
|
- newrstate := c.rstate;
|
|
|
- incstate(newrstate,$7f);
|
|
|
- memconflict := false;
|
|
|
- invalsmemwrite := false;
|
|
|
- validregs := [RS_EAX..RS_EDI];
|
|
|
- prevvalidregs := validregs;
|
|
|
- while (p <> endP) and
|
|
|
- not(memconflict) and
|
|
|
- not(invalsmemwrite) do
|
|
|
- begin
|
|
|
- if not(ptaiprop(p.optinfo)^.canberemoved) and
|
|
|
- regreadbyinstruction(supreg,p) then
|
|
|
- incstate(newrstate,1);
|
|
|
- // is this a write to memory that destroys the contents we are restoring?
|
|
|
- memconflict := modifiesConflictingMemLocation(p,supreg,ptaiprop(p.optinfo)^.regs,validregs,false,invalsmemwrite);
|
|
|
- if (validregs <> prevvalidregs) then
|
|
|
- begin
|
|
|
- prevvalidregs := validregs >< prevvalidregs;
|
|
|
- for regcounter := RS_EAX to RS_EDI do
|
|
|
- if regcounter in prevvalidregs then
|
|
|
- clearRegContentsFrom(asml,regcounter,p,endP);
|
|
|
- end;
|
|
|
- prevvalidregs := validregs;
|
|
|
- if (not memconflict and not invalsmemwrite) then
|
|
|
- begin
|
|
|
- ptaiprop(p.optinfo)^.Regs[supreg] := c;
|
|
|
- ptaiprop(p.optinfo)^.Regs[supreg].rstate := newrstate;
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- clearRegContentsFrom(asml,supreg,p,endP);
|
|
|
-{$ifdef replaceregdebug}
|
|
|
- if assigned(p) then
|
|
|
- begin
|
|
|
- hp := tai_comment.Create(strpnew(
|
|
|
- 'stopping restoring of '+std_regname(newreg(R_INTREGISTER,supreg,R_SUBWHOLE))+'because memory conflict... '+tostr(l)));
|
|
|
- insertllitem(asml,p,p.next,hp);
|
|
|
- end;
|
|
|
-{$endif replaceregdebug}
|
|
|
- exit
|
|
|
- end;
|
|
|
-
|
|
|
- getNextInstruction(p,p);
|
|
|
- end;
|
|
|
-
|
|
|
- tmpState := ptaiprop(p.optinfo)^.Regs[supreg].wState;
|
|
|
- if (newrstate = ptaiprop(p.optinfo)^.Regs[supreg].rState) then
|
|
|
- begin
|
|
|
- incstate(ptaiprop(p.optinfo)^.regs[supreg].rstate,63);
|
|
|
- if not getnextinstruction(p,hp) then
|
|
|
- exit;
|
|
|
- if (ptaiprop(hp.optinfo)^.regs[supreg].rstate = ptaiprop(p.optinfo)^.regs[supreg].rstate) then
|
|
|
- internalerror(2004122710);
|
|
|
- end;
|
|
|
- repeat
|
|
|
- newrstate := ptaiprop(p.optinfo)^.Regs[supreg].rState;
|
|
|
- prevcontenttyp := ptaiprop(p.optinfo)^.Regs[supreg].typ;
|
|
|
- // is this a write to memory that destroys the contents we are restoring?
|
|
|
- memconflict := modifiesConflictingMemLocation(p,supreg,ptaiprop(p.optinfo)^.regs,validregs,false,invalsmemwrite);
|
|
|
- if (validregs <> prevvalidregs) then
|
|
|
- begin
|
|
|
- prevvalidregs := validregs >< prevvalidregs;
|
|
|
- for regcounter := RS_EAX to RS_EDI do
|
|
|
- if regcounter in prevvalidregs then
|
|
|
- clearRegContentsFrom(asml,regcounter,p,p);
|
|
|
- end;
|
|
|
- prevvalidregs := validregs;
|
|
|
- if (not memconflict and not invalsmemwrite) then
|
|
|
- begin
|
|
|
- ptaiprop(p.optinfo)^.Regs[supreg] := c;
|
|
|
- ptaiprop(p.optinfo)^.Regs[supreg].rstate := newrstate;
|
|
|
- end;
|
|
|
- until invalsmemwrite or
|
|
|
- memconflict or
|
|
|
- not getNextInstruction(p,p) or
|
|
|
- (ptaiprop(p.optinfo)^.Regs[supreg].wState <> tmpState) or
|
|
|
- (p.typ = ait_label) or
|
|
|
- ((prevcontenttyp <> con_invalid) and
|
|
|
- (ptaiprop(p.optinfo)^.Regs[supreg].typ = con_invalid));
|
|
|
- if assigned(p) and
|
|
|
- (p.typ <> ait_marker) then
|
|
|
- if ((p.typ = ait_label) or
|
|
|
- memconflict or
|
|
|
- invalsmemwrite) then
|
|
|
- clearRegContentsFrom(asml,supreg,p,p)
|
|
|
- else if (ptaiprop(p.optinfo)^.Regs[supreg].rstate = newrstate) then
|
|
|
- incstate(ptaiprop(p.optinfo)^.Regs[supreg].rstate,20);
|
|
|
-{$ifdef replaceregdebug}
|
|
|
- if assigned(p) then
|
|
|
- begin
|
|
|
- hp := tai_comment.Create(strpnew(
|
|
|
- 'restored '+std_regname(newreg(R_INTREGISTER,supreg,R_SUBWHOLE))+' till here... '+tostr(l)));
|
|
|
- insertllitem(asml,p,p.next,hp);
|
|
|
- end;
|
|
|
-{$endif replaceregdebug}
|
|
|
-end;
|
|
|
-
|
|
|
-function NoHardCodedRegs(p: taicpu; orgReg, newReg: tsuperregister): boolean;
|
|
|
-var
|
|
|
- chCount: byte;
|
|
|
-begin
|
|
|
- case p.opcode of
|
|
|
- A_IMUL: noHardCodedRegs := p.ops <> 1;
|
|
|
- A_SHL,A_SHR,A_ROR,A_ROL,A_SAR,A_SHLD,A_SHRD: noHardCodedRegs :=
|
|
|
- (p.oper[0]^.typ <> top_reg) or
|
|
|
- ((orgReg <> RS_ECX) and (newReg <> RS_ECX));
|
|
|
- else
|
|
|
- begin
|
|
|
- NoHardCodedRegs := true;
|
|
|
- with InsProp[p.opcode] do
|
|
|
- for chCount := 1 to maxinschanges do
|
|
|
- if Ch[chCount] in ([Ch_REAX..Ch_MEDI,Ch_WMemEDI,Ch_All]-[Ch_RESP,Ch_WESP,Ch_RWESP]) then
|
|
|
- begin
|
|
|
- NoHardCodedRegs := false;
|
|
|
- break
|
|
|
- end;
|
|
|
- end;
|
|
|
- end;
|
|
|
-end;
|
|
|
-
|
|
|
-
|
|
|
-function ChangeReg(var Reg: TRegister; newReg, orgReg: tsuperregister): boolean;
|
|
|
-begin
|
|
|
- changereg := false;
|
|
|
- if (reg <> NR_NO) and
|
|
|
- (getregtype(reg) = R_INTREGISTER) and
|
|
|
- (getsupreg(reg) = newreg) then
|
|
|
- begin
|
|
|
- changereg := true;
|
|
|
- setsupreg(reg,orgreg);
|
|
|
- end;
|
|
|
-end;
|
|
|
-
|
|
|
-
|
|
|
-function changeOp(var o: toper; newReg, orgReg: tsuperregister): boolean;
|
|
|
-var
|
|
|
- tmpresult: boolean;
|
|
|
-begin
|
|
|
- changeOp := false;
|
|
|
- case o.typ of
|
|
|
- top_reg: changeOp := changeReg(o.reg,newReg,orgReg);
|
|
|
- top_ref:
|
|
|
- begin
|
|
|
- tmpresult := changeReg(o.ref^.base,newReg,orgReg);
|
|
|
- changeop := changeReg(o.ref^.index,newReg,orgReg) or tmpresult;
|
|
|
- end;
|
|
|
- end;
|
|
|
-end;
|
|
|
-
|
|
|
-
|
|
|
-procedure updateStates(orgReg,newReg: tsuperregister; hp: tai; writeStateToo: boolean);
|
|
|
-var
|
|
|
- prev: tai;
|
|
|
- newOrgRegRState, newOrgRegWState: byte;
|
|
|
-begin
|
|
|
- newOrgRegwState := 0;
|
|
|
- if getLastInstruction(hp,prev) then
|
|
|
- with ptaiprop(prev.optinfo)^ do
|
|
|
- begin
|
|
|
- newOrgRegRState := byte(longint(regs[orgReg].rState) +
|
|
|
- longint(ptaiprop(hp.optinfo)^.regs[newReg].rState) - regs[newReg].rstate);
|
|
|
- if writeStateToo then
|
|
|
- newOrgRegWState := byte(longint(regs[orgReg].wState) +
|
|
|
- longint(ptaiprop(hp.optinfo)^.regs[newReg].wState) - regs[newReg].wstate);
|
|
|
- end
|
|
|
- else
|
|
|
- with ptaiprop(hp.optinfo)^.regs[newReg] do
|
|
|
- begin
|
|
|
- newOrgRegRState := rState;
|
|
|
- if writeStateToo then
|
|
|
- newOrgRegWState := wState;
|
|
|
- end;
|
|
|
- with ptaiprop(hp.optinfo)^.regs[orgReg] do
|
|
|
- begin
|
|
|
- rState := newOrgRegRState;
|
|
|
- if writeStateToo then
|
|
|
- wState := newOrgRegwState;
|
|
|
- end;
|
|
|
-end;
|
|
|
-
|
|
|
-
|
|
|
-function doReplaceReg(hp: taicpu; newReg, orgReg: tsuperregister): boolean;
|
|
|
-var
|
|
|
- opCount: longint;
|
|
|
- tmpResult: boolean;
|
|
|
-begin
|
|
|
- tmpresult := false;
|
|
|
- for opCount := 0 to hp.ops-1 do
|
|
|
- tmpResult :=
|
|
|
- changeOp(hp.oper[opCount]^,newReg,orgReg) or tmpResult;
|
|
|
- doReplaceReg := tmpResult;
|
|
|
-end;
|
|
|
-
|
|
|
-
|
|
|
-function RegSizesOK(oldReg,newReg: tsuperregister; p: taicpu): boolean;
|
|
|
-{ oldreg and newreg must be 32bit components }
|
|
|
-var
|
|
|
- opCount: longint;
|
|
|
- tmpreg: tsuperregister;
|
|
|
-begin
|
|
|
- RegSizesOK := true;
|
|
|
- { if only one of them is a general purpose register ... }
|
|
|
- if (IsGP32reg(oldReg) xor IsGP32Reg(newReg)) then
|
|
|
- begin
|
|
|
- for opCount := 0 to p.ops-1 do
|
|
|
- if (p.oper[opCount]^.typ = top_reg) and
|
|
|
- (getsubreg(p.oper[opCount]^.reg) in [R_SUBL,R_SUBH]) then
|
|
|
- begin
|
|
|
- tmpreg := getsupreg(p.oper[opCount]^.reg);
|
|
|
- if (tmpreg = oldreg) or
|
|
|
- (tmpreg = newreg) then
|
|
|
- begin
|
|
|
- RegSizesOK := false;
|
|
|
- break
|
|
|
- end
|
|
|
- end;
|
|
|
- end;
|
|
|
-end;
|
|
|
-
|
|
|
-
|
|
|
-function doReplaceReadReg(p: taicpu; newReg,orgReg: tsuperregister): boolean;
|
|
|
-var
|
|
|
- opCount: longint;
|
|
|
-begin
|
|
|
- doReplaceReadReg := false;
|
|
|
- { handle special case }
|
|
|
- case p.opcode of
|
|
|
- A_IMUL:
|
|
|
- begin
|
|
|
- case p.ops of
|
|
|
- 1: internalerror(1301001);
|
|
|
- 2,3:
|
|
|
- begin
|
|
|
- if changeOp(p.oper[0]^,newReg,orgReg) then
|
|
|
- begin
|
|
|
-{ updateStates(orgReg,newReg,p,false);}
|
|
|
- doReplaceReadReg := true;
|
|
|
- end;
|
|
|
- if p.ops = 3 then
|
|
|
- if changeOp(p.oper[1]^,newReg,orgReg) then
|
|
|
- begin
|
|
|
-{ updateStates(orgReg,newReg,p,false);}
|
|
|
- doReplaceReadReg := true;
|
|
|
- end;
|
|
|
- end;
|
|
|
- end;
|
|
|
- end;
|
|
|
- A_DIV,A_IDIV,A_MUL: internalerror(1301002);
|
|
|
- else
|
|
|
- begin
|
|
|
- for opCount := 0 to p.ops-1 do
|
|
|
- if p.oper[opCount]^.typ = top_ref then
|
|
|
- if changeOp(p.oper[opCount]^,newReg,orgReg) then
|
|
|
- begin
|
|
|
-{ updateStates(orgReg,newReg,p,false);}
|
|
|
- doReplaceReadReg := true;
|
|
|
- end;
|
|
|
- for opCount := 1 to maxinschanges do
|
|
|
- case InsProp[p.opcode].Ch[opCount] of
|
|
|
- Ch_ROp1:
|
|
|
- if p.oper[0]^.typ = top_reg then
|
|
|
- if changeReg(p.oper[0]^.reg,newReg,orgReg) then
|
|
|
- begin
|
|
|
-{ updateStates(orgReg,newReg,p,false);}
|
|
|
- doReplaceReadReg := true;
|
|
|
- end;
|
|
|
- Ch_ROp2:
|
|
|
- if p.oper[1]^.typ = top_reg then
|
|
|
- if changeReg(p.oper[1]^.reg,newReg,orgReg) then
|
|
|
- begin
|
|
|
-{ updateStates(orgReg,newReg,p,false);}
|
|
|
- doReplaceReadReg := true;
|
|
|
- end;
|
|
|
- Ch_ROp3:
|
|
|
- if p.oper[2]^.typ = top_reg then
|
|
|
- if changeReg(p.oper[2]^.reg,newReg,orgReg) then
|
|
|
- begin
|
|
|
-{ updateStates(orgReg,newReg,p,false);}
|
|
|
- doReplaceReadReg := true;
|
|
|
- end;
|
|
|
- end;
|
|
|
- end;
|
|
|
- end;
|
|
|
-end;
|
|
|
-
|
|
|
-
|
|
|
-procedure updateState(supreg: tsuperregister; p: tai);
|
|
|
-{ this procedure updates the read and write states of the instructions }
|
|
|
-{ coming after p. It's called when the read/write state of p has been }
|
|
|
-{ changed and this change has to be propagated to the following }
|
|
|
-{ instructions as well }
|
|
|
-var
|
|
|
- newRState, newWState: byte;
|
|
|
- prevRState, prevWState: byte;
|
|
|
- doRState, doWState: boolean;
|
|
|
-begin
|
|
|
- { get the new read/write states from p }
|
|
|
- with ptaiprop(p.optinfo)^.regs[supreg] do
|
|
|
- begin
|
|
|
- newRState := rState;
|
|
|
- newWState := wState;
|
|
|
- end;
|
|
|
- if not GetNextInstruction(p,p) then
|
|
|
- exit;
|
|
|
- { get the old read/write states from the next instruction, to know }
|
|
|
- { when we can stop updating }
|
|
|
- with ptaiprop(p.optinfo)^.regs[supreg] do
|
|
|
- begin
|
|
|
- prevRState := rState;
|
|
|
- prevWState := wState;
|
|
|
- end;
|
|
|
- { adjust the states if this next instruction reads/writes the register }
|
|
|
- if regReadByInstruction(supreg,p) then
|
|
|
- incState(newRState,1);
|
|
|
- if regModifiedByInstruction(supreg,p) then
|
|
|
- incState(newWState,1);
|
|
|
- { do we still have to update the read and/or write states? }
|
|
|
- doRState := true;
|
|
|
- doWState := true;
|
|
|
- repeat
|
|
|
- { update the states }
|
|
|
- with ptaiprop(p.optinfo)^.regs[supreg] do
|
|
|
- begin
|
|
|
- if doRState then
|
|
|
- rState := newRState;
|
|
|
- if doWState then
|
|
|
- wState := newWState;
|
|
|
- end;
|
|
|
- if not getNextInstruction(p,p) then
|
|
|
- break;
|
|
|
- with ptaiprop(p.optinfo)^.regs[supreg] do
|
|
|
- begin
|
|
|
- { stop updating the read state if it changes }
|
|
|
- doRState :=
|
|
|
- doRState and (rState = prevRState);
|
|
|
- { if, by accident, this changed state is the same as the one }
|
|
|
- { we've been using, change it to a value that's definitely }
|
|
|
- { different from the previous and next state }
|
|
|
- if not doRState and
|
|
|
- (rState = newRState) then
|
|
|
- begin
|
|
|
- incState(newRState,1);
|
|
|
- prevRState := rState;
|
|
|
- doRState := true;
|
|
|
- end;
|
|
|
- { ditto for the write state }
|
|
|
- doWState :=
|
|
|
- doWState and (WState = prevWState);
|
|
|
- if not doWState and
|
|
|
- (wState = newWState) then
|
|
|
- begin
|
|
|
- incState(newWState,1);
|
|
|
- prevWState := wState;
|
|
|
- doWState := true;
|
|
|
- end;
|
|
|
- end;
|
|
|
- { stop when we don't have to update either state anymore }
|
|
|
- until not(doRState or doWState);
|
|
|
-end;
|
|
|
-
|
|
|
-
|
|
|
-function storeBack(start, current: tai; orgReg, newReg: tsuperregister): boolean;
|
|
|
-{ returns true if p1 contains an instruction that stores the contents }
|
|
|
-{ of newReg back to orgReg }
|
|
|
-begin
|
|
|
- storeback := false;
|
|
|
- if (current.typ = ait_instruction) and
|
|
|
- (taicpu(current).opcode = A_MOV) and
|
|
|
- (taicpu(current).oper[0]^.typ = top_reg) and
|
|
|
- (getsupreg(taicpu(current).oper[0]^.reg) = newReg) and
|
|
|
- (taicpu(current).oper[1]^.typ = top_reg) and
|
|
|
- (getsupreg(taicpu(current).oper[1]^.reg) = orgReg) then
|
|
|
- case taicpu(current).opsize of
|
|
|
- S_B:
|
|
|
- storeback := true;
|
|
|
- S_W:
|
|
|
- storeback := taicpu(start).opsize <> S_B;
|
|
|
- S_L:
|
|
|
- storeback := taicpu(start).opsize = S_L;
|
|
|
- else
|
|
|
- internalerror(2003121501);
|
|
|
- end;
|
|
|
-end;
|
|
|
-
|
|
|
-
|
|
|
-function canreplacereg(orgsupreg, newsupreg: tsuperregister; p: tai;
|
|
|
- orgRegCanBeModified: boolean; var resnewregmodified, resorgregread, resremovelast: boolean; var returnendp: tai): boolean;
|
|
|
-var
|
|
|
- endP, hp: tai;
|
|
|
- removeLast, sequenceEnd, tmpResult, newRegModified, orgRegRead: boolean;
|
|
|
-begin
|
|
|
- canreplacereg := false;
|
|
|
- tmpResult := true;
|
|
|
- sequenceEnd := false;
|
|
|
- newRegModified := false;
|
|
|
- orgRegRead := false;
|
|
|
- removeLast := false;
|
|
|
- endP := p;
|
|
|
- while tmpResult and not sequenceEnd do
|
|
|
- begin
|
|
|
- tmpResult :=
|
|
|
- getNextInstruction(endP,endP) and
|
|
|
- (endp.typ = ait_instruction) and
|
|
|
- not(taicpu(endp).is_jmp);
|
|
|
- if tmpresult and not assigned(endp.optinfo) then
|
|
|
- begin
|
|
|
-{ hp := tai_comment.Create(strpnew('next no optinfo'));
|
|
|
- hp.next := endp;
|
|
|
- hp.previous := endp.previous;
|
|
|
- endp.previous := hp;
|
|
|
- if assigned(hp.previous) then
|
|
|
- hp.previous.next := hp;}
|
|
|
- exit;
|
|
|
- end;
|
|
|
- if tmpResult and
|
|
|
- { don't take into account instructions that will be removed }
|
|
|
- not (ptaiprop(endp.optinfo)^.canBeRemoved) then
|
|
|
- begin
|
|
|
- { if the newsupreg gets stored back to the oldReg, we can change }
|
|
|
- { "mov %oldReg,%newReg; <operations on %newReg>; mov %newReg, }
|
|
|
- { %oldReg" to "<operations on %oldReg>" }
|
|
|
- removeLast := storeBack(p,endP, orgsupreg, newsupreg);
|
|
|
- sequenceEnd :=
|
|
|
- { no support for (i)div, mul and imul with hardcoded operands }
|
|
|
- noHardCodedRegs(taicpu(endP),orgsupreg,newsupreg) and
|
|
|
- { if newsupreg gets loaded with a new value, we can stop }
|
|
|
- { replacing newsupreg with oldReg here (possibly keeping }
|
|
|
- { the original contents of oldReg so we still know them }
|
|
|
- { afterwards) }
|
|
|
- (RegLoadedWithNewValue(newsupreg,true,taicpu(endP)) or
|
|
|
- { we can also stop if we reached the end of the use of }
|
|
|
- { newReg's current contents }
|
|
|
- (GetNextInstruction(endp,hp) and
|
|
|
- FindRegDealloc(newsupreg,hp)));
|
|
|
- { to be able to remove the first and last instruction of }
|
|
|
- { movl %reg1, %reg2 }
|
|
|
- { <operations on %reg2> (replacing reg2 with reg1 here) }
|
|
|
- { movl %reg2, %reg1 }
|
|
|
- { %reg2 must not be use afterwards (it can be as the }
|
|
|
- { result of a peepholeoptimization) }
|
|
|
- removeLast := removeLast and sequenceEnd;
|
|
|
- newRegModified :=
|
|
|
- newRegModified or
|
|
|
- (not(regLoadedWithNewValue(newsupreg,true,taicpu(endP))) and
|
|
|
- RegModifiedByInstruction(newsupreg,endP));
|
|
|
- orgRegRead := newRegModified and RegReadByInstruction(orgsupreg,endP);
|
|
|
- sequenceEnd := SequenceEnd and
|
|
|
- (removeLast or
|
|
|
- { since newsupreg will be replaced by orgsupreg, we can't allow that newsupreg }
|
|
|
- { gets modified if orgsupreg is still read afterwards (since after }
|
|
|
- { replacing, this would mean that orgsupreg first gets modified and then }
|
|
|
- { gets read in the assumption it still contains the unmodified value) }
|
|
|
- not(newRegModified and orgRegRead)) (* and
|
|
|
- { since newsupreg will be replaced by orgsupreg, we can't allow that newsupreg }
|
|
|
- { gets modified if orgRegCanBeModified = false }
|
|
|
-
|
|
|
- { this now gets checked after the loop (JM) }
|
|
|
- (orgRegCanBeModified or not(newRegModified)) *);
|
|
|
- tmpResult :=
|
|
|
- not(removeLast) and
|
|
|
- not(newRegModified and orgRegRead) and
|
|
|
-(* (orgRegCanBeModified or not(newRegModified)) and *)
|
|
|
-(* already checked at the top
|
|
|
- (endp.typ = ait_instruction) and *)
|
|
|
- NoHardCodedRegs(taicpu(endP),orgsupreg,newsupreg) and
|
|
|
- RegSizesOk(orgsupreg,newsupreg,taicpu(endP)) and
|
|
|
- not RegModifiedByInstruction(orgsupreg,endP);
|
|
|
- end;
|
|
|
- end;
|
|
|
- canreplacereg := sequenceEnd and
|
|
|
- (removeLast or
|
|
|
- (orgRegCanBeModified or not(newRegModified))) and
|
|
|
- (not(assigned(endp)) or
|
|
|
- not(endp.typ = ait_instruction) or
|
|
|
- (noHardCodedRegs(taicpu(endP),orgsupreg,newsupreg) and
|
|
|
- RegSizesOk(orgsupreg,newsupreg,taicpu(endP)) and
|
|
|
- not(newRegModified and
|
|
|
- (orgsupreg in ptaiprop(endp.optinfo)^.usedRegs) and
|
|
|
- not(RegLoadedWithNewValue(orgsupreg,true,taicpu(endP))))));
|
|
|
- if canreplacereg then
|
|
|
- begin
|
|
|
- resnewregmodified := newregmodified;
|
|
|
- resorgregread := orgregread;
|
|
|
- resremovelast := removelast;
|
|
|
- end;
|
|
|
- { needed for replaceregdebug code }
|
|
|
- returnendp := endp;
|
|
|
-end;
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-function ReplaceReg(asml: TAsmList; orgsupreg, newsupreg: tsuperregister; p,
|
|
|
- seqstart: tai; const c: TContent; orgRegCanBeModified: Boolean;
|
|
|
- var returnEndP: tai): Boolean;
|
|
|
-{ Tries to replace orgsupreg with newsupreg in all instructions coming after p }
|
|
|
-{ until orgsupreg gets loaded with a new value. Returns true if successful, }
|
|
|
-{ false otherwise. if successful, the contents of newsupreg are set to c, }
|
|
|
-{ which should hold the contents of newsupreg before the current sequence }
|
|
|
-{ started }
|
|
|
-{ if the function returns true, returnEndP holds the last instruction }
|
|
|
-{ where newsupreg was replaced by orgsupreg }
|
|
|
-var
|
|
|
- endP, hp: tai;
|
|
|
- removeLast, newRegModified, orgRegRead,
|
|
|
- stateChanged, readStateChanged: Boolean;
|
|
|
-{$ifdef replaceregdebug}
|
|
|
- l: longint;
|
|
|
-{$endif replaceregdebug}
|
|
|
-
|
|
|
-begin
|
|
|
- replacereg := false;
|
|
|
- readStateChanged := false;
|
|
|
- if canreplacereg(orgsupreg,newsupreg,p,orgregcanbemodified,newregmodified, orgregread, removelast,endp) then
|
|
|
- begin
|
|
|
-{$ifdef replaceregdebug}
|
|
|
- l := random(1000);
|
|
|
- hp := tai_comment.Create(strpnew(
|
|
|
- 'replacing '+std_regname(newreg(R_INTREGISTER,newsupreg,R_SUBWHOLE))+' with '+std_regname(newreg(R_INTREGISTER,orgsupreg,R_SUBWHOLE))+
|
|
|
- ' from here... '+tostr(l)));
|
|
|
- insertllitem(asml,p.previous,p,hp);
|
|
|
- hp := tai_comment.Create(strpnew(
|
|
|
- 'replaced '+std_regname(newreg(R_INTREGISTER,newsupreg,R_SUBWHOLE))+' with '+std_regname(newreg(R_INTREGISTER,orgsupreg,R_SUBWHOLE))+
|
|
|
- ' till here ' + tostr(l)));
|
|
|
- insertllitem(asml,endp,endp.next,hp);
|
|
|
-{$endif replaceregdebug}
|
|
|
- replaceReg := true;
|
|
|
- returnEndP := endP;
|
|
|
-
|
|
|
- if not getNextInstruction(p,hp) then
|
|
|
- exit;
|
|
|
- stateChanged := false;
|
|
|
- while hp <> endP do
|
|
|
- begin
|
|
|
- if {not(ptaiprop(hp.optinfo)^.canBeRemoved) and }
|
|
|
- (hp.typ = ait_instruction) then
|
|
|
- stateChanged :=
|
|
|
- doReplaceReg(taicpu(hp),newsupreg,orgsupreg) or stateChanged;
|
|
|
- if stateChanged then
|
|
|
- updateStates(orgsupreg,newsupreg,hp,true);
|
|
|
- getNextInstruction(hp,hp)
|
|
|
- end;
|
|
|
- if assigned(endp) and (endp.typ = ait_instruction) then
|
|
|
- readStateChanged :=
|
|
|
- doReplaceReadReg(taicpu(endP),newsupreg,orgsupreg);
|
|
|
- if stateChanged or readStateChanged then
|
|
|
- updateStates(orgsupreg,newsupreg,endP,stateChanged);
|
|
|
-
|
|
|
- if stateChanged or readStateChanged then
|
|
|
- updateState(orgsupreg,endP);
|
|
|
-
|
|
|
-{ We replaced newreg with oldreg between p and endp, so restore the contents }
|
|
|
-{ of newreg there with its contents from before the sequence. }
|
|
|
- if removeLast or
|
|
|
- RegLoadedWithNewValue(newsupreg,true,endP) then
|
|
|
- GetLastInstruction(endP,hp)
|
|
|
- else hp := endP;
|
|
|
- RestoreRegContentsTo(asml,newsupreg,c,seqstart,hp);
|
|
|
-
|
|
|
-{ Ot is possible that the new register was modified (e.g. an add/sub), so if }
|
|
|
-{ it was replaced by oldreg in that instruction, oldreg's contents have been }
|
|
|
-{ changed. To take this into account, we simply set the contents of orgsupreg }
|
|
|
-{ to "unknown" after this sequence }
|
|
|
- if newRegModified then
|
|
|
- ClearRegContentsFrom(asml,orgsupreg,p,hp);
|
|
|
- if removeLast then
|
|
|
- ptaiprop(endp.optinfo)^.canBeRemoved := true;
|
|
|
- allocRegBetween(asml,newreg(R_INTREGISTER,orgsupreg,R_SUBWHOLE),p,endP,ptaiprop(p.optinfo)^.usedregs);
|
|
|
-
|
|
|
- end
|
|
|
-{$ifdef replaceregdebug}
|
|
|
- else
|
|
|
- begin
|
|
|
- l := random(1000);
|
|
|
- hp := tai_comment.Create(strpnew(
|
|
|
- 'replacing '+std_regname(newreg(R_INTREGISTER,newsupreg,R_SUBWHOLE))+' with '+std_regname(newreg(R_INTREGISTER,orgsupreg,R_SUBWHOLE))+
|
|
|
- ' from here... '+ tostr(l)));
|
|
|
- insertllitem(asml,p.previous,p,hp);
|
|
|
- hp := tai_comment.Create(strpnew(
|
|
|
- 'replacing '+std_regname(newreg(R_INTREGISTER,newsupreg,R_SUBWHOLE))+' with '+std_regname(newreg(R_INTREGISTER,orgsupreg,R_SUBWHOLE))+
|
|
|
- ' failed here ' + tostr(l)));
|
|
|
- insertllitem(asml,endp,endp.next,hp);
|
|
|
- end;
|
|
|
-{$endif replaceregdebug}
|
|
|
-end;
|
|
|
-
|
|
|
-
|
|
|
-function FindRegWithConst(p: tai; size: topsize; l: aint; var Res: TRegister): Boolean;
|
|
|
-{Finds a register which contains the constant l}
|
|
|
-var
|
|
|
- Counter: tsuperregister;
|
|
|
-{$ifdef testing}
|
|
|
- hp: tai;
|
|
|
-{$endif testing}
|
|
|
-begin
|
|
|
- Result:=false;
|
|
|
- Counter := RS_EAX;
|
|
|
- repeat
|
|
|
-{$ifdef testing}
|
|
|
- if (ptaiprop(p.optinfo)^.regs[counter].typ in [con_const,con_noRemoveConst]) then
|
|
|
- begin
|
|
|
- hp := tai_comment.Create(strpnew(
|
|
|
- 'checking const load of '+tostr(l)+' here...'));
|
|
|
- hp.next := ptaiprop(p.optinfo)^.Regs[Counter].StartMod;
|
|
|
- hp.previous := ptaiprop(p.optinfo)^.Regs[Counter].StartMod^.previous;
|
|
|
- ptaiprop(p.optinfo)^.Regs[Counter].StartMod^.previous := hp;
|
|
|
- if assigned(hp.previous) then
|
|
|
- hp.previous.next := hp;
|
|
|
- end;
|
|
|
-{$endif testing}
|
|
|
- if (ptaiprop(p.optinfo)^.regs[counter].typ in [con_const,con_noRemoveConst]) and
|
|
|
- (taicpu(ptaiprop(p.optinfo)^.Regs[Counter].StartMod).opsize = size) and
|
|
|
- (taicpu(ptaiprop(p.optinfo)^.Regs[Counter].StartMod).oper[0]^.typ = top_const) and
|
|
|
- (taicpu(ptaiprop(p.optinfo)^.Regs[Counter].StartMod).oper[0]^.val = l) then
|
|
|
- begin
|
|
|
- res:=taicpu(ptaiprop(p.optinfo)^.Regs[Counter].StartMod).oper[1]^.reg;
|
|
|
- result:=true;
|
|
|
- exit;
|
|
|
- end;
|
|
|
- inc(counter);
|
|
|
- until (Counter > RS_EDI);
|
|
|
-end;
|
|
|
-
|
|
|
-
|
|
|
-procedure removePrevNotUsedLoad(asml: TAsmList; p: tai; supreg: tsuperregister; check: boolean);
|
|
|
-{ if check = true, it means the procedure has to check whether it isn't }
|
|
|
-{ possible that the contents are still used after p (used when removing }
|
|
|
-{ instructions because of a "call"), otherwise this is not necessary }
|
|
|
-{ (e.g. when you have a "mov 8(%ebp),%eax", you can be sure the previous }
|
|
|
-{ value of %eax isn't used anymore later on) }
|
|
|
-var
|
|
|
- hp1, next, beforestartmod: tai;
|
|
|
-begin
|
|
|
- if getLastInstruction(p,hp1) then
|
|
|
- with ptaiprop(hp1.optinfo)^.regs[supreg] do
|
|
|
- if (typ in [con_ref,con_invalid,con_const]) and
|
|
|
- (nrofMods = 1) and
|
|
|
- (rState = ptaiprop(startmod.optinfo)^.regs[supreg].rState) and
|
|
|
- (not(check) or
|
|
|
- (not(regInInstruction(supreg,p)) and
|
|
|
- (not(supreg in ptaiprop(hp1.optinfo)^.usedRegs) or
|
|
|
- findRegDealloc(supreg,p)))) then
|
|
|
- begin
|
|
|
- ptaiprop(startMod.optinfo)^.canBeRemoved := true;
|
|
|
- getnextinstruction(p,next);
|
|
|
- { give the register that was modified by this instruction again }
|
|
|
- { the contents it had before this instruction }
|
|
|
- if getlastinstruction(startmod,beforestartmod) then
|
|
|
- RestoreRegContentsTo(asml,supreg,ptaiprop(beforestartmod.optinfo)^.regs[supreg],
|
|
|
- startmod,hp1)
|
|
|
- else
|
|
|
- ClearRegContentsFrom(asml,supreg,startmod,hp1);
|
|
|
- end;
|
|
|
-end;
|
|
|
-
|
|
|
-
|
|
|
-{$ifdef notused}
|
|
|
-function is_mov_for_div(p: taicpu): boolean;
|
|
|
-begin
|
|
|
- is_mov_for_div :=
|
|
|
- (p.opcode = A_MOV) and
|
|
|
- (p.oper[0]^.typ = top_const) and
|
|
|
- (p.oper[1]^.typ = top_reg) and
|
|
|
- (p.oper[1]^.reg = RS_EDX) and
|
|
|
- getNextInstruction(p,p) and
|
|
|
- (p.typ = ait_instruction) and
|
|
|
- ((p.opcode = A_DIV) or
|
|
|
- (p.opcode = A_IDIV));
|
|
|
-end;
|
|
|
-{$endif notused}
|
|
|
-
|
|
|
-
|
|
|
-function memtoreg(t: taicpu; const ref: treference; var startp: tai): tregister;
|
|
|
-var
|
|
|
- hp: tai;
|
|
|
- p: ptaiprop;
|
|
|
- regcounter: tsuperregister;
|
|
|
- optimizable: boolean;
|
|
|
-begin
|
|
|
- memtoreg := NR_NO;
|
|
|
-
|
|
|
- if not getlastinstruction(t,hp) or
|
|
|
- not issimplememloc(ref) then
|
|
|
- exit;
|
|
|
-
|
|
|
- p := ptaiprop(hp.optinfo);
|
|
|
- optimizable := false;
|
|
|
- for regcounter := RS_EAX to RS_EDI do
|
|
|
- begin
|
|
|
- if (assigned(p^.regs[regcounter].memwrite) and
|
|
|
- refsequal(ref,p^.regs[regcounter].memwrite.oper[1]^.ref^)) then
|
|
|
- begin
|
|
|
- optimizable := true;
|
|
|
- hp := p^.regs[regcounter].memwrite;
|
|
|
- end
|
|
|
- else if ((p^.regs[regcounter].typ in [CON_REF,CON_NOREMOVEREF]) and
|
|
|
- (p^.regs[regcounter].nrofmods = 1) and
|
|
|
- ((taicpu(p^.regs[regcounter].startmod).opcode = A_MOV) or
|
|
|
- (taicpu(p^.regs[regcounter].startmod).opcode = A_MOVZX) or
|
|
|
- (taicpu(p^.regs[regcounter].startmod).opcode = A_MOVSX)) and
|
|
|
- (taicpu(p^.regs[regcounter].startmod).oper[0]^.typ = top_ref) and
|
|
|
- refsequal(ref,taicpu(p^.regs[regcounter].startmod).oper[0]^.ref^)) then
|
|
|
- begin
|
|
|
- optimizable := true;
|
|
|
- hp := p^.regs[regcounter].startmod;
|
|
|
- end;
|
|
|
- if optimizable then
|
|
|
- if ((t.opsize <> S_B) or
|
|
|
- not(regcounter in [RS_ESI,RS_EDI])) and
|
|
|
- sizescompatible(taicpu(hp).opsize,t.opsize) then
|
|
|
- begin
|
|
|
- case t.opsize of
|
|
|
- S_B:
|
|
|
- begin
|
|
|
- memtoreg := newreg(R_INTREGISTER,regcounter,R_SUBL)
|
|
|
- end;
|
|
|
- S_W,S_BW:
|
|
|
- begin
|
|
|
- memtoreg := newreg(R_INTREGISTER,regcounter,R_SUBW);
|
|
|
- if (t.opsize = S_BW) then
|
|
|
- begin
|
|
|
- t.opcode := A_MOV;
|
|
|
- t.opsize := S_W;
|
|
|
- end;
|
|
|
- end;
|
|
|
- S_L,S_BL,S_WL:
|
|
|
- begin
|
|
|
- memtoreg := newreg(R_INTREGISTER,regcounter,R_SUBWHOLE);
|
|
|
- if (t.opsize <> S_L) then
|
|
|
- begin
|
|
|
- t.opcode := A_MOV;
|
|
|
- t.opsize := S_L;
|
|
|
- end;
|
|
|
- end;
|
|
|
- end;
|
|
|
- startp := hp;
|
|
|
- exit;
|
|
|
- end;
|
|
|
- end;
|
|
|
- memtoreg := NR_NO;
|
|
|
-end;
|
|
|
-
|
|
|
-
|
|
|
-procedure removeLocalStores(const t1: tai);
|
|
|
-{var
|
|
|
- p: tai;
|
|
|
- regcount: tregister; }
|
|
|
-begin
|
|
|
-{
|
|
|
- for regcount := LoGPReg to HiGPReg do
|
|
|
- if assigned(pTaiProp(t1.optinfo)^.regs[regcount].memwrite) and
|
|
|
- (taicpu(pTaiProp(t1.optinfo)^.regs[regcount].memwrite).oper[1]^.ref^.base
|
|
|
- = current_procinfo.framepointer) then
|
|
|
- begin
|
|
|
- pTaiProp(pTaiProp(t1.optinfo)^.regs[regcount].memwrite.optinfo)^.canberemoved := true;
|
|
|
- clearmemwrites(pTaiProp(t1.optinfo)^.regs[regcount].memwrite,regcount);
|
|
|
- end;
|
|
|
-}
|
|
|
-end;
|
|
|
-
|
|
|
-
|
|
|
-procedure loadcseregs(asml: TAsmList; const reginfo: toptreginfo; curseqend, prevseqstart, curseqstart, curprev: tai; cnt: longint);
|
|
|
-var
|
|
|
- regsloaded: tregset;
|
|
|
- regloads, reguses: array[RS_EAX..RS_EDI] of tai;
|
|
|
- regcounter: tsuperregister;
|
|
|
- hp, hp2: tai;
|
|
|
- insertpos, insertoptinfo, prevseq_next: tai;
|
|
|
- i: longint;
|
|
|
- opc: tasmop;
|
|
|
-begin
|
|
|
- regsloaded := [];
|
|
|
- fillchar(regloads,sizeof(regloads),0);
|
|
|
- fillchar(reguses,sizeof(reguses),0);
|
|
|
- getnextinstruction(prevseqstart,prevseq_next);
|
|
|
- for regcounter := RS_EAX To RS_EDI do
|
|
|
- if (reginfo.new2oldreg[regcounter] <> RS_INVALID) Then
|
|
|
- begin
|
|
|
- include(regsloaded,regcounter);
|
|
|
- if assigned(ptaiprop(prevseqstart.optinfo)^.Regs[reginfo.new2oldreg[regcounter]].StartMod) then
|
|
|
- AllocRegBetween(asml,newreg(R_INTREGISTER,reginfo.new2oldreg[regcounter],R_SUBWHOLE),
|
|
|
- ptaiprop(prevseqstart.optinfo)^.Regs[reginfo.new2oldreg[regcounter]].StartMod,curseqstart,
|
|
|
- ptaiprop(ptaiprop(prevseqstart.optinfo)^.Regs[reginfo.new2oldreg[regcounter]].StartMod.optinfo)^.usedregs)
|
|
|
- else
|
|
|
- AllocRegBetween(asml,newreg(R_INTREGISTER,reginfo.new2oldreg[regcounter],R_SUBWHOLE),
|
|
|
- prevseqstart,curseqstart,ptaiprop(prevseqstart.optinfo)^.usedregs);
|
|
|
-
|
|
|
- if curprev <> prevseqstart then
|
|
|
- begin
|
|
|
- if assigned(reginfo.lastReload[regCounter]) then
|
|
|
- getLastInstruction(reginfo.lastReload[regCounter],hp)
|
|
|
- else if assigned(reginfo.lastReload[reginfo.new2oldreg[regCounter]]) then
|
|
|
- getLastInstruction(reginfo.lastReload[reginfo.new2OldReg[regCounter]],hp)
|
|
|
- else
|
|
|
- hp := curprev;
|
|
|
- clearRegContentsFrom(asml,regCounter,prevSeq_next,hp);
|
|
|
- getnextInstruction(hp,hp);
|
|
|
- allocRegBetween(asml,newreg(R_INTREGISTER,regCounter,R_SUBWHOLE),prevseqstart,hp,
|
|
|
- ptaiprop(prevseqstart.optinfo)^.usedregs);
|
|
|
- end;
|
|
|
- if not(regcounter in reginfo.RegsLoadedforRef) and
|
|
|
- {old reg new reg}
|
|
|
- (reginfo.new2oldreg[regcounter] <> regcounter) then
|
|
|
- begin
|
|
|
- getLastInstruction(curseqend,hp);
|
|
|
- opc := A_MOV;
|
|
|
- insertpos := prevseq_next;
|
|
|
- insertoptinfo := prevseqstart;
|
|
|
- if assigned(reguses[regcounter]) then
|
|
|
- if assigned(regloads[reginfo.new2oldreg[regcounter]]) then
|
|
|
- opc := A_XCHG
|
|
|
- else
|
|
|
- begin
|
|
|
- insertoptinfo := reguses[regcounter];
|
|
|
- insertpos := tai(insertoptinfo.next)
|
|
|
- end
|
|
|
- else
|
|
|
- if assigned(regloads[reginfo.new2oldreg[regcounter]]) then
|
|
|
- begin
|
|
|
- insertpos := regloads[reginfo.new2oldreg[regcounter]];
|
|
|
- if not getlastinstruction(insertpos,insertoptinfo) then
|
|
|
- internalerror(2006060701);
|
|
|
- end;
|
|
|
- hp := Tai_Marker.Create(mark_NoPropInfoStart);
|
|
|
- InsertLLItem(asml, insertpos.previous,insertpos, hp);
|
|
|
- hp2 := taicpu.Op_Reg_Reg(opc, S_L,
|
|
|
- {old reg new reg}
|
|
|
- newreg(R_INTREGISTER,reginfo.new2oldreg[regcounter],R_SUBWHOLE), newreg(R_INTREGISTER,regcounter,R_SUBWHOLE));
|
|
|
- if (opc = A_XCHG) and
|
|
|
- (taicpu(regloads[reginfo.new2oldreg[regcounter]]).opcode <> A_XCHG) then
|
|
|
- begin
|
|
|
- asml.remove(regloads[reginfo.new2oldreg[regcounter]]);
|
|
|
- regloads[reginfo.new2oldreg[regcounter]].free;
|
|
|
- regloads[reginfo.new2oldreg[regcounter]] := hp2;
|
|
|
- reguses[regcounter] := hp2;
|
|
|
- end;
|
|
|
- regloads[regcounter] := hp2;
|
|
|
- reguses[reginfo.new2oldreg[regcounter]] := hp2;
|
|
|
- new(ptaiprop(hp2.optinfo));
|
|
|
- ptaiprop(hp2.optinfo)^ := ptaiprop(insertoptinfo.optinfo)^;
|
|
|
- ptaiprop(hp2.optinfo)^.canBeRemoved := false;
|
|
|
- InsertLLItem(asml, insertpos.previous, insertpos, hp2);
|
|
|
- hp := Tai_Marker.Create(mark_NoPropInfoEnd);
|
|
|
- InsertLLItem(asml, insertpos.previous, insertpos, hp);
|
|
|
- { adjusts states in previous instruction so that it will }
|
|
|
- { definitely be different from the previous or next state }
|
|
|
- incstate(ptaiprop(hp2.optinfo)^.
|
|
|
- regs[reginfo.new2oldreg[regcounter]].rstate,20);
|
|
|
- incstate(ptaiprop(hp2.optinfo)^.
|
|
|
- regs[regCounter].wstate,20);
|
|
|
- updateState(reginfo.new2oldreg[regcounter],hp2);
|
|
|
- updateState(regcounter,hp2);
|
|
|
- end
|
|
|
- else
|
|
|
- { imagine the following code: }
|
|
|
- { normal wrong optimized }
|
|
|
- { movl 8(%ebp), %eax movl 8(%ebp), %eax }
|
|
|
- { movl (%eax), %eax movl (%eax), %eax }
|
|
|
- { cmpl 8(%ebp), %eax cmpl 8(%ebp), %eax }
|
|
|
- { jne l1 jne l1 }
|
|
|
- { movl 8(%ebp), %eax }
|
|
|
- { movl (%eax), %edi movl %eax, %edi }
|
|
|
- { movl %edi, -4(%ebp) movl %edi, -4(%ebp) }
|
|
|
- { movl 8(%ebp), %eax }
|
|
|
- { pushl 70(%eax) pushl 70(%eax) }
|
|
|
- { }
|
|
|
- { The error is that at the moment that the last instruction is executed, }
|
|
|
- { %eax doesn't contain 8(%ebp) anymore. Solution: the contents of }
|
|
|
- { registers that are completely removed from a sequence (= registers in }
|
|
|
- { RegLoadedforRef), have to be changed to their contents from before the }
|
|
|
- { sequence. }
|
|
|
- { if regcounter in reginfo.RegsLoadedforRef then }
|
|
|
- begin
|
|
|
- hp := curseqstart;
|
|
|
- { cnt still holds the number of instructions }
|
|
|
- { of the sequence, so go to the end of it }
|
|
|
- for i := 1 to pred(cnt) do
|
|
|
- getNextInstruction(hp,hp);
|
|
|
- { curprev = instruction prior to start of sequence }
|
|
|
- restoreRegContentsTo(asml,regCounter,
|
|
|
- ptaiprop(curprev.optinfo)^.Regs[regcounter],
|
|
|
- curseqstart,hp);
|
|
|
- end;
|
|
|
- end;
|
|
|
-end;
|
|
|
-
|
|
|
-
|
|
|
-procedure replaceoperandwithreg(asml: TAsmList; p: tai; opnr: byte; reg: tregister);
|
|
|
-var
|
|
|
- hp: tai;
|
|
|
-begin
|
|
|
- { new instruction -> it's info block is not in the big one allocated at the start }
|
|
|
- hp := Tai_Marker.Create(mark_NoPropInfoStart);
|
|
|
- InsertLLItem(asml, p.previous,p, hp);
|
|
|
- { duplicate the original instruction and replace it's designated operant with the register }
|
|
|
- hp := tai(p.getcopy);
|
|
|
- taicpu(hp).loadreg(opnr,reg);
|
|
|
- { add optimizer state info }
|
|
|
- new(ptaiprop(hp.optinfo));
|
|
|
- ptaiprop(hp.optinfo)^ := ptaiprop(p.optinfo)^;
|
|
|
- { new instruction can not be removed }
|
|
|
- ptaiprop(hp.optinfo)^.canBeRemoved := false;
|
|
|
- { but the old one can }
|
|
|
- ptaiprop(p.optinfo)^.canBeRemoved := true;
|
|
|
- { insert end marker }
|
|
|
- InsertLLItem(asml, p.previous, p, hp);
|
|
|
- hp := Tai_Marker.Create(mark_NoPropInfoEnd);
|
|
|
- InsertLLItem(asml, p.previous, p, hp);
|
|
|
-end;
|
|
|
-
|
|
|
-
|
|
|
-procedure doCSE(asml: TAsmList; First, Last: tai; findPrevSeqs, doSubOpts: boolean);
|
|
|
-{marks the instructions that can be removed by RemoveInstructs. They're not
|
|
|
- removed immediately because sometimes an instruction needs to be checked in
|
|
|
- two different sequences}
|
|
|
-var cnt, cnt2, {cnt3,} orgNrofMods: longint;
|
|
|
- p, hp1, hp2, hp4, hp5, prevSeq: tai;
|
|
|
- reginfo: toptreginfo;
|
|
|
- memreg: tregister;
|
|
|
- regcounter: tsuperregister;
|
|
|
-begin
|
|
|
- p := First;
|
|
|
- SkipHead(p);
|
|
|
- hp1 := nil;
|
|
|
- hp2 := nil;
|
|
|
- hp4 := nil;
|
|
|
- hp5 := nil;
|
|
|
- cnt := 0;
|
|
|
- while (p <> Last) do
|
|
|
- begin
|
|
|
- case p.typ of
|
|
|
- ait_align:
|
|
|
- if not(tai_align(p).use_op) then
|
|
|
- SetAlignReg(p);
|
|
|
- ait_instruction:
|
|
|
- begin
|
|
|
- case taicpu(p).opcode of
|
|
|
-{
|
|
|
- Does not work anymore with register calling because the registers are
|
|
|
- released before the call
|
|
|
- A_CALL:
|
|
|
- for regCounter := RS_EAX to RS_EBX do
|
|
|
- removePrevNotUsedLoad(asml,p,regCounter,true);
|
|
|
-}
|
|
|
- A_CLD: if GetLastInstruction(p, hp1) and
|
|
|
- (ptaiprop(hp1.optinfo)^.DirFlag = F_NotSet) then
|
|
|
- ptaiprop(tai(p).optinfo)^.CanBeRemoved := True;
|
|
|
- A_LEA, A_MOV, A_MOVZX, A_MOVSX:
|
|
|
- begin
|
|
|
- hp2 := p;
|
|
|
- case taicpu(p).oper[0]^.typ of
|
|
|
- top_ref, top_reg:
|
|
|
- if (taicpu(p).oper[1]^.typ = top_reg) then
|
|
|
- begin
|
|
|
- With ptaiprop(p.optinfo)^.Regs[getsupreg(taicpu(p).oper[1]^.reg)] do
|
|
|
- begin
|
|
|
- if (startmod = p) then
|
|
|
- orgNrofMods := nrofMods
|
|
|
- else
|
|
|
- orgNrofMods := 0;
|
|
|
- if (p = StartMod) and
|
|
|
- GetLastInstruction (p, hp1) and
|
|
|
- not(hp1.typ in [ait_marker,ait_label]) then
|
|
|
-{so we don't try to check a sequence when p is the first instruction of the block}
|
|
|
- begin
|
|
|
-{$ifdef csdebug}
|
|
|
- hp5 := tai_comment.Create(strpnew(
|
|
|
- 'cse checking '+std_regname(taicpu(p).oper[1]^.reg)));
|
|
|
- insertLLItem(asml,p,p.next,hp5);
|
|
|
-{$endif csdebug}
|
|
|
- if CheckSequence(p,prevSeq,getsupreg(taicpu(p).oper[1]^.reg), Cnt, reginfo, findPrevSeqs) and
|
|
|
- (Cnt > 0) then
|
|
|
- begin
|
|
|
-(*
|
|
|
- hp1 := nil;
|
|
|
-{ although it's perfectly ok to remove an instruction which doesn't contain }
|
|
|
-{ the register that we've just checked (CheckSequence takes care of that), }
|
|
|
-{ the sequence containing this other register should also be completely }
|
|
|
-{ checked and removed, otherwise we may get situations like this: }
|
|
|
-{ }
|
|
|
-{ movl 12(%ebp), %edx movl 12(%ebp), %edx }
|
|
|
-{ movl 16(%ebp), %eax movl 16(%ebp), %eax }
|
|
|
-{ movl 8(%edx), %edx movl 8(%edx), %edx }
|
|
|
-{ movl (%eax), eax movl (%eax), eax }
|
|
|
-{ cmpl %eax, %edx cmpl %eax, %edx }
|
|
|
-{ jnz l123 getting converted to jnz l123 }
|
|
|
-{ movl 12(%ebp), %edx movl 4(%eax), eax }
|
|
|
-{ movl 16(%ebp), %eax }
|
|
|
-{ movl 8(%edx), %edx }
|
|
|
-{ movl 4(%eax), eax }
|
|
|
-*)
|
|
|
-
|
|
|
-{ not anymore: if the start of a new sequence is found while checking (e.g. }
|
|
|
-{ above that of eax while checking edx, this new sequence is automatically }
|
|
|
-{ also checked }
|
|
|
- Cnt2 := 1;
|
|
|
- while Cnt2 <= Cnt do
|
|
|
- begin
|
|
|
-{$ifndef noremove}
|
|
|
- ptaiprop(p.optinfo)^.CanBeRemoved := True
|
|
|
-{$endif noremove}
|
|
|
- ; inc(Cnt2);
|
|
|
- GetNextInstruction(p, p);
|
|
|
- end;
|
|
|
- {hp4 is used to get the contents of the registers before the sequence}
|
|
|
- GetLastInstruction(hp2, hp4);
|
|
|
-
|
|
|
-{$IfDef CSDebug}
|
|
|
- for regcounter := RS_EAX To RS_EDI do
|
|
|
- if (regcounter in reginfo.RegsLoadedforRef) then
|
|
|
- begin
|
|
|
- hp5 := tai_comment.Create(strpnew('New: '+std_regname(newreg(R_INTREGISTER,regcounter,R_SUBNONE))+', Old: '+
|
|
|
- std_regname(newreg(R_INTREGISTER,reginfo.new2oldreg[regcounter],R_SUBNONE))));
|
|
|
- InsertLLItem(asml, tai(hp2.previous), hp2, hp5);
|
|
|
- end;
|
|
|
-{$EndIf CSDebug}
|
|
|
- { if some registers were different in the old and the new sequence, move }
|
|
|
- { the contents of those old registers to the new ones }
|
|
|
- loadcseregs(asml,reginfo,p,prevseq,hp2,hp4,cnt);
|
|
|
- continue;
|
|
|
- end
|
|
|
- end;
|
|
|
- end;
|
|
|
- { try to replace the new reg with the old reg }
|
|
|
- if not(ptaiprop(p.optinfo)^.canBeRemoved) then
|
|
|
- if (taicpu(p).oper[0]^.typ = top_reg) and
|
|
|
- (taicpu(p).oper[1]^.typ = top_reg) and
|
|
|
- { only remove if we're not storing something in a regvar }
|
|
|
- (getsupreg(taicpu(p).oper[1]^.reg) in [RS_EAX,RS_EBX,RS_ECX,RS_EDX,RS_ESI,RS_EDI]) and
|
|
|
-{ (taicpu(p).oper[1]^.reg in (rg.usableregsint+[RS_EDI])) and}
|
|
|
- (taicpu(p).opcode = A_MOV) and
|
|
|
- getLastInstruction(p,hp4) and
|
|
|
- { we only have to start replacing from the instruction after the mov, }
|
|
|
- { but replacereg only starts with getnextinstruction(p,p) }
|
|
|
- replaceReg(asml,getsupreg(taicpu(p).oper[0]^.reg),
|
|
|
- getsupreg(taicpu(p).oper[1]^.reg),p,p,
|
|
|
- ptaiprop(hp4.optinfo)^.regs[getsupreg(taicpu(p).oper[1]^.reg)],false,hp1) then
|
|
|
- begin
|
|
|
- ptaiprop(p.optinfo)^.canBeRemoved := true;
|
|
|
- { this is just a regular move that was here, so the source register should be }
|
|
|
- { allocated already at this point -> only allocate from here onwards }
|
|
|
- if not(getsupreg(taicpu(p).oper[0]^.reg) in pTaiProp(p.optinfo)^.usedregs) then
|
|
|
- internalerror(2004101011);
|
|
|
- allocRegBetween(asml,taicpu(p).oper[0]^.reg,
|
|
|
- p,hp1,pTaiProp(p.optinfo)^.usedregs)
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- if (taicpu(p).oper[1]^.typ = top_reg) and
|
|
|
- not regInOp(getsupreg(taicpu(p).oper[1]^.reg),taicpu(p).oper[0]^) then
|
|
|
- removePrevNotUsedLoad(asml,p,getsupreg(taicpu(p).oper[1]^.reg),false);
|
|
|
- if doSubOpts and
|
|
|
- (taicpu(p).opcode <> A_LEA) and
|
|
|
- (taicpu(p).oper[0]^.typ = top_ref) then
|
|
|
- begin
|
|
|
- memreg :=
|
|
|
- memtoreg(taicpu(p),
|
|
|
- taicpu(p).oper[0]^.ref^,hp5);
|
|
|
- if memreg <> NR_NO then
|
|
|
- if (taicpu(p).opcode = A_MOV) and
|
|
|
- (taicpu(p).oper[1]^.typ = top_reg) and
|
|
|
- (taicpu(p).oper[1]^.reg = memreg) then
|
|
|
- begin
|
|
|
- pTaiProp(p.optinfo)^.canberemoved := true;
|
|
|
- allocregbetween(asml,memreg,hp5,p,ptaiprop(hp5.optinfo)^.usedregs);
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- replaceoperandwithreg(asml,p,0,memreg);
|
|
|
- allocregbetween(asml,memreg,hp5,p,ptaiprop(hp5.optinfo)^.usedregs);
|
|
|
- regcounter := getsupreg(memreg);
|
|
|
- incstate(pTaiProp(p.optinfo)^.regs[regcounter].rstate,1);
|
|
|
- updatestate(regcounter,p);
|
|
|
- end;
|
|
|
- end;
|
|
|
- end;
|
|
|
- { at first, only try optimizations of large blocks, because doing }
|
|
|
- { doing smaller ones may prevent bigger ones from completing in }
|
|
|
- { in the next pass }
|
|
|
- if not doSubOpts and (orgNrofMods <> 0) then
|
|
|
- begin
|
|
|
- p := hp2;
|
|
|
- for cnt := 1 to pred(orgNrofMods) do
|
|
|
- getNextInstruction(p,p);
|
|
|
- end;
|
|
|
- end;
|
|
|
- top_Const:
|
|
|
- begin
|
|
|
- case taicpu(p).oper[1]^.typ of
|
|
|
- Top_Reg:
|
|
|
- begin
|
|
|
- regCounter := getsupreg(taicpu(p).oper[1]^.reg);
|
|
|
- if GetLastInstruction(p, hp1) then
|
|
|
- With ptaiprop(hp1.optinfo)^.Regs[regCounter] do
|
|
|
- if (typ in [con_const,con_noRemoveConst]) and
|
|
|
- (taicpu(startMod).opsize >= taicpu(p).opsize) and
|
|
|
- opsequal(taicpu(StartMod).oper[0]^,taicpu(p).oper[0]^) then
|
|
|
- begin
|
|
|
- ptaiprop(p.optinfo)^.CanBeRemoved := True;
|
|
|
- allocRegBetween(asml,taicpu(p).oper[1]^.reg,startmod,p,
|
|
|
- ptaiprop(startmod.optinfo)^.usedregs);
|
|
|
- end
|
|
|
- else
|
|
|
- removePrevNotUsedLoad(asml,p,getsupreg(taicpu(p).oper[1]^.reg),false);
|
|
|
-
|
|
|
- end;
|
|
|
- Top_Ref:
|
|
|
- if (taicpu(p).oper[0]^.typ = top_const) and
|
|
|
- getLastInstruction(p,hp1) and
|
|
|
- findRegWithConst(hp1,taicpu(p).opsize,taicpu(p).oper[0]^.val,memreg) then
|
|
|
- begin
|
|
|
- taicpu(p).loadreg(0,memreg);
|
|
|
- { mark the used register as read }
|
|
|
- incstate(ptaiprop(p.optinfo)^.
|
|
|
- regs[getsupreg(memreg)].rstate,20);
|
|
|
- updateState(getsupreg(memreg),p);
|
|
|
- allocRegBetween(asml,memreg,
|
|
|
- ptaiprop(hp1.optinfo)^.regs[getsupreg(memreg)].startMod,p,
|
|
|
- ptaiprop(ptaiprop(hp1.optinfo)^.regs[getsupreg(memreg)].startMod.optinfo)^.usedregs);
|
|
|
- end;
|
|
|
- end;
|
|
|
- end;
|
|
|
- end;
|
|
|
-
|
|
|
- end;
|
|
|
- A_LEAVE:
|
|
|
- begin
|
|
|
- if getlastinstruction(p,hp1) then
|
|
|
- removeLocalStores(hp1);
|
|
|
- end;
|
|
|
- A_STD: if GetLastInstruction(p, hp1) and
|
|
|
- (ptaiprop(hp1.optinfo)^.DirFlag = F_Set) then
|
|
|
- ptaiprop(tai(p).optinfo)^.CanBeRemoved := True;
|
|
|
- else
|
|
|
- begin
|
|
|
- for cnt := 1 to maxinschanges do
|
|
|
- begin
|
|
|
- case InsProp[taicpu(p).opcode].Ch[cnt] of
|
|
|
- Ch_ROp1:
|
|
|
- if (taicpu(p).oper[0]^.typ = top_ref) and
|
|
|
- ((taicpu(p).opcode < A_F2XM1) or
|
|
|
- ((taicpu(p).opcode > A_IN) and
|
|
|
- (taicpu(p).opcode < A_OUT)) or
|
|
|
- (taicpu(p).opcode = A_PUSH) or
|
|
|
- ((taicpu(p).opcode >= A_RCL) and
|
|
|
- (taicpu(p).opcode <= A_XOR))) then
|
|
|
- begin
|
|
|
- memreg :=
|
|
|
- memtoreg(taicpu(p),
|
|
|
- taicpu(p).oper[0]^.ref^,hp5);
|
|
|
- if memreg <> NR_NO then
|
|
|
- begin
|
|
|
- replaceoperandwithreg(asml,p,0,memreg);
|
|
|
- allocregbetween(asml,memreg,hp5,p,ptaiprop(hp5.optinfo)^.usedregs);
|
|
|
- regcounter := getsupreg(memreg);
|
|
|
- incstate(pTaiProp(p.optinfo)^.regs[regcounter].rstate,1);
|
|
|
- updatestate(regcounter,p);
|
|
|
- end;
|
|
|
- end;
|
|
|
- Ch_MOp1:
|
|
|
- if not(cs_opt_size in current_settings.optimizerswitches) and
|
|
|
- (taicpu(p).oper[0]^.typ = top_ref) then
|
|
|
- begin
|
|
|
- memreg :=
|
|
|
- memtoreg(taicpu(p),
|
|
|
- taicpu(p).oper[0]^.ref^,hp5);
|
|
|
- if (memreg <> NR_NO) and
|
|
|
- (not getNextInstruction(p,hp1) or
|
|
|
- (RegLoadedWithNewValue(getsupreg(memreg),false,hp1) or
|
|
|
- FindRegDealloc(getsupreg(memreg),hp1))) then
|
|
|
- begin
|
|
|
- hp1 := Tai_Marker.Create(mark_NoPropInfoEnd);
|
|
|
- insertllitem(asml,p,p.next,hp1);
|
|
|
- hp1 := taicpu.op_reg_ref(A_MOV,reg2opsize(memreg),
|
|
|
- memreg,taicpu(p).oper[0]^.ref^);
|
|
|
- new(ptaiprop(hp1.optinfo));
|
|
|
- pTaiProp(hp1.optinfo)^ := pTaiProp(p.optinfo)^;
|
|
|
- insertllitem(asml,p,p.next,hp1);
|
|
|
- regcounter := getsupreg(memreg);
|
|
|
- incstate(pTaiProp(hp1.optinfo)^.regs[regcounter].rstate,1);
|
|
|
- updatestate(regcounter,hp1);
|
|
|
- hp1 := Tai_Marker.Create(mark_NoPropInfoStart);
|
|
|
- insertllitem(asml,p,p.next,hp1);
|
|
|
- replaceoperandwithreg(asml,p,0,memreg);
|
|
|
- allocregbetween(asml,memreg,hp5,
|
|
|
- tai(p.next.next),ptaiprop(hp5.optinfo)^.usedregs);
|
|
|
- ClearRegContentsFrom(asml,regcounter,hp5,p);
|
|
|
- end;
|
|
|
- end;
|
|
|
- Ch_ROp2:
|
|
|
- if ((taicpu(p).opcode = A_CMP) or
|
|
|
- (taicpu(p).opcode = A_TEST)) and
|
|
|
- (taicpu(p).oper[1]^.typ = top_ref) then
|
|
|
- begin
|
|
|
- memreg :=
|
|
|
- memtoreg(taicpu(p),
|
|
|
- taicpu(p).oper[1]^.ref^,hp5);
|
|
|
- if memreg <> NR_NO then
|
|
|
- begin
|
|
|
- replaceoperandwithreg(asml,p,1,memreg);
|
|
|
- allocregbetween(asml,memreg,hp5,p,ptaiprop(hp5.optinfo)^.usedregs);
|
|
|
- regcounter := getsupreg(memreg);
|
|
|
- incstate(pTaiProp(p.optinfo)^.regs[regcounter].rstate,1);
|
|
|
- updatestate(regcounter,p);
|
|
|
- end;
|
|
|
- end;
|
|
|
- Ch_MOp2:
|
|
|
- if not(cs_opt_size in current_settings.optimizerswitches) and
|
|
|
- (taicpu(p).oper[1]^.typ = top_ref) and
|
|
|
- ((taicpu(p).opcode < A_BT) or
|
|
|
- ((taicpu(p).opcode > A_IN) and
|
|
|
- (taicpu(p).opcode < A_OUT)) or
|
|
|
- (taicpu(p).opcode = A_PUSH) or
|
|
|
- ((taicpu(p).opcode >= A_RCL) and
|
|
|
- (taicpu(p).opcode <= A_XOR))) then
|
|
|
- begin
|
|
|
- memreg :=
|
|
|
- memtoreg(taicpu(p),
|
|
|
- taicpu(p).oper[1]^.ref^,hp5);
|
|
|
- if (memreg <> NR_NO) and
|
|
|
- (not getNextInstruction(p,hp1) or
|
|
|
- (RegLoadedWithNewValue(getsupreg(memreg),false,hp1) or
|
|
|
- FindRegDealloc(getsupreg(memreg),hp1))) then
|
|
|
- begin
|
|
|
- hp1 := Tai_Marker.Create(mark_NoPropInfoEnd);
|
|
|
- insertllitem(asml,p,p.next,hp1);
|
|
|
- hp1 := taicpu.op_reg_ref(A_MOV,reg2opsize(memreg),
|
|
|
- memreg,taicpu(p).oper[1]^.ref^);
|
|
|
- new(ptaiprop(hp1.optinfo));
|
|
|
- pTaiProp(hp1.optinfo)^ := pTaiProp(p.optinfo)^;
|
|
|
- insertllitem(asml,p,p.next,hp1);
|
|
|
- regcounter := getsupreg(memreg);
|
|
|
- incstate(pTaiProp(hp1.optinfo)^.regs[regcounter].rstate,1);
|
|
|
- updatestate(regcounter,hp1);
|
|
|
- hp1 := Tai_Marker.Create(mark_NoPropInfoStart);
|
|
|
- insertllitem(asml,p,p.next,hp1);
|
|
|
- replaceoperandwithreg(asml,p,1,memreg);
|
|
|
- allocregbetween(asml,memreg,hp5,
|
|
|
- tai(p.next.next),ptaiprop(hp5.optinfo)^.usedregs);
|
|
|
- ClearRegContentsFrom(asml,regcounter,hp5,p);
|
|
|
- end;
|
|
|
- end;
|
|
|
- end;
|
|
|
- end;
|
|
|
- end;
|
|
|
- end
|
|
|
- end;
|
|
|
- end;
|
|
|
- GetNextInstruction(p, p);
|
|
|
- end;
|
|
|
-end;
|
|
|
-
|
|
|
-function removeInstructs(asml: TAsmList; first, last: tai): boolean;
|
|
|
-{ Removes the marked instructions and disposes the PTaiProps of the other }
|
|
|
-{ instructions }
|
|
|
-var
|
|
|
- p, hp1: tai;
|
|
|
- nopropinfolevel: longint;
|
|
|
-begin
|
|
|
- removeInstructs := false;
|
|
|
- p := First;
|
|
|
- nopropinfolevel := 0;
|
|
|
- while (p <> Last) do
|
|
|
- begin
|
|
|
- if (p.typ = ait_marker) and
|
|
|
- (Tai_marker(p).kind = mark_NoPropInfoStart) then
|
|
|
- begin
|
|
|
- hp1 := tai(p.next);
|
|
|
- asml.remove(p);
|
|
|
- p.free;
|
|
|
- nopropinfolevel := 1;
|
|
|
- while (nopropinfolevel <> 0) do
|
|
|
- begin
|
|
|
- p := tai(hp1.next);
|
|
|
-{$ifndef noinstremove}
|
|
|
- { allocregbetween can insert new ait_regalloc objects }
|
|
|
- { without optinfo }
|
|
|
- if (hp1.typ = ait_marker) then
|
|
|
- begin
|
|
|
- case Tai_marker(hp1).kind of
|
|
|
- { they can be nested! }
|
|
|
- mark_NoPropInfoStart: inc(nopropinfolevel);
|
|
|
- mark_NoPropInfoEnd: dec(nopropinfolevel);
|
|
|
- else
|
|
|
- begin
|
|
|
- hp1 := p;
|
|
|
- continue;
|
|
|
- end;
|
|
|
- end;
|
|
|
- asml.remove(hp1);
|
|
|
- hp1.free;
|
|
|
- end
|
|
|
- else if assigned(hp1.optinfo) then
|
|
|
- if ptaiprop(hp1.optinfo)^.canBeRemoved then
|
|
|
- begin
|
|
|
- dispose(ptaiprop(hp1.optinfo));
|
|
|
- hp1.optinfo := nil;
|
|
|
- asml.remove(hp1);
|
|
|
- hp1.free;
|
|
|
- end
|
|
|
- else
|
|
|
-{$endif noinstremove}
|
|
|
- begin
|
|
|
- dispose(ptaiprop(hp1.optinfo));
|
|
|
- hp1.optinfo := nil;
|
|
|
- end;
|
|
|
- hp1 := p;
|
|
|
- end;
|
|
|
- end
|
|
|
- else
|
|
|
-{$ifndef noinstremove}
|
|
|
- if assigned(p.optinfo) and
|
|
|
- ptaiprop(p.optinfo)^.canBeRemoved then
|
|
|
- begin
|
|
|
- hp1 := tai(p.next);
|
|
|
- asml.Remove(p);
|
|
|
- p.free;
|
|
|
- p := hp1;
|
|
|
- removeInstructs := true;
|
|
|
- end
|
|
|
- else
|
|
|
-{$endif noinstremove}
|
|
|
- begin
|
|
|
- p.optinfo := nil;
|
|
|
- p := tai(p.next);
|
|
|
- end;
|
|
|
- end;
|
|
|
-end;
|
|
|
-
|
|
|
-function CSE(asml: TAsmList; First, Last: tai; pass: longint): boolean;
|
|
|
-begin
|
|
|
- doCSE(asml, First, Last, not(cs_opt_level3 in current_settings.optimizerswitches) or (pass >= 2),
|
|
|
- not(cs_opt_level3 in current_settings.optimizerswitches) or (pass >= 1));
|
|
|
- { register renaming }
|
|
|
- if not(cs_opt_level3 in current_settings.optimizerswitches) or (pass > 0) then
|
|
|
- doRenaming(asml, first, last);
|
|
|
- cse := removeInstructs(asml, first, last);
|
|
|
-end;
|
|
|
-
|
|
|
-end.
|