* keep managed types in registers if possible. Under certain circumstances (if they don't require init/final code,

e.g. being a const parameter or immutable temp. values), managed types like dyn. arrays, new string types and interfaces can be kept in registers.

git-svn-id: trunk@24953 -
This commit is contained in:
florian 2013-06-23 15:16:30 +00:00
parent 58b22adaf1
commit 541d67771b
8 changed files with 67 additions and 15 deletions

View File

@ -143,7 +143,10 @@ interface
ti_readonly, ti_readonly,
{ if this is a managed temp, it doesn't have to be finalised before use { if this is a managed temp, it doesn't have to be finalised before use
} }
ti_nofini ti_nofini,
{ the value described by this temp. node is const/immutable, this is important for
managed types like ansistrings where temp. refs are pointers to the actual value }
ti_const
); );
ttempinfoflags = set of ttempinfoflag; ttempinfoflags = set of ttempinfoflag;

View File

@ -3904,12 +3904,27 @@ implementation
begin begin
tempnode := ctempcreatenode.create(para.parasym.vardef,para.parasym.vardef.size, tempnode := ctempcreatenode.create(para.parasym.vardef,para.parasym.vardef.size,
tt_persistent,tparavarsym(para.parasym).is_regvar(false)); tt_persistent,tparavarsym(para.parasym).is_regvar(false));
{ inherit const }
if tabstractvarsym(para.parasym).varspez=vs_const then
begin
include(tempnode.tempinfo^.flags,ti_const);
{ apply less strict rules for the temp. to be a register than
ttempcreatenode does
this way, dyn. array, ansistrings etc. can be put into registers as well }
if tparavarsym(para.parasym).is_regvar(false) then
include(tempnode.tempinfo^.flags,ti_may_be_in_reg);
end;
addstatement(inlineinitstatement,tempnode); addstatement(inlineinitstatement,tempnode);
if localvartrashing <> -1 then if localvartrashing <> -1 then
cnodeutils.maybe_trash_variable(inlineinitstatement,para.parasym,ctemprefnode.create(tempnode)); cnodeutils.maybe_trash_variable(inlineinitstatement,para.parasym,ctemprefnode.create(tempnode));
addstatement(inlinecleanupstatement,ctempdeletenode.create(tempnode)); addstatement(inlinecleanupstatement,ctempdeletenode.create(tempnode));
addstatement(inlineinitstatement,cassignmentnode.create(ctemprefnode.create(tempnode), addstatement(inlineinitstatement,cassignmentnode.create(ctemprefnode.create(tempnode),
para.left)); para.left));
para.left := ctemprefnode.create(tempnode); para.left := ctemprefnode.create(tempnode);
@ -3956,6 +3971,9 @@ implementation
{ inherit addr_taken flag } { inherit addr_taken flag }
if (tabstractvarsym(para.parasym).addr_taken) then if (tabstractvarsym(para.parasym).addr_taken) then
include(tempnode.tempinfo^.flags,ti_addr_taken); include(tempnode.tempinfo^.flags,ti_addr_taken);
{ inherit read only }
if tabstractvarsym(para.parasym).varspez=vs_const then
include(tempnode.tempinfo^.flags,ti_const);
paraaddr:=caddrnode.create_internal(para.left); paraaddr:=caddrnode.create_internal(para.left);
include(paraaddr.flags,nf_typedaddr); include(paraaddr.flags,nf_typedaddr);
addstatement(inlineinitstatement,cassignmentnode.create(ctemprefnode.create(tempnode), addstatement(inlineinitstatement,cassignmentnode.create(ctemprefnode.create(tempnode),

View File

@ -415,13 +415,11 @@ interface
if not(ti_reference in tempinfo^.flags) then if not(ti_reference in tempinfo^.flags) then
begin begin
{ get a (persistent) temp } { get a (persistent) temp }
if is_managed_type(tempinfo^.typedef) then if is_managed_type(tempinfo^.typedef) and
not(ti_const in tempinfo^.flags) then
begin begin
location_reset_ref(tempinfo^.location,LOC_REFERENCE,def_cgsize(tempinfo^.typedef),0); location_reset_ref(tempinfo^.location,LOC_REFERENCE,def_cgsize(tempinfo^.typedef),0);
tg.gethltemptyped(current_asmdata.CurrAsmList,tempinfo^.typedef,tempinfo^.temptype,tempinfo^.location.reference); tg.gethltemptyped(current_asmdata.CurrAsmList,tempinfo^.typedef,tempinfo^.temptype,tempinfo^.location.reference);
{ the temp could have been used previously either because the memory location was reused or
because we're in a loop. In case it's used as a function result, that doesn't matter
because it will be finalized when assigned to. }
if not(ti_nofini in tempinfo^.flags) then if not(ti_nofini in tempinfo^.flags) then
hlcg.g_finalize(current_asmdata.CurrAsmList,tempinfo^.typedef,tempinfo^.location.reference); hlcg.g_finalize(current_asmdata.CurrAsmList,tempinfo^.typedef,tempinfo^.location.reference);
end end

View File

@ -588,12 +588,13 @@ implementation
r64 : tregister64; r64 : tregister64;
oldflowcontrol : tflowcontrol; oldflowcontrol : tflowcontrol;
begin begin
{ previously, managed types were handled in firstpass
newer FPCs however can identify situations when
assignments of managed types require no special code and the
value could be just copied so this could should be able also to handle
managed types without any special "managing code"}
location_reset(location,LOC_VOID,OS_NO); location_reset(location,LOC_VOID,OS_NO);
{ managed types should be handled in firstpass }
if not(target_info.system in systems_garbage_collected_managed_types) and
(is_managed_type(left.resultdef) or
is_managed_type(right.resultdef)) then
InternalError(2012011901);
otlabel:=current_procinfo.CurrTrueLabel; otlabel:=current_procinfo.CurrTrueLabel;
oflabel:=current_procinfo.CurrFalseLabel; oflabel:=current_procinfo.CurrFalseLabel;

View File

@ -852,7 +852,8 @@ implementation
right:=nil; right:=nil;
exit; exit;
end end
else if not(target_info.system in systems_garbage_collected_managed_types) then else if not(target_info.system in systems_garbage_collected_managed_types) and
not(is_const(left)) then
begin begin
{ call helpers for pointer-sized managed types } { call helpers for pointer-sized managed types }
if is_widestring(left.resultdef) then if is_widestring(left.resultdef) then

View File

@ -118,6 +118,10 @@ interface
rough estimation how large the tree "node" is } rough estimation how large the tree "node" is }
function node_count(node : tnode) : dword; function node_count(node : tnode) : dword;
{ returns true, if the value described by node is constant/immutable, this approximation is safe
if no dirty tricks like buffer overflows or pointer magic are used }
function is_const(node : tnode) : boolean;
implementation implementation
uses uses
@ -1127,7 +1131,6 @@ implementation
end; end;
{ rough estimation how large the tree "node" is }
function node_count(node : tnode) : dword; function node_count(node : tnode) : dword;
begin begin
nodecount:=0; nodecount:=0;
@ -1136,4 +1139,9 @@ implementation
end; end;
function is_const(node : tnode) : boolean;
begin
result:=(node.nodetype=temprefn) and (ti_const in ttemprefnode(node).tempinfo^.flags)
end;
end. end.

View File

@ -105,6 +105,8 @@ interface
{ regvars } { regvars }
function is_intregable : boolean; function is_intregable : boolean;
function is_fpuregable : boolean; function is_fpuregable : boolean;
{ def can be put into a register if it is const/immutable }
function is_const_intregable : boolean;
{ generics } { generics }
procedure initgeneric; procedure initgeneric;
{ this function can be used to determine whether a def is really a { this function can be used to determine whether a def is really a
@ -1579,7 +1581,8 @@ implementation
result:=false; result:=false;
end; end;
function Tstoreddef.rtti_mangledname(rt:trttitype):string;
function tstoreddef.rtti_mangledname(rt : trttitype) : string;
var var
prefix : string[4]; prefix : string[4];
begin begin
@ -1787,6 +1790,21 @@ implementation
end; end;
function tstoreddef.is_const_intregable : boolean;
begin
case typ of
stringdef:
result:=tstringdef(self).stringtype in [st_ansistring,st_unicodestring,st_widestring];
arraydef:
result:=is_dynamic_array(self);
objectdef:
result:=is_interface(self);
else
result:=false;
end;
end;
procedure tstoreddef.initgeneric; procedure tstoreddef.initgeneric;
begin begin
if assigned(generictokenbuf) then if assigned(generictokenbuf) then

View File

@ -1484,7 +1484,7 @@ implementation
not(cs_create_pic in current_settings.moduleswitches) not(cs_create_pic in current_settings.moduleswitches)
) then ) then
begin begin
if tstoreddef(vardef).is_intregable and if (tstoreddef(vardef).is_intregable and
{ we could keep all aint*2 records in registers, but this causes { we could keep all aint*2 records in registers, but this causes
too much spilling for CPUs with 8-16 registers so keep only too much spilling for CPUs with 8-16 registers so keep only
parameters and function results of this type in register because they are normally parameters and function results of this type in register because they are normally
@ -1494,7 +1494,12 @@ implementation
((typ=paravarsym) or ((typ=paravarsym) or
(vo_is_funcret in varoptions) or (vo_is_funcret in varoptions) or
(tstoreddef(vardef).typ<>recorddef) or (tstoreddef(vardef).typ<>recorddef) or
(tstoreddef(vardef).size<=sizeof(aint))) then (tstoreddef(vardef).size<=sizeof(aint)))) or
{ const parameters can be put into registers if the def fits into a register }
(tstoreddef(vardef).is_const_intregable and
(typ=paravarsym) and
(varspez=vs_const)) then
varregable:=vr_intreg varregable:=vr_intreg
else else
{ $warning TODO: no fpu regvar in staticsymtable yet, need initialization with 0 } { $warning TODO: no fpu regvar in staticsymtable yet, need initialization with 0 }