Browse Source

* fixed some more optimizer bugs, make cycle now works with -O2p3,
-O2p3u, -O3p3 and -O3p3u

Jonas Maebe 21 years ago
parent
commit
bade472032
2 changed files with 123 additions and 77 deletions
  1. 114 71
      compiler/i386/csopt386.pas
  2. 9 6
      compiler/i386/daopt386.pas

+ 114 - 71
compiler/i386/csopt386.pas

@@ -68,7 +68,7 @@ end;
 }
 
 function modifiesConflictingMemLocation(p1: tai; supreg: tsuperregister; c: tregContent;
-   var regsStillValid: tregset; onlymem: boolean): boolean;
+   var regsStillValid: tregset; onlymem: boolean; var invalsmemwrite: boolean): boolean;
 var
   p, hp: taicpu;
   tmpRef: treference;
@@ -77,6 +77,7 @@ var
   dummy: boolean;
 begin
   modifiesConflictingMemLocation := false;
+  invalsmemwrite := false;
   if p1.typ <> ait_instruction then
     exit;
   p := taicpu(p1);
@@ -93,13 +94,15 @@ begin
                 exclude(regsStillValid,regCounter);
                 modifiesConflictingMemLocation := not(supreg in regsStillValid);
               end;
+            if (regcounter = supreg) then
+              invalsmemwrite := invalsmemwrite or dummy;
           end
       else
 {         if is_reg_var[getsupreg(p.oper[1]^.reg)] then }
         if not onlymem  then
           for regCounter := RS_EAX to RS_EDI do
             begin
-              if writeDestroysContents(p.oper[1]^,regCounter,c[regCounter]) then
+              if writeDestroysContents(p.oper[1]^,regCounter,c[regCounter],dummy) then
                 begin
                   exclude(regsStillValid,regCounter);
                   modifiesConflictingMemLocation := not(supreg in regsStillValid);
@@ -129,7 +132,7 @@ begin
             { last operand is always destination }
             for regCounter := RS_EAX to RS_EDI do
               begin
-                if writeDestroysContents(p.oper[p.ops-1]^,regCounter,c[regCounter]) then
+                if writeDestroysContents(p.oper[p.ops-1]^,regCounter,c[regCounter],dummy) then
                   begin
                     exclude(regsStillValid,regCounter);
                     modifiesConflictingMemLocation := not(supreg in regsStillValid);
@@ -144,33 +147,45 @@ begin
                  (p.oper[0]^.typ = top_ref) then
 {                or ((p.oper[0]^.typ = top_reg) and }
 {                 is_reg_var[getsupreg(p.oper[0]^.reg)]) then }
-              for regCounter := RS_EAX to RS_EDI do
-                if writeDestroysContents(p.oper[0]^,regCounter,c[regCounter]) then
+                for regCounter := RS_EAX to RS_EDI do
                   begin
-                    exclude(regsStillValid,regCounter);
-                    modifiesConflictingMemLocation := not(supreg in regsStillValid);
+                    if writeDestroysContents(p.oper[0]^,regCounter,c[regCounter],dummy) then
+                      begin
+                        exclude(regsStillValid,regCounter);
+                        modifiesConflictingMemLocation := not(supreg in regsStillValid);
+                      end;
+                    if (regcounter = supreg) then
+                      invalsmemwrite := invalsmemwrite or dummy;
                   end;
           Ch_MOp2,CH_WOp2,CH_RWOp2:
               if not(onlymem) or
                  (p.oper[1]^.typ = top_ref) then
 {                or ((p.oper[1]^.typ = top_reg) and }
 {                 is_reg_var[getsupreg(p.oper[1]^.reg)]) then }
-              for regCounter := RS_EAX to RS_EDI do
-                if writeDestroysContents(p.oper[1]^,regCounter,c[regCounter]) then
+                for regCounter := RS_EAX to RS_EDI do
                   begin
