Browse Source

* records with two times the size of a register can be kept in registers

git-svn-id: trunk@23313 -
florian 12 years ago
parent
commit
c781f21a46
4 changed files with 73 additions and 19 deletions
  1. 36 11
      compiler/ncgmem.pas
  2. 22 5
      compiler/ncgutil.pas
  3. 1 1
      compiler/symdef.pas
  4. 14 2
      compiler/symsym.pas

+ 36 - 11
compiler/ncgmem.pas

@@ -284,6 +284,7 @@ implementation
         paraloc1 : tcgpara;
         tmpref: treference;
         sref: tsubsetreference;
+        offsetcorrection : aint;
       begin
          secondpass(left);
          if codegenerror then
@@ -359,13 +360,19 @@ implementation
                LOC_MMREGISTER,
                LOC_FPUREGISTER:
                  begin
-                   // in case the result is not something that can be put
-                   // into an integer register (e.g.
-                   // function_returning_record().non_regable_field, or
-                   // a function returning a value > sizeof(intreg))
-                   // -> force to memory
+                   { in case the result is not something that can be put
+                     into an integer register (e.g.
+                     function_returning_record().non_regable_field, or
+                     a function returning a value > sizeof(intreg))
+                     -> force to memory
+                   }
+
                    if not tstoreddef(left.resultdef).is_intregable or
                       not tstoreddef(resultdef).is_intregable or
+                      { if the field spans multiple registers, we must force the record into
+                        memory as well }
+                      ((left.location.size in [OS_PAIR,OS_SPAIR]) and
+                       (vs.fieldoffset div sizeof(aword)<>(vs.fieldoffset+vs.getsize-1) div sizeof(aword))) or
                       (location.loc in [LOC_MMREGISTER,LOC_FPUREGISTER]) then
                      hlcg.location_force_mem(current_asmdata.CurrAsmList,location,left.resultdef)
                    else
@@ -375,23 +382,41 @@ implementation
                        else
                          location.loc := LOC_CSUBSETREG;
                        location.size:=def_cgsize(resultdef);
-                       location.sreg.subsetreg := left.location.register;
-                       location.sreg.subsetregsize := left.location.size;
+
+                       offsetcorrection:=0;
+                       if (left.location.size in [OS_PAIR,OS_SPAIR]) then
+                         begin
+                           if (vs.fieldoffset>=sizeof(aword)) then
+                             begin
+                               location.sreg.subsetreg := left.location.registerhi;
+                               offsetcorrection:=sizeof(aword)*8;
+                             end
+                           else
+                             location.sreg.subsetreg := left.location.register;
+
+                           location.sreg.subsetregsize := OS_INT;
+                         end
+                       else
+                         begin
+                           location.sreg.subsetreg := left.location.register;
+                           location.sreg.subsetregsize := left.location.size;
+                         end;
+
                        if not is_packed_record_or_object(left.resultdef) then
                          begin
                            if (target_info.endian = ENDIAN_BIG) then
-                             location.sreg.startbit := (tcgsize2size[location.sreg.subsetregsize] - tcgsize2size[location.size] - vs.fieldoffset) * 8
+                             location.sreg.startbit := (tcgsize2size[location.sreg.subsetregsize] - tcgsize2size[location.size] - vs.fieldoffset) * 8+offsetcorrection
                            else
-                             location.sreg.startbit := (vs.fieldoffset * 8);
+                             location.sreg.startbit := (vs.fieldoffset * 8)-offsetcorrection;
                            location.sreg.bitlen := tcgsize2size[location.size] * 8;
                          end
                        else
                          begin
                            location.sreg.bitlen := resultdef.packedbitsize;
                            if (target_info.endian = ENDIAN_BIG) then
-                             location.sreg.startbit := (tcgsize2size[location.sreg.subsetregsize]*8 - location.sreg.bitlen) - vs.fieldoffset
+                             location.sreg.startbit := (tcgsize2size[location.sreg.subsetregsize]*8 - location.sreg.bitlen) - vs.fieldoffset+offsetcorrection
                            else
-                             location.sreg.startbit := vs.fieldoffset;
+                             location.sreg.startbit := vs.fieldoffset-offsetcorrection;
                          end;
                      end;
                  end;

+ 22 - 5
compiler/ncgutil.pas

@@ -984,7 +984,8 @@ implementation
                   { in case of fpu emulation, or abi's that pass fpu values
                     via integer registers }
                   (vardef.typ=floatdef) or
-                   is_methodpointer(vardef)) then
+                   is_methodpointer(vardef) or
+                   is_record(vardef)) then
                 begin
                   case paraloc^.loc of
                     LOC_REGISTER:
@@ -1028,10 +1029,26 @@ implementation
 {$endif cpu64bitalu}
                 begin
                   if assigned(paraloc^.next) then
-                    internalerror(200410105);
-                  unget_para(paraloc^);
-                  gen_alloc_regloc(list,destloc);
-                  cg.a_load_cgparaloc_anyreg(list,destloc.size,paraloc^,destloc.register,sizeof(aint));
+                    begin
+                      if (destloc.size in [OS_PAIR,OS_SPAIR]) and
+                        (para.Size in [OS_PAIR,OS_SPAIR]) then
+                        begin
+                          unget_para(paraloc^);
+                          gen_alloc_regloc(list,destloc);
+                          cg.a_load_cgparaloc_anyreg(list,OS_32,paraloc^,destloc.register,sizeof(aint));
+                          unget_para(paraloc^.Next^);
+                          gen_alloc_regloc(list,destloc);
+                          cg.a_load_cgparaloc_anyreg(list,OS_32,paraloc^.Next^,destloc.registerhi,sizeof(aint));
+                        end
+                      else
+                        internalerror(200410105);
+                    end
+                  else
+                    begin
+                      unget_para(paraloc^);
+                      gen_alloc_regloc(list,destloc);
+                      cg.a_load_cgparaloc_anyreg(list,destloc.size,paraloc^,destloc.register,sizeof(aint));
+                    end;
                 end;
             end;
           LOC_FPUREGISTER,

+ 1 - 1
compiler/symdef.pas

@@ -1609,7 +1609,7 @@ implementation
               recsize:=size;
               is_intregable:=
                 ispowerof2(recsize,temp) and
-                (recsize <= sizeof(asizeint))
+                (recsize <= sizeof(asizeint)*2)
                 and not needs_inittable;
             end;
         end;

+ 14 - 2
compiler/symsym.pas

@@ -191,7 +191,9 @@ interface
       end;
 
       tfieldvarsym = class(tabstractvarsym)
-          fieldoffset   : asizeint;   { offset in record/object }
+          { offset in record/object, for bitpacked fields the offset is
+            given in bit, else in bytes }
+          fieldoffset   : asizeint;
           externalname  : pshortstring;
 {$ifdef symansistr}
           cachedmangledname: TSymStr; { mangled name for ObjC or Java }
@@ -1504,7 +1506,17 @@ implementation
             not(cs_create_pic in current_settings.moduleswitches)
            ) then
           begin
-            if tstoreddef(vardef).is_intregable then
+            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
+                passed by register anyways
+
+                This can be changed, as soon as we have full ssa (FK) }
+              ((typ=paravarsym) or
+                (vo_is_funcret in varoptions) or
+                (tstoreddef(vardef).typ<>recorddef) or
+                (tstoreddef(vardef).size<=sizeof(aint))) then
               varregable:=vr_intreg
             else
 { $warning TODO: no fpu regvar in staticsymtable yet, need initialization with 0 }