Browse Source

* take into account the size of a write to determine whether a write to
one reference influences the contents of another reference

Jonas Maebe 21 years ago
parent
commit
0cf348b3df
2 changed files with 95 additions and 41 deletions
  1. 12 8
      compiler/i386/csopt386.pas
  2. 83 33
      compiler/i386/daopt386.pas

+ 12 - 8
compiler/i386/csopt386.pas

@@ -89,7 +89,7 @@ begin
             if p.oper[0]^.typ<>top_reg then
                break;
             if writeToMemDestroysContents(getsupreg(p.oper[0]^.reg),p.oper[1]^.ref^,
-                 regCounter,c[regCounter],dummy) then
+                 regCounter,topsize2tcgsize[p.opsize],c[regCounter],dummy) then
               begin
                 exclude(regsStillValid,regCounter);
                 modifiesConflictingMemLocation := not(supreg in regsStillValid);
@@ -102,7 +102,7 @@ begin
         if not onlymem  then
           for regCounter := RS_EAX to RS_EDI do
             begin
-              if writeDestroysContents(p.oper[1]^,regCounter,c[regCounter],dummy) then
+              if writeDestroysContents(p.oper[1]^,regCounter,topsize2tcgsize[p.opsize],c[regCounter],dummy) then
                 begin
                   exclude(regsStillValid,regCounter);
                   modifiesConflictingMemLocation := not(supreg in regsStillValid);
@@ -132,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],dummy) then
+                if writeDestroysContents(p.oper[p.ops-1]^,regCounter,topsize2tcgsize[p.opsize],c[regCounter],dummy) then
                   begin
                     exclude(regsStillValid,regCounter);
                     modifiesConflictingMemLocation := not(supreg in regsStillValid);
@@ -149,7 +149,7 @@ begin
 {                 is_reg_var[getsupreg(p.oper[0]^.reg)]) then }
                 for regCounter := RS_EAX to RS_EDI do
                   begin
-                    if writeDestroysContents(p.oper[0]^,regCounter,c[regCounter],dummy) then
+                    if writeDestroysContents(p.oper[0]^,regCounter,topsize2tcgsize[p.opsize],c[regCounter],dummy) then
                       begin
                         exclude(regsStillValid,regCounter);
                         modifiesConflictingMemLocation := not(supreg in regsStillValid);
@@ -164,7 +164,7 @@ begin
 {                 is_reg_var[getsupreg(p.oper[1]^.reg)]) then }
                 for regCounter := RS_EAX to RS_EDI do
                   begin
-                    if writeDestroysContents(p.oper[1]^,regCounter,c[regCounter],dummy) then
+                    if writeDestroysContents(p.oper[1]^,regCounter,topsize2tcgsize[p.opsize],c[regCounter],dummy) then
                       begin
                         exclude(regsStillValid,regCounter);
                         modifiesConflictingMemLocation := not(supreg in regsStillValid);
@@ -179,7 +179,7 @@ begin
 {                 is_reg_var[getsupreg(p.oper[2]^.reg)]) then }
                 for regCounter := RS_EAX to RS_EDI do
                   begin
-                    if writeDestroysContents(p.oper[2]^,regCounter,c[regCounter],dummy) then
+                    if writeDestroysContents(p.oper[2]^,regCounter,topsize2tcgsize[p.opsize],c[regCounter],dummy) then
                       begin
                         exclude(regsStillValid,regCounter);
                         modifiesConflictingMemLocation := not(supreg in regsStillValid);
@@ -193,7 +193,7 @@ begin
               tmpRef.base := NR_EDI;
               tmpRef.index := NR_EDI;
               for regCounter := RS_EAX to RS_EDI do
-                if writeToMemDestroysContents(RS_INVALID,tmpRef,regCounter,c[regCounter],dummy) then
+                if writeToMemDestroysContents(RS_INVALID,tmpRef,regCounter,OS_32,c[regCounter],dummy) then
                   begin
                     exclude(regsStillValid,regCounter);
                     modifiesConflictingMemLocation := not(supreg in regsStillValid);