-                    exclude(regsStillValid,regCounter);
-                    modifiesConflictingMemLocation := not(supreg in regsStillValid);
+                    if writeDestroysContents(p.oper[1]^,regCounter,c[regCounter],dummy) then
+                      begin
+                        exclude(regsStillValid,regCounter);
+                        modifiesConflictingMemLocation := not(supreg in regsStillValid);
+                      end;
+                    if (regcounter = supreg) then
+                      invalsmemwrite := invalsmemwrite or dummy;
                   end;
           Ch_MOp3,CH_WOp3,CH_RWOp3:
               if not(onlymem) or
                  (p.oper[2]^.typ = top_ref) then
 {                or ((p.oper[2]^.typ = top_reg) and }
 {                 is_reg_var[getsupreg(p.oper[2]^.reg)]) then }
-              for regCounter := RS_EAX to RS_EDI do
-                if writeDestroysContents(p.oper[2]^,regCounter,c[regCounter]) then
+                for regCounter := RS_EAX to RS_EDI do
                   begin
-                    exclude(regsStillValid,regCounter);
-                    modifiesConflictingMemLocation := not(supreg in regsStillValid);
+                    if writeDestroysContents(p.oper[2]^,regCounter,c[regCounter],dummy) then
+                      begin
+                        exclude(regsStillValid,regCounter);
+                        modifiesConflictingMemLocation := not(supreg in regsStillValid);
+                      end;
+                    if (regcounter = supreg) then
+                      invalsmemwrite := invalsmemwrite or dummy;
                   end;
           Ch_WMemEDI:
             begin
@@ -183,6 +198,8 @@ begin
                     exclude(regsStillValid,regCounter);
                     modifiesConflictingMemLocation := not(supreg in regsStillValid);
                  end;
+              if (regcounter = supreg) then
+                invalsmemwrite := invalsmemwrite or dummy;
             end;
         end;
   end;
@@ -213,7 +230,8 @@ var
   regsNotRead, regsStillValid : tregset;
   checkingPrevSequences,
   passedFlagsModifyingInstr,
-  passedJump                  : boolean;
+  passedJump,
+  invalsmemwrite               : boolean;
 
   function getPrevSequence(p: tai; supreg: tsuperregister; currentPrev: tai; var newPrev: tai): tsuperregister;
 
@@ -267,6 +285,7 @@ var
   var
     hp, prevFound: tai;
     tmpResult, regCounter: tsuperregister;
+    invalsmemwrite: boolean;
   begin
     if (current_reg <> RS_EDI) and
        (current_reg <> RS_INVALID) then
@@ -296,7 +315,7 @@ var
           stillValid(hp) and
           (ptaiprop(prevFound.optinfo)^.canBeRemoved or
            not(modifiesConflictingMemLocation(prevFound,supreg,
-             ptaiprop(p.optinfo)^.regs,regsStillValid,false))) do
+             ptaiprop(p.optinfo)^.regs,regsStillValid,false, invalsmemwrite))) do
       begin
         { only update the regsread for the instructions we already passed }
         if not(ptaiprop(prevFound.optinfo)^.canBeRemoved) then
@@ -363,6 +382,7 @@ var
     var
       orgdiffregs,diffregs: tregset;
       runner: tai;
+      invalsmemwrite: boolean;
     begin
       diffregs := newreginfo.newregsencountered - oldreginfo.newregsencountered;
       orgdiffregs := diffregs;
@@ -370,7 +390,7 @@ var
         begin
           runner := startp;
           repeat
-            modifiesConflictingMemLocation(runner,RS_EAX { dummy },ptaiprop(current.optinfo)^.regs,diffregs,true);
+            modifiesConflictingMemLocation(runner,RS_EAX { dummy },ptaiprop(current.optinfo)^.regs,diffregs,true,invalsmemwrite);
             if orgdiffregs <> diffregs then
               begin
                 changedreginvalidatedbetween := true;
