mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-11-04 10:19:31 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			737 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			737 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
{
 | 
						|
    Copyright (c) 2002 by Florian Klaempfl
 | 
						|
 | 
						|
    PowerPC specific calling conventions
 | 
						|
 | 
						|
    This program is free software; you can redistribute it and/or modify
 | 
						|
    it under the terms of the GNU General Public License as published by
 | 
						|
    the Free Software Foundation; either version 2 of the License, or
 | 
						|
    (at your option) any later version.
 | 
						|
 | 
						|
    This program is distributed in the hope that it will be useful,
 | 
						|
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
    GNU General Public License for more details.
 | 
						|
 | 
						|
    You should have received a copy of the GNU General Public License
 | 
						|
    along with this program; if not, write to the Free Software
 | 
						|
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
						|
 ****************************************************************************
 | 
						|
}
 | 
						|
unit cpupara;
 | 
						|
 | 
						|
{$i fpcdefs.inc}
 | 
						|
 | 
						|
  interface
 | 
						|
 | 
						|
    uses
 | 
						|
       globtype,
 | 
						|
       aasmtai,aasmdata,
 | 
						|
       cpubase,
 | 
						|
       symconst,symtype,symdef,symsym,
 | 
						|
       paramgr,parabase,cgbase,cgutils;
 | 
						|
 | 
						|
    type
 | 
						|
       tppcparamanager = class(tparamanager)
 | 
						|
          function get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;override;
 | 
						|
          function get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;override;
 | 
						|
          function push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override;
 | 
						|
 | 
						|
          procedure getintparaloc(pd : tabstractprocdef; 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;
 | 
						|
          function get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;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;
 | 
						|
              var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword; varargsparas: boolean):longint;
 | 
						|
          function parseparaloc(p : tparavarsym;const s : string) : boolean;override;
 | 
						|
       end;
 | 
						|
 | 
						|
  implementation
 | 
						|
 | 
						|
    uses
 | 
						|
       verbose,systems,
 | 
						|
       defutil,symtable,
 | 
						|
       procinfo,cpupi;
 | 
						|
 | 
						|
 | 
						|
    function tppcparamanager.get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;
 | 
						|
      begin
 | 
						|
        if (target_info.system = system_powerpc_darwin) then
 | 
						|
          result := [RS_R0,RS_R2..RS_R12]
 | 
						|
        else
 | 
						|
          result := [RS_R0,RS_R3..RS_R12];
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function tppcparamanager.get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;
 | 
						|
      begin
 | 
						|
        case target_info.abi of
 | 
						|
          abi_powerpc_aix,
 | 
						|
          abi_powerpc_sysv:
 | 
						|
            result := [RS_F0..RS_F13];
 | 
						|
          else
 | 
						|
            internalerror(2003091401);
 | 
						|
        end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure tppcparamanager.getintparaloc(pd : tabstractprocdef; nr : longint; var cgpara : tcgpara);
 | 
						|
      var
 | 
						|
        paraloc : pcgparalocation;
 | 
						|
        psym : tparavarsym;
 | 
						|
        pdef : tdef;
 | 
						|
      begin
 | 
						|
        psym:=tparavarsym(pd.paras[nr-1]);
 | 
						|
        pdef:=psym.vardef;
 | 
						|
        if push_addr_param(psym.varspez,pdef,pd.proccalloption) then
 | 
						|
          pdef:=getpointerdef(pdef);
 | 
						|
        cgpara.reset;
 | 
						|
        cgpara.size:=def_cgsize(pdef);
 | 
						|
        cgpara.intsize:=tcgsize2size[cgpara.size];
 | 
						|
        cgpara.alignment:=get_para_align(pd.proccalloption);
 | 
						|
        cgpara.def:=pdef;
 | 
						|
        paraloc:=cgpara.add_location;
 | 
						|
        with paraloc^ do
 | 
						|
         begin
 | 
						|
           size:=def_cgsize(pdef);
 | 
						|
           def:=pdef;
 | 
						|
           if (nr<=8) then
 | 
						|
             begin
 | 
						|
               if nr=0 then
 | 
						|
                 internalerror(200309271);
 | 
						|
               loc:=LOC_REGISTER;
 | 
						|
               register:=newreg(R_INTREGISTER,RS_R2+nr,R_SUBWHOLE);
 | 
						|
             end
 | 
						|
           else
 | 
						|
             begin
 | 
						|
               loc:=LOC_REFERENCE;
 | 
						|
               paraloc^.reference.index:=NR_STACK_POINTER_REG;
 | 
						|
               if (target_info.abi <> abi_powerpc_aix) then
 | 
						|
                 reference.offset:=sizeof(pint)*(nr-8)
 | 
						|
               else
 | 
						|
                 reference.offset:=sizeof(pint)*(nr);
 | 
						|
             end;
 | 
						|
          end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
    function getparaloc(p : tdef) : tcgloc;
 | 
						|
 | 
						|
      begin
 | 
						|
         { Later, the LOC_REFERENCE is in most cases changed into LOC_REGISTER
 | 
						|
           if push_addr_param for the def is true
 | 
						|
         }
 | 
						|
         case p.typ of
 | 
						|
            orddef:
 | 
						|
              result:=LOC_REGISTER;
 | 
						|
            floatdef:
 | 
						|
              result:=LOC_FPUREGISTER;
 | 
						|
            enumdef:
 | 
						|
              result:=LOC_REGISTER;
 | 
						|
            pointerdef:
 | 
						|
              result:=LOC_REGISTER;
 | 
						|
            formaldef:
 | 
						|
              result:=LOC_REGISTER;
 | 
						|
            classrefdef:
 | 
						|
              result:=LOC_REGISTER;
 | 
						|
            procvardef:
 | 
						|
              if (target_info.abi = abi_powerpc_aix) or
 | 
						|
                 (p.size = sizeof(pint)) then
 | 
						|
                result:=LOC_REGISTER
 | 
						|
              else
 | 
						|
                result:=LOC_REFERENCE;
 | 
						|
            recorddef:
 | 
						|
              if not(target_info.system in systems_aix) and
 | 
						|
                 ((target_info.abi<>abi_powerpc_aix) or
 | 
						|
                  ((p.size >= 3) and
 | 
						|
                   ((p.size mod 4) <> 0))) then
 | 
						|
                result:=LOC_REFERENCE
 | 
						|
              else
 | 
						|
                result:=LOC_REGISTER;
 | 
						|
            objectdef:
 | 
						|
              if is_object(p) then
 | 
						|
                result:=LOC_REFERENCE
 | 
						|
              else
 | 
						|
                result:=LOC_REGISTER;
 | 
						|
            stringdef:
 | 
						|
              if is_shortstring(p) or is_longstring(p) then
 | 
						|
                result:=LOC_REFERENCE
 | 
						|
              else
 | 
						|
                result:=LOC_REGISTER;
 | 
						|
            filedef:
 | 
						|
              result:=LOC_REGISTER;
 | 
						|
            arraydef:
 | 
						|
              result:=LOC_REFERENCE;
 | 
						|
            setdef:
 | 
						|
              if is_smallset(p) then
 | 
						|
                result:=LOC_REGISTER
 | 
						|
              else
 | 
						|
                result:=LOC_REFERENCE;
 | 
						|
            variantdef:
 | 
						|
              result:=LOC_REFERENCE;
 | 
						|
            { avoid problems with errornous definitions }
 | 
						|
            errordef:
 | 
						|
              result:=LOC_REGISTER;
 | 
						|
            else
 | 
						|
              internalerror(2002071001);
 | 
						|
         end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function tppcparamanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
 | 
						|
      begin
 | 
						|
        result:=false;
 | 
						|
        { var,out,constref always require address }
 | 
						|
        if varspez in [vs_var,vs_out,vs_constref] then
 | 
						|
          begin
 | 
						|
            result:=true;
 | 
						|
            exit;
 | 
						|
          end;
 | 
						|
        case def.typ of
 | 
						|
          variantdef,
 | 
						|
          formaldef :
 | 
						|
            result:=true;
 | 
						|
          { regular procvars must be passed by value, because you cannot pass
 | 
						|
            the address of a local stack location when calling e.g.
 | 
						|
            pthread_create with the address of a function (first of all it
 | 
						|
            expects the address of the function to execute and not the address
 | 
						|
            of a memory location containing that address, and secondly if you
 | 
						|
            first store the address on the stack and then pass the address of
 | 
						|
            this stack location, then this stack location may no longer be
 | 
						|
            valid when the newly started thread accesses it.
 | 
						|
 | 
						|
            However, for "procedure of object" we must use the same calling
 | 
						|
            convention as for "8 byte record" due to the need for
 | 
						|
            interchangeability with the TMethod record type.
 | 
						|
          }
 | 
						|
          procvardef :
 | 
						|
            result:=
 | 
						|
              (target_info.abi <> abi_powerpc_aix) and
 | 
						|
              (def.size <> sizeof(pint));
 | 
						|
          recorddef :
 | 
						|
            result :=
 | 
						|
              (target_info.abi<>abi_powerpc_aix) or
 | 
						|
              ((varspez = vs_const) and
 | 
						|
               ((calloption = pocall_mwpascal) or
 | 
						|
                (not (calloption in [pocall_cdecl,pocall_cppdecl]) and
 | 
						|
                 (def.size > 8)
 | 
						|
                )
 | 
						|
               )
 | 
						|
              );
 | 
						|
          arraydef:
 | 
						|
            result:=(tarraydef(def).highrange>=tarraydef(def).lowrange) or
 | 
						|
                             is_open_array(def) or
 | 
						|
                             is_array_of_const(def) or
 | 
						|
                             is_array_constructor(def);
 | 
						|
          objectdef :
 | 
						|
            result:=is_object(def);
 | 
						|
          setdef :
 | 
						|
            result:=not is_smallset(def);
 | 
						|
          stringdef :
 | 
						|
            result:=tstringdef(def).stringtype in [st_shortstring,st_longstring];
 | 
						|
        end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure tppcparamanager.init_values(var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword);
 | 
						|
      begin
 | 
						|
        case target_info.abi of
 | 
						|
          abi_powerpc_aix:
 | 
						|
            cur_stack_offset:=24;
 | 
						|
          abi_powerpc_sysv:
 | 
						|
            cur_stack_offset:=8;
 | 
						|
          else
 | 
						|
            internalerror(2003051901);
 | 
						|
        end;
 | 
						|
        curintreg:=RS_R3;
 | 
						|
        curfloatreg:=RS_F1;
 | 
						|
        curmmreg:=RS_M1;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function tppcparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
 | 
						|
      var
 | 
						|
        paraloc : pcgparalocation;
 | 
						|
        retcgsize  : tcgsize;
 | 
						|
      begin
 | 
						|
        if set_common_funcretloc_info(p,forcetempdef,retcgsize,result) then
 | 
						|
          exit;
 | 
						|
 | 
						|
        paraloc:=result.add_location;
 | 
						|
        { Return in FPU register? }
 | 
						|
        if result.def.typ=floatdef then
 | 
						|
          begin
 | 
						|
            paraloc^.loc:=LOC_FPUREGISTER;
 | 
						|
            paraloc^.register:=NR_FPU_RESULT_REG;
 | 
						|
            paraloc^.size:=retcgsize;
 | 
						|
            paraloc^.def:=result.def;
 | 
						|
          end
 | 
						|
        else
 | 
						|
         { Return in register }
 | 
						|
          begin
 | 
						|
            if retcgsize in [OS_64,OS_S64] then
 | 
						|
             begin
 | 
						|
               { low 32bits }
 | 
						|
               paraloc^.loc:=LOC_REGISTER;
 | 
						|
               if side=callerside then
 | 
						|
                 paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG
 | 
						|
               else
 | 
						|
                 paraloc^.register:=NR_FUNCTION_RETURN64_HIGH_REG;
 | 
						|
               paraloc^.size:=OS_32;
 | 
						|
               paraloc^.def:=u32inttype;
 | 
						|
               { high 32bits }
 | 
						|
               paraloc:=result.add_location;
 | 
						|
               paraloc^.loc:=LOC_REGISTER;
 | 
						|
               if side=callerside then
 | 
						|
                 paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG
 | 
						|
               else
 | 
						|
                 paraloc^.register:=NR_FUNCTION_RETURN64_LOW_REG;
 | 
						|
               paraloc^.size:=OS_32;
 | 
						|
               paraloc^.def:=u32inttype;
 | 
						|
             end
 | 
						|
            else
 | 
						|
             begin
 | 
						|
               paraloc^.loc:=LOC_REGISTER;
 | 
						|
               if side=callerside then
 | 
						|
                 paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,cgsize2subreg(R_INTREGISTER,retcgsize))
 | 
						|
               else
 | 
						|
                 paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RETURN_REG,cgsize2subreg(R_INTREGISTER,retcgsize));
 | 
						|
               paraloc^.size:=retcgsize;
 | 
						|
               paraloc^.def:=result.def;
 | 
						|
             end;
 | 
						|
          end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function tppcparamanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
 | 
						|
 | 
						|
      var
 | 
						|
        cur_stack_offset: aword;
 | 
						|
        curintreg, curfloatreg, curmmreg: tsuperregister;
 | 
						|
      begin
 | 
						|
        init_values(curintreg,curfloatreg,curmmreg,cur_stack_offset);
 | 
						|
 | 
						|
        result := create_paraloc_info_intern(p,side,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset,false);
 | 
						|
 | 
						|
        create_funcretloc_info(p,side);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
    function tppcparamanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras:tparalist;
 | 
						|
               var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword; varargsparas: boolean):longint;
 | 
						|
      var
 | 
						|
         stack_offset: longint;
 | 
						|
         paralen: aint;
 | 
						|
         nextintreg,nextfloatreg,nextmmreg, maxfpureg : tsuperregister;
 | 
						|
         locdef,
 | 
						|
         paradef : tdef;
 | 
						|
         paraloc : pcgparalocation;
 | 
						|
         i  : integer;
 | 
						|
         hp : tparavarsym;
 | 
						|
         loc : tcgloc;
 | 
						|
         paracgsize: tcgsize;
 | 
						|
         sym: tfieldvarsym;
 | 
						|
         firstparaloc: boolean;
 | 
						|
 | 
						|
      begin
 | 
						|
{$ifdef extdebug}
 | 
						|
         if po_explicitparaloc in p.procoptions then
 | 
						|
           internalerror(200411141);
 | 
						|
{$endif extdebug}
 | 
						|
 | 
						|
         result:=0;
 | 
						|
         nextintreg := curintreg;
 | 
						|
         nextfloatreg := curfloatreg;
 | 
						|
         nextmmreg := curmmreg;
 | 
						|
         stack_offset := cur_stack_offset;
 | 
						|
         case target_info.abi of
 | 
						|
           abi_powerpc_aix:
 | 
						|
             maxfpureg := RS_F13;
 | 
						|
           abi_powerpc_sysv:
 | 
						|
             maxfpureg := RS_F8;
 | 
						|
           else internalerror(2004070912);
 | 
						|
         end;
 | 
						|
 | 
						|
          for i:=0 to paras.count-1 do
 | 
						|
            begin
 | 
						|
              hp:=tparavarsym(paras[i]);
 | 
						|
              paradef := hp.vardef;
 | 
						|
              { Syscall for Morphos can have already a paraloc set }
 | 
						|
              if (vo_has_explicit_paraloc in hp.varoptions) then
 | 
						|
                begin
 | 
						|
                  if not(vo_is_syscall_lib in hp.varoptions) then
 | 
						|
                    internalerror(200412153);
 | 
						|
                  continue;
 | 
						|
                end;
 | 
						|
              hp.paraloc[side].reset;
 | 
						|
              { currently only support C-style array of const }
 | 
						|
              if (p.proccalloption in cstylearrayofconst) and
 | 
						|
                 is_array_of_const(paradef) then
 | 
						|
                begin
 | 
						|
                  paraloc:=hp.paraloc[side].add_location;
 | 
						|
                  { hack: the paraloc must be valid, but is not actually used }
 | 
						|
                  paraloc^.loc := LOC_REGISTER;
 | 
						|
                  paraloc^.register := NR_R0;
 | 
						|
                  paraloc^.size := OS_ADDR;
 | 
						|
                  paraloc^.def:=voidpointertype;
 | 
						|
                  break;
 | 
						|
                end;
 | 
						|
 | 
						|
              if push_addr_param(hp.varspez,paradef,p.proccalloption) then
 | 
						|
                begin
 | 
						|
                  paradef:=getpointerdef(paradef);
 | 
						|
                  loc:=LOC_REGISTER;
 | 
						|
                  paracgsize := OS_ADDR;
 | 
						|
                  paralen := tcgsize2size[OS_ADDR];
 | 
						|
                end
 | 
						|
              else
 | 
						|
                begin
 | 
						|
                  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.typ = recorddef) and
 | 
						|
                     (hp.varspez in [vs_value,vs_const]) then
 | 
						|
                    begin
 | 
						|
                      { 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.      }
 | 
						|
                      sym:=nil;
 | 
						|
                      if tabstractrecordsymtable(tabstractrecorddef(paradef).symtable).has_single_field(sym) and
 | 
						|
                         ((sym.vardef.typ=floatdef) or
 | 
						|
                          ((target_info.system=system_powerpc_darwin) and
 | 
						|
                           (sym.vardef.typ in [orddef,enumdef]))) then
 | 
						|
                        begin
 | 
						|
                          paradef:=sym.vardef;
 | 
						|
                          paracgsize:=def_cgsize(paradef);
 | 
						|
                        end
 | 
						|
                      else
 | 
						|
                        begin
 | 
						|
                          paracgsize := int_cgsize(paralen);
 | 
						|
                        end;
 | 
						|
                    end
 | 
						|
                  else
 | 
						|
                    begin
 | 
						|
                      paracgsize:=def_cgsize(paradef);
 | 
						|
                      { for things like formaldef }
 | 
						|
                      if (paracgsize=OS_NO) then
 | 
						|
                        begin
 | 
						|
                          paracgsize:=OS_ADDR;
 | 
						|
                          paralen := tcgsize2size[OS_ADDR];
 | 
						|
                        end;
 | 
						|
                    end
 | 
						|
                end;
 | 
						|
 | 
						|
              loc := getparaloc(paradef);
 | 
						|
              if varargsparas and
 | 
						|
                 (target_info.abi = abi_powerpc_aix) and
 | 
						|
                 (paradef.typ = floatdef) then
 | 
						|
                begin
 | 
						|
                  loc := LOC_REGISTER;
 | 
						|
                  if paracgsize=OS_F64 then
 | 
						|
                    begin
 | 
						|
                      paracgsize:=OS_64;
 | 
						|
                      paradef:=u64inttype;
 | 
						|
                    end
 | 
						|
                  else
 | 
						|
                    begin
 | 
						|
                      paracgsize:=OS_32;
 | 
						|
                      paradef:=u32inttype;
 | 
						|
                    end;
 | 
						|
                end;
 | 
						|
 | 
						|
              hp.paraloc[side].alignment:=std_param_align;
 | 
						|
              hp.paraloc[side].size:=paracgsize;
 | 
						|
              hp.paraloc[side].intsize:=paralen;
 | 
						|
              hp.paraloc[side].def:=paradef;
 | 
						|
{$ifndef cpu64bitaddr}
 | 
						|
              if (target_info.abi=abi_powerpc_sysv) and
 | 
						|
                 is_64bit(paradef) and
 | 
						|
                 odd(nextintreg-RS_R3) then
 | 
						|
                inc(nextintreg);
 | 
						|
{$endif not cpu64bitaddr}
 | 
						|
              if (paralen = 0) then
 | 
						|
                if (paradef.typ = recorddef) then
 | 
						|
                  begin
 | 
						|
                    paraloc:=hp.paraloc[side].add_location;
 | 
						|
                    paraloc^.loc := LOC_VOID;
 | 
						|
                  end
 | 
						|
                else
 | 
						|
                  internalerror(2005011310);
 | 
						|
              locdef:=paradef;
 | 
						|
              firstparaloc:=true;
 | 
						|
              { can become < 0 for e.g. 3-byte records }
 | 
						|
              while (paralen > 0) do
 | 
						|
                begin
 | 
						|
                  paraloc:=hp.paraloc[side].add_location;
 | 
						|
                  { In case of po_delphi_nested_cc, the parent frame pointer
 | 
						|
                    is always passed on the stack. }
 | 
						|
                  if (loc = LOC_REGISTER) and
 | 
						|
                     (nextintreg <= RS_R10) and
 | 
						|
                     (not(vo_is_parentfp in hp.varoptions) or
 | 
						|
                      not(po_delphi_nested_cc in p.procoptions)) then
 | 
						|
                    begin
 | 
						|
                      paraloc^.loc := loc;
 | 
						|
                      { make sure we don't lose whether or not the type is signed }
 | 
						|
                      if (paradef.typ<>orddef) then
 | 
						|
                        begin
 | 
						|
                          paracgsize:=int_cgsize(paralen);
 | 
						|
                          locdef:=get_paraloc_def(paradef,paralen,firstparaloc);
 | 
						|
                        end;
 | 
						|
                      if (paracgsize in [OS_NO,OS_64,OS_S64,OS_128,OS_S128]) then
 | 
						|
                        begin
 | 
						|
                          paraloc^.size:=OS_INT;
 | 
						|
                          paraloc^.def:=u32inttype;
 | 
						|
                        end
 | 
						|
                      else
 | 
						|
                        begin
 | 
						|
                          paraloc^.size:=paracgsize;
 | 
						|
                          paraloc^.def:=locdef;
 | 
						|
                        end;
 | 
						|
                      { aix requires that record data stored in parameter
 | 
						|
                        registers is left-aligned }
 | 
						|
                      if (target_info.system in systems_aix) and
 | 
						|
                         (paradef.typ = recorddef) and
 | 
						|
                         (tcgsize2size[paraloc^.size] <> sizeof(aint)) then
 | 
						|
                        begin
 | 
						|
                          paraloc^.shiftval := (sizeof(aint)-tcgsize2size[paraloc^.size])*(-8);
 | 
						|
                          paraloc^.size := OS_INT;
 | 
						|
                          paraloc^.def := u32inttype;
 | 
						|
                        end;
 | 
						|
                      paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBNONE);
 | 
						|
                      inc(nextintreg);
 | 
						|
                      dec(paralen,tcgsize2size[paraloc^.size]);
 | 
						|
                      if target_info.abi=abi_powerpc_aix then
 | 
						|
                        inc(stack_offset,align(tcgsize2size[paraloc^.size],4));
 | 
						|
                    end
 | 
						|
                  else if (loc = LOC_FPUREGISTER) and
 | 
						|
                          (nextfloatreg <= maxfpureg) then
 | 
						|
                    begin
 | 
						|
                      paraloc^.loc:=loc;
 | 
						|
                      paraloc^.size := paracgsize;
 | 
						|
                      paraloc^.def := paradef;
 | 
						|
                      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     }
 | 
						|
                      if target_info.abi=abi_powerpc_aix then
 | 
						|
{$ifndef cpu64bitaddr}
 | 
						|
                        if (paracgsize = OS_F32) then
 | 
						|
                          begin
 | 
						|
                            inc(stack_offset,4);
 | 
						|
                            if (nextintreg < RS_R11) then
 | 
						|
                              inc(nextintreg);
 | 
						|
                          end
 | 
						|
                        else
 | 
						|
                          begin
 | 
						|
                            inc(stack_offset,8);
 | 
						|
                            if (nextintreg < RS_R10) then
 | 
						|
                              inc(nextintreg,2)
 | 
						|
                            else
 | 
						|
                              nextintreg := RS_R11;
 | 
						|
                          end;
 | 
						|
{$else not cpu64bitaddr}
 | 
						|
                          begin
 | 
						|
                            inc(stack_offset,tcgsize2size[paracgsize]);
 | 
						|
                            if (nextintreg < RS_R11) then
 | 
						|
                              inc(nextintreg);
 | 
						|
                          end;
 | 
						|
{$endif not cpu64bitaddr}
 | 
						|
                    end
 | 
						|
                  else { LOC_REFERENCE }
 | 
						|
                    begin
 | 
						|
                       paraloc^.loc:=LOC_REFERENCE;
 | 
						|
                       case loc of
 | 
						|
                         LOC_FPUREGISTER:
 | 
						|
                           begin
 | 
						|
                             paraloc^.size:=int_float_cgsize(paralen);
 | 
						|
                             case paraloc^.size of
 | 
						|
                               OS_F32: paraloc^.def:=s32floattype;
 | 
						|
                               OS_F64: paraloc^.def:=s64floattype;
 | 
						|
                               else
 | 
						|
                                 internalerror(2013060124);
 | 
						|
                             end;
 | 
						|
                           end;
 | 
						|
                         LOC_REGISTER,
 | 
						|
                         LOC_REFERENCE:
 | 
						|
                           begin
 | 
						|
                             paraloc^.size:=int_cgsize(paralen);
 | 
						|
                             if paraloc^.size<>OS_NO then
 | 
						|
                               paraloc^.def:=cgsize_orddef(paraloc^.size)
 | 
						|
                             else
 | 
						|
                               paraloc^.def:=getarraydef(u8inttype,paralen);
 | 
						|
                           end;
 | 
						|
                         else
 | 
						|
                           internalerror(2006011101);
 | 
						|
                       end;
 | 
						|
                       if (side = callerside) then
 | 
						|
                         paraloc^.reference.index:=NR_STACK_POINTER_REG
 | 
						|
                       else
 | 
						|
                         begin
 | 
						|
                           paraloc^.reference.index:=NR_R12;
 | 
						|
 | 
						|
                           { create_paraloc_info_intern might be also called when being outside of
 | 
						|
                             code generation so current_procinfo might be not set }
 | 
						|
                           if assigned(current_procinfo) then
 | 
						|
                             tppcprocinfo(current_procinfo).needs_frame_pointer := true;
 | 
						|
                         end;
 | 
						|
 | 
						|
                       if not((target_info.system in systems_aix) and
 | 
						|
                              (paradef.typ=recorddef)) and
 | 
						|
                          (target_info.abi = abi_powerpc_aix) and
 | 
						|
                          (hp.paraloc[side].intsize < 3) then
 | 
						|
                         paraloc^.reference.offset:=stack_offset+(4-paralen)
 | 
						|
                       else
 | 
						|
                         paraloc^.reference.offset:=stack_offset;
 | 
						|
 | 
						|
                       inc(stack_offset,align(paralen,4));
 | 
						|
                       while (paralen > 0) and
 | 
						|
                             (nextintreg < RS_R11) do
 | 
						|
                          begin
 | 
						|
                            inc(nextintreg);
 | 
						|
                            dec(paralen,sizeof(pint));
 | 
						|
                          end;
 | 
						|
                       paralen := 0;
 | 
						|
                    end;
 | 
						|
                  firstparaloc:=false;
 | 
						|
                end;
 | 
						|
            end;
 | 
						|
         curintreg:=nextintreg;
 | 
						|
         curfloatreg:=nextfloatreg;
 | 
						|
         curmmreg:=nextmmreg;
 | 
						|
         cur_stack_offset:=stack_offset;
 | 
						|
         result:=stack_offset;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function tppcparamanager.create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;
 | 
						|
      var
 | 
						|
        cur_stack_offset: aword;
 | 
						|
        parasize, l: longint;
 | 
						|
        curintreg, firstfloatreg, curfloatreg, curmmreg: tsuperregister;
 | 
						|
        i : integer;
 | 
						|
        hp: tparavarsym;
 | 
						|
        paraloc: pcgparalocation;
 | 
						|
      begin
 | 
						|
        init_values(curintreg,curfloatreg,curmmreg,cur_stack_offset);
 | 
						|
        firstfloatreg:=curfloatreg;
 | 
						|
 | 
						|
        result:=create_paraloc_info_intern(p,callerside,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset, false);
 | 
						|
        if (p.proccalloption in cstylearrayofconst) then
 | 
						|
          { just continue loading the parameters in the registers }
 | 
						|
          begin
 | 
						|
            result:=create_paraloc_info_intern(p,callerside,varargspara,curintreg,curfloatreg,curmmreg,cur_stack_offset,true);
 | 
						|
            { 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;
 | 
						|
            for i:=0 to varargspara.count-1 do
 | 
						|
              begin
 | 
						|
                hp:=tparavarsym(varargspara[i]);
 | 
						|
                hp.paraloc[callerside].alignment:=4;
 | 
						|
                paraloc:=hp.paraloc[callerside].add_location;
 | 
						|
                paraloc^.loc:=LOC_REFERENCE;
 | 
						|
                paraloc^.size:=def_cgsize(hp.vardef);
 | 
						|
                paraloc^.def:=hp.vardef;
 | 
						|
                paraloc^.reference.index:=NR_STACK_POINTER_REG;
 | 
						|
                l:=push_size(hp.varspez,hp.vardef,p.proccalloption);
 | 
						|
                paraloc^.reference.offset:=parasize;
 | 
						|
                parasize:=parasize+l;
 | 
						|
              end;
 | 
						|
            result:=parasize;
 | 
						|
          end;
 | 
						|
        if curfloatreg<>firstfloatreg then
 | 
						|
          include(varargspara.varargsinfo,va_uses_float_reg);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function tppcparamanager.parseparaloc(p : tparavarsym;const s : string) : boolean;
 | 
						|
      var
 | 
						|
        paraloc : pcgparalocation;
 | 
						|
        paracgsize : tcgsize;
 | 
						|
      begin
 | 
						|
        result:=false;
 | 
						|
        case target_info.system of
 | 
						|
          system_powerpc_morphos:
 | 
						|
            begin
 | 
						|
              paracgsize:=def_cgsize(p.vardef);
 | 
						|
              p.paraloc[callerside].alignment:=4;
 | 
						|
              p.paraloc[callerside].size:=paracgsize;
 | 
						|
              p.paraloc[callerside].intsize:=tcgsize2size[paracgsize];
 | 
						|
              paraloc:=p.paraloc[callerside].add_location;
 | 
						|
              paraloc^.loc:=LOC_REFERENCE;
 | 
						|
              paraloc^.size:=paracgsize;
 | 
						|
              paraloc^.def:=p.vardef;
 | 
						|
              paraloc^.reference.index:=newreg(R_INTREGISTER,RS_R2,R_SUBWHOLE);
 | 
						|
              { pattern is always uppercase'd }
 | 
						|
              if s='D0' then
 | 
						|
                paraloc^.reference.offset:=0
 | 
						|
              else if s='D1' then
 | 
						|
                paraloc^.reference.offset:=4
 | 
						|
              else if s='D2' then
 | 
						|
                paraloc^.reference.offset:=8
 | 
						|
              else if s='D3' then
 | 
						|
                paraloc^.reference.offset:=12
 | 
						|
              else if s='D4' then
 | 
						|
                paraloc^.reference.offset:=16
 | 
						|
              else if s='D5' then
 | 
						|
                paraloc^.reference.offset:=20
 | 
						|
              else if s='D6' then
 | 
						|
                paraloc^.reference.offset:=24
 | 
						|
              else if s='D7' then
 | 
						|
                paraloc^.reference.offset:=28
 | 
						|
              else if s='A0' then
 | 
						|
                paraloc^.reference.offset:=32
 | 
						|
              else if s='A1' then
 | 
						|
                paraloc^.reference.offset:=36
 | 
						|
              else if s='A2' then
 | 
						|
                paraloc^.reference.offset:=40
 | 
						|
              else if s='A3' then
 | 
						|
                paraloc^.reference.offset:=44
 | 
						|
              else if s='A4' then
 | 
						|
                paraloc^.reference.offset:=48
 | 
						|
              else if s='A5' then
 | 
						|
                paraloc^.reference.offset:=52
 | 
						|
              { 'A6' (offset 56) is used by mossyscall as libbase, so API
 | 
						|
                never passes parameters in it,
 | 
						|
                Indeed, but this allows to declare libbase either explicitly
 | 
						|
                or let the compiler insert it }
 | 
						|
              else if s='A6' then
 | 
						|
                paraloc^.reference.offset:=56
 | 
						|
              { 'A7' is the stack pointer on 68k, can't be overwritten
 | 
						|
                by API calls, so it has no offset }
 | 
						|
              { 'R12' is special, used internally to support r12base sysv
 | 
						|
                calling convention }
 | 
						|
              else if s='R12' then
 | 
						|
                begin
 | 
						|
                  paraloc^.loc:=LOC_REGISTER;
 | 
						|
                  paraloc^.size:=OS_ADDR;
 | 
						|
                  paraloc^.def:=voidpointertype;
 | 
						|
                  paraloc^.register:=NR_R12;
 | 
						|
                end
 | 
						|
              else
 | 
						|
                exit;
 | 
						|
 | 
						|
              { copy to callee side }
 | 
						|
              p.paraloc[calleeside].add_location^:=paraloc^;
 | 
						|
            end;
 | 
						|
          else
 | 
						|
            internalerror(200404182);
 | 
						|
        end;
 | 
						|
        result:=true;
 | 
						|
      end;
 | 
						|
 | 
						|
begin
 | 
						|
   paramanager:=tppcparamanager.create;
 | 
						|
end.
 |