Browse Source

* don't treat variant records with one element as "records with one element"
(the ABIs that prescribe special treatment for aggregates with one
scalar element don't either, since a "union containing a single scalar"
is not the same as a scalar)
* fixed passing record with a single float field on PowerPC/AIX abi's
* several changes to cgobj and ncgutil to correctly deal with transfering
such records between integer and floating point registers

git-svn-id: trunk@15416 -

Jonas Maebe 15 years ago
parent
commit
ea4bb9d752
6 changed files with 93 additions and 21 deletions
  1. 1 0
      .gitattributes
  2. 7 0
      compiler/cgobj.pas
  3. 19 12
      compiler/ncgutil.pas
  4. 8 9
      compiler/powerpc/cpupara.pas
  5. 12 0
      compiler/symtable.pas
  6. 46 0
      tests/tbs/tb0573.pp

+ 1 - 0
.gitattributes

@@ -8417,6 +8417,7 @@ tests/tbs/tb0569.pp svneol=native#text/pascal
 tests/tbs/tb0570.pp svneol=native#text/plain
 tests/tbs/tb0570.pp svneol=native#text/plain
 tests/tbs/tb0571.pas svneol=native#text/plain
 tests/tbs/tb0571.pas svneol=native#text/plain
 tests/tbs/tb0572.pp svneol=native#text/plain
 tests/tbs/tb0572.pp svneol=native#text/plain
+tests/tbs/tb0573.pp svneol=native#text/plain
 tests/tbs/tb205.pp svneol=native#text/plain
 tests/tbs/tb205.pp svneol=native#text/plain
 tests/tbs/ub0060.pp svneol=native#text/plain
 tests/tbs/ub0060.pp svneol=native#text/plain
 tests/tbs/ub0069.pp svneol=native#text/plain
 tests/tbs/ub0069.pp svneol=native#text/plain

+ 7 - 0
compiler/cgobj.pas

@@ -900,6 +900,13 @@ implementation
               end;
               end;
             LOC_MMREGISTER,LOC_CMMREGISTER:
             LOC_MMREGISTER,LOC_CMMREGISTER:
               a_loadmm_intreg_reg(list,size,cgpara.location^.size,r,cgpara.location^.register,mms_movescalar);
               a_loadmm_intreg_reg(list,size,cgpara.location^.size,r,cgpara.location^.register,mms_movescalar);
+            LOC_FPUREGISTER,LOC_CFPUREGISTER:
+              begin
+                tg.GetTemp(list,TCGSize2Size[size],TCGSize2Size[size],tt_normal,ref);
+                a_load_reg_ref(list,size,size,r,ref);
+                a_loadfpu_ref_cgpara(list,cgpara.location^.size,ref,cgpara);
+                tg.Ungettemp(list,ref);
+              end
             else
             else
               internalerror(2002071004);
               internalerror(2002071004);
          end;
          end;

+ 19 - 12
compiler/ncgutil.pas

@@ -789,8 +789,13 @@ implementation
         href   : treference;
         href   : treference;
         size   : longint;
         size   : longint;
 {$endif i386}
 {$endif i386}
+        locsize : tcgsize;
         tmploc : tlocation;
         tmploc : tlocation;
       begin
       begin
+           if not(l.size in [OS_32,OS_64,OS_128]) then
+             locsize:=l.size
+           else
+             locsize:=int_float_cgsize(tcgsize2size[l.size]);
 {$ifdef i386}
 {$ifdef i386}
            case l.loc of
            case l.loc of
              LOC_FPUREGISTER,
              LOC_FPUREGISTER,
@@ -808,11 +813,11 @@ implementation
                          end
                          end
                        else
                        else
                          reference_reset_base(href,cgpara.location^.reference.index,cgpara.location^.reference.offset,cgpara.alignment);
                          reference_reset_base(href,cgpara.location^.reference.index,cgpara.location^.reference.offset,cgpara.alignment);
-                       cg.a_loadfpu_reg_ref(list,l.size,l.size,l.register,href);
+                       cg.a_loadfpu_reg_ref(list,locsize,locsize,l.register,href);
                      end;
                      end;
                    LOC_FPUREGISTER:
                    LOC_FPUREGISTER:
                      begin
                      begin
