Browse Source

* normalize tree: - do not allow statements in expressions

Florian Klämpfl 12 years ago
parent
commit
ba74d7d3f8
4 changed files with 241 additions and 9 deletions
  1. 3 1
      compiler/globtype.pas
  2. 227 0
      compiler/opttree.pas
  3. 8 6
      compiler/psub.pas
  4. 3 2
      compiler/utils/ppuutils/ppudump.pp

+ 3 - 1
compiler/globtype.pas

@@ -834,7 +834,9 @@ interface
          { x86 only: subroutine uses ymm registers, requires vzeroupper call }
          pi_uses_ymm,
          { set if no frame pointer is needed, the rules when this applies is target specific }
-         pi_no_framepointer_needed
+         pi_no_framepointer_needed,
+         { procedure has been normalized so no expressions contain block nodes }
+         pi_normalized
        );
        tprocinfoflags=set of tprocinfoflag;
 

+ 227 - 0
compiler/opttree.pas

@@ -0,0 +1,227 @@
+{
+    General tree transformations
+
+    Copyright (c) 2013 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.
+
+ ****************************************************************************
+}
+
+{$define DEBUG_NORMALIZE}
+
+{ this unit implements routines to perform all-purpose tree transformations }
+unit opttree;
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+      node,optutils;
+
+    { tries to bring the tree in a normalized form:
+       - expressions are free of control statements
+       - callinitblock/callcleanupblocks are converted into statements
+
+      rationale is that this simplifies data flow analysis
+
+      returns true, if this was successful
+    }
+    function normalize(var n : tnode) : Boolean;
+
+  implementation
+
+    uses
+      verbose,
+      globtype,
+      defutil,
+      nbas,nld,ncal,
+      nutils,
+      pass_1;
+
+    function searchstatements(var n : tnode;arg : pointer) : foreachnoderesult;forward;
+
+    function hasblock(var n : tnode;arg : pointer) : foreachnoderesult;
+      begin
+        result:=fen_false;
+        if n.nodetype=blockn then
+          result:=fen_norecurse_true;
+      end;
+
+    function searchblock(var n : tnode;arg : pointer) : foreachnoderesult;
+      var
+        hp,
+        statements,
+        stmnt : tstatementnode;
+        res : pnode;
+        tempcreatenode : ttempcreatenode;
+        newblock : tnode;
+      begin
+        result:=fen_true;
+        if n.nodetype in [addn,orn] then
+          begin
+            { so far we cannot fiddle with short boolean evaluations containing blocks }
+            if doshortbooleval(n) and foreachnodestatic(n,@hasblock,nil) then
+              begin
+                result:=fen_norecurse_false;
+                exit;
+              end;
+          end;
+        case n.nodetype of
+          calln:
+            begin
+              if assigned(tcallnode(n).callinitblock) then
+                begin
+                  { create a new statement node and insert it }
+                  hp:=cstatementnode.create(tcallnode(n).callinitblock,pnode(arg)^);
+                  pnode(arg)^:=hp;
+                  { tree moved }
+                  tcallnode(n).callinitblock:=nil;
+                  { process the newly generated block }
+                  foreachnodestatic(pnode(arg)^,@searchstatements,nil);
+                end;
+              if assigned(tcallnode(n).callcleanupblock) then
+                begin
+                  { create a new statement node and append it }
+                  hp:=cstatementnode.create(tcallnode(n).callcleanupblock,tstatementnode(pnode(arg)^).right);
+                  tstatementnode(pnode(arg)^).right:=hp;
+                  { tree moved }
+                  tcallnode(n).callcleanupblock:=nil;
+                  { process the newly generated block }
+                  foreachnodestatic(tstatementnode(pnode(arg)^).right,@searchstatements,nil);
+                end;
+            end;
+          blockn:
+            begin
+              if assigned(tblocknode(n).left) and (tblocknode(n).left.nodetype<>statementn) then
+                internalerror(2013120502);
+
+              stmnt:=tstatementnode(tblocknode(n).left);
+              { search for the result of the block node }
+              if assigned(stmnt) then
+                begin
+                  res:=nil;
+                  hp:=tstatementnode(stmnt);
+                  while assigned(hp) do
+                    begin
+                      if assigned(hp.left) then
+                        res:[email protected];
+                      hp:=tstatementnode(hp.right);
+                    end;
+                  { did we find a last node? }
+                  if assigned(res^) then
+                    begin
+                      case res^.nodetype of
+                        ordconstn,
+                        realconstn,
+                        stringconstn,
+                        pointerconstn,
+                        setconstn,
+                        temprefn:
+                          begin
+                            { create a new statement node and insert it }
+                            hp:=cstatementnode.create(n,pnode(arg)^);
+                            pnode(arg)^:=hp;
+                            { use the result node instead of the block node }
+                            n:=res^;
+                            { the old statement is not used anymore }
+                            res^:=cnothingnode.create;
+                            { process the newly generated statement }
+                            foreachnodestatic(pnode(arg)^,@searchstatements,nil);
+                          end
+                        else if assigned(res^.resultdef) and not(is_void(res^.resultdef)) then
+                          begin
+                            { replace the last node of the block by an assignment to a temp, and move the block out
+                              of the expression }
+                            newblock:=internalstatements(statements);
+                            tempcreatenode:=ctempcreatenode.create(res^.resultdef,res^.resultdef.size,tt_persistent,true);
+                            addstatement(statements,tempcreatenode);
+                            addstatement(statements,n);
+
+                            { replace the old result node of the block by an assignement to the newly generated temp }
+                            res^:=cassignmentnode.create_internal(ctemprefnode.create(tempcreatenode),res^);
+                            do_firstpass(res^);
+                            addstatement(statements,ctempdeletenode.create_normal_temp(tempcreatenode));
+                            addstatement(statements,pnode(arg)^);
+
+                            { use the temp. ref instead of the block node }
+                            n:=ctemprefnode.create(tempcreatenode);
+                            { replace the statement with the block }
+                            pnode(arg)^:=newblock;
+                            { first pass the newly generated block }
+                            do_firstpass(newblock);
+                            { ... and the inserted temp. }
+                            do_firstpass(n);
+                            { process the newly generated block }
+                            foreachnodestatic(pnode(arg)^,@searchstatements,nil);
+                          end;
+                      end;
+                    end;
+                end;
+            end;
+          else
+            ;
+        end;
+      end;
+
+    var
+      searchstatementsproc : staticforeachnodefunction;
+
+    function searchstatements(var n : tnode;arg : pointer) : foreachnoderesult;
+      begin
+        if n.nodetype=statementn then
+          begin
+            if not(foreachnodestatic(tstatementnode(n).left,@searchblock,@n)) then
+              begin
+                pboolean(arg)^:=false;
+                result:=fen_norecurse_false;
+                exit;
+              end;
+            { do not recurse automatically, but continue with the next statement }
+            result:=fen_norecurse_false;
+            foreachnodestatic(tstatementnode(n).right,searchstatementsproc,arg);
+          end
+        else
+          result:=fen_false;
+      end;
+
+
+    function normalize(var n: tnode) : Boolean;
+      var
+        success : Boolean;
+      begin
+        success:=true;
+{$ifdef DEBUG_NORMALIZE}
+        writeln('******************************************** Before ********************************************');
+        printnode(n);
+{$endif DEBUG_NORMALIZE}
+        searchstatementsproc:=@searchstatements;
+        foreachnodestatic(n,@searchstatements,@success);
+{$ifdef DEBUG_NORMALIZE}
+        if success then
+          begin
+            writeln('******************************************** After ********************************************');
+            printnode(n);
+          end
+        else
+          writeln('************************* Normalization not possible ********************************');
+{$endif DEBUG_NORMALIZE}
+        Result:=success;
+      end;
+
+
+end.
+

