瀏覽代碼

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 on an instruction that you already know is a conditional jump }
         procedure MakeUnconditional(p: taicpu); virtual;
         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
         { 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.
           a non-label is found, or a label with a non-zero reference count.
@@ -1614,8 +1616,10 @@ Unit AoptObj;
       end;
       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
       const
 {$ifdef JVM}
 {$ifdef JVM}
         TaiFence = SkipInstr + [ait_const, ait_realconst, ait_typedconst, ait_label, ait_jcatch];
         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,
         { the following code removes all code between a jmp and the next label,
           because it can never be executed
           because it can never be executed
         }
         }
+        Result := False;
+
         while GetNextInstruction(p, hp1) and
         while GetNextInstruction(p, hp1) and
               (hp1 <> BlockEnd) and
               (hp1 <> BlockEnd) and
               not (hp1.typ in TaiFence) do
               not (hp1.typ in TaiFence) do
@@ -1639,7 +1645,12 @@ Unit AoptObj;
                  taicpu(hp1).is_jmp and
                  taicpu(hp1).is_jmp and
                  (JumpTargetOp(taicpu(hp1))^.typ = top_ref) and
                  (JumpTargetOp(taicpu(hp1))^.typ = top_ref) and
                  (JumpTargetOp(taicpu(hp1))^.ref^.symbol is TAsmLabel) then
                  (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,
               { don't kill start/end of assembler block,
                 no-line-info-start/end etc }
                 no-line-info-start/end etc }
               if (hp1.typ<>ait_marker) and
               if (hp1.typ<>ait_marker) and
@@ -1718,19 +1729,6 @@ Unit AoptObj;
                     { End of block }
                     { End of block }
                     Exit;
                     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
                   repeat
 
 
                     case tmp.typ of
                     case tmp.typ of
@@ -1848,15 +1846,8 @@ Unit AoptObj;
             ait_align:
             ait_align:
               begin
               begin
                 tmp := tai(hp.Next);
                 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;
                 hp := tmp;
                 { Control flow will now return to 'repeat' }
                 { Control flow will now return to 'repeat' }
               end;
               end;
@@ -1937,7 +1928,14 @@ Unit AoptObj;
                   begin
                   begin
                     { Do it now to get it out of the way and to aid optimisations
                     { Do it now to get it out of the way and to aid optimisations
                       later on in this method }
                       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
                     { GetNextInstruction could be factored out, but hp2 might be
                       different after "RemoveDeadCodeAfterJump" }
                       different after "RemoveDeadCodeAfterJump" }
@@ -1989,7 +1987,6 @@ Unit AoptObj;
                             taicpu(p).condition:=inverse_cond(taicpu(p).condition);
                             taicpu(p).condition:=inverse_cond(taicpu(p).condition);
                             CJLabel.decrefs;
                             CJLabel.decrefs;
 
 
-                            CJLabel := NCJLabel;
                             JumpTargetOp(taicpu(p))^.ref^.symbol := NCJLabel;
                             JumpTargetOp(taicpu(p))^.ref^.symbol := NCJLabel;
 
 
                             { when freeing hp1, the reference count
                             { when freeing hp1, the reference count
@@ -2000,24 +1997,38 @@ Unit AoptObj;
                             asml.remove(hp1);
                             asml.remove(hp1);
                             hp1.free;
                             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)}
 {$if defined(arm) or defined(aarch64)}
                           end;
                           end;
 {$endif arm or aarch64}
 {$endif arm or aarch64}
                       end
                       end
                     else if CollapseZeroDistJump(hp1, NCJLabel) then
                     else if CollapseZeroDistJump(hp1, NCJLabel) then
                       begin
                       begin
+                        if (hp1 = BlockEnd) then
+                          Exit;
+
                         { Attempt another iteration in case more jumps follow }
                         { Attempt another iteration in case more jumps follow }
+                        if (hp1.typ in SkipInstr) then
+                          GetNextInstruction(hp1, hp1);
+
                         Continue;
                         Continue;
                       end;
                       end;
                   end
                   end
                 else
                 else
                   begin
                   begin
-                    GetNextInstruction(hp1, hp2);
-
                     { Check for:
                     { Check for:
                         jmp<cond1>    @Lbl1
                         jmp<cond1>    @Lbl1
                         jmp<cond2>    @Lbl2
                         jmp<cond2>    @Lbl2
@@ -2030,9 +2041,12 @@ Unit AoptObj;
                         DebugMsg(SPeepholeOptimization+'Dominated conditional jump',p);
                         DebugMsg(SPeepholeOptimization+'Dominated conditional jump',p);
 
 
                         NCJLabel.decrefs;
                         NCJLabel.decrefs;
+                        GetNextInstruction(hp1, hp2);
+
                         AsmL.Remove(hp1);
                         AsmL.Remove(hp1);
                         hp1.Free;
                         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 }
                         { Flag another pass in case @Lbl2 appeared earlier in the procedure and is now a dead label }
                         stoploop := False;
                         stoploop := False;
@@ -2048,6 +2062,8 @@ Unit AoptObj;
                     }
                     }
                     if condition_in(inverse_cond(taicpu(hp1).condition), taicpu(p).condition) then
                     if condition_in(inverse_cond(taicpu(hp1).condition), taicpu(p).condition) then
                       begin
                       begin
+                        GetNextInstruction(hp1, hp2);
+
                         { If @lbl1 immediately follows jmp<cond2>, we can remove
                         { If @lbl1 immediately follows jmp<cond2>, we can remove
                           the first jump completely }
                           the first jump completely }
                         if FindLabel(CJLabel, hp2) then
                         if FindLabel(CJLabel, hp2) then
@@ -2185,11 +2201,9 @@ Unit AoptObj;
                   if IsJumpToLabelUncond(taicpu(p)) then
                   if IsJumpToLabelUncond(taicpu(p)) then
                     begin
                     begin
                       { Remove unreachable code between the jump and the next label }
                       { 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 }
                         { Might have caused some earlier labels to become dead }
                         stoploop := False;
                         stoploop := False;
                     end
                     end