فهرست منبع

+ 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 سال پیش
والد
کامیت
9c22d594b0
8فایلهای تغییر یافته به همراه335 افزوده شده و 172 حذف شده
  1. 24 4
      compiler/i386/cpupara.pas
  2. 14 3
      compiler/ncgcal.pas
  3. 17 7
      compiler/ncgutil.pas
  4. 22 1
      compiler/parabase.pas
  5. 14 1
      compiler/paramgr.pas
  6. 87 23
      compiler/powerpc/cgcpu.pas
  7. 149 132
      compiler/powerpc/cpupara.pas
  8. 8 1
      compiler/sparc/cpupara.pas

+ 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