| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368 | {    Copyright (c) 1998-2002 by Florian Klaempfl    Calling conventions for the SPARC64    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,      cclasses,      aasmtai,aasmdata,      cpubase,cpuinfo,      sppara,      symconst,symbase,symsym,symtype,symdef,paramgr,parabase,cgbase,cgutils;    type      tcpuparamanager=class(TSparcParaManager)        procedure create_paraloc_info_intern(p : tabstractprocdef; side : tcallercallee; paras : tparalist; var curintreg : LongInt;          curfloatreg : tsuperregister; var cur_stack_offset : aword);override;        function push_addr_param(varspez : tvarspez; def : tdef; calloption : tproccalloption) : boolean;override;        function ret_in_param(def : tdef; pd : tabstractprocdef) : boolean;override;        function get_funcretloc(p : tabstractprocdef; side : tcallercallee; forcetempdef : tdef) : tcgpara;override;      private        function push_addr_param_intern(varspez : tvarspez; def : tdef; calloption : tproccalloption; recsizelimit : aword) : boolean;        procedure create_paraloc1_info_intern(p : tabstractprocdef; side : tcallercallee; paradef : tdef; var loc : TCGPara; varspez : tvarspez; varoptions : tvaroptions; recsizelimit : aword;          var curintreg : LongInt; var curfloatreg : tsuperregister; var cur_stack_offset : aword);      end;implementation    uses      cutils,verbose,systems,      defutil,      cgobj;    { true if a parameter is too large to copy and only the address is pushed }    function tcpuparamanager.push_addr_param_intern(varspez:tvarspez;def : tdef;calloption : tproccalloption;recsizelimit : aword) : 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          arraydef:            result:=(tarraydef(def).highrange>=tarraydef(def).lowrange) or                             is_open_array(def) or                             is_array_of_const(def) or                             is_array_constructor(def);          recorddef:            result:=def.size>recsizelimit;          variantdef:            result:=false;          formaldef :            result:=true;          objectdef :            result:=(is_object(def) and (def.size>recsizelimit));          stringdef :            result:=(tstringdef(def).stringtype in [st_shortstring,st_longstring]);          procvardef :            result:=false;          setdef :            result:=not is_smallset(def);          else            ;        end;      end;    { true if a parameter is too large to copy and only the address is pushed }    function tcpuparamanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;      begin        result:=push_addr_param_intern(varspez,def,calloption,16);      end;    function tcpuparamanager.ret_in_param(def:tdef;pd:tabstractprocdef):boolean;      begin        if handle_common_ret_in_param(def,pd,result) then          exit;        case def.typ of          { it is a matter of interpretation, if objects should be returned in registers according to the abi as the            abi talks only about structures and unions            at least for the compiler, it is a problem, if an object is returned in registers            consider            tobject1 = object              function f : tobject1;              ...              contructor init;            end;            the constructor changes the size of tobject1, so its return location might change from register to memory, this            is something the compiler could not handle currently, so we do not return objects in registers yet          objectdef:            begin              result:=is_object(def) and (def.size>32);              exit;            end;}          recorddef:            begin              result:=def.size>32;              exit;            end;          else            ;        end;        result:=inherited ret_in_param(def,pd);      end;    procedure tcpuparamanager.create_paraloc1_info_intern(      p : tabstractprocdef; side: tcallercallee;paradef:tdef;var loc : TCGPara;varspez : tvarspez;varoptions : tvaroptions;recsizelimit : aword;      var curintreg: LongInt; var curfloatreg: tsuperregister; var cur_stack_offset : aword);      procedure nextloc(currsize : TCgSize);        begin          if curintreg>high(tparasupregs) then            begin              if (currsize<low(tcgsize2size)) or (currsize>high(tcgsize2size)) then                internalerror(2017080101);              { Parameters are aligned at 8 bytes }              inc(cur_stack_offset,align(tcgsize2size[currsize],sizeof(pint)));            end;          inc(curintreg);          if currsize=OS_F128 then            inc(curfloatreg,4)          else            inc(curfloatreg,2);        end;      var        paraloc      : pcgparalocation;        paracgsize   : tcgsize;        hparasupregs : pparasupregs;        paralen      : longint;      begin        if side=callerside then          hparasupregs:=@paraoutsupregs        else          hparasupregs:=@parainsupregs;        { currently only support C-style array of const,          there should be no location assigned to the vararg array itself }        if (p.proccalloption in cstylearrayofconst) and           is_array_of_const(paradef) then          begin            paraloc:=loc.add_location;            { hack: the paraloc must be valid, but is not actually used }            paraloc^.loc:=LOC_REGISTER;            paraloc^.register:=NR_G0;            paraloc^.size:=OS_ADDR;            paraloc^.def:=voidpointertype;            exit;          end;        if push_addr_param_intern(varspez,paradef,p.proccalloption,recsizelimit) then          begin            paracgsize:=OS_ADDR;            paradef:=cpointerdef.getreusable_no_free(paradef);          end        else          begin            paracgsize:=def_cgsize(paradef);            if paradef.typ=formaldef then              begin                paracgsize:=OS_ADDR;                paradef:=voidpointertype;              end;          end;        loc.reset;        loc.size:=paracgsize;        loc.def:=paradef;        if side=callerside then          loc.Alignment:=std_param_align        else          loc.Alignment:=paradef.alignment;        { sparc64 returns records up to a size of 32 in register, we cannot encode this          in paracgsize, so paracgsize is OS_NO in this case }        if paracgsize=OS_NO then          paralen:=paradef.size        else          paralen:=tcgsize2size[paracgsize];        loc.intsize:=paralen;        while paralen>0 do          begin            paraloc:=loc.add_location;            paraloc^.size:=paracgsize;            paraloc^.def:=paradef;            { ret in param? }            if vo_is_funcret in varoptions then              begin                paraloc^.loc:=LOC_REFERENCE;                paraloc^.reference.offset:=128;                if side=callerside then                  paraloc^.reference.index:=NR_STACK_POINTER_REG                else                  paraloc^.reference.index:=NR_FRAME_POINTER_REG;                inc(paraloc^.reference.offset,STACK_BIAS);              end            { In case of po_delphi_nested_cc, the parent frame pointer              is always passed on the stack. }            else if (curintreg<=high(tparasupregs)) and               (not(vo_is_parentfp in varoptions) or                not(po_delphi_nested_cc in p.procoptions)) then              begin                if paraloc^.size in [OS_F32,OS_F64,OS_F128] then                  begin                    paraloc^.loc:=LOC_FPUREGISTER;                    case paraloc^.size of                      OS_F32:                        { singles are put into the uneven register }                        paraloc^.register:=newreg(R_FPUREGISTER,curfloatreg+1,R_SUBFS);                      OS_F64:                        paraloc^.register:=newreg(R_FPUREGISTER,curfloatreg,R_SUBFD);                      OS_F128:                        paraloc^.register:=newreg(R_FPUREGISTER,curfloatreg,R_SUBFQ);                      else                        Internalerror(2017072301);                    end;                  end                else                  begin                    if paracgsize in [OS_NO,OS_128,OS_S128] then                      begin                        if paralen>4 then                          begin                            paraloc^.size:=OS_INT;                            paraloc^.def:=u64inttype;                          end                        else                          begin                            { for 3-byte records }                            paraloc^.size:=OS_32;                            paraloc^.def:=u32inttype;                          end;                      end;                    paraloc^.loc:=LOC_REGISTER;                    paraloc^.register:=newreg(R_INTREGISTER,hparasupregs^[curintreg],R_SUBWHOLE);                    { left align }                    if (target_info.endian=endian_big) and                       not(paraloc^.size in [OS_64,OS_S64]) and                       (paradef.typ in [setdef,recorddef,arraydef,objectdef]) then                      begin                        paraloc^.shiftval:=-(8-tcgsize2size[paraloc^.size])*8;                        paraloc^.Size:=OS_64;                      end;                  end;                nextloc(paraloc^.Size);              end            else              begin                paraloc^.loc:=LOC_REFERENCE;                paraloc^.reference.offset:=target_info.first_parm_offset+cur_stack_offset;                if side=callerside then                  paraloc^.reference.index:=NR_STACK_POINTER_REG                else                  paraloc^.reference.index:=NR_FRAME_POINTER_REG;                inc(paraloc^.reference.offset,STACK_BIAS);                if (target_info.endian=endian_big) and                   (paralen<tcgsize2size[OS_INT]) and                   (paradef.typ<>recorddef) then                  inc(paraloc^.reference.offset,4-paralen);                { Parameters are aligned to 8 byte boundaries }                inc(cur_stack_offset,align(paralen,8));                { a stack location covers always the remainder of a parameter }                exit;              end;            dec(paralen,tcgsize2size[paraloc^.size]);          end;      end;    procedure tcpuparamanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee;paras:tparalist;                                                  var curintreg: LongInt; curfloatreg: tsuperregister; var cur_stack_offset : aword);      var        i : integer;      begin        for i:=0 to paras.count-1 do          create_paraloc1_info_intern(p,side,tparavarsym(paras[i]).vardef,tparavarsym(paras[i]).paraloc[side],tparavarsym(paras[i]).varspez,            tparavarsym(paras[i]).varoptions,16,curintreg,curfloatreg,cur_stack_offset);      end;    function tcpuparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;      var        paraloc : pcgparalocation;        retcgsize  : tcgsize;        curintreg : LongInt;        curfloatreg : tsuperregister;        cur_stack_offset : aword;      begin        if set_common_funcretloc_info(p,forcetempdef,retcgsize,result) then          exit;        if ret_in_param(result.def,p) then          Internalerror(2017080601);        if is_record(result.def) or is_object(result.def) then          begin            curintreg:=0;            curfloatreg:=RS_F0;            cur_stack_offset:=0;            create_paraloc1_info_intern(p,side,result.def,result,vs_value,              [],32,curintreg,curfloatreg,cur_stack_offset);            { sparc64 calling conventions are difficult, so better check if everything is ok }            if result.location^.loc=LOC_INVALID then              Internalerror(2017080501);          end        else          begin            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;                if retcgsize=OS_F64 then                  setsubreg(paraloc^.register,R_SUBFD);                paraloc^.size:=retcgsize;                paraloc^.def:=result.def;              end            else             { Return in register }              begin                paraloc^.loc:=LOC_REGISTER;                paraloc^.size:=retcgsize;                paraloc^.def:=result.def;                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));              end;          end;      end;begin   ParaManager:=tcpuparamanager.create;end.
 |