Przeglądaj źródła

+ support for passing records in registers under darwin
* tcgpara now also has an intsize field, which contains the size in
bytes of the whole parameter

Jonas Maebe 20 lat temu
rodzic
commit
9c22d594b0

+ 24 - 4
compiler/i386/cpupara.pas

@@ -192,6 +192,7 @@ unit cpupara;
       begin
         cgpara.reset;
         cgpara.size:=OS_INT;
+        cgpara.intsize:=tcgsize2size[OS_INT];
         cgpara.alignment:=get_para_align(calloption);
         paraloc:=cgpara.add_location;
         with paraloc^ do
@@ -313,12 +314,16 @@ unit cpupara;
           begin
             hp:=tparavarsym(paras[i]);
             if push_addr_param(hp.varspez,hp.vartype.def,p.proccalloption) then
-              paracgsize:=OS_ADDR
+              begin
+                paracgsize:=OS_ADDR;
+                hp.paraloc[side].intsize:=tcgsize2size[OS_ADDR];
+              end
             else
               begin
                 paracgsize:=def_cgSize(hp.vartype.def);
                 if paracgsize=OS_NO then
                   paracgsize:=OS_ADDR;
+                hp.paraloc[side].intsize := tcgsize2size[paracgsize];
               end;
             hp.paraloc[side].reset;
             hp.paraloc[side].size:=paracgsize;
@@ -388,9 +393,19 @@ unit cpupara;
             hp:=tparavarsym(paras[i]);
             pushaddr:=push_addr_param(hp.varspez,hp.vartype.def,p.proccalloption);
             if pushaddr then
-              paracgsize:=OS_ADDR
+              begin
+                paracgsize:=OS_ADDR;
+                hp.paraloc[side].intsize:=tcgsize2size[OS_ADDR];
+              end
             else
-              paracgsize:=def_cgsize(hp.vartype.def);
+              begin
+                paracgsize:=def_cgSize(hp.vartype.def);
+                hp.paraloc[side].intsize := hp.vartype.def.size;
+                if (hp.paraloc[side].intsize = 0) and
+                   { records can have size 0}
+                   (hp.vartype.def.deftype <> recorddef) then
+                  hp.paraloc[side].intsize := tcgsize2size[OS_ADDR];
+              end;
             is_64bit:=(paracgsize in [OS_64,OS_S64,OS_F64]);
             hp.paraloc[side].reset;
             hp.paraloc[side].size:=paracgsize;