@@ -463,9 +483,11 @@ begin {CheckSequence}
                        ((taicpu(hp3).oper[0]^.ref^.index = NR_NO) or
                         regModified[index]) and
                        not(regInRef(tmpReg,taicpu(hp3).oper[0]^.ref^)) then
-                      with ptaiprop(hp3.optinfo)^.regs[tmpreg] do
-                        if nrofMods > (oldNrofMods - found) then
-                          oldNrofMods := found + nrofMods;
+                      begin
+                        with ptaiprop(hp3.optinfo)^.regs[tmpreg] do
+                          if nrofMods > (oldNrofMods - found) then
+                            oldNrofMods := found + nrofMods;
+                      end;
                   end;
                 top_reg:
                   if regModified[getsupreg(taicpu(hp3).oper[0]^.reg)] then
@@ -637,7 +659,7 @@ begin
                       exclude(regsUsable,regCounter);
 {$ifdef alignregdebug}
                       temp := tai_comment.Create(strpnew(
-                                std_reg2str[regCounter]+' removed')));
+                                std_regname(newreg(R_INTREGISTER,regCounter,R_SUBWHOLE))+' removed')));
                       temp.next := prev.next;
                       temp.previous := prev;
                       prev.next := temp;
@@ -687,7 +709,7 @@ begin
                       exclude(regsUsable,regCounter);
 {$ifdef alignregdebug}
                       temp := tai_comment.Create(strpnew(
-                                std_reg2str[regCounter]+' removed')));
+                                std_regname(newreg(R_INTREGISTER,regCounter,R_SUBWHOLE))+' removed')));
                       temp.next := next.next;
                       temp.previous := next;
                       next.next := temp;
@@ -730,7 +752,7 @@ begin
           break
         end;
 {$ifdef alignregdebug}
-  next := tai_comment.Create(strpnew(std_reg2str[lastRemoved]+
+  next := tai_comment.Create(strpnew(std_regname(newreg(R_INTREGISTER,lastremoved,R_SUBWHOLE))+
                ' chosen as alignment register')));
   next.next := p.next;
   next.previous := p;
@@ -768,12 +790,12 @@ begin
 {$ifdef replaceregdebug}
   l := random(1000);
   hp := tai_comment.Create(strpnew(
-          'cleared '+std_reg2str[reg]+' from here... '+tostr(l))));
+          'cleared '+std_regname(newreg(R_INTREGISTER,supreg,R_SUBWHOLE))+' from here... '+tostr(l)));
   hp.next := p;
   hp.previous := p.previous;
   p.previous := hp;
   if assigned(hp.previous) then
-    hp.previous^.next := hp;
+    hp.previous.next := hp;
 {$endif replaceregdebug}
   ptaiprop(p.optinfo)^.Regs[supreg].typ := con_unknown;
   while (p <> endP) do
@@ -803,12 +825,12 @@ begin
   if assigned(p) then
     begin
       hp := tai_comment.Create(strpnew(
-        'cleared '+std_reg2str[reg]+' till here... '+tostr(l))));
+        'cleared '+std_regname(newreg(R_INTREGISTER,supreg,R_SUBWHOLE))+' till here... '+tostr(l)));
       hp.next := p;
       hp.previous := p.previous;
       p.previous := hp;
       if assigned(hp.previous) then
-        hp.previous^.next := hp;
+        hp.previous.next := hp;
     end;
 {$endif replaceregdebug}
 end;
@@ -819,18 +841,21 @@ var
   hp: tai;
   l: longint;
 {$endif replaceregdebug}
+  dummyregs: tregset;
   tmpState: byte;
   prevcontenttyp: byte;
+  memconflict: boolean;
+  invalsmemwrite: boolean;
 begin
 {$ifdef replaceregdebug}
   l := random(1000);
   hp := tai_comment.Create(strpnew(
-          'restored '+std_reg2str[supreg]+' with data from here... '+tostr(l))));
+          'restored '+std_regname(newreg(R_INTREGISTER,supreg,R_SUBWHOLE))+' with data from here... '+tostr(l)));
   hp.next := p;
   hp.previous := p.previous;
   p.previous := hp;
   if assigned(hp.previous) then
