Browse Source

* x86: Fixed movzwl/movzbl bug in OptPass2Movx (resolves i40003)

J. Gareth "Curious Kit" Moreton 2 years ago
parent
commit
cc27576339
1 changed files with 58 additions and 24 deletions
  1. 58 24
      compiler/x86/aoptx86.pas

+ 58 - 24
compiler/x86/aoptx86.pas

@@ -9652,20 +9652,26 @@ unit aoptx86;
                     { Convert the output MOVZX to a MOV }
                     if SuperRegistersEqual(taicpu(hp1).oper[1]^.reg, ThisReg) then
                       begin
-                        { Or remove it completely! }
-                        DebugMsg(SPeepholeOptimization + 'Movzx2Nop 2', hp1);
-
-                        { Be careful; if p = hp1 and p was also removed, p
-                          will become a dangling pointer }
-                        if p = hp1 then
+                        { Make sure the zero-expansion covers at least the minimum size (fixes i40003) }
+                        if (MinSize = S_B) or
+                          (not ShiftDownOverflow and (TryShiftDown = S_B)) or
+                          ((MinSize = S_W) and (taicpu(hp1).opsize = S_WL)) then
                           begin
-                            RemoveCurrentp(p); { p = hp1 and will then become the next instruction }
-                            p_removed := True;
-                          end
-                        else
-                          RemoveInstruction(hp1);
+                            { Remove it completely! }
+                            DebugMsg(SPeepholeOptimization + 'Movzx2Nop 2', hp1);
+
+                            { Be careful; if p = hp1 and p was also removed, p
+                              will become a dangling pointer }
+                            if p = hp1 then
+                              begin
+                                RemoveCurrentp(p); { p = hp1 and will then become the next instruction }
+                                p_removed := True;
+                              end
+                            else
+                              RemoveInstruction(hp1);
 
-                        hp1_removed := True;
+                            hp1_removed := True;
+                          end;
                       end
                     else
                       begin
@@ -10583,21 +10589,49 @@ unit aoptx86;
                   if UpperUnsignedOverflow or (taicpu(hp1).oper[0]^.typ <> top_reg) then
                     Break;
 
-                  if not SuperRegistersEqual(taicpu(hp1).oper[0]^.reg, ThisReg) then
+                  if (InstrMax = -1) then
                     begin
-                      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
+                      if SuperRegistersEqual(taicpu(hp1).oper[0]^.reg, ThisReg) then
                         begin
-                          { The two MOVZX instructions are adjacent, so remove the first one }
-                          DebugMsg(SPeepholeOptimization + 'Movzx2Nop 5', p);
-                          RemoveCurrentP(p);
-                          Result := True;
-                          Exit;
-                        end;
+                          { Optimise around i40003 }
+                          if SuperRegistersEqual(taicpu(hp1).oper[1]^.reg, ThisReg) and
+                            (taicpu(p).opsize = S_WL) and (taicpu(hp1).opsize = S_BL)
+{$ifndef x86_64}
+                            and (
+                              (taicpu(p).oper[0]^.typ <> top_reg) or
+                              { Cannot encode byte-sized ESI, EDI, EBP or ESP under i386 }
+                              (GetSupReg(taicpu(p).oper[0]^.reg) in [RS_EAX, RS_EBX, RS_ECX, RS_EDX])
+                            )
+{$endif not x86_64}
+                            then
+                              begin
+                                if (taicpu(p).oper[0]^.typ = top_reg) then
+                                  setsubreg(taicpu(p).oper[0]^.reg, R_SUBL);
 
-                      Break;
+                                DebugMsg(SPeepholeOptimization + 'movzwl2movzbl 1', p);
+                                taicpu(p).opsize := S_BL;
+
+                                DebugMsg(SPeepholeOptimization + 'Movzx2Nop 2a', hp1);
+                                RemoveInstruction(hp1);
+                                Result := True;
+                                Exit;
+                              end;
+                        end
+                      else
+                        begin
+                          { Will return false if the second parameter isn't ThisReg
+                            (can happen on -O2 and under) }
+                          if Reg1WriteOverwritesReg2Entirely(taicpu(hp1).oper[1]^.reg, ThisReg) then
+                            begin
+                              { The two MOVZX instructions are adjacent, so remove the first one }
+                              DebugMsg(SPeepholeOptimization + 'Movzx2Nop 5', p);
+                              RemoveCurrentP(p);
+                              Result := True;
+                              Exit;
+                            end;
+
+                          Break;
+                        end;
                     end;
 
                   Result := CompressInstructions;