-                       cg.a_loadfpu_reg_reg(list,l.size,cgpara.location^.size,l.register,cgpara.location^.register);
+                       cg.a_loadfpu_reg_reg(list,locsize,cgpara.location^.size,l.register,cgpara.location^.register);
                      end;
                      end;
                    { can happen if a record with only 1 "single field" is
                    { can happen if a record with only 1 "single field" is
                      returned in a floating point register and then is directly
                      returned in a floating point register and then is directly
@@ -821,7 +826,7 @@ implementation
                      begin
                      begin
                        tmploc:=l;
                        tmploc:=l;
                        location_force_mem(list,tmploc);
                        location_force_mem(list,tmploc);
-                       case l.size of
+                       case locsize of
                          OS_F32:
                          OS_F32:
                            tmploc.size:=OS_32;
                            tmploc.size:=OS_32;
                          OS_F64:
                          OS_F64:
@@ -853,7 +858,7 @@ implementation
                          end
                          end
                        else
                        else
                          reference_reset_base(href,cgpara.location^.reference.index,cgpara.location^.reference.offset,cgpara.alignment);
                          reference_reset_base(href,cgpara.location^.reference.index,cgpara.location^.reference.offset,cgpara.alignment);
-                       cg.a_loadmm_reg_ref(list,l.size,l.size,l.register,href,mms_movescalar);
+                       cg.a_loadmm_reg_ref(list,locsize,locsize,l.register,href,mms_movescalar);
                      end;
                      end;
                    LOC_FPUREGISTER:
                    LOC_FPUREGISTER:
                      begin
                      begin
@@ -875,7 +880,7 @@ implementation
                        size:=align(locintsize,cgpara.alignment);
                        size:=align(locintsize,cgpara.alignment);
                        if (not use_fixed_stack) and
                        if (not use_fixed_stack) and
                           (cgpara.location^.reference.index=NR_STACK_POINTER_REG) then
                           (cgpara.location^.reference.index=NR_STACK_POINTER_REG) then
-                         cg.a_load_ref_cgpara(list,l.size,l.reference,cgpara)
+                         cg.a_load_ref_cgpara(list,locsize,l.reference,cgpara)
                        else
                        else
                          begin
                          begin
                            reference_reset_base(href,cgpara.location^.reference.index,cgpara.location^.reference.offset,cgpara.alignment);
                            reference_reset_base(href,cgpara.location^.reference.index,cgpara.location^.reference.offset,cgpara.alignment);
@@ -884,7 +889,7 @@ implementation
                      end;
                      end;
                    LOC_FPUREGISTER:
                    LOC_FPUREGISTER:
                      begin
                      begin
-                       cg.a_loadfpu_ref_cgpara(list,l.size,l.reference,cgpara);
+                       cg.a_loadfpu_ref_cgpara(list,locsize,l.reference,cgpara);
                      end;
                      end;
                    else
                    else
                      internalerror(2010053005);
                      internalerror(2010053005);
@@ -904,7 +909,7 @@ implementation
                  LOC_CMMREGISTER,
                  LOC_CMMREGISTER,
                  LOC_REGISTER,
                  LOC_REGISTER,
                  LOC_CREGISTER :
                  LOC_CREGISTER :
-                   cg.a_loadmm_reg_cgpara(list,l.size,l.register,cgpara,mms_movescalar);
+                   cg.a_loadmm_reg_cgpara(list,locsize,l.register,cgpara,mms_movescalar);
                  LOC_FPUREGISTER,
                  LOC_FPUREGISTER,
                  LOC_CFPUREGISTER:
                  LOC_CFPUREGISTER:
                    begin
                    begin
@@ -932,7 +937,7 @@ implementation
                  LOC_CREFERENCE,
                  LOC_CREFERENCE,
                  LOC_FPUREGISTER,
                  LOC_FPUREGISTER,
                  LOC_CFPUREGISTER:
                  LOC_CFPUREGISTER:
-                   cg.a_loadfpu_reg_cgpara(list,l.size,l.register,cgpara);
+                   cg.a_loadfpu_reg_cgpara(list,locsize,l.register,cgpara);
                  else
                  else
                    internalerror(2002042433);
                    internalerror(2002042433);
                end;
                end;
@@ -941,7 +946,7 @@ implementation
                case cgpara.location^.loc of
                case cgpara.location^.loc of
                  LOC_MMREGISTER,
                  LOC_MMREGISTER,
                  LOC_CMMREGISTER:
                  LOC_CMMREGISTER:
-                   cg.a_loadmm_ref_cgpara(list,l.size,l.reference,cgpara,mms_movescalar);
+                   cg.a_loadmm_ref_cgpara(list,locsize,l.reference,cgpara,mms_movescalar);
                  { Some targets pass floats in normal registers }
                  { Some targets pass floats in normal registers }
                  LOC_REGISTER,
                  LOC_REGISTER,
                  LOC_CREGISTER,
                  LOC_CREGISTER,
@@ -949,7 +954,7 @@ implementation
                  LOC_CREFERENCE,
                  LOC_CREFERENCE,
                  LOC_FPUREGISTER,
                  LOC_FPUREGISTER,
                  LOC_CFPUREGISTER:
                  LOC_CFPUREGISTER:
-                   cg.a_loadfpu_ref_cgpara(list,l.size,l.reference,cgpara);
+                   cg.a_loadfpu_ref_cgpara(list,locsize,l.reference,cgpara);
                  else
                  else
                    internalerror(2002042431);
                    internalerror(2002042431);
                end;
                end;
@@ -961,7 +966,7 @@ implementation
                     value is still a const or in a register then write it
                     value is still a const or in a register then write it
                     to a reference first. This situation can be triggered
                     to a reference first. This situation can be triggered
                     by typecasting an int64 constant to a record of 8 bytes }
                     by typecasting an int64 constant to a record of 8 bytes }
