Przeglądaj źródła

+ 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 lat temu
rodzic
commit
742ff35c48
3 zmienionych plików z 37 dodań i 10 usunięć
  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;
     procedure tcallnode.maybe_create_funcret_node;
       var
       var
         temp : ttempcreatenode;
         temp : ttempcreatenode;
+        realassignmenttarget: tnode;
       begin
       begin
         { For the function result we need to create a temp node for:
         { For the function result we need to create a temp node for:
             - Inlined functions
             - Inlined functions
@@ -1683,6 +1684,8 @@ implementation
               of the refcount before being assigned. This is all done after the call so there
               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
               is no issue with exceptions and possible use of the old value in the called
               function }
               function }
+            if assigned(aktassignmentnode) then
+              realassignmenttarget:=aktassignmentnode.left.actualtargetnode;
             if assigned(aktassignmentnode) and
             if assigned(aktassignmentnode) and
                (aktassignmentnode.right=self) and
                (aktassignmentnode.right=self) and
                (aktassignmentnode.left.resultdef=resultdef) and
                (aktassignmentnode.left.resultdef=resultdef) and
@@ -1700,27 +1703,30 @@ implementation
                  is_simple_para_load(aktassignmentnode.left,false)
                  is_simple_para_load(aktassignmentnode.left,false)
                 ) or
                 ) 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
                 ) or
                 (
                 (
-                 (aktassignmentnode.left.nodetype = loadn) and
+                 (realassignmenttarget.nodetype=loadn) and
                  { nested procedures may access the current procedure's locals }
                  { nested procedures may access the current procedure's locals }
                  (procdefinition.parast.symtablelevel=normal_function_level) and
                  (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
                  ) and
                  { the address may not have been taken of the variable/parameter, because }
                  { 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   }
                  { otherwise it's possible that the called function can access it via a   }
                  { global variable or other stored state                                  }
                  { 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
                ) then
               begin
               begin

+ 11 - 0
compiler/ncnv.pas

@@ -47,6 +47,7 @@ interface
           procedure buildderefimpl;override;
           procedure buildderefimpl;override;
           procedure derefimpl;override;
           procedure derefimpl;override;
           function dogetcopy : tnode;override;
           function dogetcopy : tnode;override;
+          function actualtargetnode: tnode;override;
           procedure printnodeinfo(var t : text);override;
           procedure printnodeinfo(var t : text);override;
           function pass_1 : tnode;override;
           function pass_1 : tnode;override;
           function pass_typecheck:tnode;override;
           function pass_typecheck:tnode;override;
@@ -1631,6 +1632,16 @@ implementation
       end;
       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;
     function ttypeconvnode.pass_typecheck:tnode;
 
 
       var
       var

+ 10 - 0
compiler/node.pas

@@ -343,6 +343,10 @@ interface
 
 
          { does the real copying of a node }
          { does the real copying of a node }
          function dogetcopy : tnode;virtual;
          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;
          procedure insertintolist(l : tnodelist);virtual;
          { writes a node for debugging purpose, shouldn't be called }
          { writes a node for debugging purpose, shouldn't be called }
@@ -871,6 +875,12 @@ implementation
       end;
       end;
 
 
 
 
+    function tnode.actualtargetnode: tnode;
+      begin
+        result:=self;
+      end;
+
+
     procedure tnode.insertintolist(l : tnodelist);
     procedure tnode.insertintolist(l : tnodelist);
       begin
       begin
       end;
       end;