-    hp.previous^.next := hp;
+    hp.previous.next := hp;
 {$endif replaceregdebug}
 {  ptaiprop(p.optinfo)^.Regs[reg] := c;}
   while (p <> endP) do
@@ -839,27 +864,35 @@ begin
       getNextInstruction(p,p);
     end;
   tmpState := ptaiprop(p.optinfo)^.Regs[supreg].wState;
-   repeat
+  dummyregs := [supreg];
+  repeat
     prevcontenttyp := ptaiprop(p.optinfo)^.Regs[supreg].typ;
-    ptaiprop(p.optinfo)^.Regs[supreg] := c;
-  until not getNextInstruction(p,p) or
+    // 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
+      ptaiprop(p.optinfo)^.Regs[supreg] := c;
+  until invalsmemwrite or
+        memconflict or
+        not getNextInstruction(p,p) or
         (ptaiprop(p.optinfo)^.Regs[supreg].wState <> tmpState) or
         (p.typ = ait_label) or
         ((prevcontenttyp <> con_invalid) and
          (ptaiprop(p.optinfo)^.Regs[supreg].typ = con_invalid));
   if assigned(p) and
-     (p.typ = ait_label) then
+     ((p.typ = ait_label) or
+      memconflict or
+      invalsmemwrite) then
     clearRegContentsFrom(supreg,p,p);
 {$ifdef replaceregdebug}
   if assigned(p) then
     begin
       hp := tai_comment.Create(strpnew(
-        'restored '+std_reg2str[reg]+' till here... '+tostr(l))));
+        'restored '+std_regname(newreg(R_INTREGISTER,supreg,R_SUBWHOLE))+' till here... '+tostr(l)));
       hp.next := p;
       hp.previous := p.previous;
       p.previous := hp;
       if assigned(hp.previous) then
-        hp.previous^.next := hp;
+        hp.previous.next := hp;
     end;
 {$endif replaceregdebug}
 end;
@@ -1159,9 +1192,9 @@ begin
 end;
 
 
-function ReplaceReg(asml: TAAsmOutput; orgsupreg, newsupreg: tsuperregister; p: tai;
-           const c: TContent; orgRegCanBeModified: Boolean;
-           var returnEndP: tai): Boolean;
+function ReplaceReg(asml: TAAsmOutput; orgsupreg, newsupreg: tsuperregister; p,
+          seqstart: tai; const c: TContent; orgRegCanBeModified: Boolean;
+          var returnEndP: tai): Boolean;
 { Tries to replace orgsupreg with newsupreg in all instructions coming after p }
 { until orgsupreg gets loaded with a new value. Returns true if successful, }
 { false otherwise. if successful, the contents of newsupreg are set to c,   }
@@ -1196,7 +1229,7 @@ begin
           hp.previous := endp.previous;
           endp.previous := hp;
           if assigned(hp.previous) then
-            hp.previous^.next := hp;}
+            hp.previous.next := hp;}
           exit;
         end;
       if tmpResult and
@@ -1268,17 +1301,17 @@ begin
     begin
 {$ifdef replaceregdebug}
       hp := tai_comment.Create(strpnew(
-        'replacing '+std_reg2str[newsupreg]+' with '+std_reg2str[orgsupreg]+
-        ' from here...')));
+        'replacing '+std_regname(newreg(R_INTREGISTER,newsupreg,R_SUBWHOLE))+' with '+std_regname(newreg(R_INTREGISTER,orgsupreg,R_SUBWHOLE))+
+        ' from here...'));
       hp.next := p;
       hp.previous := p.previous;
       p.previous := hp;
       if assigned(hp.previous) then