-                  if l.size in [OS_64,OS_S64] then
+                  if locsize = OS_F64 then
                     begin
                     begin
                       tmploc:=l;
                       tmploc:=l;
                       location_force_mem(list,tmploc);
                       location_force_mem(list,tmploc);
@@ -991,7 +996,9 @@ implementation
           be handled by cpupara }
           be handled by cpupara }
         if (vardef.typ=floatdef) or
         if (vardef.typ=floatdef) or
            { some ABIs return certain records in an fpu register }
            { some ABIs return certain records in an fpu register }
-           (l.loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER]) then
+           (l.loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER]) or
+           (assigned(cgpara.location) and
+            (cgpara.Location^.loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER])) then
           begin
           begin
             gen_loadfpu_loc_cgpara(list,l,cgpara,vardef.size);
             gen_loadfpu_loc_cgpara(list,l,cgpara,vardef.size);
             exit;
             exit;

+ 8 - 9
compiler/powerpc/cpupara.pas

@@ -53,7 +53,7 @@ unit cpupara;
 
 
     uses
     uses
        verbose,systems,
        verbose,systems,
-       defutil,
+       defutil,symtable,
        procinfo,cpupi;
        procinfo,cpupi;
 
 
 
 
@@ -357,6 +357,7 @@ unit cpupara;
          hp : tparavarsym;
          hp : tparavarsym;
          loc : tcgloc;
          loc : tcgloc;
          paracgsize: tcgsize;
          paracgsize: tcgsize;
+         sym: tfieldvarsym;
 
 
       begin
       begin
 {$ifdef extdebug}
 {$ifdef extdebug}
@@ -417,7 +418,6 @@ unit cpupara;
                     paralen := paradef.size
                     paralen := paradef.size
                   else
                   else
                     paralen := tcgsize2size[def_cgsize(paradef)];
                     paralen := tcgsize2size[def_cgsize(paradef)];
-                  loc := getparaloc(paradef);
                   if (target_info.abi = abi_powerpc_aix) and
                   if (target_info.abi = abi_powerpc_aix) and
                      (paradef.typ = recorddef) and
                      (paradef.typ = recorddef) and
                      (hp.varspez in [vs_value,vs_const]) then
                      (hp.varspez in [vs_value,vs_const]) then
