Parcourir la source

Merged revisions 3329,3480,3644 via svnmerge from
svn+ssh://[email protected]/FPC/svn/fpc/trunk

........
r3329 | jonas | 2006-04-24 13:12:17 +0200 (Mon, 24 Apr 2006) | 5 lines

* when restoring a register's previous contents after it's been replaced
completely, there were some missing checks to make certain these
previous contents didn't conflict with memory operations in the new
sequence

........
r3480 | jonas | 2006-05-11 18:46:58 +0200 (Thu, 11 May 2006) | 4 lines

* if while we are restoring the contents of a register, we encounter an
operation which changes a register, clear the contents of all registers
which depend on this register

........
r3644 | jonas | 2006-05-23 19:17:23 +0200 (Tue, 23 May 2006) | 4 lines

* fixed web bug #5094. Renaming registers is now done sequentially instead
of all at the same time, because otherwise circular renamings could
cause errors

........

git-svn-id: branches/fixes_2_0@3645 -

Jonas Maebe il y a 19 ans
Parent
commit
b5a390c026
4 fichiers modifiés avec 135 ajouts et 67 suppressions
  1. 1 0
      .gitattributes
  2. 113 67
      compiler/i386/csopt386.pas
  3. 1 0
      compiler/i386/daopt386.pas
  4. 20 0
      tests/webtbs/tw5094.pp

+ 1 - 0
.gitattributes

@@ -6488,6 +6488,7 @@ tests/webtbs/tw4950.pp svneol=native#text/plain
 tests/webtbs/tw4999.pp svneol=native#text/plain
 tests/webtbs/tw5036.pp svneol=native#text/plain
 tests/webtbs/tw5082.pp -text svneol=unset#text/plain
+tests/webtbs/tw5094.pp -text
 tests/webtbs/tw6435.pp svneol=native#text/plain
 tests/webtbs/tw6735.pp svneol=native#text/plain
 tests/webtbs/tw6960.pp svneol=native#text/plain

+ 113 - 67
compiler/i386/csopt386.pas

@@ -842,6 +842,7 @@ var
 {$endif replaceregdebug}
     regcounter: tsuperregister;
     oldStartmod: tai;
+    regstoclear: tregset;
 begin
 {$ifdef replaceregdebug}
   l := random(1000);
@@ -850,26 +851,43 @@ begin
   insertllitem(asml,p.previous,p,hp);
 {$endif replaceregdebug}
   ptaiprop(p.optinfo)^.Regs[supreg].typ := con_unknown;
+  regstoclear := [supreg];
   while (p <> endP) do
     begin
       for regcounter := RS_EAX to RS_EDI do
-        if (regcounter <> supreg) and
-           assigned(ptaiprop(p.optinfo)^.regs[supreg].memwrite) and
-           reginref(regcounter,ptaiprop(p.optinfo)^.regs[supreg].memwrite.oper[1]^.ref^) then
-          clearmemwrites(p,regcounter);
-      with ptaiprop(p.optinfo)^.Regs[supreg] do
         begin
-          typ := con_unknown;
-          memwrite := nil;
+          if (regcounter <> supreg) and
+             assigned(ptaiprop(p.optinfo)^.regs[supreg].memwrite) and
+             reginref(regcounter,ptaiprop(p.optinfo)^.regs[supreg].memwrite.oper[1]^.ref^) then
+            clearmemwrites(p,regcounter);
+          { needs double loop to cheack for each dependency combination? }
+          if assigned(ptaiprop(p.optinfo)^.regs[regcounter].startmod) and
+             sequencedependsonreg(ptaiprop(p.optinfo)^.regs[regcounter],regcounter,supreg) then
+            include(regstoclear,regcounter);
+
+          if regcounter in regstoclear then
+            with ptaiprop(p.optinfo)^.Regs[regcounter] do
+              begin
+                typ := con_unknown;
+                memwrite := nil;
+              end;
         end;
       getNextInstruction(p,p);
     end;
   oldStartmod := ptaiprop(p.optinfo)^.Regs[supreg].startmod;
   repeat
