mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-06-01 19:23:02 +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;
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user