From 02d0ac4c3ecd9196e7fb619c008f4bd4a905c1bd Mon Sep 17 00:00:00 2001
From: florian <florian@freepascal.org>
Date: Tue, 10 Oct 2006 20:29:48 +0000
Subject: [PATCH] + only procedures doing recursive calls are checked for tail
 recursivity + parameters are tested if they are usable with tail recursion
 removal

git-svn-id: trunk@4853 -
---
 compiler/globtype.pas |  4 +++-
 compiler/htypechk.pas |  9 +++++----
 compiler/ncal.pas     |  5 +++++
 compiler/node.pas     |  4 ++++
 compiler/opttail.pas  | 26 +++++++++++++++++++++++---
 compiler/psub.pas     |  5 +++--
 6 files changed, 43 insertions(+), 10 deletions(-)

diff --git a/compiler/globtype.pas b/compiler/globtype.pas
index a148eacff4..afad5a73ea 100644
--- a/compiler/globtype.pas
+++ b/compiler/globtype.pas
@@ -299,7 +299,9 @@ than 255 characters. That's why using Ansi Strings}
          { set if the procedure has to push parameters onto the stack }
          pi_has_stackparameter,
          { set if the procedure has at least one got }
-         pi_has_goto
+         pi_has_goto,
+         { calls itself recursive }
+         pi_is_recursive
        );
        tprocinfoflags=set of tprocinfoflag;
 
diff --git a/compiler/htypechk.pas b/compiler/htypechk.pas
index e9952b50b9..60abc3b20f 100644
--- a/compiler/htypechk.pas
+++ b/compiler/htypechk.pas
@@ -1255,11 +1255,12 @@ implementation
                        if (tabstractvarsym(tloadnode(hp).symtableentry).varspez=vs_const) then
                         begin
                           { allow p^:= constructions with p is const parameter }
-                          if gotderef or gotdynarray or (Valid_Const in opts) then
-                           result:=true
+                          if gotderef or gotdynarray or (Valid_Const in opts) or
+                            (nf_isinternal_ignoreconst in tloadnode(hp).flags) then
+                            result:=true
                           else
-                           if report_errors then
-                            CGMessagePos(tloadnode(hp).fileinfo,type_e_no_assign_to_const);
+                            if report_errors then
+                              CGMessagePos(tloadnode(hp).fileinfo,type_e_no_assign_to_const);
                           exit;
                         end;
                        result:=true;
diff --git a/compiler/ncal.pas b/compiler/ncal.pas
index ae15444706..7e4702d943 100644
--- a/compiler/ncal.pas
+++ b/compiler/ncal.pas
@@ -1766,6 +1766,11 @@ type
               end;
            end;
 
+          { recursive call? }
+          if assigned(current_procinfo) and
+             (procdefinition=current_procinfo.procdef) then
+            include(current_procinfo.flags,pi_is_recursive);
+
           { handle predefined procedures }
           is_const:=(po_internconst in procdefinition.procoptions) and
                     ((block_type in [bt_const,bt_type]) or
diff --git a/compiler/node.pas b/compiler/node.pas
index 4783bf806a..a6e558afba 100644
--- a/compiler/node.pas
+++ b/compiler/node.pas
@@ -216,6 +216,10 @@ interface
          nf_is_self,
          nf_load_self_pointer,
          nf_inherited,
+         { the loadnode is generated internally and a varspez=vs_const should be ignore,
+           this requires that the parameter is actually passed by value
+           Be really carefull when using this flag! }
+         nf_isinternal_ignoreconst,
 
          { taddnode }
          nf_is_currency,
diff --git a/compiler/opttail.pas b/compiler/opttail.pas
index 7f9de1bcf0..0ae5a7a061 100644
--- a/compiler/opttail.pas
+++ b/compiler/opttail.pas
@@ -34,13 +34,17 @@ unit opttail;
 
     uses
       globtype,
+      symconst,symsym,
       defcmp,
       nbas,nflw,ncal,nld,ncnv,
-      pass_1;
+      pass_1,
+      paramgr;
 
     procedure do_opttail(var n : tnode;p : tprocdef);
+
       var
         labelnode : tlabelnode;
+
       function find_and_replace_tailcalls(var n : tnode) : boolean;
 
         var
@@ -71,6 +75,7 @@ unit opttail;
           copystatements : tstatementnode;
           paranode : tcallparanode;
           tempnode : ttempcreatenode;
+          loadnode : tloadnode;
         begin
           { no tail call found and replaced so far }
           result:=false;
@@ -118,12 +123,17 @@ unit opttail;
                             ctemprefnode.create(tempnode),
                             paranode.left
                             ));
+
+                        { "cast" away const varspezs }
+                        loadnode:=cloadnode.create(paranode.parasym,paranode.parasym.owner);
+                        include(loadnode.flags,nf_isinternal_ignoreconst);
+
                         addstatement(copystatements,
                           cassignmentnode.create(
-                            cloadnode.create(paranode.parasym,paranode.parasym.owner),
+                            loadnode,
                             ctemprefnode.create(tempnode)
                             ));
-                       addstatement(copystatements,ctempdeletenode.create_normal_temp(tempnode));
+                        addstatement(copystatements,ctempdeletenode.create_normal_temp(tempnode));
 
                         { reused }
                         paranode.left:=nil;
@@ -146,11 +156,21 @@ unit opttail;
               result:=find_and_replace_tailcalls(tblocknode(n).left);
           end;
         end;
+
       var
         s : tstatementnode;
         oldnodes : tnode;
+        i : aint;
       begin
         labelnode:=clabelnode.create(cnothingnode.create);
+
+        { check if the parameters actually would support tail recursion elimination }
+        for i:=0 to p.paras.count-1 do
+          with tparavarsym(p.paras[i]) do
+            if (varspez in [vs_out,vs_var]) or
+              ((varspez=vs_const) and
+               (paramanager.push_addr_param(varspez,vartype.def,p.proccalloption))) then
+               exit;
         if find_and_replace_tailcalls(n) then
           begin
             oldnodes:=n;
diff --git a/compiler/psub.pas b/compiler/psub.pas
index 4ae49ffbd2..ae12ee49c5 100644
--- a/compiler/psub.pas
+++ b/compiler/psub.pas
@@ -729,9 +729,10 @@ implementation
           include(flags,pi_uses_fpu);
 
         { do this before adding the entry code else the tail recursion recognition won't work,
-          if this causes troubles, it must be ifdef'ed
+          if this causes troubles, it must be if'ed
         }
-        if cs_opt_tailrecursion in aktoptimizerswitches then
+        if (cs_opt_tailrecursion in aktoptimizerswitches) and
+          (pi_is_recursive in flags) then
           do_opttail(code,procdef);
 
         { add implicit entry and exit code }