* 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; 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 }