mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-10 01:26:03 +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,
|
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;
|
||||||
|
|
||||||
|
@ -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),
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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 }
|
||||||
|
Loading…
Reference in New Issue
Block a user