Explorar el Código

* 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 -

florian hace 12 años
padre
commit
541d67771b
Se han modificado 8 ficheros con 67 adiciones y 15 borrados
  1. 4 1
      compiler/nbas.pas
  2. 18 0
      compiler/ncal.pas
  3. 2 4
      compiler/ncgbas.pas
  4. 6 5
      compiler/ncgld.pas
  5. 2 1
      compiler/nld.pas
  6. 9 1
      compiler/nutils.pas
  7. 19 1
      compiler/symdef.pas
  8. 7 2
      compiler/symsym.pas

+ 4 - 1
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;
 

+ 18 - 0
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),

+ 2 - 4
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

+ 6 - 5
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;

+ 2 - 1
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

+ 9 - 1
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.

+ 19 - 1
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

+ 7 - 2
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 }