@@ -2109,7 +2109,11 @@ end.
 
 {
   $Log$
-  Revision 1.66  2004-10-04 20:46:22  peter
+  Revision 1.67  2004-10-06 19:24:38  jonas
+    * take into account the size of a write to determine whether a write to
+      one reference influences the contents of another reference
+
+  Revision 1.66  2004/10/04 20:46:22  peter
     * spilling code rewritten for x86. It now used the generic
       spilling routines. Special x86 optimization still needs
       to be added.

+ 83 - 33
compiler/i386/daopt386.pas

@@ -50,6 +50,16 @@ const
   { same, but for constants }
   con_noRemoveConst = 5;
 
+
+const
+  topsize2tcgsize: array[topsize] of tcgsize = (OS_NO,
+    OS_8,OS_16,OS_32,OS_64,OS_16,OS_32,OS_32,
+    OS_16,OS_32,OS_64,
+    OS_F32,OS_F64,OS_F80,OS_C64,OS_F128,
+    OS_M32,OS_ADDR,OS_NO,OS_NO);
+
+
+
 {********************************* Types *********************************}
 
 type
@@ -171,10 +181,10 @@ function instrWritesFlags(p: tai): boolean;
 function instrReadsFlags(p: tai): boolean;
 
 function writeToMemDestroysContents(regWritten: tsuperregister; const ref: treference;
-  supreg: tsuperregister; const c: tcontent; var invalsmemwrite: boolean): boolean;
+  supreg: tsuperregister; size: tcgsize; const c: tcontent; var invalsmemwrite: boolean): boolean;
 function writeToRegDestroysContents(destReg, supreg: tsuperregister;
   const c: tcontent): boolean;
-function writeDestroysContents(const op: toper; supreg: tsuperregister;
+function writeDestroysContents(const op: toper; supreg: tsuperregister; size: tcgsize;
   const c: tcontent; var memwritedestroyed: boolean): boolean;
 
 
@@ -258,7 +268,7 @@ Uses
    rgobj, procinfo;
 
 Type
-  TRefCompare = function(const r1, r2: TReference): Boolean;
+  TRefCompare = function(const r1, r2: treference; size: tcgsize): boolean;
 
 var
  {How many instructions are between the current instruction and the last one
@@ -672,6 +682,31 @@ begin
 end;
 
 
+{$ifdef q+}
+{$q-}
+{$define overflowon}
+{$endif q+}
+
+// checks whether a write to r2 of size "size" contains address r1
+function refsoverlapping(const r1, r2: treference; size: tcgsize): boolean;
+var
+  realsize: aword;
+begin
+  realsize := tcgsize2size[size];
+  refsoverlapping :=
+    (aword(r1.offset-r2.offset) <= realsize) and
+    (r1.segment = r2.segment) and (r1.base = r2.base) and
+    (r1.index = r2.index) and (r1.scalefactor = r2.scalefactor) and
+    (r1.symbol=r2.symbol) and (r1.refaddr = r2.refaddr) and
+    (r1.relsymbol = r2.relsymbol);
+end;
+
+{$ifdef overflowon}
+{$q+}
+{$undef overflowon}
+{$endif overflowon}
+
+
 function isgp32reg(supreg: tsuperregister): boolean;
 {Checks if the register is a 32 bit general purpose register}
 begin
@@ -1601,31 +1636,32 @@ end;
 
 
 function RefInInstruction(const ref: TReference; p: tai;
-           RefsEq: TRefCompare): Boolean;
+           RefsEq: TRefCompare; size: tcgsize): Boolean;
 {checks whehter ref is used in p}
-var TmpResult: Boolean;
+var
+  TmpResult: Boolean;
 begin
   TmpResult := False;
   if (p.typ = ait_instruction) then
     begin
       if (taicpu(p).ops >= 1) and
          (taicpu(p).oper[0]^.typ = top_ref) then
-        TmpResult := RefsEq(ref, taicpu(p).oper[0]^.ref^);
+        TmpResult := RefsEq(taicpu(p).oper[0]^.ref^,ref,size);
       if not(TmpResult) and
          (taicpu(p).ops >= 2) and
          (taicpu(p).oper[1]^.typ = top_ref) then
-        TmpResult := RefsEq(ref, taicpu(p).oper[1]^.ref^);
+        TmpResult := RefsEq(taicpu(p).oper[1]^.ref^,ref,size);
       if not(TmpResult) and
          (taicpu(p).ops >= 3) and
          (taicpu(p).oper[2]^.typ = top_ref) then
-        TmpResult := RefsEq(ref, taicpu(p).oper[2]^.ref^);
+        TmpResult := RefsEq(taicpu(p).oper[2]^.ref^,ref,size);
     end;
   RefInInstruction := TmpResult;
 end;
 
 
 function RefInSequence(const ref: TReference; Content: TContent;
-           RefsEq: TRefCompare): Boolean;
+           RefsEq: TRefCompare; size: tcgsize): Boolean;
 {checks the whole sequence of Content (so StartMod and and the next NrOfMods
  tai objects) to see whether ref is used somewhere}
 var p: tai;
