浏览代码

* Prevent spilling of spill-helper registers which contain the value of a
previously spilled register. These helper registers must never be spilled.
This fixes failures of the register allocator in rare corner cases.

Yuriy Sydorov 3 年之前
父节点
当前提交
b4df9dbe1d
共有 1 个文件被更改,包括 107 次插入54 次删除
  1. 107 54
      compiler/rgobj.pas

+ 107 - 54
compiler/rgobj.pas

@@ -95,7 +95,7 @@ unit rgobj;
       Treginfoflag=(
       Treginfoflag=(
         ri_coalesced,       { the register is coalesced with other register }
         ri_coalesced,       { the register is coalesced with other register }
         ri_selected,        { the register is put to selectstack }
         ri_selected,        { the register is put to selectstack }
-        ri_spill_read,      { the register contains a value loaded from a spilled register }
+        ri_spill_helper,    { the register contains a value of a previously spilled register }
         ri_has_initial_loc  { the register has the initial memory location (e.g. a parameter in the stack) }
         ri_has_initial_loc  { the register has the initial memory location (e.g. a parameter in the stack) }
       );
       );
       Treginfoflagset=set of Treginfoflag;
       Treginfoflagset=set of Treginfoflag;
@@ -1621,9 +1621,9 @@ unit rgobj;
         to get too much conflicts with the result that the spilling code
         to get too much conflicts with the result that the spilling code
         will never converge (PFV)
         will never converge (PFV)
 
 
-        We need a special processing for nodes with the ri_spill_read flag set. 
-        These nodes contain a value loaded from a previously spilled node. 
-        We need to avoid another spilling of ri_spill_read nodes, since it will 
+        We need a special processing for nodes with the ri_spill_helper flag set. 
+        These nodes contain a value of a previously spilled node.
+        We need to avoid another spilling of ri_spill_helper nodes, since it will 
         likely lead to an endless loop and the register allocation will fail.
         likely lead to an endless loop and the register allocation will fail.
       }
       }
       maxlength:=0;
       maxlength:=0;
@@ -1632,9 +1632,9 @@ unit rgobj;
       with spillworklist do
       with spillworklist do
         begin
         begin
           {Safe: This procedure is only called if length<>0}
           {Safe: This procedure is only called if length<>0}
-          { Search for a candidate to be spilled, ignoring nodes with the ri_spill_read flag set. }
+          { Search for a candidate to be spilled, ignoring nodes with the ri_spill_helper flag set. }
           for i:=0 to length-1 do
           for i:=0 to length-1 do
-            if not(ri_spill_read in reginfo[buf^[i]].flags) then
+            if not(ri_spill_helper in reginfo[buf^[i]].flags) then
               begin
               begin
                 adj:=reginfo[buf^[i]].adjlist;
                 adj:=reginfo[buf^[i]].adjlist;
                 if assigned(adj) and
                 if assigned(adj) and
@@ -1651,10 +1651,10 @@ unit rgobj;
 
 
           if p=high(p) then
           if p=high(p) then
             begin
             begin
-              { If no normal nodes found, then only ri_spill_read nodes are present
+              { If no normal nodes found, then only ri_spill_helper nodes are present
                 in the list. Finding the node with the least interferences and
                 in the list. Finding the node with the least interferences and
                 the least weight.
                 the least weight.
-                This allows us to put the most restricted ri_spill_read nodes
+                This allows us to put the most restricted ri_spill_helper nodes
                 to the top of selectstack so they will be the first to get
                 to the top of selectstack so they will be the first to get
                 a color assigned.
                 a color assigned.
               }
               }
@@ -1688,63 +1688,115 @@ unit rgobj;
 
 
     {Assign_colours assigns the actual colours to the registers.}
     {Assign_colours assigns the actual colours to the registers.}
 
 
-    var adj : Psuperregisterworklist;
-        i,j,k : cardinal;
-        n,a,c : Tsuperregister;
-        colourednodes : Tsuperregisterset;
+    var
+      colourednodes : Tsuperregisterset;
+
+      procedure reset_colours;
+        var
+          n : Tsuperregister;
+        begin
+          spillednodes.clear;
+          {Reset colours}
+          for n:=0 to maxreg-1 do
+            reginfo[n].colour:=n;
+          {Colour the cpu registers...}
+          supregset_reset(colourednodes,false,maxreg);
+          for n:=0 to first_imaginary-1 do
+            supregset_include(colourednodes,n);
+        end;
+
+    function colour_regitser(n : Tsuperregister) : boolean;
+      var
+        j,k : cardinal;
+        adj : Psuperregisterworklist;
         adj_colours:set of 0..255;
         adj_colours:set of 0..255;
-        found : boolean;
+        a,c : Tsuperregister;
 {$if declared(RS_STACK_POINTER_REG) and (RS_STACK_POINTER_REG<>RS_INVALID)}
 {$if declared(RS_STACK_POINTER_REG) and (RS_STACK_POINTER_REG<>RS_INVALID)}
         tmpr: tregister;
         tmpr: tregister;
 {$endif}
 {$endif}
