* 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,
{ 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;

View File

@ -3904,12 +3904,27 @@ implementation
begin
tempnode := ctempcreatenode.create(para.parasym.vardef,para.parasym.vardef.size,
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);
if localvartrashing <> -1 then
cnodeutils.maybe_trash_variable(inlineinitstatement,para.parasym,ctemprefnode.create(tempnode));
addstatement(inlinecleanupstatement,ctempdeletenode.create(tempnode));
addstatement(inlineinitstatement,cassignmentnode.create(ctemprefnode.create(tempnode),
para.left));
para.left := ctemprefnode.create(tempnode);
@ -3956,6 +3971,9 @@ implementation
{ inherit addr_taken flag }
if (tabstractvarsym(para.parasym).addr_taken) then
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);
include(paraaddr.flags,nf_typedaddr);
addstatement(inlineinitstatement,cassignmentnode.create(ctemprefnode.create(tempnode),

View File

@ -415,13 +415,11 @@ interface
if not(ti_reference in tempinfo^.flags) then
begin
{ 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
location_reset_ref(tempinfo^.location,LOC_REFERENCE,def_cgsize(tempinfo^.typedef),0);
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
hlcg.g_finalize(current_asmdata.CurrAsmList,tempinfo^.typedef,tempinfo^.location.reference);
end

View File

@ -588,12 +588,13 @@ implementation
r64 : tregister64;
oldflowcontrol : tflowcontrol;
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);
{ 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;
oflabel:=current_procinfo.CurrFalseLabel;

View File

@ -852,7 +852,8 @@ implementation
right:=nil;
exit;
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
{ call helpers for pointer-sized managed types }
if is_widestring(left.resultdef) then

View File

@ -118,6 +118,10 @@ interface
rough estimation how large the tree "node" is }
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
uses
@ -1127,7 +1131,6 @@ implementation
end;
{ rough estimation how large the tree "node" is }
function node_count(node : tnode) : dword;
begin
nodecount:=0;
@ -1136,4 +1139,9 @@ implementation
end;
function is_const(node : tnode) : boolean;
begin
result:=(node.nodetype=temprefn) and (ti_const in ttemprefnode(node).tempinfo^.flags)
end;
end.

View File

@ -105,6 +105,8 @@ interface
{ regvars }
function is_intregable : boolean;
function is_fpuregable : boolean;
{ def can be put into a register if it is const/immutable }
function is_const_intregable : boolean;
{ generics }
procedure initgeneric;
{ this function can be used to determine whether a def is really a
@ -1579,7 +1581,8 @@ implementation
result:=false;
end;
function Tstoreddef.rtti_mangledname(rt:trttitype):string;
function tstoreddef.rtti_mangledname(rt : trttitype) : string;
var
prefix : string[4];
begin
@ -1787,6 +1790,21 @@ implementation
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;
begin
if assigned(generictokenbuf) then

View File

@ -1484,7 +1484,7 @@ implementation
not(cs_create_pic in current_settings.moduleswitches)
) then
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
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
@ -1494,7 +1494,12 @@ implementation
((typ=paravarsym) or
(vo_is_funcret in varoptions) 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
else
{ $warning TODO: no fpu regvar in staticsymtable yet, need initialization with 0 }