o patch by J. Gareth Moreton, resolves r36371:

* This patch makes some minor improvements to the cross-platform code that deals with jump optimisations.
      More specifically, it attempts to do more in a single pass which has the nice side-effect of
      fixing a couple of minor mistakes (in some situations, it would erroneously remove an alignment entry).
      - Most improvements are with dealing with Jcc/JMP pairs and their equivalents on other platforms, by
      collapsing label clusters and stripping dead code as soon as it has enough information to do so, and being
      more intelligent before calling Continue to see if another optimisation can be performed in the same sitting.

      - RemoveDeadCodeAfterJump is now a function that returns True if a jump was found among the dead code,
      thus allowing the ability to flag the peephole optimizer for another iteration of Pass 1 - the
      destination label may have appeared earlier in the code and become dead as a result of the removal
      of the jump, thus opening up new optimisations with instructions that sat either side of the label.

      - Preliminary tests show that it does sometimes reduce the number of passes required to optimise a subroutine
      under -O3.

git-svn-id: trunk@43668 -
This commit is contained in:
florian 2019-12-09 20:58:31 +00:00
parent 2a315df80c
commit 599e2df71f

View File

@ -380,8 +380,10 @@ Unit AoptObj;
procedure on an instruction that you already know is a conditional jump }
procedure MakeUnconditional(p: taicpu); virtual;
{ Removes all instructions between an unconditional jump and the next label }
procedure RemoveDeadCodeAfterJump(p: tai);
{ Removes all instructions between an unconditional jump and the next label.
Returns True if a jump in between was removed (as it may open up new
optimisations if the label appeared earlier in the stream) }
function RemoveDeadCodeAfterJump(p: tai): Boolean;
{ If hp is a label, strip it if its reference count is zero. Repeat until
a non-label is found, or a label with a non-zero reference count.
@ -1614,8 +1616,10 @@ Unit AoptObj;
end;
{ Removes all instructions between an unconditional jump and the next label }
procedure TAOptObj.RemoveDeadCodeAfterJump(p: tai);
{ Removes all instructions between an unconditional jump and the next label.
Returns True if a jump in between was removed (as it may open up new
optimisations if the label appeared earlier in the stream) }
function TAOptObj.RemoveDeadCodeAfterJump(p: tai): Boolean;
const
{$ifdef JVM}
TaiFence = SkipInstr + [ait_const, ait_realconst, ait_typedconst, ait_label, ait_jcatch];
@ -1631,6 +1635,8 @@ Unit AoptObj;
{ the following code removes all code between a jmp and the next label,
because it can never be executed
}
Result := False;
while GetNextInstruction(p, hp1) and
(hp1 <> BlockEnd) and
not (hp1.typ in TaiFence) do
@ -1639,7 +1645,12 @@ Unit AoptObj;
taicpu(hp1).is_jmp and
(JumpTargetOp(taicpu(hp1))^.typ = top_ref) and
(JumpTargetOp(taicpu(hp1))^.ref^.symbol is TAsmLabel) then
TAsmLabel(JumpTargetOp(taicpu(hp1))^.ref^.symbol).decrefs;
begin
{ If the destination label appears earlier, it may permit
further optimisations, so signal this in the Result }
Result := True;
TAsmLabel(JumpTargetOp(taicpu(hp1))^.ref^.symbol).decrefs;
end;
{ don't kill start/end of assembler block,
no-line-info-start/end etc }
if (hp1.typ<>ait_marker) and
@ -1718,19 +1729,6 @@ Unit AoptObj;
{ End of block }
Exit;
if (cs_debuginfo in current_settings.moduleswitches) or
(cs_use_lineinfo in current_settings.globalswitches) then
{ Don't remove aligns if debuginfo is present }
begin
if (tmp.typ in [ait_label,ait_align]) then
begin
hp1 := tmp;
Continue;
end
else
Break;
end;
repeat
case tmp.typ of
@ -1848,15 +1846,8 @@ Unit AoptObj;
ait_align:
begin
tmp := tai(hp.Next);
if not(
(cs_debuginfo in current_settings.moduleswitches) or
(cs_use_lineinfo in current_settings.globalswitches)
) then
{ Don't remove aligns if debuginfo is present }
begin
asml.Remove(hp);
hp.Free;
end;
asml.Remove(hp);
hp.Free;
hp := tmp;
{ Control flow will now return to 'repeat' }
end;
@ -1937,7 +1928,14 @@ Unit AoptObj;
begin
{ Do it now to get it out of the way and to aid optimisations
later on in this method }
RemoveDeadCodeAfterJump(taicpu(hp1));
if RemoveDeadCodeAfterJump(taicpu(hp1)) then
stoploop := False;
hp2 := getlabelwithsym(NCJLabel);
if Assigned(hp2) then
{ Collapse the cluster now to aid optimisation and potentially
cut down on the number of iterations required }
NCJLabel := CollapseLabelCluster(hp1, hp2);
{ GetNextInstruction could be factored out, but hp2 might be
different after "RemoveDeadCodeAfterJump" }
@ -1989,7 +1987,6 @@ Unit AoptObj;
taicpu(p).condition:=inverse_cond(taicpu(p).condition);
CJLabel.decrefs;
CJLabel := NCJLabel;
JumpTargetOp(taicpu(p))^.ref^.symbol := NCJLabel;
{ when freeing hp1, the reference count
@ -2000,24 +1997,38 @@ Unit AoptObj;
asml.remove(hp1);
hp1.free;
hp1 := tai(p.Next);
if not CJLabel.is_used then
begin
CJLabel := NCJLabel;
{ Attempt another iteration in case more jumps follow }
Continue;
StripDeadLabels(tai(p.Next), hp1);
if (hp1 = BlockEnd) then
Exit;
{ Attempt another iteration in case more jumps follow }
if (hp1.typ in SkipInstr) then
GetNextInstruction(hp1, hp1);
Continue;
end;
{$if defined(arm) or defined(aarch64)}
end;
{$endif arm or aarch64}
end
else if CollapseZeroDistJump(hp1, NCJLabel) then
begin
if (hp1 = BlockEnd) then
Exit;
{ Attempt another iteration in case more jumps follow }
if (hp1.typ in SkipInstr) then
GetNextInstruction(hp1, hp1);
Continue;
end;
end
else
begin
GetNextInstruction(hp1, hp2);
{ Check for:
jmp<cond1> @Lbl1
jmp<cond2> @Lbl2
@ -2030,9 +2041,12 @@ Unit AoptObj;
DebugMsg(SPeepholeOptimization+'Dominated conditional jump',p);
NCJLabel.decrefs;
GetNextInstruction(hp1, hp2);
AsmL.Remove(hp1);
hp1.Free;
hp1 := tai(p.Next);
hp1 := hp2;
{ Flag another pass in case @Lbl2 appeared earlier in the procedure and is now a dead label }
stoploop := False;
@ -2048,6 +2062,8 @@ Unit AoptObj;
}
if condition_in(inverse_cond(taicpu(hp1).condition), taicpu(p).condition) then
begin
GetNextInstruction(hp1, hp2);
{ If @lbl1 immediately follows jmp<cond2>, we can remove
the first jump completely }
if FindLabel(CJLabel, hp2) then
@ -2185,11 +2201,9 @@ Unit AoptObj;
if IsJumpToLabelUncond(taicpu(p)) then
begin
{ Remove unreachable code between the jump and the next label }
RemoveDeadCodeAfterJump(taicpu(p));
ThisPassResult := RemoveDeadCodeAfterJump(taicpu(p));
ThisPassResult := GetFinalDestination(taicpu(p), 0);
if ThisPassResult then
if GetFinalDestination(taicpu(p), 0) or ThisPassResult then
{ Might have caused some earlier labels to become dead }
stoploop := False;
end