浏览代码

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 -

florian 5 年之前
父节点
当前提交
599e2df71f
共有 1 个文件被更改,包括 53 次插入39 次删除
  1. 53 39
      compiler/aoptobj.pas

+ 53 - 39
compiler/aoptobj.pas

@@ -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 := GetFinalDestination(taicpu(p), 0);
+                      ThisPassResult := RemoveDeadCodeAfterJump(taicpu(p));
 
-                      if ThisPassResult then
+                      if GetFinalDestination(taicpu(p), 0) or ThisPassResult then
                         { Might have caused some earlier labels to become dead }
                         stoploop := False;
                     end