|
@@ -268,6 +268,9 @@ interface
|
|
between the callparanodes and the callnode they belong to }
|
|
between the callparanodes and the callnode they belong to }
|
|
aktcallnode : tcallnode;
|
|
aktcallnode : tcallnode;
|
|
|
|
|
|
|
|
+ const
|
|
|
|
+ { track current inlining depth }
|
|
|
|
+ inlinelevel : longint = 0;
|
|
|
|
|
|
implementation
|
|
implementation
|
|
|
|
|
|
@@ -1004,10 +1007,17 @@ implementation
|
|
{ uninitialized warnings (tbs/tb0542) }
|
|
{ uninitialized warnings (tbs/tb0542) }
|
|
set_varstate(left,vs_written,[]);
|
|
set_varstate(left,vs_written,[]);
|
|
set_varstate(left,vs_readwritten,[]);
|
|
set_varstate(left,vs_readwritten,[]);
|
|
|
|
+ make_not_regable(left,[ra_addr_regable,ra_addr_taken]);
|
|
end;
|
|
end;
|
|
vs_var,
|
|
vs_var,
|
|
vs_constref:
|
|
vs_constref:
|
|
- set_varstate(left,vs_readwritten,[vsf_must_be_valid,vsf_use_hints]);
|
|
|
|
|
|
+ begin
|
|
|
|
+ set_varstate(left,vs_readwritten,[vsf_must_be_valid,vsf_use_hints]);
|
|
|
|
+ { constref takes also the address, but storing it is actually the compiler
|
|
|
|
+ is not supposed to expect }
|
|
|
|
+ if parasym.varspez=vs_var then
|
|
|
|
+ make_not_regable(left,[ra_addr_regable,ra_addr_taken]);
|
|
|
|
+ end;
|
|
else
|
|
else
|
|
set_varstate(left,vs_read,[vsf_must_be_valid]);
|
|
set_varstate(left,vs_read,[vsf_must_be_valid]);
|
|
end;
|
|
end;
|
|
@@ -1702,7 +1712,10 @@ implementation
|
|
typecheckpass(temp);
|
|
typecheckpass(temp);
|
|
if (temp.nodetype <> ordconstn) or
|
|
if (temp.nodetype <> ordconstn) or
|
|
(tordconstnode(temp).value <> 0) then
|
|
(tordconstnode(temp).value <> 0) then
|
|
- hightree := caddnode.create(subn,hightree,temp)
|
|
|
|
|
|
+ begin
|
|
|
|
+ hightree:=caddnode.create(subn,hightree,temp);
|
|
|
|
+ include(hightree.flags,nf_internal);
|
|
|
|
+ end
|
|
else
|
|
else
|
|
temp.free;
|
|
temp.free;
|
|
end;
|
|
end;
|
|
@@ -2821,6 +2834,7 @@ implementation
|
|
end;
|
|
end;
|
|
if (i>0) then
|
|
if (i>0) then
|
|
begin
|
|
begin
|
|
|
|
+ include(current_procinfo.flags,pi_calls_c_varargs);
|
|
varargsparas:=tvarargsparalist.create;
|
|
varargsparas:=tvarargsparalist.create;
|
|
pt:=tcallparanode(left);
|
|
pt:=tcallparanode(left);
|
|
while assigned(pt) do
|
|
while assigned(pt) do
|
|
@@ -3489,9 +3503,25 @@ implementation
|
|
{ Can we inline the procedure? }
|
|
{ Can we inline the procedure? }
|
|
if (po_inline in procdefinition.procoptions) and
|
|
if (po_inline in procdefinition.procoptions) and
|
|
(procdefinition.typ=procdef) and
|
|
(procdefinition.typ=procdef) and
|
|
- tprocdef(procdefinition).has_inlininginfo then
|
|
|
|
|
|
+ tprocdef(procdefinition).has_inlininginfo and
|
|
|
|
+ { Prevent too deep inlining recursion and code bloat by inlining
|
|
|
|
+
|
|
|
|
+ The actual formuala is
|
|
|
|
+ inlinelevel+1 /-------
|
|
|
|
+ node count < -------------\/ 10000
|
|
|
|
+
|
|
|
|
+ This allows exponential grow of the code only to a certain limit.
|
|
|
|
+
|
|
|
|
+ Remarks
|
|
|
|
+ - The current approach calculates the inlining level top down, so outer call nodes (nodes closer to the leaf) might not be inlined
|
|
|
|
+ if the max. complexity is reached. This is done because it makes the implementation easier and because
|
|
|
|
+ there might be situations were it is more beneficial to inline inner nodes and do the calls to the outer nodes
|
|
|
|
+ if the outer nodes are in a seldomly used code path
|
|
|
|
+ - The code avoids to use functions from the math unit
|
|
|
|
+ }
|
|
|
|
+ (node_count(tprocdef(procdefinition).inlininginfo^.code)<round(exp((1.0/(inlinelevel+1))*ln(10000)))) then
|
|
begin
|
|
begin
|
|
- include(callnodeflags,cnf_do_inline);
|
|
|
|
|
|
+ include(callnodeflags,cnf_do_inline);
|
|
{ Check if we can inline the procedure when it references proc/var that
|
|
{ Check if we can inline the procedure when it references proc/var that
|
|
are not in the globally available }
|
|
are not in the globally available }
|
|
st:=procdefinition.owner;
|
|
st:=procdefinition.owner;
|
|
@@ -3883,7 +3913,10 @@ implementation
|
|
((tloadnode(n).symtable.symtabletype in [globalsymtable,ObjectSymtable]) or
|
|
((tloadnode(n).symtable.symtabletype in [globalsymtable,ObjectSymtable]) or
|
|
{ statics can only be modified by functions in the same unit }
|
|
{ statics can only be modified by functions in the same unit }
|
|
((tloadnode(n).symtable.symtabletype = staticsymtable) and
|
|
((tloadnode(n).symtable.symtabletype = staticsymtable) and
|
|
- (tloadnode(n).symtable = TSymtable(arg))))) or
|
|
|
|
|
|
+ (tloadnode(n).symtable = TSymtable(arg))) or
|
|
|
|
+ { if the addr of the symbol is taken somewhere, it can be also non-local }
|
|
|
|
+ (tabstractvarsym(tloadnode(n).symtableentry).addr_taken)
|
|
|
|
+ )) or
|
|
((n.nodetype = subscriptn) and
|
|
((n.nodetype = subscriptn) and
|
|
(tsubscriptnode(n).vs.owner.symtabletype = ObjectSymtable)) then
|
|
(tsubscriptnode(n).vs.owner.symtabletype = ObjectSymtable)) then
|
|
result := fen_norecurse_true;
|
|
result := fen_norecurse_true;
|
|
@@ -4159,6 +4192,7 @@ implementation
|
|
inlineblock,
|
|
inlineblock,
|
|
inlinecleanupblock : tblocknode;
|
|
inlinecleanupblock : tblocknode;
|
|
begin
|
|
begin
|
|
|
|
+ inc(inlinelevel);
|
|
result:=nil;
|
|
result:=nil;
|
|
if not(assigned(tprocdef(procdefinition).inlininginfo) and
|
|
if not(assigned(tprocdef(procdefinition).inlininginfo) and
|
|
assigned(tprocdef(procdefinition).inlininginfo^.code)) then
|
|
assigned(tprocdef(procdefinition).inlininginfo^.code)) then
|
|
@@ -4256,6 +4290,7 @@ implementation
|
|
writeln('**************************',tprocdef(procdefinition).mangledname);
|
|
writeln('**************************',tprocdef(procdefinition).mangledname);
|
|
printnode(output,result);
|
|
printnode(output,result);
|
|
{$endif DEBUGINLINE}
|
|
{$endif DEBUGINLINE}
|
|
|
|
+ dec(inlinelevel);
|
|
end;
|
|
end;
|
|
|
|
|
|
end.
|
|
end.
|