浏览代码

+ 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
       begin
         cgpara.reset;
         cgpara.reset;
         cgpara.size:=OS_INT;
         cgpara.size:=OS_INT;
+        cgpara.intsize:=tcgsize2size[OS_INT];
         cgpara.alignment:=get_para_align(calloption);
         cgpara.alignment:=get_para_align(calloption);
         paraloc:=cgpara.add_location;
         paraloc:=cgpara.add_location;
         with paraloc^ do
         with paraloc^ do
@@ -313,12 +314,16 @@ unit cpupara;
           begin
           begin
             hp:=tparavarsym(paras[i]);
             hp:=tparavarsym(paras[i]);
             if push_addr_param(hp.varspez,hp.vartype.def,p.proccalloption) then
             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
             else
               begin
               begin
                 paracgsize:=def_cgSize(hp.vartype.def);
                 paracgsize:=def_cgSize(hp.vartype.def);
                 if paracgsize=OS_NO then
                 if paracgsize=OS_NO then
                   paracgsize:=OS_ADDR;
                   paracgsize:=OS_ADDR;
+                hp.paraloc[side].intsize := tcgsize2size[paracgsize];
               end;
               end;
             hp.paraloc[side].reset;
             hp.paraloc[side].reset;
             hp.paraloc[side].size:=paracgsize;
             hp.paraloc[side].size:=paracgsize;
@@ -388,9 +393,19 @@ unit cpupara;
             hp:=tparavarsym(paras[i]);
             hp:=tparavarsym(paras[i]);
             pushaddr:=push_addr_param(hp.varspez,hp.vartype.def,p.proccalloption);
             pushaddr:=push_addr_param(hp.varspez,hp.vartype.def,p.proccalloption);
             if pushaddr then
             if pushaddr then
-              paracgsize:=OS_ADDR
+              begin
+                paracgsize:=OS_ADDR;
+                hp.paraloc[side].intsize:=tcgsize2size[OS_ADDR];
+              end
             else
             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]);
             is_64bit:=(paracgsize in [OS_64,OS_S64,OS_F64]);
             hp.paraloc[side].reset;
             hp.paraloc[side].reset;
             hp.paraloc[side].size:=paracgsize;
             hp.paraloc[side].size:=paracgsize;