@@ -425,14 +425,12 @@ unit cpupara;
                       { if a record has only one field and that field is }
                       { if a record has only one field and that field is }
                       { non-composite (not array or record), it must be  }
                       { non-composite (not array or record), it must be  }
                       { passed according to the rules of that type.       }
                       { passed according to the rules of that type.       }
-                      if (trecorddef(hp.vardef).symtable.SymList.count = 1) and
-                         (not trecorddef(hp.vardef).isunion) and
-                         ((tabstractvarsym(trecorddef(hp.vardef).symtable.SymList[0]).vardef.typ = floatdef) or
-                          ((target_info.system = system_powerpc_darwin) and
-                           (tabstractvarsym(trecorddef(hp.vardef).symtable.SymList[0]).vardef.typ in [orddef,enumdef]))) then
+                      if tabstractrecordsymtable(tabstractrecorddef(paradef).symtable).has_single_field(sym) and
+                         ((sym.vardef.typ=floatdef) or
+                          ((target_info.system=system_powerpc_darwin) and
+                           (sym.vardef.typ in [orddef,enumdef]))) then
                         begin
                         begin
-                          paradef :=
-                           tabstractvarsym(trecorddef(hp.vardef).symtable.SymList[0]).vardef;
+                          paradef:=sym.vardef;
                           paracgsize:=def_cgsize(paradef);
                           paracgsize:=def_cgsize(paradef);
                         end
                         end
                       else
                       else
@@ -452,6 +450,7 @@ unit cpupara;
                     end
                     end
                 end;
                 end;
 
 
+              loc := getparaloc(paradef);
               if varargsparas and
               if varargsparas and
                  (target_info.abi = abi_powerpc_aix) and
                  (target_info.abi = abi_powerpc_aix) and
                  (paradef.typ = floatdef) then
                  (paradef.typ = floatdef) then

+ 12 - 0
compiler/symtable.pas

@@ -1009,6 +1009,13 @@ implementation
         i: longint;
         i: longint;
       begin
       begin
         result:=false;
         result:=false;
+        { If a record contains a union, it does not contain a "single
+          non-composite field" in the context of certain ABIs requiring
+          special treatment for such records }
+        if (defowner.typ=recorddef) and
+           trecorddef(defowner).isunion then
+          exit;
+        { a record/object can contain other things than fields }
         for i:=0 to SymList.Count-1 do
         for i:=0 to SymList.Count-1 do
           begin
           begin
             if tsym(symlist[i]).typ=fieldvarsym then
             if tsym(symlist[i]).typ=fieldvarsym then
@@ -1144,6 +1151,11 @@ implementation
           end;
           end;
         _datasize:=storesize;
         _datasize:=storesize;
         fieldalignment:=storealign;
         fieldalignment:=storealign;
+        { If a record contains a union, it does not contain a "single
+          non-composite field" in the context of certain ABIs requiring
+          special treatment for such records }
+        if defowner.typ=recorddef then
+          trecorddef(defowner).isunion:=true;
       end;
       end;
 
 
 
 

+ 46 - 0
tests/tbs/tb0573.pp

@@ -0,0 +1,46 @@
+{$mode objfpc}
+
+type
+  tr1 = record
+    s: single;
+  end;
+
+  tr2 = record
+    case byte of
+      1: (s: single);
+  end;
+
+function f1(r1:tr1): tr1;
+var
+  s: single;
+begin
+  s:=r1.s;
+  result.s:=s;
+end;
+
+function f2(r2:tr2): tr2;
+var
+  s: single;
+begin
+  s:=r2.s;
+  result.s:=s;
+end;
+
+procedure test;
+var
+  r1,r1a: tr1;
+  r2,r2a: tr2;
+begin
+  r1.s:=1.0;
+  r2.s:=2.0;
+  r1a:=f1(r1);
+  r2a:=f2(r2);
+  if r1a.s<>1.0 then
+    halt(1);
+  if r2a.s<>2.0 then
+    halt(1);
+end;
+
+begin
+  test;
+end.