+      begin
+        {Create a list of colours that we cannot assign to n.}
+        adj_colours:=[];
+        adj:=reginfo[n].adjlist;
+        if adj<>nil then
+          for j:=0 to adj^.length-1 do
+            begin
+              a:=get_alias(adj^.buf^[j]);
+              if supregset_in(colourednodes,a) and (reginfo[a].colour<=255) then
+                include(adj_colours,reginfo[a].colour);
+            end;
+        { e.g. AVR does not have a stack pointer register }
+{$if declared(RS_STACK_POINTER_REG) and (RS_STACK_POINTER_REG<>RS_INVALID)}
+        { FIXME: temp variable r is needed here to avoid Internal error 20060521 }
+        {        while compiling the compiler. }
+        tmpr:=NR_STACK_POINTER_REG;
+        if (regtype=getregtype(tmpr)) then
+          include(adj_colours,RS_STACK_POINTER_REG);
+{$ifend}
+        {Assume a spill by default...}
+        result:=false;
+        {Search for a colour not in this list.}
+        for k:=0 to usable_registers_cnt-1 do
+          begin
+            c:=usable_registers[k];
+            if not(c in adj_colours) then
+              begin
+                reginfo[n].colour:=c;
+                result:=true;
+                supregset_include(colourednodes,n);
+                break;
+              end;
+          end;
+        if not result then
+          spillednodes.add(n);
+      end;
+
+    var
+        i,k : cardinal;
+        n : Tsuperregister;
+        spill_loop : boolean;
     begin
     begin
-      spillednodes.clear;
-      {Reset colours}
-      for n:=0 to maxreg-1 do
-        reginfo[n].colour:=n;
-      {Colour the cpu registers...}
-      supregset_reset(colourednodes,false,maxreg);
-      for n:=0 to first_imaginary-1 do
-        supregset_include(colourednodes,n);
+      reset_colours;
       {Now colour the imaginary registers on the select-stack.}
       {Now colour the imaginary registers on the select-stack.}
+      spill_loop:=false;
       for i:=selectstack.length downto 1 do
       for i:=selectstack.length downto 1 do
         begin
         begin
           n:=selectstack.buf^[i-1];
           n:=selectstack.buf^[i-1];
-          {Create a list of colours that we cannot assign to n.}
-          adj_colours:=[];
-          adj:=reginfo[n].adjlist;
-          if adj<>nil then
-            for j:=0 to adj^.length-1 do
-              begin
-                a:=get_alias(adj^.buf^[j]);
-                if supregset_in(colourednodes,a) and (reginfo[a].colour<=255) then
-                  include(adj_colours,reginfo[a].colour);
-              end;
-          { e.g. AVR does not have a stack pointer register }
-{$if declared(RS_STACK_POINTER_REG) and (RS_STACK_POINTER_REG<>RS_INVALID)}
-          { FIXME: temp variable r is needed here to avoid Internal error 20060521 }
-          {        while compiling the compiler. }
-          tmpr:=NR_STACK_POINTER_REG;
-          if (regtype=getregtype(tmpr)) then
-            include(adj_colours,RS_STACK_POINTER_REG);
-{$ifend}
-          {Assume a spill by default...}
-          found:=false;
-          {Search for a colour not in this list.}
-          for k:=0 to usable_registers_cnt-1 do
+          if not colour_regitser(n) and
+            (ri_spill_helper in reginfo[n].flags) then
             begin
             begin
-              c:=usable_registers[k];
-               if not(c in adj_colours) then
-                 begin
-                   reginfo[n].colour:=c;
-                   found:=true;
-                   supregset_include(colourednodes,n);
-                   break;
-                 end;
+              { Register n is a helper register which holds the value
+                of a previously spilled register. Register n must never
+                be spilled. Report the spilling loop and break. }
+              spill_loop:=true;
+              break;
             end;
             end;
-          if not found then
-            spillednodes.add(n);
         end;
         end;
+
+      if spill_loop then
+        begin
+          { Spilling loop is detected when colouring registers using the select-stack order.
+            Trying to eliminte this by using a different colouring order. }
+          reset_colours;
+          { To prevent spilling of helper registers it is needed to assign colours to them first. }
+          for i:=selectstack.length downto 1 do
+            begin
+              n:=selectstack.buf^[i-1];
+              if ri_spill_helper in reginfo[n].flags then
+                if not colour_regitser(n) then
+                  { Can't colour the spill helper register n.
+                    This can happen only when the code generator produces invalid code. }
+                  internalerror(2021091001);
+            end;
+          { Assign colours for the rest of the registers }
+          for i:=selectstack.length downto 1 do
+            begin
+              n:=selectstack.buf^[i-1];
+              if not (ri_spill_helper in reginfo[n].flags) then
+                colour_regitser(n);
+            end;
+        end;
+
       {Finally colour the nodes that were coalesced.}
       {Finally colour the nodes that were coalesced.}
       for i:=1 to coalescednodes.length do
       for i:=1 to coalescednodes.length do
         begin
         begin
@@ -2833,7 +2885,7 @@ unit rgobj;
                 begin
                 begin
                   loadreg:=getregisterinline(list,regs.reginfo[counter].spillregconstraints);
                   loadreg:=getregisterinline(list,regs.reginfo[counter].spillregconstraints);
                   do_spill_read(list,tai(loadpos.previous),spilltemplist[orgreg],loadreg,orgreg);
                   do_spill_read(list,tai(loadpos.previous),spilltemplist[orgreg],loadreg,orgreg);
-                  include(reginfo[getsupreg(loadreg)].flags,ri_spill_read);
+                  include(reginfo[getsupreg(loadreg)].flags,ri_spill_helper);
                 end;
                 end;
             end;
             end;
 
 
@@ -2871,6 +2923,7 @@ unit rgobj;
                      ssa_safe then
                      ssa_safe then
                     begin
                     begin
                       storereg:=getregisterinline(list,regs.reginfo[counter].spillregconstraints);
                       storereg:=getregisterinline(list,regs.reginfo[counter].spillregconstraints);
+                      include(reginfo[getsupreg(storereg)].flags,ri_spill_helper);
                       { we also use loadreg for store replacements in case we
                       { we also use loadreg for store replacements in case we
                         don't have ensure ssa -> initialise loadreg even if
                         don't have ensure ssa -> initialise loadreg even if
                         there are no reads }
                         there are no reads }