@@ -1639,7 +1675,7 @@ begin
         (Counter <= Content.NrOfMods) Do
     begin
       if (p.typ = ait_instruction) and
-         RefInInstruction(ref, p, RefsEq)
+         RefInInstruction(ref, p, RefsEq, size)
         then TmpResult := True;
       inc(Counter);
       GetNextInstruction(p,p)
@@ -1647,15 +1683,25 @@ begin
   RefInSequence := TmpResult
 end;
 
-
-function ArrayRefsEq(const r1, r2: TReference): Boolean;
+{$ifdef q+}
+{$q-}
+{$define overflowon}
+{$endif q+}
+// checks whether a write to r2 of size "size" contains address r1
+function ArrayRefsOverlapping(const r1, r2: treference; size: tcgsize): Boolean;
+var
+  realsize: aword;
 begin
-  ArrayRefsEq := (R1.Offset = R2.Offset) and
-                 (R1.Segment = R2.Segment) and
-                 (R1.Symbol=R2.Symbol) and
-                 (R1.base = R2.base)
+  realsize := tcgsize2size[size];
+  ArrayRefsOverlapping := (aword(r1.offset-r2.offset) <= realsize) and
+                 (r1.segment = r2.segment) and
+                 (r1.symbol=r2.symbol) and
+                 (r1.base = r2.base)
 end;
-
+{$ifdef overflowon}
+{$q+}
+{$undef overflowon}
+{$endif overflowon}
 
 function isSimpleRef(const ref: treference): boolean;
 { returns true if ref is reference to a local or global variable, to a  }
@@ -1715,7 +1761,7 @@ end;
 
 
 function writeToMemDestroysContents(regWritten: tsuperregister; const ref: treference;
-  supreg: tsuperregister; const c: tcontent; var invalsmemwrite: boolean): boolean;
+  supreg: tsuperregister; size: tcgsize; const c: tcontent; var invalsmemwrite: boolean): boolean;
 { returns whether the contents c of reg are invalid after regWritten is }
 { is written to ref                                                     }
 var
@@ -1727,15 +1773,15 @@ begin
          (assigned(ref.symbol) and
           (ref.base <> NR_NO)) then
         { local/global variable or parameter which is an array }
-        refsEq := {$ifdef fpc}@{$endif}arrayRefsEq
+        refsEq := {$ifdef fpc}@{$endif}arrayRefsOverlapping
       else
         { local/global variable or parameter which is not an array }
-        refsEq := {$ifdef fpc}@{$endif}refsEqual;
+        refsEq := {$ifdef fpc}@{$endif}refsOverlapping;
       invalsmemwrite :=
         assigned(c.memwrite) and
         ((not(cs_uncertainOpts in aktglobalswitches) and
           containsPointerRef(c.memwrite)) or
-         refsEq(c.memwrite.oper[1]^.ref^,ref));
+         refsEq(c.memwrite.oper[1]^.ref^,ref,size));
       if not(c.typ in [con_ref,con_noRemoveRef,con_invalid]) then
         begin
           writeToMemDestroysContents := false;
