فهرست منبع

* fixed spilling of and operations on spilled 32 bit values for x86_64
(mantis #14403)

git-svn-id: trunk@13573 -

Jonas Maebe 16 سال پیش
والد
کامیت
146a819615
4فایلهای تغییر یافته به همراه75 افزوده شده و 2 حذف شده
  1. 1 0
      .gitattributes
  2. 17 1
      compiler/x86/aasmcpu.pas
  3. 10 1
      compiler/x86/rgx86.pas
  4. 47 0
      tests/webtbs/tw14403.pp

+ 1 - 0
.gitattributes

@@ -9238,6 +9238,7 @@ tests/webtbs/tw1430.pp svneol=native#text/plain
 tests/webtbs/tw14307.pp svneol=native#text/plain
 tests/webtbs/tw1433.pp svneol=native#text/plain
 tests/webtbs/tw14363.pp svneol=native#text/plain
+tests/webtbs/tw14403.pp svneol=native#text/plain
 tests/webtbs/tw1445.pp svneol=native#text/plain
 tests/webtbs/tw1450.pp svneol=native#text/plain
 tests/webtbs/tw1451.pp svneol=native#text/plain

+ 17 - 1
compiler/x86/aasmcpu.pas

@@ -2402,6 +2402,8 @@ implementation
       begin
         case getregtype(r) of
           R_INTREGISTER :
+            { we don't need special code here for 32 bit loads on x86_64, since
+              those will automatically zero-extend the upper 32 bits. }
             result:=taicpu.op_ref_reg(A_MOV,reg2opsize(r),ref,r);
           R_MMREGISTER :
             case getsubreg(r) of
@@ -2421,10 +2423,24 @@ implementation
 
 
     function spilling_create_store(r:tregister; const ref:treference):Taicpu;
+      var
+        size: topsize;
       begin
         case getregtype(r) of
           R_INTREGISTER :
-            result:=taicpu.op_reg_ref(A_MOV,reg2opsize(r),r,ref);
+            begin
+              size:=reg2opsize(r);
+{$ifdef x86_64}
+              { even if it's a 32 bit reg, we still have to spill 64 bits
+                because we often perform 64 bit operations on them }
+              if (size=S_L) then
+                begin
+                  size:=S_Q;
+                  r:=newreg(getregtype(r),getsupreg(r),R_SUBWHOLE);
+                end;
+{$endif x86_64}
+              result:=taicpu.op_reg_ref(A_MOV,size,r,ref);
+            end;
           R_MMREGISTER :
             case getsubreg(r) of
               R_SUBMMD:

+ 10 - 1
compiler/x86/rgx86.pas

@@ -247,7 +247,16 @@ implementation
                       end;
                     end;
                 end;
-            end;
+             end;
+
+            {$ifdef x86_64}
+            { 32 bit operations on 32 bit registers on x86_64 can result in
+              zeroing the upper 32 bits of the register. This does not happen
+              with memory operations, so we have to perform these calculations
+              in registers.  }
+            if (instr.opsize=S_L) then
+              replaceoper:=-1;
+            {$endif x86_64}
 
             { Replace register with spill reference }
             if replaceoper<>-1 then

+ 47 - 0
tests/webtbs/tw14403.pp

@@ -0,0 +1,47 @@
+{$R+}
+{$mode objfpc}
+
+type
+  TDummyShapeTree = class
+    function ShapesCount(const OnlyActive, OnlyVisible, OnlyCollidable: boolean): Cardinal; virtual; abstract;
+  end;
+
+  TDummyShapeTreeGroup = class(TDummyShapeTree)
+  public
+    Child: TDummyShapeTree;
+
+    function ShapesCount(const OnlyActive, OnlyVisible, OnlyCollidable: boolean): Cardinal; override;
+  end;
+
+  TDummyShape = class(TDummyShapeTree)
+  public
+    function ShapesCount(const OnlyActive, OnlyVisible, OnlyCollidable: boolean): Cardinal; override;
+  end;
+
+function TDummyShape.ShapesCount(
+  const OnlyActive, OnlyVisible, OnlyCollidable: boolean): Cardinal;
+begin
+  Result := 1;
+end;
+
+function TDummyShapeTreeGroup.ShapesCount(
+  const OnlyActive, OnlyVisible, OnlyCollidable: boolean): Cardinal;
+var
+  I: Integer;
+  Something: Cardinal;
+begin
+  Result := 0;
+  for I := 0 to 1 do
+  begin
+    Result := Result + Child.ShapesCount(OnlyActive, OnlyVisible, OnlyCollidable);
+  end;
+end;
+
+var
+  G: TDummyShapeTreeGroup;
+begin
+  G := TDummyShapeTreeGroup.Create;
+  G.Child := TDummyShape.Create;
+  Writeln(G.ShapesCount(true, true, false));
+  G.Free;
+end.