mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-23 19:29:33 +02:00
* 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:
parent
58b22adaf1
commit
541d67771b
@ -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;
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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 }
|
||||
|
Loading…
Reference in New Issue
Block a user