-        hp.previous^.next := hp;
+        hp.previous.next := hp;
 
       hp := tai_comment.Create(strpnew(
-        'replaced '+std_reg2str[newsupreg]+' with '+std_reg2str[orgsupreg]+
-        ' till here')));
+        'replaced '+std_regname(newreg(R_INTREGISTER,newsupreg,R_SUBWHOLE))+' with '+std_regname(newreg(R_INTREGISTER,orgsupreg,R_SUBWHOLE))+
+        ' till here'));
       hp.next := endp.next;
       hp.previous := endp;
       endp.next := hp;
@@ -1309,26 +1342,18 @@ begin
       if stateChanged or readStateChanged then
         updateState(orgsupreg,endP);
 
-{ the replacing stops either at the moment that                             }
-{  a) the newsupreg gets loaded with a new value (one not depending on the     }
-{     current value of newsupreg)                                              }
-{  b) newsupreg is completely replaced in this sequence and it's current value }
-{     isn't used anymore                                                    }
-{ in case b, the newsupreg was completely replaced by oldreg, so it's contents }
-{ are unchanged compared the start of this sequence, so restore them        }
+{ We replaced newreg with oldreg between p and endp, so restore the contents }
+{ of newreg there with its contents from before the sequence.                }
       if removeLast or
          RegLoadedWithNewValue(newsupreg,true,endP) then
         GetLastInstruction(endP,hp)
       else hp := endP;
-      if removeLast or
-         (p <> endp) or
-         not RegLoadedWithNewValue(newsupreg,true,endP) then
-        RestoreRegContentsTo(newsupreg,c,p,hp);
-
-{ in both case a and b, it is possible that the new register was modified   }
-{ (e.g. an add/sub), so if it was replaced by oldreg in that instruction,   }
-{ oldreg's contents have been changed. To take this into account, we simply }
-{ set the contents of orgsupreg to "unknown" after this sequence               }
+      RestoreRegContentsTo(newsupreg,c,seqstart,hp);
+
+{ Ot is possible that the new register was modified (e.g. an add/sub), so if  }
+{ it was replaced by oldreg in that instruction, oldreg's contents have been  }
+{ changed. To take this into account, we simply set the contents of orgsupreg }
+{ to "unknown" after this sequence                                            }
       if newRegModified then
         ClearRegContentsFrom(orgsupreg,p,hp);
       if removeLast then
@@ -1340,17 +1365,17 @@ begin
      else
        begin
          hp := tai_comment.Create(strpnew(
-           'replacing '+std_reg2str[newsupreg]+' with '+std_reg2str[orgsupreg]+
-           ' from here...')));
+           'replacing '+std_regname(newreg(R_INTREGISTER,newsupreg,R_SUBWHOLE))+' with '+std_regname(newreg(R_INTREGISTER,orgsupreg,R_SUBWHOLE))+
+           ' from here...'));
          hp.previous := p.previous;
          hp.next := p;
          p.previous := hp;
         if assigned(hp.previous) then
-          hp.previous^.next := hp;
+          hp.previous.next := hp;
 
       hp := tai_comment.Create(strpnew(
-        'replacing '+std_reg2str[newsupreg]+' with '+std_reg2str[orgsupreg]+
-        ' failed here')));
+        'replacing '+std_regname(newreg(R_INTREGISTER,newsupreg,R_SUBWHOLE))+' with '+std_regname(newreg(R_INTREGISTER,orgsupreg,R_SUBWHOLE))+
+        ' failed here'));
       hp.next := endp.next;
       hp.previous := endp;
       endp.next := hp;
@@ -1376,12 +1401,12 @@ begin
      if (ptaiprop(p.optinfo)^.regs[counter].typ in [con_const,con_noRemoveConst]) then
        begin
          hp := tai_comment.Create(strpnew(
-           'checking const load of '+tostr(l)+' here...')));
+           'checking const load of '+tostr(l)+' here...'));
          hp.next := ptaiprop(p.optinfo)^.Regs[Counter].StartMod;
          hp.previous := ptaiprop(p.optinfo)^.Regs[Counter].StartMod^.previous;
          ptaiprop(p.optinfo)^.Regs[Counter].StartMod^.previous := hp;
          if assigned(hp.previous) then