-    with ptaiprop(p.optinfo)^.Regs[supreg] do
+    for regcounter := RS_EAX to RS_EDI do
       begin
-        typ := con_unknown;
-        memwrite := nil;
+        { needs double loop to cheack for each dependency combination? }
+        if assigned(ptaiprop(p.optinfo)^.regs[regcounter].startmod) and
+           sequencedependsonreg(ptaiprop(p.optinfo)^.regs[regcounter],regcounter,supreg) then
+          include(regstoclear,regcounter);
+        with ptaiprop(p.optinfo)^.Regs[supreg] do
+          if regcounter in regstoclear then
+            begin
+              typ := con_unknown;
+              memwrite := nil;
+            end;
       end;
   until not getNextInstruction(p,p) or
         (ptaiprop(p.optinfo)^.Regs[supreg].startmod <> oldStartmod);
@@ -889,7 +907,8 @@ var
   l: longint;
 {$endif replaceregdebug}
   hp: tai;
-  dummyregs: tregset;
+  validregs, prevvalidregs: tregset;
+  regcounter: tsuperregister;
   tmpState, newrstate: byte;
   prevcontenttyp: byte;
   memconflict: boolean;
@@ -904,15 +923,49 @@ begin
 {  ptaiprop(p.optinfo)^.Regs[reg] := c;}
   newrstate := c.rstate;
   incstate(newrstate,$7f);
-  while (p <> endP) do
+  memconflict := false;
+  invalsmemwrite := false;
+  validregs := [RS_EAX..RS_EDI];
+  prevvalidregs := validregs;
+  while (p <> endP) and
+        not(memconflict) and
+        not(invalsmemwrite) do
     begin
       if not(ptaiprop(p.optinfo)^.canberemoved) and
          regreadbyinstruction(supreg,p) then
         incstate(newrstate,1);
-      ptaiprop(p.optinfo)^.Regs[supreg] := c;
-      ptaiprop(p.optinfo)^.Regs[supreg].rstate := newrstate;
+      // is this a write to memory that destroys the contents we are restoring?
+      memconflict := modifiesConflictingMemLocation(p,supreg,ptaiprop(p.optinfo)^.regs,validregs,false,invalsmemwrite);
+      if (validregs <> prevvalidregs) then
+        begin
+          prevvalidregs := validregs >< prevvalidregs;
+          for regcounter := RS_EAX to RS_EDI do
+            if regcounter in prevvalidregs then
+              clearRegContentsFrom(asml,regcounter,p,endP);
+        end;
+      prevvalidregs := validregs;
+      if (not memconflict and not invalsmemwrite) then
+        begin
+          ptaiprop(p.optinfo)^.Regs[supreg] := c;
+          ptaiprop(p.optinfo)^.Regs[supreg].rstate := newrstate;
+        end
+      else
+        begin
+          clearRegContentsFrom(asml,supreg,p,endP);
+{$ifdef replaceregdebug}
+           if assigned(p) then
+             begin
+               hp := tai_comment.Create(strpnew(
+                 'stopping restoring of '+std_regname(newreg(R_INTREGISTER,supreg,R_SUBWHOLE))+'because memory conflict... '+tostr(l)));
+               insertllitem(asml,p,p.next,hp);
+             end;
+{$endif replaceregdebug}
+          exit
+        end;
+    
       getNextInstruction(p,p);
     end;
+  
   tmpState := ptaiprop(p.optinfo)^.Regs[supreg].wState;
   if (newrstate = ptaiprop(p.optinfo)^.Regs[supreg].rState) then
     begin
@@ -922,13 +975,20 @@ begin
       if (ptaiprop(hp.optinfo)^.regs[supreg].rstate = ptaiprop(p.optinfo)^.regs[supreg].rstate) then
         internalerror(2004122710);
      end;
