Просмотр исходного кода

+ also optimize assignments from calls to by-reference "results":
o it's a by-reference parameter, but ignore that since it's
guaranteed to be safe because of the escape analysis
o it's wrapped in an absolute type conversion -> added
actualtargetnode method to tnode which digs through that

git-svn-id: trunk@9412 -

Jonas Maebe 17 лет назад
Родитель
Сommit
742ff35c48
3 измененных файлов с 37 добавлено и 10 удалено
  1. 16 10
      compiler/ncal.pas
  2. 11 0
      compiler/ncnv.pas
  3. 10 0
      compiler/node.pas

+ 16 - 10
compiler/ncal.pas

@@ -1657,6 +1657,7 @@ implementation
     procedure tcallnode.maybe_create_funcret_node;
       var
         temp : ttempcreatenode;
+        realassignmenttarget: tnode;
       begin
         { For the function result we need to create a temp node for:
             - Inlined functions
@@ -1683,6 +1684,8 @@ implementation
               of the refcount before being assigned. This is all done after the call so there
               is no issue with exceptions and possible use of the old value in the called
               function }
+            if assigned(aktassignmentnode) then
+              realassignmenttarget:=aktassignmentnode.left.actualtargetnode;
             if assigned(aktassignmentnode) and
                (aktassignmentnode.right=self) and
                (aktassignmentnode.left.resultdef=resultdef) and
@@ -1700,27 +1703,30 @@ implementation
                  is_simple_para_load(aktassignmentnode.left,false)
                 ) or
                 (
-                 (aktassignmentnode.left.nodetype = temprefn) and
-                 not(ti_addr_taken in ttemprefnode(aktassignmentnode.left).tempinfo^.flags) and
-                 not(ti_may_be_in_reg in ttemprefnode(aktassignmentnode.left).tempinfo^.flags)
+                 (realassignmenttarget.nodetype=temprefn) and
+                 not(ti_addr_taken in ttemprefnode(realassignmenttarget).tempinfo^.flags) and
+                 not(ti_may_be_in_reg in ttemprefnode(realassignmenttarget).tempinfo^.flags)
                 ) or
                 (
-                 (aktassignmentnode.left.nodetype = loadn) and
+                 (realassignmenttarget.nodetype=loadn) and
                  { nested procedures may access the current procedure's locals }
                  (procdefinition.parast.symtablelevel=normal_function_level) and
-                 { must be a local variable or a value para }
+                 { must be a local variable, a value para or a hidden function result }
+                 { parameter (which can be passed by address, but in that case it got }
+                 { through these same checks at the caller side and is thus safe      }
                  (
-                  (tloadnode(aktassignmentnode.left).symtableentry.typ = localvarsym) or
+                  (tloadnode(realassignmenttarget).symtableentry.typ=localvarsym) or
                   (
-                   (tloadnode(aktassignmentnode.left).symtableentry.typ = paravarsym) and
-                   (tparavarsym(tloadnode(aktassignmentnode.left).symtableentry).varspez = vs_value)
+                   (tloadnode(realassignmenttarget).symtableentry.typ=paravarsym) and
+                   ((tparavarsym(tloadnode(realassignmenttarget).symtableentry).varspez = vs_value) or
+                    (vo_is_funcret in tparavarsym(tloadnode(realassignmenttarget).symtableentry).varoptions))
                   )
                  ) and
                  { the address may not have been taken of the variable/parameter, because }
                  { otherwise it's possible that the called function can access it via a   }
                  { global variable or other stored state                                  }
-                 not(tabstractvarsym(tloadnode(aktassignmentnode.left).symtableentry).addr_taken) and
-                 (tabstractvarsym(tloadnode(aktassignmentnode.left).symtableentry).varregable in [vr_none,vr_addr])
+                 not(tabstractvarsym(tloadnode(realassignmenttarget).symtableentry).addr_taken) and
+                 (tabstractvarsym(tloadnode(realassignmenttarget).symtableentry).varregable in [vr_none,vr_addr])
                 )
                ) then
               begin

+ 11 - 0
compiler/ncnv.pas

@@ -47,6 +47,7 @@ interface
           procedure buildderefimpl;override;
           procedure derefimpl;override;
           function dogetcopy : tnode;override;
+          function actualtargetnode: tnode;override;
           procedure printnodeinfo(var t : text);override;
           function pass_1 : tnode;override;
           function pass_typecheck:tnode;override;
@@ -1631,6 +1632,16 @@ implementation
       end;
 
 
+    function ttypeconvnode.actualtargetnode: tnode;
+      begin
+        result:=self;
+        while (result.nodetype=typeconvn) and
+              (nf_absolute in result.flags) and
+              (resultdef.size=left.resultdef.size) do
+          result:=ttypeconvnode(result).left;
+      end;
+
+
     function ttypeconvnode.pass_typecheck:tnode;
 
       var

+ 10 - 0
compiler/node.pas

@@ -343,6 +343,10 @@ interface
 
          { does the real copying of a node }
          function dogetcopy : tnode;virtual;
+         
+         { returns the real loadn/temprefn a node refers to,
+           skipping (absolute) equal type conversions        }
+         function actualtargetnode: tnode;virtual;
 
          procedure insertintolist(l : tnodelist);virtual;
          { writes a node for debugging purpose, shouldn't be called }
@@ -871,6 +875,12 @@ implementation
       end;
 
 
+    function tnode.actualtargetnode: tnode;
+      begin
+        result:=self;
+      end;
+
+
     procedure tnode.insertintolist(l : tnodelist);
       begin
       end;