Browse Source

+ framework for strength reduction of induction variables
+ constant multiplications can be eliminated testwise

git-svn-id: trunk@11803 -

florian 17 năm trước cách đây
mục cha
commit
ecd05a1043
3 tập tin đã thay đổi với 183 bổ sung14 xóa
  1. 2 2
      compiler/globtype.pas
  2. 21 9
      compiler/nflw.pas
  3. 160 3
      compiler/optloop.pas

+ 2 - 2
compiler/globtype.pas

@@ -183,7 +183,7 @@ interface
          cs_opt_level1,cs_opt_level2,cs_opt_level3,
          cs_opt_regvar,cs_opt_uncertain,cs_opt_size,cs_opt_stackframe,
          cs_opt_peephole,cs_opt_asmcse,cs_opt_loopunroll,cs_opt_tailrecursion,cs_opt_nodecse,
-         cs_opt_nodedfa
+         cs_opt_nodedfa,cs_opt_loopstrength
        );
        toptimizerswitches = set of toptimizerswitch;
 
@@ -191,7 +191,7 @@ interface
        OptimizerSwitchStr : array[toptimizerswitch] of string[10] = ('',
          'LEVEL1','LEVEL2','LEVEL3',
          'REGVAR','UNCERTAIN','SIZE','STACKFRAME',
-         'PEEPHOLE','ASMCSE','LOOPUNROLL','TAILREC','CSE','DFA'
+         'PEEPHOLE','ASMCSE','LOOPUNROLL','TAILREC','CSE','DFA','STRENGTH'
        );
 
        DebugSwitchStr : array[tdebugswitch] of string[9] = ('',

+ 21 - 9
compiler/nflw.pas

@@ -781,27 +781,39 @@ implementation
 
     function tfornode.pass_typecheck:tnode;
       var
-        unrollres : tnode;
+        res : tnode;
       begin
          result:=nil;
          resultdef:=voidtype;
 
+         { process the loopvar, from and to, varstates are already set }
+         typecheckpass(left);
+         typecheckpass(right);
+         typecheckpass(t1);
+
          { loop unrolling }
          if cs_opt_loopunroll in current_settings.optimizerswitches then
            begin
-             unrollres:=unroll_loop(self);
-             if assigned(unrollres) then
+             res:=unroll_loop(self);
+             if assigned(res) then
                begin
-                 typecheckpass(unrollres);
-                 result:=unrollres;
+                 typecheckpass(res);
+                 result:=res;
                  exit;
                end;
            end;
 
-         { process the loopvar, from and to, varstates are already set }
-         typecheckpass(left);
-         typecheckpass(right);
-         typecheckpass(t1);
+         { loop invariant/strength reduction }
+         if cs_opt_loopstrength in current_settings.optimizerswitches then
+           begin
+             res:=optimize_induction_variables(self);
+             if assigned(res) then
+               begin
+                 typecheckpass(res);
+                 result:=res;
+                 exit;
+               end;
+           end;
 
          {Can we spare the first comparision?}
          if (t1.nodetype=ordconstn) and

+ 160 - 3
compiler/optloop.pas

@@ -1,5 +1,5 @@
 {
-    Loop unrolling
+    Loop optimization
 
     Copyright (c) 2005 by Florian Klaempfl
 
@@ -29,15 +29,17 @@ unit optloop;
       node;
 
     function unroll_loop(node : tnode) : tnode;
+    function optimize_induction_variables(node : tnode) : tnode;
 
   implementation
 
     uses
+      cclasses,
       globtype,globals,constexp,
-      symsym,
+      symdef,symsym,
       cpuinfo,
       nutils,
-      nbas,nflw,ncon,ninl,ncal,nld;
+      nadd,nbas,nflw,ncon,ninl,ncal,nld;
 
     var
       nodecount : aword;
@@ -174,4 +176,159 @@ unit optloop;
           end;
       end;
 
+    var
+      initcode,
+      calccode,
+      deletecode : tblocknode;
+      initcodestatements,
+      calccodestatements,
+      deletecodestatements: tstatementnode;
+      templist : tfplist;
+      inductionexprs : tfplist;
+
+    function is_loop_invariant(loop : tnode;expr : tnode) : boolean;
+      begin
+        result:=is_constnode(expr);
+      end;
+
+
+    { checks if the strength of n can be recuded, arg is the tforloop being considered }
+    function dostrengthreductiontest(var n: tnode; arg: pointer): foreachnoderesult;
+
+      function findpreviousstrengthreduction : boolean;
+        var
+          i : longint;
+        begin
+          result:=false;
+          for i:=0 to inductionexprs.count-1 do
+            begin
+              { do we already maintain one expression? }
+              if tnode(inductionexprs[i]).isequal(n) then
+                begin
+                  n.free;
+                  n:=ttemprefnode.create(ttempcreatenode(templist[i]));
+                  result:=true;
+                  exit;
+                end;
+            end;
+        end;
+
+
+      procedure CreateNodes;
+        begin
+          if not assigned(initcode) then
+            begin
+              initcode:=internalstatements(initcodestatements);
+              calccode:=internalstatements(calccodestatements);
+              deletecode:=internalstatements(deletecodestatements);
+            end;
+        end;
+
+      var
+        tempnode : ttempcreatenode;
+      begin
+        result:=fen_false;
+        case n.nodetype of
+          muln:
+            begin
+              if (taddnode(n).left.nodetype=loadn) and
+                taddnode(n).left.isequal(tfornode(arg).left) and
+                { plain read of the loop variable? }
+                not(nf_write in taddnode(n).left.flags) and
+                not(nf_modify in taddnode(n).left.flags) and
+                is_loop_invariant(tfornode(arg),taddnode(n).right) and
+                { for now, we can handle only constant lower borders }
+                is_constnode(tfornode(arg).right) then
+                begin
+                  { did we use the same expression before already? }
+                  if not(findpreviousstrengthreduction) then
+                    begin
+                      tempnode:=ctempcreatenode.create(n.resultdef,n.resultdef.size,tt_persistent,
+                        tstoreddef(n.resultdef).is_intregable or tstoreddef(n.resultdef).is_fpuregable);
+
+                      templist.Add(tempnode);
+                      inductionexprs.Add(n);
+                      CreateNodes;
+
+                      if lnf_backward in tfornode(arg).loopflags then
+                        addstatement(calccodestatements,
+                          geninlinenode(in_dec_x,false,
+                          ccallparanode.create(ctemprefnode.create(tempnode),ccallparanode.create(taddnode(n).right.getcopy,nil))))
+                      else
+                        addstatement(calccodestatements,
+                          geninlinenode(in_inc_x,false,
+                          ccallparanode.create(ctemprefnode.create(tempnode),ccallparanode.create(taddnode(n).right.getcopy,nil))));
+                      addstatement(initcodestatements,tempnode);
+                      addstatement(initcodestatements,cassignmentnode.create(ctemprefnode.create(tempnode),
+                        caddnode.create(muln,
+                          caddnode.create(subn,tfornode(arg).right.getcopy,cordconstnode.create(1,tfornode(arg).right.resultdef,false)),
+                          taddnode(n).right.getcopy)
+                        )
+                      );
+
+                      { finally replace the node by a temp. ref }
+                      n:=ctemprefnode.create(tempnode);
+
+                      { ... and add a temp. release node }
+                      addstatement(deletecodestatements,ctempdeletenode.create(tempnode));
+                    end;
+                  result:=fen_norecurse_false;
+                end;
+            end;
+        end;
+      end;
+
+
+    function optimize_induction_variables(node : tnode) : tnode;
+      var
+        loopcode,
+        newcode : tblocknode;
+        loopcodestatements,
+        newcodestatements : tstatementnode;
+        fornode : tfornode;
+      begin
+        if node.nodetype<>forn then
+          exit;
+        templist:=TFPList.Create;
+        inductionexprs:=TFPList.Create;
+        result:=nil;
+        initcode:=nil;
+        calccode:=nil;
+        deletecode:=nil;
+        initcodestatements:=nil;
+        calccodestatements:=nil;
+        deletecodestatements:=nil;
+        { find all expressions being candidates for strength reduction
+          and replace them }
+        foreachnodestatic(pm_postprocess,node,@dostrengthreductiontest,node);
+
+        { clue everything together }
+        if assigned(initcode) then
+          begin
+            { create a new for node, the old one will be released by the compiler }
+            with tfornode(node) do
+              begin
+                fornode:=cfornode.create(left,right,t1,t2,lnf_backward in loopflags);
+                left:=nil;
+                right:=nil;
+                t1:=nil;
+                t2:=nil;
+              end;
+            node:=fornode;
+
+            loopcode:=internalstatements(loopcodestatements);
+            addstatement(loopcodestatements,calccode);
+            addstatement(loopcodestatements,tfornode(node).t2);
+            tfornode(node).t2:=loopcode;
+
+            result:=internalstatements(newcodestatements);
+            addstatement(newcodestatements,initcode);
+            addstatement(newcodestatements,node);
+            addstatement(newcodestatements,deletecode);
+            printnode(output,result);
+          end;
+        templist.Free;
+        inductionexprs.Free;
+      end;
+
 end.