mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-07-23 08:16:33 +02:00
* search much further back for CSE sequences (non-conflicting stores are
now passed) * remove more unnecessary loads of registers (especially the self pointer)
This commit is contained in:
parent
ec5edf7be2
commit
9e77e31a28
@ -58,61 +58,100 @@ Begin
|
|||||||
End;
|
End;
|
||||||
}
|
}
|
||||||
|
|
||||||
function modifiesMemLocation(p1: pai): boolean;
|
function modifiesConflictingMemLocation(p1: pai; reg: tregister; c: tregContent;
|
||||||
var p: paicpu;
|
var regsStillValid: tregset): boolean;
|
||||||
opCount: byte;
|
var
|
||||||
|
p: paicpu;
|
||||||
|
tmpRef: treference;
|
||||||
|
regCounter: tregister;
|
||||||
|
opCount: byte;
|
||||||
begin
|
begin
|
||||||
modifiesMemLocation := false;
|
modifiesConflictingMemLocation := false;
|
||||||
if p1^.typ <> ait_instruction then
|
if p1^.typ <> ait_instruction then
|
||||||
exit;
|
exit;
|
||||||
p := paicpu(p1);
|
p := paicpu(p1);
|
||||||
for opCount := 1 to MaxCh do
|
case p^.opcode of
|
||||||
case InsProp[p^.opcode].Ch[opCount] of
|
A_MOV,A_MOVSX,A_MOVZX:
|
||||||
Ch_MOp1,CH_WOp1,CH_RWOp1:
|
if p^.oper[1].typ = top_ref then
|
||||||
if (p^.oper[0].typ = top_ref) or
|
for regCounter := R_EAX to R_EDI do
|
||||||
((p^.oper[0].typ = top_reg) and
|
|
||||||
not(reg32(p^.oper[0].reg) in (usableregs+[R_EDI]))) then
|
|
||||||
begin
|
begin
|
||||||
modifiesMemLocation := true;
|
if writeToMemDestroysContents(reg32(p^.oper[0].reg),p^.oper[1].ref^,
|
||||||
exit
|
regCounter,c[regCounter]) then
|
||||||
end;
|
begin
|
||||||
Ch_MOp2,CH_WOp2,CH_RWOp2:
|
exclude(regsStillValid,regCounter);
|
||||||
if (p^.oper[1].typ = top_ref) or
|
modifiesConflictingMemLocation := not(reg in regsStillValid);
|
||||||
((p^.oper[1].typ = top_reg) and
|
end;
|
||||||
not(reg32(p^.oper[1].reg) in (usableregs+[R_EDI]))) then
|
end
|
||||||
|
{ else
|
||||||
|
for regCounter := R_EAX to R_EDI do
|
||||||
begin
|
begin
|
||||||
modifiesMemLocation := true;
|
if writeDestroysContents(p^.oper[1],regCounter,c[regCounter]) then
|
||||||
exit
|
begin
|
||||||
end;
|
exclude(regsStillValid,regCounter);
|
||||||
Ch_MOp3,CH_WOp3,CH_RWOp3:
|
modifiesConflictingMemLocation := not(reg in regsStillValid);
|
||||||
if (p^.oper[2].typ = top_ref) or
|
end
|
||||||
((p^.oper[2].typ = top_reg) and
|
end};
|
||||||
not(reg32(p^.oper[2].reg) in (usableregs+[R_EDI]))) then
|
A_IMUL,A_DIV, A_IDIV, A_MUL:; { they never write to memory }
|
||||||
begin
|
else
|
||||||
modifiesMemLocation := true;
|
for opCount := 1 to MaxCh do
|
||||||
exit
|
case InsProp[p^.opcode].Ch[opCount] of
|
||||||
end;
|
Ch_MOp1,CH_WOp1,CH_RWOp1:
|
||||||
Ch_WMemEDI:
|
if paicpu(p)^.oper[0].typ = top_ref then
|
||||||
begin
|
for regCounter := R_EAX to R_EDI do
|
||||||
modifiesMemLocation := true;
|
if writeDestroysContents(p^.oper[0],regCounter,c[regCounter]) then
|
||||||
exit;
|
begin
|
||||||
|
exclude(regsStillValid,regCounter);
|
||||||
|
modifiesConflictingMemLocation := not(reg in regsStillValid);
|
||||||
|
end;
|
||||||
|
Ch_MOp2,CH_WOp2,CH_RWOp2:
|
||||||
|
if paicpu(p)^.oper[1].typ = top_ref then
|
||||||
|
for regCounter := R_EAX to R_EDI do
|
||||||
|
if writeDestroysContents(p^.oper[1],regCounter,c[regCounter]) then
|
||||||
|
begin
|
||||||
|
exclude(regsStillValid,regCounter);
|
||||||
|
modifiesConflictingMemLocation := not(reg in regsStillValid);
|
||||||
|
end;
|
||||||
|
Ch_MOp3,CH_WOp3,CH_RWOp3:
|
||||||
|
if paicpu(p)^.oper[2].typ = top_ref then
|
||||||
|
for regCounter := R_EAX to R_EDI do
|
||||||
|
if writeDestroysContents(p^.oper[2],regCounter,c[regCounter]) then
|
||||||
|
begin
|
||||||
|
exclude(regsStillValid,regCounter);
|
||||||
|
modifiesConflictingMemLocation := not(reg in regsStillValid);
|
||||||
|
end;
|
||||||
|
Ch_WMemEDI:
|
||||||
|
begin
|
||||||
|
fillchar(tmpref,sizeof(tmpref),0);
|
||||||
|
tmpRef.base := R_EDI;
|
||||||
|
tmpRef.index := R_EDI;
|
||||||
|
for regCounter := R_EAX to R_EDI do
|
||||||
|
if writeToMemDestroysContents(R_NO,tmpRef,regCounter,c[regCounter]) then
|
||||||
|
begin
|
||||||
|
exclude(regsStillValid,regCounter);
|
||||||
|
modifiesConflictingMemLocation := not(reg in regsStillValid);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function getPrevSequence(reg: tregister; current: pai; var prev: pai; var passedJump: boolean):
|
function getPrevSequence(p: pai; reg: tregister; currentPrev: pai; var newPrev: pai;
|
||||||
tregister;
|
var passedJump: boolean; var regsNotRead, regsStillValid: tregset): tregister;
|
||||||
|
|
||||||
|
const
|
||||||
|
current_reg: tregister = R_NO;
|
||||||
|
|
||||||
function stillValid(p: pai): boolean;
|
function stillValid(p: pai): boolean;
|
||||||
begin
|
begin
|
||||||
stillValid :=
|
stillValid :=
|
||||||
(p^.typ = ait_instruction) and
|
(p^.typ = ait_instruction) and
|
||||||
(paicpu(p)^.opcode <> a_jmp) and
|
(paicpu(p)^.opcode <> a_jmp) and
|
||||||
(ppaiprop(p^.optinfo)^.regs[reg].state =
|
(ppaiprop(p^.optinfo)^.regs[reg].wstate =
|
||||||
ppaiprop(current^.optinfo)^.regs[reg].state) and
|
ppaiprop(currentPrev^.optinfo)^.regs[reg].wstate) and
|
||||||
{ in case destroyreg is called with doIncState = false }
|
{ in case destroyreg is called with doIncState = false }
|
||||||
(ppaiprop(p^.optinfo)^.regs[reg].typ =
|
(ppaiprop(p^.optinfo)^.regs[reg].typ =
|
||||||
ppaiprop(current^.optinfo)^.regs[reg].typ);
|
ppaiprop(currentPrev^.optinfo)^.regs[reg].typ) and
|
||||||
|
(reg in (regsNotRead * regsStillValid));
|
||||||
passedJump :=
|
passedJump :=
|
||||||
(p^.typ = ait_instruction) and
|
(p^.typ = ait_instruction) and
|
||||||
(paicpu(p)^.is_jmp);
|
(paicpu(p)^.is_jmp);
|
||||||
@ -122,54 +161,86 @@ function getPrevSequence(reg: tregister; current: pai; var prev: pai; var passed
|
|||||||
var
|
var
|
||||||
regCounter: tregister;
|
regCounter: tregister;
|
||||||
begin
|
begin
|
||||||
for regCounter := R_EAX to R_EDI do
|
for regCounter := succ(current_reg) to R_EDI do
|
||||||
with ppaiprop(p^.optinfo)^.regs[regCounter] do
|
with ppaiprop(p^.optinfo)^.regs[regCounter] do
|
||||||
if ((startmod <>
|
if ((startmod <>
|
||||||
ppaiprop(current^.optinfo)^.regs[regCounter].startmod) or
|
ppaiprop(currentPrev^.optinfo)^.regs[regCounter].startmod) or
|
||||||
(nrOfMods <>
|
(nrOfMods <>
|
||||||
ppaiprop(current^.optinfo)^.regs[regCounter].nrOfMods)) and
|
ppaiprop(currentPrev^.optinfo)^.regs[regCounter].nrOfMods)) and
|
||||||
(not ppaiprop(p^.optinfo)^.canBeRemoved) and
|
|
||||||
(ppaiprop(p^.optinfo)^.regs[regCounter].typ in
|
(ppaiprop(p^.optinfo)^.regs[regCounter].typ in
|
||||||
[con_ref,con_noRemoveRef]) then
|
[con_ref,con_noRemoveRef]) then
|
||||||
begin
|
begin
|
||||||
findChangedRegister := regCounter;
|
findChangedRegister := regCounter;
|
||||||
|
current_reg := regCounter;
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
|
current_reg := R_NO;
|
||||||
findChangedRegister := R_NO;
|
findChangedRegister := R_NO;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
var
|
var
|
||||||
hp, prevFound: pai;
|
hp, prevFound: pai;
|
||||||
tmpResult: tregister;
|
tmpResult, regCounter: tregister;
|
||||||
begin
|
begin
|
||||||
getPrevSequence := R_NO;
|
if not(current_reg in [R_NO,R_EDI]) then
|
||||||
{ no memory writes (could be refined further) }
|
|
||||||
passedJump := passedJump or
|
|
||||||
((current^.typ = ait_instruction) and
|
|
||||||
(paicpu(current)^.is_jmp));
|
|
||||||
if modifiesMemLocation(current) or
|
|
||||||
(passedJump and not(reg in (usableregs+[R_EDI]))) or
|
|
||||||
not getLastInstruction(current,hp) then
|
|
||||||
exit;
|
|
||||||
tmpResult := R_NO;
|
|
||||||
while (tmpResult = R_NO) and
|
|
||||||
stillValid(hp) do
|
|
||||||
begin
|
begin
|
||||||
|
tmpResult := findChangedRegister(currentPrev);
|
||||||
|
if tmpResult <> R_NO then
|
||||||
|
begin
|
||||||
|
getPrevSequence := tmpResult;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
getPrevSequence := R_NO;
|
||||||
|
passedJump := passedJump or
|
||||||
|
((currentPrev^.typ = ait_instruction) and
|
||||||
|
(paicpu(currentPrev)^.is_jmp));
|
||||||
|
|
||||||
|
if (passedJump and not(reg in (usableregs+[R_EDI]))) or
|
||||||
|
not getLastInstruction(currentPrev,hp) then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
prevFound := currentPrev;
|
||||||
|
tmpResult := R_NO;
|
||||||
|
|
||||||
|
while (tmpResult = R_NO) and
|
||||||
|
stillValid(hp) and
|
||||||
|
not(modifiesConflictingMemLocation(prevFound,reg,
|
||||||
|
ppaiprop(p^.optinfo)^.regs,regsStillValid)) do
|
||||||
|
begin
|
||||||
|
{ only update the regsread for the instructions we already passed }
|
||||||
|
if not(ppaiprop(prevFound^.optinfo)^.canBeRemoved) then
|
||||||
|
for regCounter := R_EAX to R_EDI do
|
||||||
|
if regReadByInstruction(regCounter,prevFound) then
|
||||||
|
exclude(regsNotRead,regCounter);
|
||||||
|
|
||||||
{ in case getPreviousInstruction fails and sets hp to nil in the }
|
{ in case getPreviousInstruction fails and sets hp to nil in the }
|
||||||
{ next iteration }
|
{ next iteration }
|
||||||
prevFound := hp;
|
prevFound := hp;
|
||||||
tmpResult := findChangedRegister(hp);
|
if not(ppaiprop(hp^.optinfo)^.canBeRemoved) then
|
||||||
if modifiesMemLocation(hp) or
|
tmpResult := findChangedRegister(hp);
|
||||||
{ do not load the self pointer or a regvar before a (conditional) }
|
if { do not load the self pointer or a regvar before a (conditional) }
|
||||||
{ jump with a new value, since if the jump is taken, the old value }
|
{ jump with a new value, since if the jump is taken, the old value }
|
||||||
{ is (probably) still necessary }
|
{ is (probably) still necessary }
|
||||||
(passedJump and not(reg in (usableregs+[R_EDI]))) or
|
(passedJump and not(reg in (usableregs+[R_EDI]))) or
|
||||||
not getLastInstruction(hp,hp) then
|
not getLastInstruction(hp,hp) then
|
||||||
break;
|
break;
|
||||||
end;
|
end;
|
||||||
getPrevSequence := tmpResult;
|
getPrevSequence := tmpResult;
|
||||||
if tmpResult <> R_NO then
|
if tmpResult <> R_NO then
|
||||||
prev := prevFound;
|
newPrev := prevFound;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function isSimpleMemLoc(const ref: treference): boolean;
|
||||||
|
begin
|
||||||
|
isSimpleMemLoc :=
|
||||||
|
(ref.index = R_NO) and
|
||||||
|
(not(ref.base in (usableregs+[R_EDI])) or
|
||||||
|
(assigned(ref.symbol) and
|
||||||
|
(ref.base = R_NO) and
|
||||||
|
(ref.index = R_NO)));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -181,26 +252,25 @@ end;
|
|||||||
Function CheckSequence(p: Pai; var prev: pai; Reg: TRegister; Var Found: Longint;
|
Function CheckSequence(p: Pai; var prev: pai; Reg: TRegister; Var Found: Longint;
|
||||||
Var RegInfo: TRegInfo): Boolean;
|
Var RegInfo: TRegInfo): Boolean;
|
||||||
|
|
||||||
|
const
|
||||||
|
checkingPrevSequences: boolean = false;
|
||||||
|
var
|
||||||
|
regsNotRead, regsStillValid: tregset;
|
||||||
|
|
||||||
function getNextRegToTest(var orgP: pai; currentReg: tregister): tregister;
|
function getNextRegToTest(var prev: pai; currentReg: tregister): tregister;
|
||||||
const
|
const
|
||||||
checkingPrevSequences: boolean = false;
|
|
||||||
passedJump: boolean = false;
|
passedJump: boolean = false;
|
||||||
begin
|
begin
|
||||||
if currentReg = R_NO then
|
|
||||||
checkingPrevSequences := false;
|
|
||||||
if not checkingPrevSequences then
|
if not checkingPrevSequences then
|
||||||
begin
|
begin
|
||||||
Repeat
|
Repeat
|
||||||
Inc(currentReg);
|
Inc(currentReg);
|
||||||
Until (currentReg > R_EDI) or
|
Until (currentReg > R_EDI) or
|
||||||
(ppaiprop(orgP^.optInfo)^.regs[currentReg].typ
|
(ppaiprop(prev^.optInfo)^.regs[currentReg].typ
|
||||||
in [con_ref,con_noRemoveRef]);
|
in [con_ref,con_noRemoveRef]);
|
||||||
if currentReg > R_EDI then
|
if currentReg > R_EDI then
|
||||||
begin
|
begin
|
||||||
if not modifiesMemLocation(orgP) and
|
if isSimpleMemLoc(paicpu(p)^.oper[0].ref^) then
|
||||||
(ppaiprop(orgP^.optinfo)^.regs[reg].rstate =
|
|
||||||
ppaiprop(p^.optinfo)^.regs[reg].rstate) then
|
|
||||||
begin
|
begin
|
||||||
checkingPrevSequences := true;
|
checkingPrevSequences := true;
|
||||||
passedJump := false;
|
passedJump := false;
|
||||||
@ -211,7 +281,8 @@ Function CheckSequence(p: Pai; var prev: pai; Reg: TRegister; Var Found: Longint
|
|||||||
else getNextRegToTest := currentReg;
|
else getNextRegToTest := currentReg;
|
||||||
end;
|
end;
|
||||||
if checkingPrevSequences then
|
if checkingPrevSequences then
|
||||||
getNextRegToTest := getPrevSequence(reg,orgP,orgP, passedJump);
|
getNextRegToTest :=
|
||||||
|
getPrevSequence(p,reg,prev,prev,passedJump,regsNotRead,RegsStillValid);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Var hp2, hp3{, EndMod},highPrev, orgPrev: Pai;
|
Var hp2, hp3{, EndMod},highPrev, orgPrev: Pai;
|
||||||
@ -238,6 +309,9 @@ Begin {CheckSequence}
|
|||||||
oldRegsEncountered := newRegsEncountered;
|
oldRegsEncountered := newRegsEncountered;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
checkingPrevSequences := false;
|
||||||
|
regsNotRead := [R_EAX,R_EBX,R_ECX,R_EDX,R_ESP,R_EBP,R_EDI,R_ESI];
|
||||||
|
regsStillValid := regsNotRead;
|
||||||
GetLastInstruction(p, prev);
|
GetLastInstruction(p, prev);
|
||||||
regCounter := getNextRegToTest(prev,R_NO);
|
regCounter := getNextRegToTest(prev,R_NO);
|
||||||
While (RegCounter <> R_NO) Do
|
While (RegCounter <> R_NO) Do
|
||||||
@ -268,11 +342,23 @@ Begin {CheckSequence}
|
|||||||
GetNextInstruction(hp3, hp3);
|
GetNextInstruction(hp3, hp3);
|
||||||
Inc(Found)
|
Inc(Found)
|
||||||
End;
|
End;
|
||||||
for regCounter2 := R_EAX to R_EDX do
|
|
||||||
|
for regCounter2 := R_EAX to R_EDI do
|
||||||
if (regInfo.new2OldReg[regCounter2] <> R_NO) and
|
if (regInfo.new2OldReg[regCounter2] <> R_NO) and
|
||||||
(regCounter2 in PPaiProp(hp3^.optInfo)^.usedRegs) and
|
(regCounter2 in PPaiProp(hp3^.optInfo)^.usedRegs) and
|
||||||
not regLoadedWithNewValue(regCounter2,false,hp3) then
|
not regLoadedWithNewValue(regCounter2,false,hp3) then
|
||||||
include(regInfo.regsStillUsedAfterSeq,regCounter2);
|
include(regInfo.regsStillUsedAfterSeq,regCounter2);
|
||||||
|
|
||||||
|
if checkingPrevSequences then
|
||||||
|
for regCounter2 := R_EAX to R_EDI do
|
||||||
|
if not(regInfo.new2OldReg[regCounter2] in [R_NO,regCounter2]) and
|
||||||
|
(not(regCounter2 in (regsNotRead * regsStillValid)) or
|
||||||
|
not(regInfo.new2OldReg[regCounter2] in regsStillValid)) then
|
||||||
|
begin
|
||||||
|
found := 0;
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
|
||||||
If (Found <> OldNrOfMods) or
|
If (Found <> OldNrOfMods) or
|
||||||
{ the following is to avoid problems with rangecheck code (see testcse2) }
|
{ the following is to avoid problems with rangecheck code (see testcse2) }
|
||||||
(assigned(hp3) and
|
(assigned(hp3) and
|
||||||
@ -1144,6 +1230,7 @@ begin
|
|||||||
ppaiprop(startMod^.optInfo)^.canBeRemoved := true;
|
ppaiprop(startMod^.optInfo)^.canBeRemoved := true;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
Procedure DoCSE(AsmL: PAasmOutput; First, Last: Pai);
|
Procedure DoCSE(AsmL: PAasmOutput; First, Last: Pai);
|
||||||
{marks the instructions that can be removed by RemoveInstructs. They're not
|
{marks the instructions that can be removed by RemoveInstructs. They're not
|
||||||
removed immediately because sometimes an instruction needs to be checked in
|
removed immediately because sometimes an instruction needs to be checked in
|
||||||
@ -1407,7 +1494,11 @@ Begin
|
|||||||
allocRegBetween(asmL,paicpu(p)^.oper[0].reg,
|
allocRegBetween(asmL,paicpu(p)^.oper[0].reg,
|
||||||
PPaiProp(p^.optInfo)^.regs[paicpu(p)^.oper[0].reg].startMod,
|
PPaiProp(p^.optInfo)^.regs[paicpu(p)^.oper[0].reg].startMod,
|
||||||
hp1);
|
hp1);
|
||||||
end;
|
end
|
||||||
|
else
|
||||||
|
if reg32(paicpu(p)^.oper[0].reg) <> reg32(paicpu(p)^.oper[1].reg) then
|
||||||
|
removePrevNotUsedLoad(p,reg32(paicpu(p)^.oper[1].reg),false);
|
||||||
|
|
||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
top_symbol,Top_Const:
|
top_symbol,Top_Const:
|
||||||
@ -1424,7 +1515,10 @@ Begin
|
|||||||
begin
|
begin
|
||||||
PPaiProp(p^.OptInfo)^.CanBeRemoved := True;
|
PPaiProp(p^.OptInfo)^.CanBeRemoved := True;
|
||||||
allocRegBetween(asmL,regCounter,startMod,p);
|
allocRegBetween(asmL,regCounter,startMod,p);
|
||||||
end;
|
end
|
||||||
|
else
|
||||||
|
removePrevNotUsedLoad(p,reg32(paicpu(p)^.oper[1].reg),false);
|
||||||
|
|
||||||
End;
|
End;
|
||||||
Top_Ref:
|
Top_Ref:
|
||||||
if (paicpu(p)^.oper[0].typ = top_const) and
|
if (paicpu(p)^.oper[0].typ = top_const) and
|
||||||
@ -1438,6 +1532,7 @@ Begin
|
|||||||
End;
|
End;
|
||||||
End;
|
End;
|
||||||
End;
|
End;
|
||||||
|
|
||||||
End;
|
End;
|
||||||
A_STD: If GetLastInstruction(p, hp1) And
|
A_STD: If GetLastInstruction(p, hp1) And
|
||||||
(PPaiProp(hp1^.OptInfo)^.DirFlag = F_Set) Then
|
(PPaiProp(hp1^.OptInfo)^.DirFlag = F_Set) Then
|
||||||
@ -1495,7 +1590,12 @@ End.
|
|||||||
|
|
||||||
{
|
{
|
||||||
$Log$
|
$Log$
|
||||||
Revision 1.12 2000-09-26 11:49:41 jonas
|
Revision 1.13 2000-09-29 23:14:45 jonas
|
||||||
|
* search much further back for CSE sequences (non-conflicting stores are
|
||||||
|
now passed)
|
||||||
|
* remove more unnecessary loads of registers (especially the self pointer)
|
||||||
|
|
||||||
|
Revision 1.12 2000/09/26 11:49:41 jonas
|
||||||
* writes to register variables and to the self pointer now also count as
|
* writes to register variables and to the self pointer now also count as
|
||||||
memore writes
|
memore writes
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user