summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorflorian <florian@3ad0048d-3df7-0310-abae-a5850022a9f2>2014-02-01 22:26:23 +0000
committerflorian <florian@3ad0048d-3df7-0310-abae-a5850022a9f2>2014-02-01 22:26:23 +0000
commit622f74e9170b9e1b84fa8eae42321f4020111560 (patch)
tree755521ee0c61bfaec39525dfbdae8e1c8f13b809
parentb3729a5f511c4b2977c30d1acce7920202f0592c (diff)
downloadfpc-622f74e9170b9e1b84fa8eae42321f4020111560.tar.gz
* 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: http://svn.freepascal.org/svn/fpc/trunk@26649 3ad0048d-3df7-0310-abae-a5850022a9f2
-rw-r--r--compiler/ncal.pas74
1 files changed, 42 insertions, 32 deletions
diff --git a/compiler/ncal.pas b/compiler/ncal.pas
index 515ec69c20..87fe111535 100644
--- a/compiler/ncal.pas
+++ b/compiler/ncal.pas
@@ -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;