@@ -1757,12 +1803,12 @@ begin
           ((not(cs_uncertainOpts in aktglobalswitches) and
             containsPointerLoad(c)
            ) or
-           (refInSequence(ref,c,refsEq) and
+           (refInSequence(ref,c,refsEq,size) and
             ((supreg <> regWritten) or
              not((nrOfMods = 1) and
                  {StarMod is always of the type ait_instruction}
                  (taicpu(StartMod).oper[0]^.typ = top_ref) and
-                 refsEq(taicpu(StartMod).oper[0]^.ref^, ref)
+                 refsEq(taicpu(StartMod).oper[0]^.ref^, ref, size)
                 )
             )
            )
@@ -1809,7 +1855,7 @@ begin
 end;
 
 
-function writeDestroysContents(const op: toper; supreg: tsuperregister;
+function writeDestroysContents(const op: toper; supreg: tsuperregister; size: tcgsize;
   const c: tcontent; var memwritedestroyed: boolean): boolean;
 { returns whether the contents c of reg are invalid after regWritten is }
 { is written to op                                                      }
@@ -1821,14 +1867,14 @@ begin
         writeToRegDestroysContents(getsupreg(op.reg),supreg,c);
     top_ref:
       writeDestroysContents :=
-        writeToMemDestroysContents(RS_INVALID,op.ref^,supreg,c,memwritedestroyed);
+        writeToMemDestroysContents(RS_INVALID,op.ref^,supreg,size,c,memwritedestroyed);
   else
     writeDestroysContents := false;
   end;
 end;
 
 
-procedure destroyRefs(p: tai; const ref: treference; regwritten: tsuperregister);
+procedure destroyRefs(p: tai; const ref: treference; regwritten: tsuperregister; size: tcgsize);
 { destroys all registers which possibly contain a reference to ref, regWritten }
 { is the register whose contents are being written to memory (if this proc     }
 { is called because of a "mov?? %reg, (mem)" instruction)                      }
@@ -1838,7 +1884,7 @@ var
 begin
   for counter := RS_EAX to RS_EDI Do
     begin
-      if writeToMemDestroysContents(regwritten,ref,counter,
+      if writeToMemDestroysContents(regwritten,ref,counter,size,
            ptaiprop(p.optInfo)^.regs[counter],destroymemwrite) then
         destroyReg(ptaiprop(p.optInfo), counter, false)
       else if destroymemwrite then
@@ -1883,7 +1929,7 @@ begin
     top_ref:
       begin
         readref(ptaiprop(taiObj.OptInfo), o.ref);
-        DestroyRefs(taiObj, o.ref^, RS_INVALID);
+        DestroyRefs(taiObj, o.ref^, RS_INVALID,topsize2tcgsize[(taiobj as taicpu).opsize]);
       end;
   end;
 end;
@@ -2452,12 +2498,12 @@ begin
                             if taicpu(p).oper[0]^.typ = top_reg then
                               begin
                                 readreg(curprop, getsupreg(taicpu(p).oper[0]^.reg));
-                                DestroyRefs(p, taicpu(p).oper[1]^.ref^, getsupreg(taicpu(p).oper[0]^.reg));
+                                DestroyRefs(p, taicpu(p).oper[1]^.ref^, getsupreg(taicpu(p).oper[0]^.reg),topsize2tcgsize[taicpu(p).opsize]);
                                 ptaiprop(p.optinfo)^.regs[getsupreg(taicpu(p).oper[0]^.reg)].memwrite :=
                                   taicpu(p);
                               end
                             else
-                              DestroyRefs(p, taicpu(p).oper[1]^.ref^, RS_INVALID);
+                              DestroyRefs(p, taicpu(p).oper[1]^.ref^, RS_INVALID,topsize2tcgsize[taicpu(p).opsize]);
                           end;
                       end;
                     top_Const:
@@ -2480,7 +2526,7 @@ begin
                           top_ref:
                             begin
                               readref(curprop, taicpu(p).oper[1]^.ref);
-                              DestroyRefs(p, taicpu(p).oper[1]^.ref^, RS_INVALID);
+                              DestroyRefs(p, taicpu(p).oper[1]^.ref^, RS_INVALID,topsize2tcgsize[taicpu(p).opsize]);
                             end;
                         end;
                       end;
@@ -2623,7 +2669,7 @@ begin
                             fillchar(tmpref, SizeOf(tmpref), 0);
                             tmpref.base := NR_EDI;
                             tmpref.index := NR_EDI;
-                            DestroyRefs(p, tmpref,RS_INVALID)
+                            DestroyRefs(p, tmpref,RS_INVALID,OS_32)
                           end;
                         Ch_RFlags:
                           if assigned(LastFlagsChangeProp) then
@@ -2719,7 +2765,11 @@ end.
 
 {
   $Log$
-  Revision 1.71  2004-10-05 20:41:01  peter
+  Revision 1.72  2004-10-06 19:24:38  jonas
+    * take into account the size of a write to determine whether a write to
+      one reference influences the contents of another reference
+
+  Revision 1.71  2004/10/05 20:41:01  peter
     * more spilling rewrites
 
   Revision 1.70  2004/10/04 20:46:22  peter