@@ -514,7 +529,12 @@ begin
 end.
 {
   $Log$
-  Revision 1.60  2004-11-22 22:01:19  peter
+  Revision 1.61  2005-01-10 21:50:05  jonas
+    + support for passing records in registers under darwin
+    * tcgpara now also has an intsize field, which contains the size in
+      bytes of the whole parameter
+
+  Revision 1.60  2004/11/22 22:01:19  peter
     * fixed varargs
     * replaced dynarray with tlist
 

+ 14 - 3
compiler/ncgcal.pas

@@ -329,7 +329,8 @@ implementation
                 LOC_CREFERENCE :
                   begin
 {$ifndef cpu64bit}
-                    if left.location.size in [OS_64,OS_S64] then
+                    { don't call the cg64 stuff for 8-byte sized records etc }
+                    if is_64bit(left.resulttype.def) then
                       cg64.a_param64_loc(exprasmlist,left.location,tempcgpara)
                     else
 {$endif cpu64bit}
@@ -684,6 +685,7 @@ implementation
          ppn : tcgcallparanode;
          callerparaloc,
          tmpparaloc : pcgparalocation;
+         sizeleft: aint;
 {$ifdef cputargethasfixedstack}
          htempref,
          href : treference;
@@ -703,6 +705,7 @@ implementation
 {$endif PASS2INLINE}
                    paramanager.freeparaloc(exprasmlist,ppn.tempcgpara);
                  tmpparaloc:=ppn.tempcgpara.location;
+                 sizeleft:=ppn.tempcgpara.intsize;
                  callerparaloc:=ppn.parasym.paraloc[callerside].location;
                  while assigned(callerparaloc) do
                    begin
@@ -745,6 +748,8 @@ implementation
 {$endif PASS2INLINE}
                              begin
 {$ifdef cputargethasfixedstack}
+                               if (assigned(tmpparaloc^.next)) then
+                                 internalerror(20050111);
                                reference_reset_base(href,callerparaloc^.reference.index,callerparaloc^.reference.offset);
                                { copy parameters in case they were moved to a temp. location because we've a fixed stack }
                                case tmpparaloc^.loc of
@@ -753,7 +758,7 @@ implementation
                                      reference_reset_base(htempref,tmpparaloc^.reference.index,tmpparaloc^.reference.offset);
                                      { use concatcopy, because it can also be a float which fails when
                                        load_ref_ref is used }
-                                     cg.g_concatcopy(exprasmlist,htempref,href,tcgsize2size[tmpparaloc^.size]);
+                                     cg.g_concatcopy(exprasmlist,htempref,href,sizeleft);
                                    end;
                                  LOC_REGISTER:
                                    cg.a_load_reg_ref(exprasmlist,tmpparaloc^.size,tmpparaloc^.size,tmpparaloc^.register,href);
@@ -768,6 +773,7 @@ implementation
                              end;
                          end;
                      end;
+                     dec(sizeleft,tcgsize2size[tmpparaloc^.size]);
                      callerparaloc:=callerparaloc^.next;
                      tmpparaloc:=tmpparaloc^.next;
                    end;
@@ -1256,7 +1262,12 @@ begin
 end.
 {
   $Log$
-  Revision 1.193  2005-01-07 16:22:54  florian
+  Revision 1.194  2005-01-10 21:50:05  jonas
+    + support for passing records in registers under darwin
+    * tcgpara now also has an intsize field, which contains the size in
+      bytes of the whole parameter
+
+  Revision 1.193  2005/01/07 16:22:54  florian
     + implemented abi compliant handling of strucutured functions results on sparc platform
 
   Revision 1.192  2005/01/04 16:36:51  peter

+ 17 - 7
compiler/ncgutil.pas

@@ -1267,7 +1267,7 @@ implementation
          end;
 
 
-       procedure gen_load_ref(const paraloc:TCGParaLocation;const ref:treference);
+       procedure gen_load_ref(const paraloc:TCGParaLocation;const ref:treference;sizeleft:aint);
          var
            href : treference;
          begin
@@ -1284,7 +1284,7 @@ implementation
                   { use concatcopy, because it can also be a float which fails when
                     load_ref_ref is used. Don't copy data when the references are equal }
                   if not((href.base=ref.base) and (href.offset=ref.offset)) then
-                    cg.g_concatcopy(list,href,ref,tcgsize2size[paraloc.size]);
+                    cg.g_concatcopy(list,href,ref,sizeleft);
                 end;
               else
                 internalerror(2002081302);
@@ -1323,7 +1323,7 @@ implementation
          end;
 
       var
-        i : integer;
+        i, sizeleft : aint;
         currpara : tparavarsym;
         paraloc : pcgparalocation;
 {$ifdef sparc}
@@ -1339,6 +1339,7 @@ implementation
           begin
             currpara:=tparavarsym(current_procinfo.procdef.paras[i]);
             paraloc:=currpara.paraloc[calleeside].location;
+            sizeleft:=currpara.paraloc[calleeside].intsize;
             while assigned(paraloc) do
               begin
                 if paraloc^.loc in [LOC_REGISTER,LOC_FPUREGISTER,LOC_MMREGISTER] then
@@ -1352,6 +1353,7 @@ implementation
           begin
             currpara:=tparavarsym(current_procinfo.procdef.paras[i]);
             paraloc:=currpara.paraloc[calleeside].location;
+            sizeleft:=currpara.paraloc[calleeside].intsize;
             if not assigned(paraloc) then
               internalerror(200408203);
             case currpara.localloc.loc of
@@ -1361,8 +1363,9 @@ implementation
                   while assigned(paraloc) do
                     begin
                       unget_para(paraloc^);
-                      gen_load_ref(paraloc^,href);
+                      gen_load_ref(paraloc^,href,sizeleft);
                       inc(href.offset,TCGSize2Size[paraloc^.size]);
+                      dec(sizeleft,TCGSize2Size[paraloc^.size]);
                       paraloc:=paraloc^.next;
                     end;
                 end;
@@ -1422,13 +1425,15 @@ implementation
 {$ifdef sparc}
                   { Sparc passes floats in int registers, when loading to fpu register
                     we need a temp }
-                  tg.GetTemp(list,TCGSize2Size[currpara.localloc.size],tt_normal,tempref);
+                  sizeleft := TCGSize2Size[currpara.localloc.size];
+                  tg.GetTemp(list,sizeleft,tt_normal,tempref);
                   href:=tempref;
                   while assigned(paraloc) do
                     begin
                       unget_para(paraloc^);
-                      gen_load_ref(paraloc^,href);
+                      gen_load_ref(paraloc^,href,sizeleft);
                       inc(href.offset,TCGSize2Size[paraloc^.size]);
+                      dec(sizeleft,TCGSize2Size[paraloc^.size]);
                       paraloc:=paraloc^.next;
                     end;
                   cg.a_loadfpu_ref_reg(list,currpara.localloc.size,tempref,currpara.localloc.register);
@@ -2341,7 +2346,12 @@ implementation
 end.
 {
   $Log$
-  Revision 1.251  2005-01-03 22:27:56  peter
+  Revision 1.252  2005-01-10 21:50:05  jonas
+    + support for passing records in registers under darwin
+    * tcgpara now also has an intsize field, which contains the size in
+      bytes of the whole parameter
+
+  Revision 1.251  2005/01/03 22:27:56  peter
     * insert stack_check helper call before doing register allocation
       so the used registers can't be reused when parameters are loaded
       into register variables

+ 22 - 1
compiler/parabase.pas

@@ -54,6 +54,10 @@ unit parabase;
           Location  : PCGParalocation;
           Alignment : ShortInt;
           Size      : TCGSize;  { Size of the parameter included in all locations }
+          IntSize: aint; { size of the total location in bytes }
+{$ifdef powerpc}
+          composite: boolean; { under the AIX abi, how certain parameters are passed depends on whether they are composite or not }
+{$endif powerpc}
           constructor init;
           destructor  done;
           procedure   reset;
@@ -97,7 +101,11 @@ implementation
       begin
         alignment:=0;
         size:=OS_NO;
+        intsize:=0;
         location:=nil;
+{$ifdef powerpc}
+        composite:=false;
+{$endif powerpc}
       end;
 
 
@@ -119,6 +127,10 @@ implementation
           end;
         alignment:=0;
         size:=OS_NO;
+        intsize:=0;
+{$ifdef powerpc}
+        composite:=false;
+{$endif powerpc}
       end;
 
 
@@ -136,6 +148,10 @@ implementation
           end;
         result.alignment:=alignment;
         result.size:=size;
+        result.intsize:=intsize;
+{$ifdef powerpc}
+        result.composite:=composite;
+{$endif powerpc}
       end;
 
 
@@ -251,7 +267,12 @@ end.
 
 {
    $Log$
-   Revision 1.7  2005-01-07 16:22:54  florian
+   Revision 1.8  2005-01-10 21:50:05  jonas
+     + support for passing records in registers under darwin
+     * tcgpara now also has an intsize field, which contains the size in
+       bytes of the whole parameter
+
+   Revision 1.7  2005/01/07 16:22:54  florian
      + implemented abi compliant handling of strucutured functions results on sparc platform
 
    Revision 1.6  2004/11/22 22:01:19  peter

+ 14 - 1
compiler/paramgr.pas

@@ -379,7 +379,11 @@ implementation
       begin
         cgpara.reset;
         cgpara.size:=parasym.paraloc[callerside].size;
+        cgpara.intsize:=parasym.paraloc[callerside].intsize;
         cgpara.alignment:=parasym.paraloc[callerside].alignment;
+{$ifdef powerpc}
+        cgpara.composite:=parasym.paraloc[callerside].composite;
+{$endif powerpc}
         paraloc:=parasym.paraloc[callerside].location;
         while assigned(paraloc) do
           begin
@@ -423,7 +427,11 @@ implementation
       begin
         cgpara.reset;
         cgpara.size:=parasym.paraloc[callerside].size;
+        cgpara.intsize:=parasym.paraloc[callerside].intsize;
         cgpara.alignment:=parasym.paraloc[callerside].alignment;
+{$ifdef powerpc}
+        cgpara.composite:=parasym.paraloc[callerside].composite;
+{$endif powerpc}
         paraloc:=parasym.paraloc[callerside].location;
         while assigned(paraloc) do
           begin
@@ -451,7 +459,12 @@ end.
 
 {
    $Log$
-   Revision 1.82  2004-11-21 17:17:03  florian
+   Revision 1.83  2005-01-10 21:50:05  jonas
+     + support for passing records in registers under darwin
+     * tcgpara now also has an intsize field, which contains the size in
+       bytes of the whole parameter
+
+   Revision 1.82  2004/11/21 17:17:03  florian
      * changed funcret location back to tlocation
 
    Revision 1.81  2004/11/15 23:35:31  peter

+ 87 - 23
compiler/powerpc/cgcpu.pas

@@ -244,31 +244,90 @@ const
     procedure tcgppc.a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const paraloc : tcgpara);
 
       var
-        ref: treference;
-        tmpreg: tregister;
+        tmpref, ref: treference;
+        location: pcgparalocation;
+        sizeleft: aint;
 
       begin
-        paraloc.check_simple_location;
-        case paraloc.location^.loc of
-          LOC_REGISTER,LOC_CREGISTER:
-            a_load_ref_reg(list,size,size,r,paraloc.location^.register);
-          LOC_REFERENCE:
-            begin
-               reference_reset_base(ref,paraloc.location^.reference.index,paraloc.location^.reference.offset);
-               tmpreg := rg[R_INTREGISTER].getregister(list,R_SUBWHOLE);
-               a_load_ref_reg(list,size,size,r,tmpreg);
-               a_load_reg_ref(list,size,size,tmpreg,ref);
-            end;
-          LOC_FPUREGISTER,LOC_CFPUREGISTER:
-            case size of
-               OS_F32, OS_F64:
-                 a_loadfpu_ref_reg(list,size,r,paraloc.location^.register);
-               else
-                 internalerror(2002072801);
+        location := paraloc.location;
+        tmpref := r;
+        sizeleft := paraloc.intsize;
+        while assigned(location) do
+          begin
+            case location^.loc of
+              LOC_REGISTER,LOC_CREGISTER:
+                begin
+{$ifndef cpu64bit}
+                  if (sizeleft <> 3) then
+                    begin
+                      a_load_ref_reg(list,location^.size,location^.size,tmpref,location^.register);
+                      { the following is only for AIX abi systems, but the }
+                      { conditions should never be true for SYSV (if they  }
+                      { are, there is a bug in cpupara)                    }
+                      
+                      { update: this doesn't work yet (we have to shift     }
+                      { right again in ncgutil when storing the parameters, }
+                      { and additionally Apple's documentation seems to be  }
+                      { wrong, in that these values are always kept in the  }
+                      { lower bytes of the registers                        }
+                      
+{
+                      if (paraloc.composite) and
+                         (sizeleft <= 2) and
+                         ((paraloc.intsize > 4) or
+                          (target_info.system <> system_powerpc_darwin)) then
+                        begin
+                          case sizeleft of
+                            1:
+                              a_op_const_reg(list,OP_SHL,OS_INT,24,location^.register);
+                            2:
+                              a_op_const_reg(list,OP_SHL,OS_INT,16,location^.register);
+                            else
+                              internalerror(2005010910);
+                          end;
+                        end;
+}
+                    end
+                  else
+                    begin
+                      a_load_ref_reg(list,OS_16,OS_16,tmpref,location^.register);
+                      a_reg_alloc(list,NR_R0);
+                      inc(tmpref.offset,2);
+                      a_load_ref_reg(list,OS_8,OS_8,tmpref,newreg(R_INTREGISTER,RS_R0,R_SUBNONE));
+                      a_op_const_reg(list,OP_SHL,OS_INT,16,location^.register);
+                      list.concat(taicpu.op_reg_reg_const_const_const(A_RLWIMI,location^.register,newreg(R_INTREGISTER,RS_R0,R_SUBNONE),8,16,31-8));
+                      a_reg_dealloc(list,NR_R0);
+                      dec(tmpref.offset,2);
+                    end;
+{$else not cpu64bit}
+{$error add 64 bit support for non power of 2 loads in a_param_ref}
+{$endif not cpu64bit}
+                end;
+              LOC_REFERENCE:
+                begin
+                   reference_reset_base(ref,location^.reference.index,location^.reference.offset);
+                   g_concatcopy(list,tmpref,ref,sizeleft);
+                   if assigned(location^.next) then
+                     internalerror(2005010710);
+                end;
+              LOC_FPUREGISTER,LOC_CFPUREGISTER:
+                case location^.size of
+                   OS_F32, OS_F64:
+                     a_loadfpu_ref_reg(list,location^.size,tmpref,location^.register);
+                   else
+                     internalerror(2002072801);
+                end;
+              LOC_VOID:
+                begin
+                  // nothing to do
+                end;
+              else
+                internalerror(2002081103);
             end;
-          else
-            internalerror(2002081103);
-        end;
+            inc(tmpref.offset,tcgsize2size[location^.size]);
+            dec(sizeleft,tcgsize2size[location^.size]);
+            location := location^.next;
+          end;
       end;
 
 
@@ -2299,7 +2358,12 @@ begin
 end.
 {
   $Log$
-  Revision 1.190  2005-01-05 19:01:53  karoly
+  Revision 1.191  2005-01-10 21:50:05  jonas
+    + support for passing records in registers under darwin
+    * tcgpara now also has an intsize field, which contains the size in
+      bytes of the whole parameter
+
+  Revision 1.190  2005/01/05 19:01:53  karoly
     * sysv abi also uses F0-F13 as volatile registers
 
   Revision 1.189  2004/12/24 11:51:55  jonas

+ 149 - 132
compiler/powerpc/cpupara.pas

@@ -42,8 +42,9 @@ unit cpupara;
           procedure getintparaloc(calloption : tproccalloption; nr : longint;var cgpara:TCGPara);override;
           function create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;override;
           function create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;override;
-
           procedure create_funcretloc_info(p : tabstractprocdef; side: tcallercallee);
+         
+//          function copy_value_on_stack(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean; override;
          private
           procedure init_values(var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword);
           function create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras:tparalist;
@@ -86,6 +87,7 @@ unit cpupara;
       begin
         cgpara.reset;
         cgpara.size:=OS_INT;
+        cgpara.intsize:=tcgsize2size[OS_INT];
         cgpara.alignment:=get_para_align(calloption);
         paraloc:=cgpara.add_location;
         with paraloc^ do
@@ -102,7 +104,10 @@ unit cpupara;
              begin
                loc:=LOC_REFERENCE;
                paraloc^.reference.index:=NR_STACK_POINTER_REG;
-               reference.offset:=sizeof(aint)*(nr-8);
+               if (target_info.abi <> abi_powerpc_aix) then
+                 reference.offset:=sizeof(aint)*(nr-8)
+               else
+                 reference.offset:=sizeof(aint)*(nr);
              end;
           end;
       end;
@@ -129,7 +134,10 @@ unit cpupara;
             classrefdef:
               result:=LOC_REGISTER;
             recorddef:
-              result:=LOC_REFERENCE;
+              if (target_info.abi<>abi_powerpc_aix) then
+                result:=LOC_REFERENCE
+              else
+                result:=LOC_REGISTER;
             objectdef:
               if is_object(p) then
                 result:=LOC_REFERENCE
@@ -166,8 +174,6 @@ unit cpupara;
 
 
     function tppcparamanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
-      var
-        size, dummy: aint;
       begin
         { var,out always require address }
         if varspez in [vs_var,vs_out] then
@@ -177,18 +183,7 @@ unit cpupara;
           end;
         case def.deftype of
           recorddef:
-            begin
-              if (target_info.abi = abi_powerpc_aix) then
-                begin
-                  // all records should be passed by value under the aix abi,
-                  // but we can only fake this for 1, 2 and 4 bytes for now
-                  size := def.size;
-                  result := (size > 4) or
-                            not(byte(size) in [1,2,4]);
-                end
-              else
-                result := true;
-            end;
+            result :=(target_info.abi<>abi_powerpc_aix);
           arraydef:
             result:=(tarraydef(def).highrange>=tarraydef(def).lowrange) or
                              is_open_array(def) or
@@ -221,6 +216,14 @@ unit cpupara;
         curmmreg:=RS_M1;
       end;
 
+{
+    function tppcparamanager.copy_value_on_stack(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
+      begin
+        result := false;
+        if (target_info.abi <> abi_powerpc_aix) then
+          result := inherited copy_value_on_stack(varspez,def,calloption);
+      end;
+}
 
     procedure tppcparamanager.create_funcretloc_info(p : tabstractprocdef; side: tcallercallee);
       var
@@ -304,7 +307,8 @@ unit cpupara;
     function tppcparamanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras:tparalist;
                var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword):longint;
       var
-         stack_offset: aword;
+         stack_offset, parasize: longint;
+         paralen: aint;
          nextintreg,nextfloatreg,nextmmreg, maxfpureg : tsuperregister;
          paradef : tdef;
          paraloc,paraloc2 : pcgparalocation;
@@ -312,8 +316,9 @@ unit cpupara;
          hp : tparavarsym;
          loc : tcgloc;
          paracgsize: tcgsize;
-         is_64bit: boolean;
+         def64bit: boolean;
 
+(*
       procedure assignintreg;
 
         begin
@@ -336,6 +341,7 @@ unit cpupara;
                 inc(stack_offset,4);
             end;
         end;
+*)
 
       begin
 {$ifdef extdebug}
@@ -348,6 +354,7 @@ unit cpupara;
          nextfloatreg := curfloatreg;
          nextmmreg := curmmreg;
          stack_offset := cur_stack_offset;
+         parasize := cur_stack_offset;
          case target_info.abi of
            abi_powerpc_aix:
              maxfpureg := RS_F13;
@@ -359,6 +366,7 @@ unit cpupara;
           for i:=0 to paras.count-1 do
             begin
               hp:=tparavarsym(paras[i]);
+              paradef := hp.vartype.def;
               { Syscall for Morphos can have already a paraloc set }
               if (vo_has_explicit_paraloc in hp.varoptions) then
                 begin
@@ -369,7 +377,7 @@ unit cpupara;
               hp.paraloc[side].reset;
               { currently only support C-style array of const }
               if (p.proccalloption in [pocall_cdecl,pocall_cppdecl]) and
-                 is_array_of_const(hp.vartype.def) then
+                 is_array_of_const(paradef) then
                 begin
                   paraloc:=hp.paraloc[side].add_location;
                   { hack: the paraloc must be valid, but is not actually used }
@@ -379,146 +387,144 @@ unit cpupara;
                   break;
                 end;
 
-              if (hp.varspez in [vs_var,vs_out]) then
+              if (hp.varspez in [vs_var,vs_out]) or
+                 push_addr_param(hp.varspez,paradef,p.proccalloption) or
+                 is_open_array(paradef) or
+                 is_array_of_const(paradef) then
                 begin
                   paradef:=voidpointertype.def;
                   loc:=LOC_REGISTER;
                   paracgsize := OS_ADDR;
+                  paralen := tcgsize2size[OS_ADDR];
                 end
               else
                 begin
-                  paradef := hp.vartype.def;
-                  loc:=getparaloc(paradef);
-                  if (hp.vartype.def.deftype = recorddef) and
-                     (target_info.abi = abi_powerpc_aix) and
-                     (hp.vartype.def.size <= 4) and
-                     (byte(hp.vartype.def.size) in [1,2,4]) then
+                  if not is_special_array(paradef) then
+                    paralen := paradef.size
+                  else
+                    paralen := tcgsize2size[def_cgsize(paradef)];
+                  if (target_info.abi = abi_powerpc_aix) and 
+                     (paradef.deftype = recorddef) and
+                     (hp.varspez in [vs_value,vs_const]) then
                     begin
-                      loc := LOC_REGISTER;
-                      paracgsize := def_cgsize(paradef);
+                      { if a record has only one field and that field is }
+                      { non-composite (not array or record), it must be  }
+                      { passed according to the rules of that type.       }
+                      if (trecorddef(hp.vartype.def).symtable.symindex.count = 1) and
+                         ((tabstractvarsym(trecorddef(hp.vartype.def).symtable.symindex.search(1)).vartype.def.deftype = floatdef) or
+                          ((target_info.system = system_powerpc_darwin) and
+                           (tabstractvarsym(trecorddef(hp.vartype.def).symtable.symindex.search(1)).vartype.def.deftype in [orddef,enumdef]))) then
+                        begin
+                          paradef :=
+                           tabstractvarsym(trecorddef(hp.vartype.def).symtable.symindex.search(1)).vartype.def;
+                          loc := getparaloc(paradef);
+                          paracgsize:=def_cgsize(paradef);
+                        end
+                      else
+                        begin
+                          loc := LOC_REGISTER;
+                          paracgsize := int_cgsize(paralen);
+                        end;
                     end
                   else
                     begin
+                      loc:=getparaloc(paradef);
                       paracgsize:=def_cgsize(paradef);
                       { for things like formaldef }
-                      if paracgsize=OS_NO then
-                        paracgsize:=OS_ADDR;
-                   end
+                      if (paracgsize=OS_NO) then
+                        begin
+                          paracgsize:=OS_ADDR;
+                          paralen := tcgsize2size[OS_ADDR];
+                        end;
+                    end
                 end;
               hp.paraloc[side].alignment:=std_param_align;
               hp.paraloc[side].size:=paracgsize;
-              { First location }
-              paraloc:=hp.paraloc[side].add_location;
-              paraloc^.size:=paracgsize;
-              case loc of
-                 LOC_REGISTER:
-                   begin
-                      is_64bit:=paraloc^.size in [OS_64,OS_S64];
-                      if nextintreg<=(RS_R10-ord(is_64bit))  then
-                        begin
-                           paraloc^.loc:=LOC_REGISTER;
+              hp.paraloc[side].intsize:=paralen;
+              if (target_info.abi = abi_powerpc_aix) and
+                 (paradef.deftype = recorddef) then
+                hp.paraloc[side].composite:=true;
 {$ifndef cpu64bit}
-                           if is_64bit then
-                             begin
-                               if odd(nextintreg-RS_R3) and (target_info.abi=abi_powerpc_sysv) Then
-                                 inc(nextintreg);
-                               paraloc^.size:=OS_32;
-                               paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBNONE);
-                               inc(nextintreg);
-                               paraloc2:=hp.paraloc[side].add_location;
-                               paraloc2^.loc:=LOC_REGISTER;
-                               paraloc2^.size:=OS_32;
-                               paraloc2^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBNONE);
-                               inc(nextintreg);
-                               if target_info.abi=abi_powerpc_aix then
-                                 inc(stack_offset,8);
-                             end
-                           else
-{$endif cpu64bit}
-                             begin
-                               paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBNONE);
-                               inc(nextintreg);
-                               if target_info.abi=abi_powerpc_aix then
-                                 inc(stack_offset,sizeof(aword));
-                              end;
-                        end
+              if (target_info.abi=abi_powerpc_sysv) and
+                 is_64bit(paradef) and
+                 odd(nextintreg-RS_R3) then
+                inc(nextintreg);
+{$endif not cpu64bit}
+              { can become < 0 for e.g. 3-byte records }
+              while (paralen > 0) do
+                begin
+                  paraloc:=hp.paraloc[side].add_location;
+                  if (loc = LOC_REGISTER) and
+                     (nextintreg <= RS_R10) then
+                    begin
+                      paraloc^.loc := loc;
+                      paracgsize := int_cgsize(paralen);
+                      if (paracgsize in [OS_NO,OS_64,OS_S64]) then
+                        paraloc^.size := OS_INT
                       else
-                         begin
-                            nextintreg:=RS_R11;
-                            paraloc^.loc:=LOC_REFERENCE;
-                            if (side = callerside) then
-                              paraloc^.reference.index:=NR_STACK_POINTER_REG
-                            else
-                              paraloc^.reference.index:=NR_R12;
-                            paraloc^.reference.offset:=stack_offset;
-                            if not is_64bit then
-                              inc(stack_offset,4)
-                            else
-                              inc(stack_offset,8);
-                        end;
-                   end;
-                 LOC_FPUREGISTER:
-                   begin
-                      if nextfloatreg<=maxfpureg then
+                        paraloc^.size := paracgsize;
+                      paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBNONE);
+                      inc(nextintreg);
+                      dec(paralen,tcgsize2size[paraloc^.size]);
+                      inc(parasize,tcgsize2size[paraloc^.size]);
+                      if target_info.abi=abi_powerpc_aix then
+                        stack_offset := parasize;
+                    end
+                  else if (loc = LOC_FPUREGISTER) and
+                          (nextfloatreg <= maxfpureg) then
+                    begin
+                      paraloc^.loc:=loc;
+                      paraloc^.size := paracgsize;
+                      paraloc^.register:=newreg(R_FPUREGISTER,nextfloatreg,R_SUBWHOLE);
+                      inc(nextfloatreg);
+                      dec(paralen,tcgsize2size[paraloc^.size]);
+                      { if nextfpureg > maxfpureg, all intregs are already used, since there }
+                      { are less of those available for parameter passing in the AIX abi     }
+{$ifndef cpu64bit}
+                      if (paracgsize = OS_F32) then
                         begin
-                           paraloc^.loc:=LOC_FPUREGISTER;
-                           paraloc^.register:=newreg(R_FPUREGISTER,nextfloatreg,R_SUBWHOLE);
-                           inc(nextfloatreg);
+                          inc(parasize,4);
+                          if (nextintreg < RS_R11) then
+                            inc(nextintreg);
                         end
                       else
-                         begin
-                            paraloc^.loc:=LOC_REFERENCE;
-                            if (side = callerside) then
-                              paraloc^.reference.index:=NR_STACK_POINTER_REG
-                            else
-                              paraloc^.reference.index:=NR_R12;
-                            paraloc^.reference.offset:=stack_offset;
-                        end;
-                      if target_info.abi=abi_powerpc_aix then
                         begin
-                          if paraloc^.size = OS_F32 then
-                            begin
-                              inc(stack_offset,4);
-                              if (nextintreg < RS_R11) then
-                                inc(nextintreg);
-                            end
+                          inc(parasize,8);
+                          if (nextintreg < RS_R10) then
+                            inc(nextintreg,2)
                           else
-                            begin
-                              inc(stack_offset,8);
-                              if (nextintreg < RS_R10) then
-                                inc(nextintreg,2)
-                              else
-                                nextintreg := RS_R11;
-                            end;
+                            nextintreg := RS_R11;
                         end;
-                   end;
-                 LOC_REFERENCE:
-                   begin
-                      paraloc^.size:=OS_ADDR;
-                      if push_addr_param(hp.varspez,paradef,p.proccalloption) or
-                        is_open_array(paradef) or
-                        is_array_of_const(paradef) then
-                        assignintreg
-                      else
+{$else not cpu64bit}
                         begin
-                           paraloc^.loc:=LOC_REFERENCE;
-                           if (side = callerside) then
-                             paraloc^.reference.index:=NR_STACK_POINTER_REG
-                           else
-                             paraloc^.reference.index:=NR_R12;
-                           paraloc^.reference.offset:=stack_offset;
-                           inc(stack_offset,hp.vartype.def.size);
+                          inc(parasize,tcgsize2size[paracgsize]);
+                          if (nextintreg < RS_R11) then
+                            inc(nextintreg);
                         end;
-                   end;
-                 else
-                   internalerror(2002071002);
-              end;
-           end;
+{$endif not cpu64bit}
+                      if target_info.abi=abi_powerpc_aix then
+                        stack_offset := parasize;
+                    end
+                  else { LOC_REFERENCE }
+                    begin
+                       paraloc^.loc:=LOC_REFERENCE;
+                       paraloc^.size:=int_cgsize(paralen);
+                       if (side = callerside) then
+                         paraloc^.reference.index:=NR_STACK_POINTER_REG
+                       else
+                         paraloc^.reference.index:=NR_R12;
+                       paraloc^.reference.offset:=stack_offset;
+                       inc(stack_offset,align(paralen,4));
+                       inc(parasize,align(paralen,4));
+                       paralen := 0;
+                    end;
+                end;
+            end;
          curintreg:=nextintreg;
          curfloatreg:=nextfloatreg;
          curmmreg:=nextmmreg;
          cur_stack_offset:=stack_offset;
-         result:=cur_stack_offset;
+         result:=parasize;
       end;
 
 
@@ -537,7 +543,13 @@ unit cpupara;
         result:=create_paraloc_info_intern(p,callerside,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset);
         if (p.proccalloption in [pocall_cdecl,pocall_cppdecl]) then
           { just continue loading the parameters in the registers }
-          result:=create_paraloc_info_intern(p,callerside,varargspara,curintreg,curfloatreg,curmmreg,cur_stack_offset)
+          begin
+            result:=create_paraloc_info_intern(p,callerside,varargspara,curintreg,curfloatreg,curmmreg,cur_stack_offset);
+            { varargs routines have to reserve at least 32 bytes for the AIX abi }
+            if (target_info.abi = abi_powerpc_aix) and
+               (result < 32) then
+              result := 32;
+           end
         else
           begin
             parasize:=cur_stack_offset;
@@ -637,7 +649,12 @@ begin
 end.
 {
   $Log$
-  Revision 1.80  2005-01-07 10:58:03  jonas
+  Revision 1.81  2005-01-10 21:50:05  jonas
+    + support for passing records in registers under darwin
+    * tcgpara now also has an intsize field, which contains the size in
+      bytes of the whole parameter
+
+  Revision 1.80  2005/01/07 10:58:03  jonas
     * fixed stupid tregister/tsuperregister bug (type checking circumvented
       using explicit typecase), caused bug3523
 

+ 8 - 1
compiler/sparc/cpupara.pas

@@ -84,6 +84,7 @@ implementation
           InternalError(2002100806);
         cgpara.reset;
         cgpara.size:=OS_INT;
+        cgpara.intsize:=tcgsize2size[OS_INT];
         cgpara.alignment:=std_param_align;
         paraloc:=cgpara.add_location;
         with paraloc^ do
@@ -249,6 +250,7 @@ implementation
             hp.paraloc[side].size:=paracgsize;
             hp.paraloc[side].Alignment:=std_param_align;
             paralen:=tcgsize2size[paracgsize];
+            hp.paraloc[side].intsize:=paralen;
             while paralen>0 do
               begin
                 paraloc:=hp.paraloc[side].add_location;
@@ -327,7 +329,12 @@ begin
 end.
 {
   $Log$
-  Revision 1.52  2005-01-07 16:22:54  florian
+  Revision 1.53  2005-01-10 21:50:05  jonas
+    + support for passing records in registers under darwin
+    * tcgpara now also has an intsize field, which contains the size in
+      bytes of the whole parameter
+
+  Revision 1.52  2005/01/07 16:22:54  florian
     + implemented abi compliant handling of strucutured functions results on sparc platform
 
   Revision 1.51  2004/11/22 22:01:19  peter