-  dummyregs := [supreg];
   repeat
     newrstate := ptaiprop(p.optinfo)^.Regs[supreg].rState;
     prevcontenttyp := ptaiprop(p.optinfo)^.Regs[supreg].typ;
     // is this a write to memory that destroys the contents we are restoring?
-    memconflict := modifiesConflictingMemLocation(p,supreg,ptaiprop(p.optinfo)^.regs,dummyregs,true,invalsmemwrite);
-    if not memconflict and not invalsmemwrite then
+    memconflict := modifiesConflictingMemLocation(p,supreg,ptaiprop(p.optinfo)^.regs,validregs,false,invalsmemwrite);
+    if (validregs <> prevvalidregs) then
+      begin
+        prevvalidregs := validregs >< prevvalidregs;
+        for regcounter := RS_EAX to RS_EDI do
+          if regcounter in prevvalidregs then
+            clearRegContentsFrom(asml,regcounter,p,p);
+      end;
+    prevvalidregs := validregs;
+    if (not memconflict and not invalsmemwrite) then
       begin
         ptaiprop(p.optinfo)^.Regs[supreg] := c;
         ptaiprop(p.optinfo)^.Regs[supreg].rstate := newrstate;
@@ -1671,59 +1731,45 @@ begin
             (reginfo.new2oldreg[regcounter] <> regcounter) then
           begin
             getLastInstruction(curseqend,hp);
-            if (curprev <> prevseqstart) or
-                {not(regCounter in rg.usableregsint + [RS_EDI,RS_ESI]) or}
-                not(regCounter in [RS_EAX,RS_EBX,RS_ECX,RS_EDX,RS_EDI,RS_ESI]) or
-                not ReplaceReg(asml,reginfo.new2oldreg[regcounter],
-                    regCounter,hp,curseqstart,
-                    ptaiprop(prevseqstart.optinfo)^.Regs[regCounter],true,hp2) then
-              begin
-                opc := A_MOV;
-                insertpos := prevseq_next;
-                if assigned(reguses[regcounter]) then
-                  if assigned(regloads[reginfo.new2oldreg[regcounter]]) then
-                    opc := A_XCHG
-                  else
-                    insertpos := tai(reguses[regcounter].next)
-                else
-                  if assigned(regloads[reginfo.new2oldreg[regcounter]]) then
-                    insertpos := regloads[reginfo.new2oldreg[regcounter]];
-                hp := Tai_Marker.Create(NoPropInfoStart);
-                InsertLLItem(asml, insertpos.previous,insertpos, hp);
-                hp2 := taicpu.Op_Reg_Reg(opc, S_L,
-                                           {old reg                                        new reg}
-                      newreg(R_INTREGISTER,reginfo.new2oldreg[regcounter],R_SUBWHOLE), newreg(R_INTREGISTER,regcounter,R_SUBWHOLE));
-                regloads[regcounter] := hp2;
-                reguses[reginfo.new2oldreg[regcounter]] := hp2;
-                new(ptaiprop(hp2.optinfo));
-                ptaiprop(hp2.optinfo)^ := ptaiprop(insertpos.optinfo)^;
-                ptaiprop(hp2.optinfo)^.canBeRemoved := false;
-                InsertLLItem(asml, insertpos.previous, insertpos, hp2);
-                hp := Tai_Marker.Create(NoPropInfoEnd);
-                InsertLLItem(asml, insertpos.previous, insertpos, hp);
-                { adjusts states in previous instruction so that it will  }
-                { definitely be different from the previous or next state }
-                incstate(ptaiprop(hp2.optinfo)^.
-                  regs[reginfo.new2oldreg[regcounter]].rstate,20);
-                incstate(ptaiprop(hp2.optinfo)^.
-                  regs[regCounter].wstate,20);
-                updateState(reginfo.new2oldreg[regcounter],hp2);
-                updateState(regcounter,hp2);
-              end
+            opc := A_MOV;
+            insertpos := prevseq_next;
+            if assigned(reguses[regcounter]) then
+              if assigned(regloads[reginfo.new2oldreg[regcounter]]) then
+                opc := A_XCHG
+              else
+                insertpos := tai(reguses[regcounter].next)
             else
