فهرست منبع

Refactoring of OptPass2Movx to remove goto

J. Gareth "Curious Kit" Moreton 3 سال پیش
والد
کامیت
cafd708b6d
1فایلهای تغییر یافته به همراه278 افزوده شده و 278 حذف شده
  1. 278 278
      compiler/x86/aoptx86.pas

+ 278 - 278
compiler/x86/aoptx86.pas

@@ -7939,9 +7939,6 @@ unit aoptx86;
 {$push}
 {$q-}{$r-}
     function TX86AsmOptimizer.OptPass2Movx(var p : tai) : boolean;
-      label
-        { This label permits the case block for MOVSX/D to pass into the MOVZX block }
-        movzx_cascade;
       var
         ThisReg: TRegister;
         MinSize, MaxSize, TryShiftDown, TargetSize: TOpSize;
@@ -8034,6 +8031,278 @@ unit aoptx86;
               end;
           end;
 
+        function CompressInstructions: Boolean;
+          var
+            LocalIndex: Integer;
+          begin
+            Result := False;
+
+            { The objective here is to try to find a combination that
+              removes one of the MOV/Z instructions. }
+
+            if (
+                (taicpu(p).oper[0]^.typ <> top_reg) or
+                not SuperRegistersEqual(taicpu(p).oper[0]^.reg, ThisReg)
+              ) and
+              (taicpu(hp1).oper[1]^.typ = top_reg) and
+              SuperRegistersEqual(taicpu(hp1).oper[1]^.reg, ThisReg) then
+              begin
+                { Make a preference to remove the second MOVZX instruction }
+                case taicpu(hp1).opsize of
+                  S_BL, S_WL:
+                    begin
+                      TargetSize := S_L;
+                      TargetSubReg := R_SUBD;
+                    end;
+
+                  S_BW:
+                    begin
+                      TargetSize := S_W;
+                      TargetSubReg := R_SUBW;
+                    end;
+
+                  else
+                    InternalError(2020112302);
+                end;
+
+              end
+            else
+              begin
+
+                if LowerUnsignedOverflow and not UpperUnsignedOverflow then
+                  begin
+                    { Exceeded lower bound but not upper bound }
+                    TargetSize := MaxSize;
+                  end
+                else if not LowerUnsignedOverflow then
+                  begin
+                    { Size didn't exceed lower bound }
+                    TargetSize := MinSize;
+                  end
+                else
+                  Exit;
+
+              end;
+
+            case TargetSize of
+              S_B:
+                TargetSubReg := R_SUBL;
+              S_W:
+                TargetSubReg := R_SUBW;
+              S_L:
+                TargetSubReg := R_SUBD;
+              else
+                InternalError(2020112350);
+            end;
+
+            { Update the register to its new size }
+            setsubreg(ThisReg, TargetSubReg);
+
+            if not SuperRegistersEqual(taicpu(hp1).oper[1]^.reg, ThisReg) then
+              begin
+
+                { Check to see if the active register is used afterwards;
+                  if not, we can change it and make a saving. }
+
+                RegInUse := False;
+                TransferUsedRegs(TmpUsedRegs);
+
+                { The target register may be marked as in use to cross
+                  a jump to a distant label, so exclude it }
+                ExcludeRegFromUsedRegs(taicpu(hp1).oper[1]^.reg, TmpUsedRegs);
+
+                hp2 := p;
+                repeat
+
+                  { Explicitly check for the excluded register (don't include the first
+                    instruction as it may be reading from here }
+                  if ((p <> hp2) and (RegInInstruction(taicpu(hp1).oper[1]^.reg, hp2))) or
+                    RegInUsedRegs(taicpu(hp1).oper[1]^.reg, TmpUsedRegs) then
+                    begin
+                      RegInUse := True;
+                      Break;
+                    end;
+
+                  UpdateUsedRegs(TmpUsedRegs, tai(hp2.next));
+
+                  if not GetNextInstruction(hp2, hp2) then
+                    InternalError(2020112340);
+
+                until (hp2 = hp1);
+
+                if not RegInUse and RegUsedAfterInstruction(ThisReg, hp1, TmpUsedRegs) then
+                  { We might still be able to get away with this }
+                  RegInUse := not
+                    (
+                      GetNextInstructionUsingReg(hp1, hp2, ThisReg) and
+                      (hp2.typ = ait_instruction) and
+                      (
+                        { Under -O1 and -O2, GetNextInstructionUsingReg may return an
+                          instruction that doesn't actually contain ThisReg }
+                        (cs_opt_level3 in current_settings.optimizerswitches) or
+                        RegInInstruction(ThisReg, hp2)
+                      ) and
+                      RegLoadedWithNewValue(ThisReg, hp2)
+                    );
+
+                if not RegInUse then
+                  begin
+                    { Force the register size to the same as this instruction so it can be removed}
+                    if (taicpu(hp1).opsize in [S_L, S_BL, S_WL]) then
+                      begin
+                        TargetSize := S_L;
+                        TargetSubReg := R_SUBD;
+                      end
+                    else if (taicpu(hp1).opsize in [S_W, S_BW]) then
+                      begin
+                        TargetSize := S_W;
+                        TargetSubReg := R_SUBW;
+                      end;
+
+                    ThisReg := taicpu(hp1).oper[1]^.reg;
+                    setsubreg(ThisReg, TargetSubReg);
+                    RegChanged := True;
+
+                    DebugMsg(SPeepholeOptimization + 'Simplified register usage so ' + debug_regname(ThisReg) + ' = ' + debug_regname(taicpu(p).oper[1]^.reg), p);
+
+                    TransferUsedRegs(TmpUsedRegs);
+                    AllocRegBetween(ThisReg, p, hp1, TmpUsedRegs);
+
+                    DebugMsg(SPeepholeOptimization + 'Movzx2Nop 3', hp1);
+                    if p = hp1 then
+                      begin
+                        RemoveCurrentp(p); { p = hp1 and will then become the next instruction }
+                        p_removed := True;
+                      end
+                    else
+                      RemoveInstruction(hp1);
+
+                    { Instruction will become "mov %reg,%reg" }
+                    if not p_removed and (taicpu(p).opcode = A_MOV) and
+                      MatchOperand(taicpu(p).oper[0]^, ThisReg) then
+                      begin
+                        DebugMsg(SPeepholeOptimization + 'Movzx2Nop 6', p);
+                        RemoveCurrentP(p);
+                        p_removed := True;
+                      end
+                    else
+                      taicpu(p).oper[1]^.reg := ThisReg;
+
+                    Result := True;
+                  end
+                else
+                  begin
+                    if TargetSize <> MaxSize then
+                      begin
+                        { Since the register is in use, we have to force it to
+                          MaxSize otherwise part of it may become undefined later on }
+                        TargetSize := MaxSize;
+
+                        case TargetSize of
+                          S_B:
+                            TargetSubReg := R_SUBL;
+                          S_W:
+                            TargetSubReg := R_SUBW;
+                          S_L:
+                            TargetSubReg := R_SUBD;
+                          else
+                            InternalError(2020112351);
+                        end;
+
+                        setsubreg(ThisReg, TargetSubReg);
+                      end;
+
+                    AdjustFinalLoad;
+                  end;
+              end
+            else
+              AdjustFinalLoad;
+
+            if not p_removed then
+              begin
+                if TargetSize = MinSize then
+                  begin
+                    { Convert the input MOVZX to a MOV }
+                    if (taicpu(p).oper[0]^.typ = top_reg) and
+                      SuperRegistersEqual(taicpu(p).oper[0]^.reg, ThisReg) then
+                      begin
+                        { Or remove it completely! }
+                        DebugMsg(SPeepholeOptimization + 'Movzx2Nop 1', p);
+                        DebugMsg(SPeepholeOptimization + tostr(InstrMax), p);
+                        RemoveCurrentP(p);
+                        p_removed := True;
+                      end
+                    else
+                      begin
+                        DebugMsg(SPeepholeOptimization + 'Movzx2Mov 1', p);
+                        taicpu(p).opcode := A_MOV;
+                        taicpu(p).oper[1]^.reg := ThisReg;
+                        taicpu(p).opsize := TargetSize;
+                      end;
+
+                    Result := True;
+                  end
+                else if TargetSize <> MaxSize then
+                  begin
+
+                    case MaxSize of
+                      S_L:
+                        if TargetSize = S_W then
+                          begin
+                            DebugMsg(SPeepholeOptimization + 'movzbl2movzbw', p);
+                            taicpu(p).opsize := S_BW;
+                            taicpu(p).oper[1]^.reg := ThisReg;
+                            Result := True;
+                          end
+                        else
+                          InternalError(2020112341);
+
+                      S_W:
+                        if TargetSize = S_L then
+                          begin
+                            DebugMsg(SPeepholeOptimization + 'movzbw2movzbl', p);
+                            taicpu(p).opsize := S_BL;
+                            taicpu(p).oper[1]^.reg := ThisReg;
+                            Result := True;
+                          end
+                        else
+                          InternalError(2020112342);
+                      else
+                        ;
+                    end;
+                  end;
+              end;
+
+            { Now go through every instruction we found and change the
+              size. If TargetSize = MaxSize, then almost no changes are
+              needed and Result can remain False if it hasn't been set
+              yet.
+
+              If RegChanged is True, then the register requires changing
+              and so the point about TargetSize = MaxSize doesn't apply. }
+
+            if ((TargetSize <> MaxSize) or RegChanged) and (InstrMax >= 0) then
+              begin
+                for LocalIndex := 0 to InstrMax do
+                  begin
+
+                    { If p_removed is true, then the original MOV/Z was removed
+                      and removing the AND instruction may not be safe if it
+                      appears first }
+                    if (InstrList[LocalIndex].oper[InstrList[LocalIndex].ops - 1]^.typ <> top_reg) then
+                      InternalError(2020112310);
+
+                    if InstrList[LocalIndex].oper[0]^.typ = top_reg then
+                      InstrList[LocalIndex].oper[0]^.reg := ThisReg;
+
+                    InstrList[LocalIndex].oper[InstrList[LocalIndex].ops - 1]^.reg := ThisReg;
+                    InstrList[LocalIndex].opsize := TargetSize;
+                  end;
+
+                Result := True;
+              end;
+          end;
+
       begin
         Result := False;
         p_removed := False;
@@ -8671,7 +8940,7 @@ unit aoptx86;
                   }
 
 {$ifdef x86_64}
-                  if (taicpu(hp1).opcode = A_MOVSXD) and SuperRegistersEqual(taicpu(hp1).oper[1]^.reg, ThisReg) then
+                  if (taicpu(hp1).opsize = S_LQ) and SuperRegistersEqual(taicpu(hp1).oper[1]^.reg, ThisReg) then
                     begin
                       { this becomes a zero extension from 32-bit to 64-bit, but
                         the upper 32 bits are already zero, so just delete the
@@ -8715,10 +8984,8 @@ unit aoptx86;
                           ;
                       end;
 {$endif x86_64}
-                      Result := True;
-
-                      { Enter the A_MOVZX block below }
-                      goto movzx_cascade;
+                      Result := CompressInstructions;
+                      Exit;
                     end;
                 end;
 
@@ -8729,11 +8996,9 @@ unit aoptx86;
 
                   if not SuperRegistersEqual(taicpu(hp1).oper[0]^.reg, ThisReg) then
                     begin
-                      { Because hp1 was obtained via GetNextInstructionUsingReg
-                        and ThisReg doesn't appear in the first operand, it
-                        must appear in the second operand and hence gets
-                        overwritten }
                       if (InstrMax = -1) and
+                        { Will return false if the second parameter isn't ThisReg
+                          (can happen on -O2 and under) }
                         Reg1WriteOverwritesReg2Entirely(taicpu(hp1).oper[1]^.reg, ThisReg) then
                         begin
                           { The two MOVZX instructions are adjacent, so remove the first one }
@@ -8746,272 +9011,7 @@ unit aoptx86;
                       Break;
                     end;
 
-movzx_cascade:
-                  { The objective here is to try to find a combination that
-                    removes one of the MOV/Z instructions. }
-
-                  if (
-                      (taicpu(p).oper[0]^.typ <> top_reg) or
-                      not SuperRegistersEqual(taicpu(p).oper[0]^.reg, ThisReg)
-                    ) and
-                    (taicpu(hp1).oper[1]^.typ = top_reg) and
-                    SuperRegistersEqual(taicpu(hp1).oper[1]^.reg, ThisReg) then
-                    begin
-                      { Make a preference to remove the second MOVZX instruction }
-                      case taicpu(hp1).opsize of
-                        S_BL, S_WL:
-                          begin
-                            TargetSize := S_L;
-                            TargetSubReg := R_SUBD;
-                          end;
-
-                        S_BW:
-                          begin
-                            TargetSize := S_W;
-                            TargetSubReg := R_SUBW;
-                          end;
-
-                        else
-                          InternalError(2020112302);
-                      end;
-
-                    end
-                  else
-                    begin
-
-                      if LowerUnsignedOverflow and not UpperUnsignedOverflow then
-                        begin
-                          { Exceeded lower bound but not upper bound }
-                          TargetSize := MaxSize;
-                        end
-                      else if not LowerUnsignedOverflow then
-                        begin
-                          { Size didn't exceed lower bound }
-                          TargetSize := MinSize;
-                        end
-                      else
-                        Break;
-
-                    end;
-
-                  case TargetSize of
-                    S_B:
-                      TargetSubReg := R_SUBL;
-                    S_W:
-                      TargetSubReg := R_SUBW;
-                    S_L:
-                      TargetSubReg := R_SUBD;
-                    else
-                      InternalError(2020112350);
-                  end;
-
-                  { Update the register to its new size }
-                  setsubreg(ThisReg, TargetSubReg);
-
-                  if not SuperRegistersEqual(taicpu(hp1).oper[1]^.reg, ThisReg) then
-                    begin
-
-                      { Check to see if the active register is used afterwards;
-                        if not, we can change it and make a saving. }
-
-                      RegInUse := False;
-                      TransferUsedRegs(TmpUsedRegs);
-
-                      { The target register may be marked as in use to cross
-                        a jump to a distant label, so exclude it }
-                      ExcludeRegFromUsedRegs(taicpu(hp1).oper[1]^.reg, TmpUsedRegs);
-
-                      hp2 := p;
-                      repeat
-
-                        { Explicitly check for the excluded register (don't include the first
-                          instruction as it may be reading from here }
-                        if ((p <> hp2) and (RegInInstruction(taicpu(hp1).oper[1]^.reg, hp2))) or
-                          RegInUsedRegs(taicpu(hp1).oper[1]^.reg, TmpUsedRegs) then
-                          begin
-                            RegInUse := True;
-                            Break;
-                          end;
-
-                        UpdateUsedRegs(TmpUsedRegs, tai(hp2.next));
-
-                        if not GetNextInstruction(hp2, hp2) then
-                          InternalError(2020112340);
-
-                      until (hp2 = hp1);
-
-                      if not RegInUse and RegUsedAfterInstruction(ThisReg, hp1, TmpUsedRegs) then
-                        { We might still be able to get away with this }
-                        RegInUse := not
-                          (
-                            GetNextInstructionUsingReg(hp1, hp2, ThisReg) and
-                            (hp2.typ = ait_instruction) and
-                            (
-                              { Under -O1 and -O2, GetNextInstructionUsingReg may return an
-                                instruction that doesn't actually contain ThisReg }
-                              (cs_opt_level3 in current_settings.optimizerswitches) or
-                              RegInInstruction(ThisReg, hp2)
-                            ) and
-                            RegLoadedWithNewValue(ThisReg, hp2)
-                          );
-
-                      if not RegInUse then
-                        begin
-                          { Force the register size to the same as this instruction so it can be removed}
-                          if (taicpu(hp1).opsize in [S_L, S_BL, S_WL]) then
-                            begin
-                              TargetSize := S_L;
-                              TargetSubReg := R_SUBD;
-                            end
-                          else if (taicpu(hp1).opsize in [S_W, S_BW]) then
-                            begin
-                              TargetSize := S_W;
-                              TargetSubReg := R_SUBW;
-                            end;
-
-                          ThisReg := taicpu(hp1).oper[1]^.reg;
-                          setsubreg(ThisReg, TargetSubReg);
-                          RegChanged := True;
-
-                          DebugMsg(SPeepholeOptimization + 'Simplified register usage so ' + debug_regname(ThisReg) + ' = ' + debug_regname(taicpu(p).oper[1]^.reg), p);
-
-                          TransferUsedRegs(TmpUsedRegs);
-                          AllocRegBetween(ThisReg, p, hp1, TmpUsedRegs);
-
-                          DebugMsg(SPeepholeOptimization + 'Movzx2Nop 3', hp1);
-                          if p = hp1 then
-                            begin
-                              RemoveCurrentp(p); { p = hp1 and will then become the next instruction }
-                              p_removed := True;
-                            end
-                          else
-                            RemoveInstruction(hp1);
-
-                          { Instruction will become "mov %reg,%reg" }
-                          if not p_removed and (taicpu(p).opcode = A_MOV) and
-                            MatchOperand(taicpu(p).oper[0]^, ThisReg) then
-                            begin
-                              DebugMsg(SPeepholeOptimization + 'Movzx2Nop 6', p);
-                              RemoveCurrentP(p);
-                              p_removed := True;
-                            end
-                          else
-                            taicpu(p).oper[1]^.reg := ThisReg;
-
-                          Result := True;
-                        end
-                      else
-                        begin
-                          if TargetSize <> MaxSize then
-                            begin
-                              { Since the register is in use, we have to force it to
-                                MaxSize otherwise part of it may become undefined later on }
-                              TargetSize := MaxSize;
-
-                              case TargetSize of
-                                S_B:
-                                  TargetSubReg := R_SUBL;
-                                S_W:
-                                  TargetSubReg := R_SUBW;
-                                S_L:
-                                  TargetSubReg := R_SUBD;
-                                else
-                                  InternalError(2020112351);
-                              end;
-
-                              setsubreg(ThisReg, TargetSubReg);
-                            end;
-
-                          AdjustFinalLoad;
-                        end;
-                    end
-                  else
-                    AdjustFinalLoad;
-
-                  if not p_removed then
-                    begin
-                      if TargetSize = MinSize then
-                        begin
-                          { Convert the input MOVZX to a MOV }
-                          if (taicpu(p).oper[0]^.typ = top_reg) and
-                            SuperRegistersEqual(taicpu(p).oper[0]^.reg, ThisReg) then
-                            begin
-                              { Or remove it completely! }
-                              DebugMsg(SPeepholeOptimization + 'Movzx2Nop 1', p);
-                              DebugMsg(SPeepholeOptimization + tostr(InstrMax), p);
-                              RemoveCurrentP(p);
-                              p_removed := True;
-                            end
-                          else
-                            begin
-                              DebugMsg(SPeepholeOptimization + 'Movzx2Mov 1', p);
-                              taicpu(p).opcode := A_MOV;
-                              taicpu(p).oper[1]^.reg := ThisReg;
-                              taicpu(p).opsize := TargetSize;
-                            end;
-
-                          Result := True;
-                        end
-                      else if TargetSize <> MaxSize then
-                        begin
-
-                          case MaxSize of
-                            S_L:
-                              if TargetSize = S_W then
-                                begin
-                                  DebugMsg(SPeepholeOptimization + 'movzbl2movzbw', p);
-                                  taicpu(p).opsize := S_BW;
-                                  taicpu(p).oper[1]^.reg := ThisReg;
-                                  Result := True;
-                                end
-                              else
-                                InternalError(2020112341);
-
-                            S_W:
-                              if TargetSize = S_L then
-                                begin
-                                  DebugMsg(SPeepholeOptimization + 'movzbw2movzbl', p);
-                                  taicpu(p).opsize := S_BL;
-                                  taicpu(p).oper[1]^.reg := ThisReg;
-                                  Result := True;
-                                end
-                              else
-                                InternalError(2020112342);
-                            else
-                              ;
-                          end;
-                        end;
-                    end;
-
-                  { Now go through every instruction we found and change the
-                    size. If TargetSize = MaxSize, then almost no changes are
-                    needed and Result can remain False if it hasn't been set
-                    yet.
-
-                    If RegChanged is True, then the register requires changing
-                    and so the point about TargetSize = MaxSize doesn't apply. }
-
-                  if ((TargetSize <> MaxSize) or RegChanged) and (InstrMax >= 0) then
-                    begin
-                      for Index := 0 to InstrMax do
-                        begin
-
-                          { If p_removed is true, then the original MOV/Z was removed
-                            and removing the AND instruction may not be safe if it
-                            appears first }
-                          if (InstrList[Index].oper[InstrList[Index].ops - 1]^.typ <> top_reg) then
-                            InternalError(2020112310);
-
-                          if InstrList[Index].oper[0]^.typ = top_reg then
-                            InstrList[Index].oper[0]^.reg := ThisReg;
-
-                          InstrList[Index].oper[InstrList[Index].ops - 1]^.reg := ThisReg;
-                          InstrList[Index].opsize := TargetSize;
-                        end;
-
-                      Result := True;
-                    end;
-
+                  Result := CompressInstructions;
                   Exit;
                 end;