From 541d67771b82e9b1cc6386b334c6fe226889c170 Mon Sep 17 00:00:00 2001 From: florian Date: Sun, 23 Jun 2013 15:16:30 +0000 Subject: [PATCH] * 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 - --- compiler/nbas.pas | 5 ++++- compiler/ncal.pas | 18 ++++++++++++++++++ compiler/ncgbas.pas | 6 ++---- compiler/ncgld.pas | 11 ++++++----- compiler/nld.pas | 3 ++- compiler/nutils.pas | 10 +++++++++- compiler/symdef.pas | 20 +++++++++++++++++++- compiler/symsym.pas | 9 +++++++-- 8 files changed, 67 insertions(+), 15 deletions(-) diff --git a/compiler/nbas.pas b/compiler/nbas.pas index fbefee7d2b..5d359140b7 100644 --- a/compiler/nbas.pas +++ b/compiler/nbas.pas @@ -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; diff --git a/compiler/ncal.pas b/compiler/ncal.pas index 80b59597db..5d493b30a7 100644 --- a/compiler/ncal.pas +++ b/compiler/ncal.pas @@ -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), diff --git a/compiler/ncgbas.pas b/compiler/ncgbas.pas index 86aaa680dd..9d799eaaed 100644 --- a/compiler/ncgbas.pas +++ b/compiler/ncgbas.pas @@ -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 diff --git a/compiler/ncgld.pas b/compiler/ncgld.pas index 19cef7969f..c0fc12f8df 100644 --- a/compiler/ncgld.pas +++ b/compiler/ncgld.pas @@ -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; diff --git a/compiler/nld.pas b/compiler/nld.pas index 1b0fb5d2af..518ca3468e 100644 --- a/compiler/nld.pas +++ b/compiler/nld.pas @@ -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 diff --git a/compiler/nutils.pas b/compiler/nutils.pas index 157989012b..9b07c3c8cc 100644 --- a/compiler/nutils.pas +++ b/compiler/nutils.pas @@ -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. diff --git a/compiler/symdef.pas b/compiler/symdef.pas index a45f407c50..9f367d1ee4 100644 --- a/compiler/symdef.pas +++ b/compiler/symdef.pas @@ -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 diff --git a/compiler/symsym.pas b/compiler/symsym.pas index 8d538f4104..52920cb649 100644 --- a/compiler/symsym.pas +++ b/compiler/symsym.pas @@ -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 }