* 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:
florian 2014-02-01 22:26:23 +00:00
parent 07b2982e77
commit e6b68d19c8

View File

@ -3826,6 +3826,7 @@ implementation
n: tnode;
paracomplexity: longint;
pushconstaddr: boolean;
trytotakeaddress : Boolean;
begin
{ parameters }
para := tcallparanode(left);
@ -3847,30 +3848,50 @@ implementation
firstpass(para.left);
{ create temps for value parameters, function result and also for }
{ const parameters which are passed by value instead of by reference }
{ 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) }
paracomplexity := node_complexity(para.left);
{ determine how a parameter is passed to the inlined body
There are three options:
- insert the node tree of the callparanode directly
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);
if para.parasym.varspez=vs_const then
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 }
{ with the temp everywhere in the function }
{ if the parameter is "complex", try to take the address
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
((tparavarsym(para.parasym).varregable in [vr_none,vr_addr]) and
not(para.left.expectloc in [LOC_REFERENCE,LOC_CREFERENCE])) or
{ we can't assign to formaldef temps }
((para.parasym.vardef.typ<>formaldef) and
(
{ if paracomplexity > 1, we normally take the address of }
{ the parameter expression, store it in a temp and }
{ substitute the dereferenced temp in the inlined function }
{ 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
{ can we take the address of the argument? }
(trytotakeaddress and not(para.left.expectloc in [LOC_REFERENCE,LOC_CREFERENCE])) or
(trytotakeaddress and
(not valid_for_addr(para.left,false) or
(para.left.nodetype = calln) or
is_constnode(para.left))) or
@ -3880,9 +3901,9 @@ implementation
{ address is taken }
((((para.parasym.varspez = vs_value) and
(para.parasym.varstate in [vs_initialised,vs_declared,vs_read])) or
{ in case of const, this is only necessary if the }
{ variable would be passed by value normally, or if }
{ there is such a variable somewhere in an expression }
{ in case of const, this is only necessary if the
variable would be passed by value normally and if it is modified or if
there is such a variable somewhere in an expression }
((para.parasym.varspez = vs_const) and
(not pushconstaddr))) and
{ however, if we pass a global variable, an object field or}
@ -3960,19 +3981,8 @@ implementation
include(tempnode.tempinfo^.flags,ti_addr_taken);
end;
end
{ otherwise if the parameter is "complex", take the address }
{ 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);
end;
else if trytotakeaddress then
wrapcomplexinlinepara(para);
end;
para := tcallparanode(para.right);
end;