mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-16 06:39:39 +02:00
+ 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 -
This commit is contained in:
parent
915aa94e2d
commit
742ff35c48
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user