mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-27 00:50:33 +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;
|
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
|
(realassignmenttarget.nodetype=temprefn) and
|
||||||
not(ti_addr_taken in ttemprefnode(aktassignmentnode.left).tempinfo^.flags) and
|
not(ti_addr_taken in ttemprefnode(realassignmenttarget).tempinfo^.flags) and
|
||||||
not(ti_may_be_in_reg in ttemprefnode(aktassignmentnode.left).tempinfo^.flags)
|
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
|
(tloadnode(realassignmenttarget).symtableentry.typ=paravarsym) and
|
||||||
(tparavarsym(tloadnode(aktassignmentnode.left).symtableentry).varspez = vs_value)
|
((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
|
not(tabstractvarsym(tloadnode(realassignmenttarget).symtableentry).addr_taken) and
|
||||||
(tabstractvarsym(tloadnode(aktassignmentnode.left).symtableentry).varregable in [vr_none,vr_addr])
|
(tabstractvarsym(tloadnode(realassignmenttarget).symtableentry).varregable in [vr_none,vr_addr])
|
||||||
)
|
)
|
||||||
) then
|
) then
|
||||||
begin
|
begin
|
||||||
|
@ -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
|
||||||
|
@ -344,6 +344,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 }
|
||||||
{ direct, because there is no test for nil, use printnode }
|
{ direct, because there is no test for nil, use printnode }
|
||||||
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user