Jelajahi Sumber

* x86: CheckJumpMovTransferOpt now also copies over register deallocations to allow better optimisations

J. Gareth "Curious Kit" Moreton 2 tahun lalu
induk
melakukan
fb66369a3b
3 mengubah file dengan 116 tambahan dan 93 penghapusan
  1. 2 0
      compiler/aasmtai.pas
  2. 14 10
      compiler/aoptbase.pas
  3. 100 83
      compiler/x86/aoptx86.pas

+ 2 - 0
compiler/aasmtai.pas

@@ -108,6 +108,8 @@ interface
           ait_eabi_attribute
           );
 
+        taitypes = set of taitype;
+
         taiconst_type = (
           aitconst_128bit,
           aitconst_64bit,

+ 14 - 10
compiler/aoptbase.pas

@@ -60,12 +60,15 @@ unit aoptbase;
 
         { gets the next tai object after current that contains info relevant }
         { to the optimizer in p1. If there is none, it returns false and     }
-        { sets p1 to nil                                                     }
-        class function GetNextInstruction(Current: tai; out Next: tai): Boolean; static;
+        { sets p1 to nil.  If AlsoStopOn is set, it will also stop on these  }
+        { object types that are normally skipped over.                       }
+        class function GetNextInstruction(Current: tai; out Next: tai; AlsoStopOn: taitypes = []): Boolean; static;
+
         { gets the previous tai object after current that contains info   }
         { relevant to the optimizer in last. If there is none, it returns }
-        { false and sets last to nil                                      }
-        class function GetLastInstruction(Current: tai; out Last: tai): Boolean; static;
+        { false and sets last to nil.  If AlsoStopOn is set, it will also }
+        { stop on these object types that are normally skipped over.      }
+        class function GetLastInstruction(Current: tai; out Last: tai; AlsoStopOn: taitypes = []): Boolean; static;
 
         class function SkipEntryExitMarker(current: tai; out next: tai): boolean; static;
 
@@ -185,12 +188,12 @@ unit aoptbase;
   end;
 
 
-  class function TAOptBase.GetNextInstruction(Current: tai; out Next: tai): Boolean;
+  class function TAOptBase.GetNextInstruction(Current: tai; out Next: tai; AlsoStopOn: taitypes): Boolean;
   Begin
     Repeat
       Current := tai(Current.Next);
       While Assigned(Current) And
-            ((Current.typ In SkipInstr) or
+            ((Current.typ In SkipInstr - AlsoStopOn) or
 {$ifdef cpudelayslot}
              ((Current.typ=ait_instruction) and
               (taicpu(Current).opcode=A_NOP)
@@ -223,7 +226,7 @@ unit aoptbase;
           (Tai_Marker(Current).Kind <> mark_NoPropInfoEnd);
     Next := Current;
     If Assigned(Current) And
-       Not((Current.typ In SkipInstr) or
+       Not((Current.typ In SkipInstr - AlsoStopOn) or
            ((Current.typ = ait_label) And
             labelCanBeSkipped(Tai_Label(Current))))
       Then GetNextInstruction := True
@@ -234,14 +237,15 @@ unit aoptbase;
         End;
   End;
 
-  class function TAOptBase.GetLastInstruction(Current: tai; out Last: tai): Boolean;
+
+  class function TAOptBase.GetLastInstruction(Current: tai; out Last: tai; AlsoStopOn: taitypes): Boolean;
   Begin
     Repeat
       Current := Tai(Current.previous);
       While Assigned(Current) And
             (((Current.typ = ait_Marker) And
               Not(Tai_Marker(Current).Kind in [mark_AsmBlockEnd{,mark_NoPropInfoEnd}])) or
-             (Current.typ In SkipInstr) or
+             (Current.typ In SkipInstr - AlsoStopOn) or
              ((Current.typ = ait_label) And
               labelCanBeSkipped(Tai_Label(Current)))) Do
         Current := Tai(Current.previous);
@@ -258,7 +262,7 @@ unit aoptbase;
           (Current.typ <> ait_Marker) Or
           not(tai_Marker(current).Kind in [mark_NoPropInfoStart,mark_NoPropInfoEnd]);
     If Not(Assigned(Current)) or
-       (Current.typ In SkipInstr) or
+       (Current.typ In SkipInstr - AlsoStopOn) or
        ((Current.typ = ait_label) And
         labelCanBeSkipped(Tai_Label(Current))) or
        ((Current.typ = ait_Marker) And

+ 100 - 83
compiler/x86/aoptx86.pas

@@ -9226,104 +9226,121 @@ unit aoptx86;
               if Assigned(hp1) and (hp1.typ = ait_label) then
                 SkipLabels(hp1,hp1);
 
-              if (hp1.typ <> ait_instruction) then
-                InternalError(2021040720);
+              case hp1.typ of
+                ait_regalloc:
+                  if tai_regalloc(hp1).ratype = ra_dealloc then
+                    begin
+                      { Duplicate the register deallocation... }
+                      hp3:=tai(hp1.getcopy);
+                      if first_assignment = nil then
+                        first_assignment := hp3;
 
-              case taicpu(hp1).opcode of
-                A_JMP:
-                  begin
-                    { Change the original jump to the new destination }
-                    OrigLabel.decrefs;
-                    taicpu(hp1).oper[0]^.ref^.symbol.increfs;
-                    taicpu(p).loadref(0, taicpu(hp1).oper[0]^.ref^);
-
-                    { Set p to the first duplicated assignment so it can get optimised if needs be }
-                    if not Assigned(first_assignment) then
-                      InternalError(2021040810)
-                    else
-                      p := first_assignment;
+                      asml.InsertBefore(hp3, p);
 
-                    Exit;
-                  end;
-                A_RET:
-                  begin
-                    { Now change the jump into a RET instruction }
-                    ConvertJumpToRET(p, hp1);
+                      { ... but also reallocate it after the jump }
+                      hp3:=tai(hp1.getcopy);
+                      tai_regalloc(hp3).ratype := ra_alloc;
 
-                    { Set p to the first duplicated assignment so it can get optimised if needs be }
-                    if not Assigned(first_assignment) then
-                      InternalError(2021040811)
-                    else
-                      p := first_assignment;
+                      asml.InsertAfter(hp3, p);
+                    end;
+                ait_instruction:
+                  case taicpu(hp1).opcode of
+                    A_JMP:
+                      begin
+                        { Change the original jump to the new destination }
+                        OrigLabel.decrefs;
+                        taicpu(hp1).oper[0]^.ref^.symbol.increfs;
+                        taicpu(p).loadref(0, taicpu(hp1).oper[0]^.ref^);
+
+                        { Set p to the first duplicated assignment so it can get optimised if needs be }
+                        if not Assigned(first_assignment) then
+                          InternalError(2021040810)
+                        else
+                          p := first_assignment;
 
-                    Exit;
-                  end;
-                else
-                  begin
-                    { Duplicate the MOV instruction }
-                    hp3:=tai(hp1.getcopy);
+                        Exit;
+                      end;
+                    A_RET:
+                      begin
+                        { Now change the jump into a RET instruction }
+                        ConvertJumpToRET(p, hp1);
 
-                    asml.InsertBefore(hp3, p);
+                        { Set p to the first duplicated assignment so it can get optimised if needs be }
+                        if not Assigned(first_assignment) then
+                          InternalError(2021040811)
+                        else
+                          p := first_assignment;
 
-                    { Make sure the compiler knows about any final registers written here }
-                    for OperIdx := 0 to taicpu(hp3).ops - 1 do
-                      with taicpu(hp3).oper[OperIdx]^ do
-                        begin
-                          case typ of
-                            top_ref:
-                              begin
-                                if (ref^.base <> NR_NO) and
-                                  (getsupreg(ref^.base) <> RS_STACK_POINTER_REG) and
-                                  (
-                                    (getsupreg(ref^.base) <> RS_FRAME_POINTER_REG) or
-                                    (
-                                      { Allow the frame pointer if it's not being used by the procedure as such }
-                                      Assigned(current_procinfo) and
-                                      (current_procinfo.framepointer <> NR_FRAME_POINTER_REG)
-                                    )
-                                  )
-                                  {$ifdef x86_64} and (ref^.base <> NR_RIP) {$endif x86_64}
-                                  then
+                        Exit;
+                      end;
+                    else
+                      begin
+                        { Duplicate the MOV instruction }
+                        hp3:=tai(hp1.getcopy);
+                        if first_assignment = nil then
+                          first_assignment := hp3;
+
+                        asml.InsertBefore(hp3, p);
+
+                        { Make sure the compiler knows about any final registers written here }
+                        for OperIdx := 0 to taicpu(hp3).ops - 1 do
+                          with taicpu(hp3).oper[OperIdx]^ do
+                            begin
+                              case typ of
+                                top_ref:
                                   begin
-                                    AllocRegBetween(ref^.base, hp3, p, TmpUsedRegs);
-                                    if not Assigned(first_assignment) then
-                                      IncludeRegInUsedRegs(ref^.base, UsedRegs);
+                                    if (ref^.base <> NR_NO) and
+                                      (getsupreg(ref^.base) <> RS_STACK_POINTER_REG) and
+                                      (
+                                        (getsupreg(ref^.base) <> RS_FRAME_POINTER_REG) or
+                                        (
+                                          { Allow the frame pointer if it's not being used by the procedure as such }
+                                          Assigned(current_procinfo) and
+                                          (current_procinfo.framepointer <> NR_FRAME_POINTER_REG)
+                                        )
+                                      )
+                                      {$ifdef x86_64} and (ref^.base <> NR_RIP) {$endif x86_64}
+                                      then
+                                      begin
+                                        AllocRegBetween(ref^.base, hp3, p, TmpUsedRegs);
+                                        if not Assigned(first_assignment) then
+                                          IncludeRegInUsedRegs(ref^.base, UsedRegs);
+                                      end;
+                                    if (ref^.index <> NR_NO) and
+                                      (getsupreg(ref^.index) <> RS_STACK_POINTER_REG) and
+                                      (
+                                        (getsupreg(ref^.index) <> RS_FRAME_POINTER_REG) or
+                                        (
+                                          { Allow the frame pointer if it's not being used by the procedure as such }
+                                          Assigned(current_procinfo) and
+                                          (current_procinfo.framepointer <> NR_FRAME_POINTER_REG)
+                                        )
+                                      )
+                                      {$ifdef x86_64} and (ref^.index <> NR_RIP) {$endif x86_64} and
+                                      (ref^.index <> ref^.base) then
+                                      begin
+                                        AllocRegBetween(ref^.index, hp3, p, TmpUsedRegs);
+                                        if not Assigned(first_assignment) then
+                                          IncludeRegInUsedRegs(ref^.index, UsedRegs);
+                                      end;
                                   end;
-                                if (ref^.index <> NR_NO) and
-                                  (getsupreg(ref^.index) <> RS_STACK_POINTER_REG) and
-                                  (
-                                    (getsupreg(ref^.index) <> RS_FRAME_POINTER_REG) or
-                                    (
-                                      { Allow the frame pointer if it's not being used by the procedure as such }
-                                      Assigned(current_procinfo) and
-                                      (current_procinfo.framepointer <> NR_FRAME_POINTER_REG)
-                                    )
-                                  )
-                                  {$ifdef x86_64} and (ref^.index <> NR_RIP) {$endif x86_64} and
-                                  (ref^.index <> ref^.base) then
+                                top_reg:
                                   begin
-                                    AllocRegBetween(ref^.index, hp3, p, TmpUsedRegs);
+                                    AllocRegBetween(reg, hp3, p, TmpUsedRegs);
                                     if not Assigned(first_assignment) then
-                                      IncludeRegInUsedRegs(ref^.index, UsedRegs);
+                                      IncludeRegInUsedRegs(reg, UsedRegs);
                                   end;
+                                else
+                                  ;
                               end;
-                            top_reg:
-                              begin
-                                AllocRegBetween(reg, hp3, p, TmpUsedRegs);
-                                if not Assigned(first_assignment) then
-                                  IncludeRegInUsedRegs(reg, UsedRegs);
-                              end;
-                            else
-                              ;
-                          end;
-                        end;
-
-                    if first_assignment = nil then
-                      first_assignment := hp3;
+                            end;
+                      end;
                   end;
+                else
+                  InternalError(2021040720);
               end;
 
-              if not GetNextInstruction(hp1, hp1) then
+              if not GetNextInstruction(hp1, hp1, [ait_regalloc]) then
                 { Should have dropped out earlier }
                 InternalError(2021040710);
             end;