| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346 | {    Constant propagation across statements    Copyright (c) 2005-2012 by Jeppe Johansen and 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 optconstprop;{$i fpcdefs.inc}{ $define DEBUG_CONSTPROP}  interface    uses      node;    { does constant propagation for rootnode      The approach is simple: It search for constant assignment statements. As soon as such      a statement is found, the following statements are search if they contain      a usage of the assigned variable. If this is a the case, the variable is      replaced by the constant. This does not work across points where the      program flow joins so e.g.      if ... then        ...        a:=1;        ...      else        ...        a:=1;        ...      writeln(a);      will not result in any constant propagation.    }    function do_optconstpropagate(var rootnode : tnode) : tnode;  implementation    uses      fmodule,      pass_1,procinfo,      symsym, symconst,      nutils, nbas, ncnv, nld, nflw, ncal;    function check_written(var n: tnode; arg: pointer): foreachnoderesult;      begin        result:=fen_false;        if n.isequal(tnode(arg)) and           ((n.flags*[nf_write,nf_modify])<>[]) then          begin            result:=fen_norecurse_true;          end;      end;    { propagates the constant assignment passed in arg into n }    function replaceBasicAssign(var n: tnode; arg: tnode; var tree_modified: boolean): boolean;      var        st2, oldnode: tnode;        old: pnode;        changed, tree_modified2,tree_modified3: boolean;        written : Boolean;      begin        result:=true;        if n = nil then          exit;        tree_modified:=false;        tree_modified2:=false;        tree_modified3:=false;        { while it might be usefull, to use foreach to iterate all nodes, it is safer to          iterate manually here so we have full controll how all nodes are processed }        { We cannot analyze beyond those nodes, so we terminate to be on the safe side }        if (n.nodetype in [addrn,derefn,dataconstn,asmn,withn,casen,whilerepeatn,labeln,continuen,breakn,                           tryexceptn,raisen,tryfinallyn,onn,loadparentfpn,loadvmtaddrn,guidconstn,rttin,addoptn,asn,goton,                           objcselectorn,objcprotocoln]) then          exit(false)        else if n.nodetype=assignn then          begin            tree_modified:=false;            { we can propage the constant in both branches because the evaluation order is not defined }            result:=replaceBasicAssign(tassignmentnode(n).right, arg, tree_modified);            { do not use the intuitive way result:=result and replace... because this would prevent              replaceBasicAssign being called if the result is already false }            result:=replaceBasicAssign(tassignmentnode(n).left, arg, tree_modified2) and result;            tree_modified:=tree_modified or tree_modified2;            { but we have to check if left writes to the currently searched variable ... }            written:=foreachnodestatic(pm_postprocess, tassignmentnode(n).left, @check_written, tassignmentnode(arg).left);            { ... if this is the case, we have to stop searching }            result:=result and not(written);          end        else if n.isequal(tassignmentnode(arg).left) and ((n.flags*[nf_write,nf_modify])=[]) then          begin            n.Free;            n:=tassignmentnode(arg).right.getcopy;            inserttypeconv_internal(n, tassignmentnode(arg).left.resultdef);            tree_modified:=true;          end        else if n.nodetype=statementn then          result:=replaceBasicAssign(tstatementnode(n).left, arg, tree_modified)        else if n.nodetype=forn then          begin            result:=replaceBasicAssign(tfornode(n).right, arg, tree_modified);            if result then              replaceBasicAssign(tfornode(n).t1, arg, tree_modified2);            tree_modified:=tree_modified or tree_modified2;            { after a for node we cannot continue with our simple approach }            result:=false;          end        else if n.nodetype=blockn then          begin            changed:=false;            st2:=tstatementnode(tblocknode(n).statements);            old:=@tblocknode(n).statements;            while assigned(st2) do              begin                repeat                  oldnode:=st2;                  tree_modified2:=false;                  if not replaceBasicAssign(st2, arg, tree_modified2) then                    begin                      old^:=st2;                      oldnode:=nil;                      changed:=changed or tree_modified2;                      result:=false;                      break;                    end                  else                    old^:=st2;                  changed:=changed or tree_modified2;                until oldnode=st2;                if oldnode = nil then                  break;                old:=@tstatementnode(st2).next;                st2:=tstatementnode(st2).next;              end;            tree_modified:=changed;          end        else if n.nodetype=ifn then          begin            result:=replaceBasicAssign(tifnode(n).left, arg, tree_modified);            if result then              begin                if assigned(tifnode(n).t1) then                  begin                    { we can propagate the constant in both branches of an if statement                      because even if the the branch writes to it, the else branch gets the                      unmodified value }                    result:=replaceBasicAssign(tifnode(n).right, arg, tree_modified2);                    { do not use the intuitive way result:=result and replace... because this would prevent                      replaceBasicAssign being called if the result is already false }                    result:=replaceBasicAssign(tifnode(n).t1, arg, tree_modified3) and result;                    tree_modified:=tree_modified or tree_modified2 or tree_modified3;                  end                else                  begin                    result:=replaceBasicAssign(tifnode(n).right, arg, tree_modified2);                    tree_modified:=tree_modified or tree_modified2;                  end;              end;          end        else if n.nodetype in [calln,inlinen] then          begin            if might_have_sideeffects(n) and (n.nodetype=inlinen) then              exit(false);            if n.nodetype=calln then              exit(false);            replaceBasicAssign(tunarynode(n).left, arg, tree_modified);            result:=false;          end        else if n.InheritsFrom(tbinarynode) then          begin            result:=replaceBasicAssign(tbinarynode(n).left, arg, tree_modified);            if result then              result:=replaceBasicAssign(tbinarynode(n).right, arg, tree_modified2);            tree_modified:=tree_modified or tree_modified2;          end        else if n.InheritsFrom(tunarynode) then          begin            result:=replaceBasicAssign(tunarynode(n).left, arg, tree_modified);          end;        if n.nodetype<>callparan then          begin            if tree_modified then              exclude(n.flags,nf_pass1_done);            do_firstpass(n);          end;      end;    function propagate(var n: tnode; arg: pointer): foreachnoderesult;      var        l,        st, st2, oldnode: tnode;        old: pnode;        a: tassignmentnode;        tree_mod, changed: boolean;      begin        result:=fen_true;        changed:=false;        PBoolean(arg)^:=false;        if not assigned(n) then          exit;        if n.nodetype in [calln] then          exit(fen_norecurse_true);        if n.nodetype=blockn then          begin            st:=tblocknode(n).statements;            while assigned(st) and                  (st.nodetype=statementn) and                  assigned(tstatementnode(st).statement) do              begin                if tstatementnode(st).statement.nodetype=assignn then                  begin                    a:=tassignmentnode(tstatementnode(st).statement);                    l:=a.left;                    if ((((l.nodetype=loadn) and                         { its address cannot have escaped the current routine }                         not(tabstractvarsym(tloadnode(l).symtableentry).addr_taken)) and                         ((                           (tloadnode(l).symtableentry.typ=localvarsym) and                           (tloadnode(l).symtable=current_procinfo.procdef.localst)                          ) or                          ((tloadnode(l).symtableentry.typ=paravarsym) and                           (tloadnode(l).symtable=current_procinfo.procdef.parast)                          ) or                          ((tloadnode(l).symtableentry.typ=staticvarsym) and                           (tloadnode(l).symtable.symtabletype=staticsymtable)                          )                         )) or                        (l.nodetype = temprefn)) and                       (is_constintnode(a.right) or                        is_constboolnode(a.right) or                        is_constcharnode(a.right) or                        is_constenumnode(a.right) or                        is_conststringnode(a.right)) then                      begin                        st2:=tstatementnode(tstatementnode(st).right);                        old:=@tstatementnode(st).right;                        while assigned(st2) do                          begin                            repeat                              oldnode:=st2;                              { Simple assignment of constant found }                              tree_mod:=false;                              if not replaceBasicAssign(st2, a, tree_mod) then                                begin                                  old^:=st2;                                  oldnode:=nil;                                  changed:=changed or tree_mod;                                  break;                                end                              else                                old^:=st2;                              changed:=changed or tree_mod;                            until oldnode=st2;                            if oldnode = nil then                              break;                            old:=@tstatementnode(st2).next;                            st2:=tstatementnode(st2).next;                          end;                      end;                  end;                st:=tstatementnode(st).next;              end;          end;        PBoolean(arg)^:=changed;      end;    function do_optconstpropagate(var rootnode: tnode): tnode;      var        changed: boolean;        runsimplify : Boolean;      begin{$ifdef DEBUG_CONSTPROP}        writeln('************************ before constant propagation ***************************');        printnode(rootnode);{$endif DEBUG_CONSTPROP}        runsimplify:=false;        repeat          changed:=false;          foreachnodestatic(pm_postandagain, rootnode, @propagate, @changed);          runsimplify:=runsimplify or changed;        until changed=false;        if runsimplify then          doinlinesimplify(rootnode);{$ifdef DEBUG_CONSTPROP}        writeln('************************ after constant propagation ***************************');        printnode(rootnode);        writeln('*******************************************************************************');{$endif DEBUG_CONSTPROP}        result:=rootnode;      end;end.
 |