-           hp.previous^.next := hp;
+           hp.previous.next := hp;
        end;
 {$endif testing}
      if (ptaiprop(p.optinfo)^.regs[counter].typ in [con_const,con_noRemoveConst]) and
@@ -1564,7 +1589,7 @@ begin
                 {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,
+                    regCounter,hp,curseqstart,
                     ptaiprop(prevseqstart.optinfo)^.Regs[regCounter],true,hp2) then
               begin
                 if not(reginfo.new2oldreg[regcounter] in regsloaded) or
@@ -1598,6 +1623,20 @@ begin
                 updateState(reginfo.new2oldreg[regcounter],hp2);
                 updateState(regcounter,hp2);
               end
+            else
+              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;
+              end;
           end
         else
   {   imagine the following code:                                            }
@@ -1778,7 +1817,7 @@ begin
                           { we only have to start replacing from the instruction after the mov, }
                           { but replacereg only starts with getnextinstruction(p,p)             }
                             replaceReg(asml,getsupreg(taicpu(p).oper[0]^.reg),
-                              getsupreg(taicpu(p).oper[1]^.reg),p,
+                              getsupreg(taicpu(p).oper[1]^.reg),p,p,
                               ptaiprop(hp4.optinfo)^.regs[getsupreg(taicpu(p).oper[1]^.reg)],false,hp1) then
                           begin
                             ptaiprop(p.optinfo)^.canBeRemoved := true;
@@ -2074,7 +2113,11 @@ end.
 
 {
   $Log$
-  Revision 1.58  2003-12-15 21:25:49  peter
+  Revision 1.59  2003-12-20 22:53:33  jonas
+    * fixed some more optimizer bugs, make cycle now works with -O2p3,
+      -O2p3u, -O3p3 and -O3p3u
+
+  Revision 1.58  2003/12/15 21:25:49  peter
     * reg allocations for imaginary register are now inserted just
       before reg allocation
     * tregister changed to enum to allow compile time check

+ 9 - 6
compiler/i386/daopt386.pas

@@ -175,7 +175,7 @@ function writeToMemDestroysContents(regWritten: tsuperregister; const ref: trefe
 function writeToRegDestroysContents(destReg, supreg: tsuperregister;
   const c: tcontent): boolean;
 function writeDestroysContents(const op: toper; supreg: tsuperregister;
-  const c: tcontent): boolean;
+  const c: tcontent; var memwritedestroyed: boolean): boolean;
 
 
 function GetNextInstruction(Current: tai; var Next: tai): Boolean;
@@ -1805,19 +1805,18 @@ end;
 
 
 function writeDestroysContents(const op: toper; supreg: tsuperregister;
-  const c: tcontent): boolean;
+  const c: tcontent; var memwritedestroyed: boolean): boolean;
 { returns whether the contents c of reg are invalid after regWritten is }
 { is written to op                                                      }
-var
-  dummy: boolean;
 begin
+  memwritedestroyed := false;
   case op.typ of
     top_reg:
       writeDestroysContents :=
         writeToRegDestroysContents(getsupreg(op.reg),supreg,c);
     top_ref:
       writeDestroysContents :=
-        writeToMemDestroysContents(RS_INVALID,op.ref^,supreg,c,dummy);
+        writeToMemDestroysContents(RS_INVALID,op.ref^,supreg,c,memwritedestroyed);
   else
     writeDestroysContents := false;
   end;
@@ -2714,7 +2713,11 @@ end.
 
 {
   $Log$
-  Revision 1.61  2003-12-15 21:25:49  peter
+  Revision 1.62  2003-12-20 22:53:33  jonas
+    * fixed some more optimizer bugs, make cycle now works with -O2p3,
+      -O2p3u, -O3p3 and -O3p3u
+
+  Revision 1.61  2003/12/15 21:25:49  peter
     * reg allocations for imaginary register are now inserted just
       before reg allocation
     * tregister changed to enum to allow compile time check