Browse Source

* fixed some small problems in loop unrolling

git-svn-id: trunk@447 -
florian 20 years ago
parent
commit
b7d874635c
4 changed files with 84 additions and 7 deletions
  1. 7 2
      compiler/ncgflw.pas
  2. 23 0
      compiler/optcse.pas
  3. 51 4
      compiler/optunrol.pas
  4. 3 1
      tests/test/tunroll1.pp

+ 7 - 2
compiler/ncgflw.pas

@@ -354,8 +354,13 @@ implementation
          count_var_is_signed:=is_signed(left.resulttype.def);
 
          { first set the to value
-           because the count var can be in the expression !! }
-         do_loopvar_at_end:=lnf_dont_mind_loopvar_on_exit in loopflags;
+           because the count var can be in the expression ! }
+         do_loopvar_at_end:=(lnf_dont_mind_loopvar_on_exit in loopflags)
+         { if the loop is unrolled and there is a jump into the loop,
+           then we can't do the trick with incrementing the loop var only at the
+           end
+         }
+           and not(assigned(entrylabel));
 
          secondpass(t1);
          { calculate pointer value and check if changeable and if so }

+ 23 - 0
compiler/optcse.pas

@@ -1,5 +1,28 @@
+{
+    Common subexpression elimination on base blocks
+
+    Copyright (c) 2005 by Florian Klaempfl
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
 unit optcse;
 
+{$i fpcdefs.inc}
+
   interface
 
     procedure docse(rootnode : tnode);

+ 51 - 4
compiler/optunrol.pas

@@ -1,3 +1,24 @@
+{
+    Loop unrolling
+
+    Copyright (c) 2005 by Florian Klaempfl
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
 unit optunrol;
 
 {$i fpcdefs.inc}
@@ -85,15 +106,16 @@ unit optunrol;
                 { let's unroll (and rock of course) }
                 for i:=1 to unrolls do
                   begin
+                    { create and insert copy of the statement block }
+                    addstatement(unrollstatement,tfornode(tfornode(node).t2).getcopy);
+
                     { set and insert entry label? }
                     if (counts mod unrolls<>0) and
-                      ((counts mod unrolls)=unrolls-i+1) then
+                      ((counts mod unrolls)=unrolls-i) then
                       begin
                         tfornode(node).entrylabel:=clabelnode.create(cnothingnode.create);
                         addstatement(unrollstatement,tfornode(node).entrylabel);
                       end;
-                    { create and insert copy of the statement block }
-                    addstatement(unrollstatement,tfornode(tfornode(node).t2).getcopy);
 
                     { for itself increases at the last iteration }
                     if i<unrolls then
@@ -109,7 +131,32 @@ unit optunrol;
               end
             else
               begin
-                { for now, we can't handle this }
+                { unrolling is a little bit more tricky if we don't know the
+                  loop count at compile time, but the solution is to use a jump table
+                  which is indexed by "loop count mod unrolls" at run time and which
+                  jumps then at the appropriate place inside the loop. Because
+                  a module division is expensive, we can use only unroll counts dividable
+                  by 2 }
+                case unrolls of
+                  1..2:
+                    ;
+                  3:
+                    unrolls:=2;
+                  4..7:
+                    unrolls:=4;
+                  { unrolls>4 already make no sense imo, but who knows (FK) }
+                  8..15:
+                    unrolls:=8;
+                  16..31:
+                    unrolls:=16;
+                  32..63:
+                    unrolls:=32;
+                  64..$7fff:
+                    unrolls:=64;
+                  else
+                    exit;
+                end;
+                { we don't handle this yet }
                 exit;
               end;
             if not(assigned(result)) then

+ 3 - 1
tests/test/tunroll1.pp

@@ -5,11 +5,13 @@ var
 
 begin
   s:=0.0;
+  for i:=1 to 2 do
+    s:=s+1;
   for i:=1 to 10 do
     s:=s+1;
   for i:=1 to 11 do
     s:=s+1;
-  if s<>21 then
+  if s<>23 then
     halt(1);
   writeln('ok');
 end.