@@ -514,7 +529,12 @@ begin
 end.
 end.
 {
 {
   $Log$
   $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
     * fixed varargs
     * replaced dynarray with tlist
     * replaced dynarray with tlist
 
 

+ 14 - 3
compiler/ncgcal.pas

@@ -329,7 +329,8 @@ implementation
                 LOC_CREFERENCE :
                 LOC_CREFERENCE :
                   begin
                   begin
 {$ifndef cpu64bit}
 {$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)
                       cg64.a_param64_loc(exprasmlist,left.location,tempcgpara)
                     else
                     else
 {$endif cpu64bit}
 {$endif cpu64bit}
@@ -684,6 +685,7 @@ implementation
          ppn : tcgcallparanode;
          ppn : tcgcallparanode;
          callerparaloc,
          callerparaloc,
          tmpparaloc : pcgparalocation;
          tmpparaloc : pcgparalocation;
+         sizeleft: aint;
 {$ifdef cputargethasfixedstack}
 {$ifdef cputargethasfixedstack}
          htempref,
          htempref,
          href : treference;
          href : treference;
@@ -703,6 +705,7 @@ implementation
 {$endif PASS2INLINE}
 {$endif PASS2INLINE}
                    paramanager.freeparaloc(exprasmlist,ppn.tempcgpara);
                    paramanager.freeparaloc(exprasmlist,ppn.tempcgpara);
                  tmpparaloc:=ppn.tempcgpara.location;
                  tmpparaloc:=ppn.tempcgpara.location;
+                 sizeleft:=ppn.tempcgpara.intsize;
                  callerparaloc:=ppn.parasym.paraloc[callerside].location;
                  callerparaloc:=ppn.parasym.paraloc[callerside].location;
                  while assigned(callerparaloc) do
                  while assigned(callerparaloc) do
                    begin
                    begin
@@ -745,6 +748,8 @@ implementation
 {$endif PASS2INLINE}
 {$endif PASS2INLINE}
                              begin
                              begin
 {$ifdef cputargethasfixedstack}
 {$ifdef cputargethasfixedstack}
+                               if (assigned(tmpparaloc^.next)) then
+                                 internalerror(20050111);
                                reference_reset_base(href,callerparaloc^.reference.index,callerparaloc^.reference.offset);
                                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 }
                                { copy parameters in case they were moved to a temp. location because we've a fixed stack }
                                case tmpparaloc^.loc of
                                case tmpparaloc^.loc of
@@ -753,7 +758,7 @@ implementation
                                      reference_reset_base(htempref,tmpparaloc^.reference.index,tmpparaloc^.reference.offset);
                                      reference_reset_base(htempref,tmpparaloc^.reference.index,tmpparaloc^.reference.offset);
                                      { use concatcopy, because it can also be a float which fails when
                                      { use concatcopy, because it can also be a float which fails when
                                        load_ref_ref is used }
                                        load_ref_ref is used }
-                                     cg.g_concatcopy(exprasmlist,htempref,href,tcgsize2size[tmpparaloc^.size]);
+                                     cg.g_concatcopy(exprasmlist,htempref,href,sizeleft);
                                    end;
                                    end;
                                  LOC_REGISTER:
                                  LOC_REGISTER:
                                    cg.a_load_reg_ref(exprasmlist,tmpparaloc^.size,tmpparaloc^.size,tmpparaloc^.register,href);
                                    cg.a_load_reg_ref(exprasmlist,tmpparaloc^.size,tmpparaloc^.size,tmpparaloc^.register,href);
@@ -768,6 +773,7 @@ implementation
                              end;
                              end;
                          end;
                          end;
                      end;
                      end;
+                     dec(sizeleft,tcgsize2size[tmpparaloc^.size]);
                      callerparaloc:=callerparaloc^.next;
                      callerparaloc:=callerparaloc^.next;
                      tmpparaloc:=tmpparaloc^.next;
                      tmpparaloc:=tmpparaloc^.next;
                    end;
                    end;
@@ -1256,7 +1262,12 @@ begin
 end.
 end.
 {
 {
   $Log$
   $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
     + implemented abi compliant handling of strucutured functions results on sparc platform
 
 
   Revision 1.192  2005/01/04 16:36:51  peter
   Revision 1.192  2005/01/04 16:36:51  peter

+ 17 - 7
compiler/ncgutil.pas

@@ -1267,7 +1267,7 @@ implementation
          end;
          end;
 
 
 
 
-       procedure gen_load_ref(const paraloc:TCGParaLocation;const ref:treference);
+       procedure gen_load_ref(const paraloc:TCGParaLocation;const ref:treference;sizeleft:aint);
          var
          var
            href : treference;
            href : treference;
          begin
          begin
@@ -1284,7 +1284,7 @@ implementation
                   { use concatcopy, because it can also be a float which fails when
                   { 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 }
                     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
                   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;
                 end;
               else
               else
                 internalerror(2002081302);
                 internalerror(2002081302);
@@ -1323,7 +1323,7 @@ implementation
          end;
          end;
 
 
       var
       var
-        i : integer;
+        i, sizeleft : aint;
         currpara : tparavarsym;
         currpara : tparavarsym;
         paraloc : pcgparalocation;
         paraloc : pcgparalocation;
 {$ifdef sparc}
 {$ifdef sparc}
@@ -1339,6 +1339,7 @@ implementation
           begin
           begin
             currpara:=tparavarsym(current_procinfo.procdef.paras[i]);
             currpara:=tparavarsym(current_procinfo.procdef.paras[i]);
             paraloc:=currpara.paraloc[calleeside].location;
             paraloc:=currpara.paraloc[calleeside].location;
+            sizeleft:=currpara.paraloc[calleeside].intsize;
             while assigned(paraloc) do
             while assigned(paraloc) do
               begin
               begin
                 if paraloc^.loc in [LOC_REGISTER,LOC_FPUREGISTER,LOC_MMREGISTER] then
                 if paraloc^.loc in [LOC_REGISTER,LOC_FPUREGISTER,LOC_MMREGISTER] then
@@ -1352,6 +1353,7 @@ implementation
           begin
           begin
             currpara:=tparavarsym(current_procinfo.procdef.paras[i]);
             currpara:=tparavarsym(current_procinfo.procdef.paras[i]);
             paraloc:=currpara.paraloc[calleeside].location;
             paraloc:=currpara.paraloc[calleeside].location;
+            sizeleft:=currpara.paraloc[calleeside].intsize;
             if not assigned(paraloc) then
             if not assigned(paraloc) then
               internalerror(200408203);
               internalerror(200408203);
             case currpara.localloc.loc of
             case currpara.localloc.loc of
@@ -1361,8 +1363,9 @@ implementation
                   while assigned(paraloc) do
                   while assigned(paraloc) do
                     begin
                     begin
                       unget_para(paraloc^);
                       unget_para(paraloc^);
-                      gen_load_ref(paraloc^,href);
+                      gen_load_ref(paraloc^,href,sizeleft);
                       inc(href.offset,TCGSize2Size[paraloc^.size]);
                       inc(href.offset,TCGSize2Size[paraloc^.size]);
+                      dec(sizeleft,TCGSize2Size[paraloc^.size]);
                       paraloc:=paraloc^.next;
                       paraloc:=paraloc^.next;
                     end;
                     end;
                 end;
                 end;
@@ -1422,13 +1425,15 @@ implementation
 {$ifdef sparc}
 {$ifdef sparc}
                   { Sparc passes floats in int registers, when loading to fpu register
                   { Sparc passes floats in int registers, when loading to fpu register
                     we need a temp }
                     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;
                   href:=tempref;
                   while assigned(paraloc) do
                   while assigned(paraloc) do
                     begin
                     begin
                       unget_para(paraloc^);
                       unget_para(paraloc^);
-                      gen_load_ref(paraloc^,href);
+                      gen_load_ref(paraloc^,href,sizeleft);
                       inc(href.offset,TCGSize2Size[paraloc^.size]);
                       inc(href.offset,TCGSize2Size[paraloc^.size]);
+                      dec(sizeleft,TCGSize2Size[paraloc^.size]);
                       paraloc:=paraloc^.next;
                       paraloc:=paraloc^.next;
                     end;
                     end;
                   cg.a_loadfpu_ref_reg(list,currpara.localloc.size,tempref,currpara.localloc.register);
                   cg.a_loadfpu_ref_reg(list,currpara.localloc.size,tempref,currpara.localloc.register);
@@ -2341,7 +2346,12 @@ implementation
 end.
 end.
 {
 {
   $Log$
   $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
     * insert stack_check helper call before doing register allocation
       so the used registers can't be reused when parameters are loaded
       so the used registers can't be reused when parameters are loaded
       into register variables
       into register variables

+ 22 - 1
compiler/parabase.pas

@@ -54,6 +54,10 @@ unit parabase;
           Location  : PCGParalocation;
           Location  : PCGParalocation;
           Alignment : ShortInt;
           Alignment : ShortInt;
           Size      : TCGSize;  { Size of the parameter included in all locations }
           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;
           constructor init;
           destructor  done;
           destructor  done;
           procedure   reset;
           procedure   reset;
@@ -97,7 +101,11 @@ implementation
       begin
       begin
         alignment:=0;
         alignment:=0;
         size:=OS_NO;
         size:=OS_NO;
+        intsize:=0;
         location:=nil;
         location:=nil;
+{$ifdef powerpc}
+        composite:=false;
+{$endif powerpc}
       end;
       end;
 
 
 
 
@@ -119,6 +127,10 @@ implementation
           end;
           end;
         alignment:=0;
         alignment:=0;
         size:=OS_NO;
         size:=OS_NO;
+        intsize:=0;
+{$ifdef powerpc}
+        composite:=false;
+{$endif powerpc}
       end;
       end;
 
 
 
 
@@ -136,6 +148,10 @@ implementation
           end;
           end;
         result.alignment:=alignment;
         result.alignment:=alignment;
         result.size:=size;
         result.size:=size;
+        result.intsize:=intsize;
+{$ifdef powerpc}
+        result.composite:=composite;
+{$endif powerpc}
       end;
       end;
 
 
 
 
@@ -251,7 +267,12 @@ end.
 
 
 {
 {
    $Log$
    $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
      + implemented abi compliant handling of strucutured functions results on sparc platform
 
 
    Revision 1.6  2004/11/22 22:01:19  peter
    Revision 1.6  2004/11/22 22:01:19  peter

+ 14 - 1
compiler/paramgr.pas

@@ -379,7 +379,11 @@ implementation
       begin
       begin
         cgpara.reset;
         cgpara.reset;
         cgpara.size:=parasym.paraloc[callerside].size;
         cgpara.size:=parasym.paraloc[callerside].size;
+        cgpara.intsize:=parasym.paraloc[callerside].intsize;
         cgpara.alignment:=parasym.paraloc[callerside].alignment;
         cgpara.alignment:=parasym.paraloc[callerside].alignment;
+{$ifdef powerpc}
+        cgpara.composite:=parasym.paraloc[callerside].composite;
+{$endif powerpc}
         paraloc:=parasym.paraloc[callerside].location;
         paraloc:=parasym.paraloc[callerside].location;
         while assigned(paraloc) do
         while assigned(paraloc) do
           begin
           begin
@@ -423,7 +427,11 @@ implementation
       begin
       begin
         cgpara.reset;
         cgpara.reset;
         cgpara.size:=parasym.paraloc[callerside].size;
         cgpara.size:=parasym.paraloc[callerside].size;
+        cgpara.intsize:=parasym.paraloc[callerside].intsize;
         cgpara.alignment:=parasym.paraloc[callerside].alignment;
         cgpara.alignment:=parasym.paraloc[callerside].alignment;
+{$ifdef powerpc}
+        cgpara.composite:=parasym.paraloc[callerside].composite;
+{$endif powerpc}
         paraloc:=parasym.paraloc[callerside].location;
         paraloc:=parasym.paraloc[callerside].location;
         while assigned(paraloc) do
         while assigned(paraloc) do
           begin
           begin
@@ -451,7 +459,12 @@ end.
 
 
 {
 {
    $Log$
    $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
      * changed funcret location back to tlocation
 
 
    Revision 1.81  2004/11/15 23:35:31  peter
    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);
     procedure tcgppc.a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const paraloc : tcgpara);
 
 
       var
       var
-        ref: treference;
-        tmpreg: tregister;
+        tmpref, ref: treference;
+        location: pcgparalocation;
+        sizeleft: aint;
 
 
       begin
       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;
             end;
-          else
-            internalerror(2002081103);
-        end;
+            inc(tmpref.offset,tcgsize2size[location^.size]);
+            dec(sizeleft,tcgsize2size[location^.size]);
+            location := location^.next;
+          end;
       end;
       end;
 
 
 
 
@@ -2299,7 +2358,12 @@ begin
 end.
 end.
 {
 {
   $Log$
   $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
     * sysv abi also uses F0-F13 as volatile registers
 
 
   Revision 1.189  2004/12/24 11:51:55  jonas
   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;
           procedure getintparaloc(calloption : tproccalloption; nr : longint;var cgpara:TCGPara);override;
           function create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;override;
           function create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;override;
           function create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;override;
           function create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;override;
-
           procedure create_funcretloc_info(p : tabstractprocdef; side: tcallercallee);
           procedure create_funcretloc_info(p : tabstractprocdef; side: tcallercallee);
+         
+//          function copy_value_on_stack(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean; override;
          private
          private
           procedure init_values(var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword);
           procedure init_values(var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword);
           function create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras:tparalist;
           function create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras:tparalist;
@@ -86,6 +87,7 @@ unit cpupara;
       begin
       begin
         cgpara.reset;
         cgpara.reset;
         cgpara.size:=OS_INT;
         cgpara.size:=OS_INT;
+        cgpara.intsize:=tcgsize2size[OS_INT];
         cgpara.alignment:=get_para_align(calloption);
         cgpara.alignment:=get_para_align(calloption);
         paraloc:=cgpara.add_location;
         paraloc:=cgpara.add_location;
         with paraloc^ do
         with paraloc^ do
@@ -102,7 +104,10 @@ unit cpupara;
              begin
              begin
                loc:=LOC_REFERENCE;
                loc:=LOC_REFERENCE;
                paraloc^.reference.index:=NR_STACK_POINTER_REG;
                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;
           end;
       end;
       end;
@@ -129,7 +134,10 @@ unit cpupara;
             classrefdef:
             classrefdef:
               result:=LOC_REGISTER;
               result:=LOC_REGISTER;
             recorddef:
             recorddef:
-              result:=LOC_REFERENCE;
+              if (target_info.abi<>abi_powerpc_aix) then
+                result:=LOC_REFERENCE
+              else
+                result:=LOC_REGISTER;
             objectdef:
             objectdef:
               if is_object(p) then
               if is_object(p) then
                 result:=LOC_REFERENCE
                 result:=LOC_REFERENCE
@@ -166,8 +174,6 @@ unit cpupara;
 
 
 
 
     function tppcparamanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
     function tppcparamanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
-      var
-        size, dummy: aint;
       begin
       begin
         { var,out always require address }
         { var,out always require address }
         if varspez in [vs_var,vs_out] then
         if varspez in [vs_var,vs_out] then
@@ -177,18 +183,7 @@ unit cpupara;
           end;
           end;
         case def.deftype of
         case def.deftype of
           recorddef:
           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:
           arraydef:
             result:=(tarraydef(def).highrange>=tarraydef(def).lowrange) or
             result:=(tarraydef(def).highrange>=tarraydef(def).lowrange) or
                              is_open_array(def) or
                              is_open_array(def) or
@@ -221,6 +216,14 @@ unit cpupara;
         curmmreg:=RS_M1;
         curmmreg:=RS_M1;
       end;
       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);
     procedure tppcparamanager.create_funcretloc_info(p : tabstractprocdef; side: tcallercallee);
       var
       var
@@ -304,7 +307,8 @@ unit cpupara;
     function tppcparamanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras:tparalist;
     function tppcparamanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras:tparalist;
                var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword):longint;
                var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword):longint;
       var
       var
-         stack_offset: aword;
+         stack_offset, parasize: longint;
+         paralen: aint;
          nextintreg,nextfloatreg,nextmmreg, maxfpureg : tsuperregister;
          nextintreg,nextfloatreg,nextmmreg, maxfpureg : tsuperregister;
          paradef : tdef;
          paradef : tdef;
          paraloc,paraloc2 : pcgparalocation;
          paraloc,paraloc2 : pcgparalocation;
@@ -312,8 +316,9 @@ unit cpupara;
          hp : tparavarsym;
          hp : tparavarsym;
          loc : tcgloc;
          loc : tcgloc;
          paracgsize: tcgsize;
          paracgsize: tcgsize;
-         is_64bit: boolean;
+         def64bit: boolean;
 
 
+(*
       procedure assignintreg;
       procedure assignintreg;
 
 
         begin
         begin
@@ -336,6 +341,7 @@ unit cpupara;
                 inc(stack_offset,4);
                 inc(stack_offset,4);
             end;
             end;
         end;
         end;
+*)
 
 
       begin
       begin
 {$ifdef extdebug}
 {$ifdef extdebug}
@@ -348,6 +354,7 @@ unit cpupara;
          nextfloatreg := curfloatreg;
          nextfloatreg := curfloatreg;
          nextmmreg := curmmreg;
          nextmmreg := curmmreg;
          stack_offset := cur_stack_offset;
          stack_offset := cur_stack_offset;
+         parasize := cur_stack_offset;
          case target_info.abi of
          case target_info.abi of
            abi_powerpc_aix:
            abi_powerpc_aix:
              maxfpureg := RS_F13;
              maxfpureg := RS_F13;
@@ -359,6 +366,7 @@ unit cpupara;
           for i:=0 to paras.count-1 do
           for i:=0 to paras.count-1 do
             begin
             begin
               hp:=tparavarsym(paras[i]);
               hp:=tparavarsym(paras[i]);
+              paradef := hp.vartype.def;
               { Syscall for Morphos can have already a paraloc set }
               { Syscall for Morphos can have already a paraloc set }
               if (vo_has_explicit_paraloc in hp.varoptions) then
               if (vo_has_explicit_paraloc in hp.varoptions) then
                 begin
                 begin
@@ -369,7 +377,7 @@ unit cpupara;
               hp.paraloc[side].reset;
               hp.paraloc[side].reset;
               { currently only support C-style array of const }
               { currently only support C-style array of const }
               if (p.proccalloption in [pocall_cdecl,pocall_cppdecl]) and
               if (p.proccalloption in [pocall_cdecl,pocall_cppdecl]) and
-                 is_array_of_const(hp.vartype.def) then
+                 is_array_of_const(paradef) then
                 begin
                 begin
                   paraloc:=hp.paraloc[side].add_location;
                   paraloc:=hp.paraloc[side].add_location;
                   { hack: the paraloc must be valid, but is not actually used }
                   { hack: the paraloc must be valid, but is not actually used }
@@ -379,146 +387,144 @@ unit cpupara;
                   break;
                   break;
                 end;
                 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
                 begin
                   paradef:=voidpointertype.def;
                   paradef:=voidpointertype.def;
                   loc:=LOC_REGISTER;
                   loc:=LOC_REGISTER;
                   paracgsize := OS_ADDR;
                   paracgsize := OS_ADDR;
+                  paralen := tcgsize2size[OS_ADDR];
                 end
                 end
               else
               else
                 begin
                 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
                     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
                     end
                   else
                   else
                     begin
                     begin
+                      loc:=getparaloc(paradef);
                       paracgsize:=def_cgsize(paradef);
                       paracgsize:=def_cgsize(paradef);
                       { for things like formaldef }
                       { 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;
                 end;
               hp.paraloc[side].alignment:=std_param_align;
               hp.paraloc[side].alignment:=std_param_align;
               hp.paraloc[side].size:=paracgsize;
               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}
 {$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
                       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
                         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
                         end
                       else
                       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
                         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
                           else
-                            begin
-                              inc(stack_offset,8);
-                              if (nextintreg < RS_R10) then
-                                inc(nextintreg,2)
-                              else
-                                nextintreg := RS_R11;
-                            end;
+                            nextintreg := RS_R11;
                         end;
                         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
                         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;
-                   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;
          curintreg:=nextintreg;
          curfloatreg:=nextfloatreg;
          curfloatreg:=nextfloatreg;
          curmmreg:=nextmmreg;
          curmmreg:=nextmmreg;
          cur_stack_offset:=stack_offset;
          cur_stack_offset:=stack_offset;
-         result:=cur_stack_offset;
+         result:=parasize;
       end;
       end;
 
 
 
 
@@ -537,7 +543,13 @@ unit cpupara;
         result:=create_paraloc_info_intern(p,callerside,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset);
         result:=create_paraloc_info_intern(p,callerside,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset);
         if (p.proccalloption in [pocall_cdecl,pocall_cppdecl]) then
         if (p.proccalloption in [pocall_cdecl,pocall_cppdecl]) then
           { just continue loading the parameters in the registers }
           { 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
         else
           begin
           begin
             parasize:=cur_stack_offset;
             parasize:=cur_stack_offset;
@@ -637,7 +649,12 @@ begin
 end.
 end.
 {
 {
   $Log$
   $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
     * fixed stupid tregister/tsuperregister bug (type checking circumvented
       using explicit typecase), caused bug3523
       using explicit typecase), caused bug3523
 
 

+ 8 - 1
compiler/sparc/cpupara.pas

@@ -84,6 +84,7 @@ implementation
           InternalError(2002100806);
           InternalError(2002100806);
         cgpara.reset;
         cgpara.reset;
         cgpara.size:=OS_INT;
         cgpara.size:=OS_INT;
+        cgpara.intsize:=tcgsize2size[OS_INT];
         cgpara.alignment:=std_param_align;
         cgpara.alignment:=std_param_align;
         paraloc:=cgpara.add_location;
         paraloc:=cgpara.add_location;
         with paraloc^ do
         with paraloc^ do
@@ -249,6 +250,7 @@ implementation
             hp.paraloc[side].size:=paracgsize;
             hp.paraloc[side].size:=paracgsize;
             hp.paraloc[side].Alignment:=std_param_align;
             hp.paraloc[side].Alignment:=std_param_align;
             paralen:=tcgsize2size[paracgsize];
             paralen:=tcgsize2size[paracgsize];
+            hp.paraloc[side].intsize:=paralen;
             while paralen>0 do
             while paralen>0 do
               begin
               begin
                 paraloc:=hp.paraloc[side].add_location;
                 paraloc:=hp.paraloc[side].add_location;
@@ -327,7 +329,12 @@ begin
 end.
 end.
 {
 {
   $Log$
   $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
     + implemented abi compliant handling of strucutured functions results on sparc platform
 
 
   Revision 1.51  2004/11/22 22:01:19  peter
   Revision 1.51  2004/11/22 22:01:19  peter