mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-06-08 18:20:12 +02:00
* reordered decision how arguments for inlining are handled
* improved comments for inline argument handling * replace arguments more aggressively with a copy of their original node tree when inlining git-svn-id: trunk@26649 -
This commit is contained in:
parent
07b2982e77
commit
e6b68d19c8
@ -3826,6 +3826,7 @@ implementation
|
|||||||
n: tnode;
|
n: tnode;
|
||||||
paracomplexity: longint;
|
paracomplexity: longint;
|
||||||
pushconstaddr: boolean;
|
pushconstaddr: boolean;
|
||||||
|
trytotakeaddress : Boolean;
|
||||||
begin
|
begin
|
||||||
{ parameters }
|
{ parameters }
|
||||||
para := tcallparanode(left);
|
para := tcallparanode(left);
|
||||||
@ -3847,30 +3848,50 @@ implementation
|
|||||||
|
|
||||||
firstpass(para.left);
|
firstpass(para.left);
|
||||||
|
|
||||||
{ create temps for value parameters, function result and also for }
|
{ determine how a parameter is passed to the inlined body
|
||||||
{ const parameters which are passed by value instead of by reference }
|
There are three options:
|
||||||
{ we need to take care that we use the type of the defined parameter and not of the
|
- insert the node tree of the callparanode directly
|
||||||
passed parameter, because these can be different in case of a formaldef (PFV) }
|
If a parameter is used only once, this is the best option if we can do so
|
||||||
|
- get the address of the argument, store it in a temp and insert a dereference to this temp
|
||||||
|
If the node tree cannot be inserted directly, taking the address of the argument and using it
|
||||||
|
is the second best option, but even this is not always possible
|
||||||
|
- assign the value of the argument to a newly created temp
|
||||||
|
This is the fall back which works always
|
||||||
|
Notes:
|
||||||
|
- we need to take care that we use the type of the defined parameter and not of the
|
||||||
|
passed parameter, because these can be different in case of a formaldef (PFV)
|
||||||
|
}
|
||||||
|
|
||||||
|
{ pre-compute some values }
|
||||||
paracomplexity:=node_complexity(para.left);
|
paracomplexity:=node_complexity(para.left);
|
||||||
if para.parasym.varspez=vs_const then
|
if para.parasym.varspez=vs_const then
|
||||||
pushconstaddr:=paramanager.push_addr_param(vs_const,para.parasym.vardef,procdefinition.proccalloption);
|
pushconstaddr:=paramanager.push_addr_param(vs_const,para.parasym.vardef,procdefinition.proccalloption);
|
||||||
{ check if we have to create a temp, assign the parameter's }
|
|
||||||
{ contents to that temp and then substitute the parameter }
|
{ if the parameter is "complex", try to take the address
|
||||||
{ with the temp everywhere in the function }
|
of the parameter expression, store it in a temp and replace
|
||||||
|
occurrences of the parameter with dereferencings of this
|
||||||
|
temp
|
||||||
|
}
|
||||||
|
trytotakeaddress:=
|
||||||
|
{ don't create a temp. for function results }
|
||||||
|
not(nf_is_funcret in para.left.flags) and
|
||||||
|
{ this makes only sense if the parameter is reasonable complex else inserting directly is a better solution }
|
||||||
|
((paracomplexity>2) or
|
||||||
|
{ don't create a temp. for the often seen case that p^ is passed to a var parameter }
|
||||||
|
((paracomplexity>1) and not((para.left.nodetype=derefn) and (para.parasym.varspez = vs_var))));
|
||||||
|
|
||||||
|
{ check if we have to create a temp, assign the parameter's
|
||||||
|
contents to that temp and then substitute the parameter
|
||||||
|
with the temp everywhere in the function }
|
||||||
if
|
if
|
||||||
((tparavarsym(para.parasym).varregable in [vr_none,vr_addr]) and
|
((tparavarsym(para.parasym).varregable in [vr_none,vr_addr]) and
|
||||||
not(para.left.expectloc in [LOC_REFERENCE,LOC_CREFERENCE])) or
|
not(para.left.expectloc in [LOC_REFERENCE,LOC_CREFERENCE])) or
|
||||||
{ we can't assign to formaldef temps }
|
{ we can't assign to formaldef temps }
|
||||||
((para.parasym.vardef.typ<>formaldef) and
|
((para.parasym.vardef.typ<>formaldef) and
|
||||||
(
|
(
|
||||||
{ if paracomplexity > 1, we normally take the address of }
|
{ can we take the address of the argument? }
|
||||||
{ the parameter expression, store it in a temp and }
|
(trytotakeaddress and not(para.left.expectloc in [LOC_REFERENCE,LOC_CREFERENCE])) or
|
||||||
{ substitute the dereferenced temp in the inlined function }
|
(trytotakeaddress and
|
||||||
{ We can't do this if we can't take the address of the }
|
|
||||||
{ parameter expression, so in that case assign to a temp }
|
|
||||||
not(para.left.expectloc in [LOC_REFERENCE,LOC_CREFERENCE,LOC_CONSTANT]) or
|
|
||||||
((paracomplexity > 1) and
|
|
||||||
not(nf_is_funcret in para.left.flags) and
|
|
||||||
(not valid_for_addr(para.left,false) or
|
(not valid_for_addr(para.left,false) or
|
||||||
(para.left.nodetype = calln) or
|
(para.left.nodetype = calln) or
|
||||||
is_constnode(para.left))) or
|
is_constnode(para.left))) or
|
||||||
@ -3880,9 +3901,9 @@ implementation
|
|||||||
{ address is taken }
|
{ address is taken }
|
||||||
((((para.parasym.varspez = vs_value) and
|
((((para.parasym.varspez = vs_value) and
|
||||||
(para.parasym.varstate in [vs_initialised,vs_declared,vs_read])) or
|
(para.parasym.varstate in [vs_initialised,vs_declared,vs_read])) or
|
||||||
{ in case of const, this is only necessary if the }
|
{ in case of const, this is only necessary if the
|
||||||
{ variable would be passed by value normally, or if }
|
variable would be passed by value normally and if it is modified or if
|
||||||
{ there is such a variable somewhere in an expression }
|
there is such a variable somewhere in an expression }
|
||||||
((para.parasym.varspez = vs_const) and
|
((para.parasym.varspez = vs_const) and
|
||||||
(not pushconstaddr))) and
|
(not pushconstaddr))) and
|
||||||
{ however, if we pass a global variable, an object field or}
|
{ however, if we pass a global variable, an object field or}
|
||||||
@ -3960,20 +3981,9 @@ implementation
|
|||||||
include(tempnode.tempinfo^.flags,ti_addr_taken);
|
include(tempnode.tempinfo^.flags,ti_addr_taken);
|
||||||
end;
|
end;
|
||||||
end
|
end
|
||||||
{ otherwise if the parameter is "complex", take the address }
|
else if trytotakeaddress then
|
||||||
{ of the parameter expression, store it in a temp and replace }
|
|
||||||
{ occurrences of the parameter with dereferencings of this }
|
|
||||||
{ temp }
|
|
||||||
else
|
|
||||||
{ don't create a temp. for function results }
|
|
||||||
if not(nf_is_funcret in para.left.flags) and
|
|
||||||
((paracomplexity>2) or
|
|
||||||
{ don't create a temp. for the often seen case that p^ is passed to a var parameter }
|
|
||||||
((paracomplexity>1) and not((para.left.nodetype=derefn) and (para.parasym.varspez = vs_var)))) then
|
|
||||||
begin
|
|
||||||
wrapcomplexinlinepara(para);
|
wrapcomplexinlinepara(para);
|
||||||
end;
|
end;
|
||||||
end;
|
|
||||||
para := tcallparanode(para.right);
|
para := tcallparanode(para.right);
|
||||||
end;
|
end;
|
||||||
{ local variables }
|
{ local variables }
|
||||||
|
Loading…
Reference in New Issue
Block a user