+              if assigned(regloads[reginfo.new2oldreg[regcounter]]) then
+                 insertpos := regloads[reginfo.new2oldreg[regcounter]];
+            hp := Tai_Marker.Create(NoPropInfoStart);
+            InsertLLItem(asml, insertpos.previous,insertpos, hp);
+            hp2 := taicpu.Op_Reg_Reg(opc, S_L,
+                                            {old reg                                        new reg}
+                     newreg(R_INTREGISTER,reginfo.new2oldreg[regcounter],R_SUBWHOLE), newreg(R_INTREGISTER,regcounter,R_SUBWHOLE));
+            if (opc = A_XCHG) and
+               (taicpu(regloads[reginfo.new2oldreg[regcounter]]).opcode <> A_XCHG) then
               begin
-                // replace the new register with the old register in the
-                // sequence itself as well so later comparisons get the
-                // correct knowledge about which registers are used
-                hp2 := curseqstart;
-                // curseqend = instruction following last instruction of this
-                // sequence
-                while hp2 <> curseqend do
-                  begin
-                    doreplacereg(taicpu(hp2),regcounter,reginfo.new2oldreg[regcounter]);
-                    getnextinstruction(hp2,hp2);
-                  end;
+                asml.remove(regloads[reginfo.new2oldreg[regcounter]]);
+                regloads[reginfo.new2oldreg[regcounter]].free;
+                regloads[reginfo.new2oldreg[regcounter]] := hp2;
+                reguses[regcounter] := hp2;
               end;
+            regloads[regcounter] := hp2;
+            reguses[reginfo.new2oldreg[regcounter]] := hp2;
+            new(ptaiprop(hp2.optinfo));
+            ptaiprop(hp2.optinfo)^ := ptaiprop(insertpos.optinfo)^;
+            ptaiprop(hp2.optinfo)^.canBeRemoved := false;
+            InsertLLItem(asml, insertpos.previous, insertpos, hp2);
+            hp := Tai_Marker.Create(NoPropInfoEnd);
+            InsertLLItem(asml, insertpos.previous, insertpos, hp);
+            { adjusts states in previous instruction so that it will  }
+            { definitely be different from the previous or next state }
+            incstate(ptaiprop(hp2.optinfo)^.
+              regs[reginfo.new2oldreg[regcounter]].rstate,20);
+            incstate(ptaiprop(hp2.optinfo)^.
+              regs[regCounter].wstate,20);
+            updateState(reginfo.new2oldreg[regcounter],hp2);
+            updateState(regcounter,hp2);
           end
         else
   {   imagine the following code:                                            }

+ 1 - 0
compiler/i386/daopt386.pas

@@ -186,6 +186,7 @@ function writeToRegDestroysContents(destReg, supreg: tsuperregister;
 function writeDestroysContents(const op: toper; supreg: tsuperregister; size: tcgsize;
   const c: tcontent; var memwritedestroyed: boolean): boolean;
 
+function sequenceDependsonReg(const Content: TContent; seqreg: tsuperregister; supreg: tsuperregister): Boolean;
 
 function GetNextInstruction(Current: tai; var Next: tai): Boolean;
 function GetLastInstruction(Current: tai; var Last: tai): Boolean;

+ 20 - 0
tests/webtbs/tw5094.pp

@@ -0,0 +1,20 @@
+{ %OPT=-O-2 }
+
+function B(n, k: Integer):Integer;
+var
+  i: Integer;
+begin
+  if k > n-k then
+    k := n-k;
+  B := 1;
+  for i := n-k+1 to n do
+    B := B * i;
+  for i := 2 to k do
+    B := B div i;
+end;
+begin
+  if B(0,1) <> 1 then
+    halt(1); { Should write 1; fpc -O1 binom.pas writes 0 }
+end.
+
+