+ 8 - 6
compiler/psub.pas

@@ -156,6 +156,7 @@ implementation
        ncgutil,
 
        optbase,
+       opttree,
        opttail,
        optcse,
        optloop,
@@ -1262,15 +1263,16 @@ implementation
 
            if cs_opt_dead_store_eliminate in current_settings.optimizerswitches then
              begin
-               do_optdeadstoreelim(code,RedoDFA);
-               if RedoDFA then
-                 dfabuilder.redodfainfo(code);
+               if normalize(code) then
+                 begin
+                   do_optdeadstoreelim(code,RedoDFA);
+                   if RedoDFA then
+                     dfabuilder.redodfainfo(code);
+                 end;
              end;
          end
        else
-         begin
-           ConvertForLoops(code);
-         end;
+         ConvertForLoops(code);
 
        if (cs_opt_remove_empty_proc in current_settings.optimizerswitches) and
          (procdef.proctypeoption in [potype_operator,potype_procedure,potype_function]) and

+ 3 - 2
compiler/utils/ppuutils/ppudump.pp

@@ -1707,8 +1707,9 @@ const
          (mask:pi_uses_ymm;
          str:' uses ymm register (x86 only)'),
          (mask:pi_no_framepointer_needed;
-         str:' set if no frame pointer is needed, the rules when this applies is target specific'
-         )
+         str:' set if no frame pointer is needed, the rules when this applies is target specific'), 
+         (mask:pi_normalized;
+         str:'  has been normalized so no expressions contain block nodes ')
   );
 var
   procinfooptions : tprocinfoflags;