Преглед на файлове

* fixed SSE2 substraction when both operands are on the 80x87 fpu stack

git-svn-id: trunk@6959 -
Jonas Maebe преди 18 години
родител
ревизия
5f169f97ff
променени са 3 файла, в които са добавени 44 реда и са изтрити 16 реда
  1. 1 0
      .gitattributes
  2. 30 16
      compiler/x86/nx86add.pas
  3. 13 0
      tests/tbs/tb0535.pp

+ 1 - 0
.gitattributes

@@ -6265,6 +6265,7 @@ tests/tbs/tb0531.pp svneol=native#text/plain
 tests/tbs/tb0532.pp svneol=native#text/x-pascal
 tests/tbs/tb0532.pp svneol=native#text/x-pascal
 tests/tbs/tb0533.pp svneol=native#text/plain
 tests/tbs/tb0533.pp svneol=native#text/plain
 tests/tbs/tb0534.pp svneol=native#text/plain
 tests/tbs/tb0534.pp svneol=native#text/plain
+tests/tbs/tb0535.pp svneol=native#text/plain
 tests/tbs/ub0060.pp svneol=native#text/plain
 tests/tbs/ub0060.pp svneol=native#text/plain
 tests/tbs/ub0069.pp svneol=native#text/plain
 tests/tbs/ub0069.pp svneol=native#text/plain
 tests/tbs/ub0119.pp svneol=native#text/plain
 tests/tbs/ub0119.pp svneol=native#text/plain

+ 30 - 16
compiler/x86/nx86add.pas

@@ -35,7 +35,7 @@ unit nx86add;
       protected
       protected
         function  getresflags(unsigned : boolean) : tresflags;
         function  getresflags(unsigned : boolean) : tresflags;
         procedure left_must_be_reg(opsize:TCGSize;noswap:boolean);
         procedure left_must_be_reg(opsize:TCGSize;noswap:boolean);
-        procedure left_and_right_must_be_fpureg;
+        procedure check_left_and_right_fpureg(force_fpureg: boolean);
         procedure emit_op_right_left(op:TAsmOp;opsize:TCgSize);
         procedure emit_op_right_left(op:TAsmOp;opsize:TCgSize);
         procedure emit_generic_code(op:TAsmOp;opsize:TCgSize;unsigned,extra_not,mboverflow:boolean);
         procedure emit_generic_code(op:TAsmOp;opsize:TCgSize;unsigned,extra_not,mboverflow:boolean);
 
 
@@ -212,25 +212,31 @@ unit nx86add;
        end;
        end;
 
 
 
 
-    procedure tx86addnode.left_and_right_must_be_fpureg;
+    procedure tx86addnode.check_left_and_right_fpureg(force_fpureg: boolean);
       begin
       begin
         if (right.location.loc<>LOC_FPUREGISTER) then
         if (right.location.loc<>LOC_FPUREGISTER) then
          begin
          begin
-           location_force_fpureg(current_asmdata.CurrAsmList,right.location,false);
-           if (left.location.loc<>LOC_FPUREGISTER) then
-             location_force_fpureg(current_asmdata.CurrAsmList,left.location,false)
-           else
-             { left was on the stack => swap }
-             toggleflag(nf_swapped);
+           if (force_fpureg) then
+             begin
+               location_force_fpureg(current_asmdata.CurrAsmList,right.location,false);
+                if (left.location.loc<>LOC_FPUREGISTER) then
+                  location_force_fpureg(current_asmdata.CurrAsmList,left.location,false)
+                else
+                  { left was on the stack => swap }
+                  toggleflag(nf_swapped);
+             end
          end
          end
         { the nominator in st0 }
         { the nominator in st0 }
         else if (left.location.loc<>LOC_FPUREGISTER) then
         else if (left.location.loc<>LOC_FPUREGISTER) then
-          location_force_fpureg(current_asmdata.CurrAsmList,left.location,false)
+          begin
+            if (force_fpureg) then
+              location_force_fpureg(current_asmdata.CurrAsmList,left.location,false)
+          end
         else
         else
-         begin
-           { fpu operands are always in the wrong order on the stack }
-           toggleflag(nf_swapped);
-         end;
+          begin
+            { fpu operands are always in the wrong order on the stack }
+            toggleflag(nf_swapped);
+          end;
       end;
       end;
 
 
 
 
@@ -700,8 +706,16 @@ unit nx86add;
         op : topcg;
         op : topcg;
       begin
       begin
         pass_left_right;
         pass_left_right;
+        check_left_and_right_fpureg(false);
+
         if (nf_swapped in flags) then
         if (nf_swapped in flags) then
-          swapleftright;
+          { can't use swapleftright if both are on the fpu stack, since then }
+          { both are "R_ST" -> nothing would change -> manually switch       }
+          if (left.location.loc = LOC_FPUREGISTER) and
+             (right.location.loc = LOC_FPUREGISTER) then
+            emit_none(A_FXCH,S_NO)
+          else
+            swapleftright;
 
 
         case nodetype of
         case nodetype of
           addn :
           addn :
@@ -885,7 +899,7 @@ unit nx86add;
             internalerror(2003042214);
             internalerror(2003042214);
         end;
         end;
 
 
-        left_and_right_must_be_fpureg;
+        check_left_and_right_fpureg(true);
 
 
         { if we swaped the tree nodes, then use the reverse operator }
         { if we swaped the tree nodes, then use the reverse operator }
         if nf_swapped in flags then
         if nf_swapped in flags then
@@ -915,7 +929,7 @@ unit nx86add;
           end;
           end;
 
 
         pass_left_right;
         pass_left_right;
-        left_and_right_must_be_fpureg;
+        check_left_and_right_fpureg(true);
 
 
 {$ifndef x86_64}
 {$ifndef x86_64}
         if current_settings.cputype<cpu_Pentium2 then
         if current_settings.cputype<cpu_Pentium2 then

+ 13 - 0
tests/tbs/tb0535.pp

@@ -0,0 +1,13 @@
+program bug;
+
+var l,h:longint;
+    r:single;
+
+begin
+  l:=-2;
+  h:=1;
+  r:=0;
+  r:=r+(single(h)-single(l))-1;
+  if trunc(r) <> 2 then
+    halt(1);
+end.