mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-07-24 17:36:17 +02:00

a) cpu64bitaddr, which means that we are generating a compiler which will generate code for targets with a 64 bit address space/abi b) cpu64bitalu, which means that we are generating a compiler which will generate code for a cpu with support for 64 bit integer operations (possibly running in a 32 bit address space, depending on the cpu64bitaddr define) All cpus which had cpu64bit set now have both the above defines set, and none of the 32 bit cpus have cpu64bitalu set (and none will compile with it currently) + pint and puint types, similar to aint/aword (not pword because that that conflicts with pword=^word) * several changes from aint/aword to pint/pword * some changes of tcgsize2size[OS_INT] to sizeof(pint) git-svn-id: trunk@10320 -
329 lines
12 KiB
ObjectPascal
329 lines
12 KiB
ObjectPascal
{
|
|
Copyright (c) 1998-2002 by Florian Klaempfl
|
|
|
|
Calling conventions for the SPARC
|
|
|
|
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,
|
|
symconst,symbase,symsym,symtype,symdef,paramgr,parabase,cgbase;
|
|
|
|
type
|
|
TSparcParaManager=class(TParaManager)
|
|
function push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override;
|
|
function get_volatile_registers_int(calloption : tproccalloption):TCpuRegisterSet;override;
|
|
function get_volatile_registers_fpu(calloption : tproccalloption):TCpuRegisterSet;override;
|
|
{Returns a structure giving the information on the storage of the parameter
|
|
(which must be an integer parameter)
|
|
@param(nr Parameter number of routine, starting from 1)}
|
|
procedure getintparaloc(calloption : tproccalloption; nr : longint;var cgpara : TCGPara);override;
|
|
function create_paraloc_info(p : TAbstractProcDef; side: tcallercallee):longint;override;
|
|
function create_varargs_paraloc_info(p : TAbstractProcDef; varargspara:tvarargsparalist):longint;override;
|
|
private
|
|
procedure create_funcretloc_info(p : tabstractprocdef; side: tcallercallee);
|
|
procedure create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
|
|
var intparareg,parasize:longint);
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
cutils,verbose,systems,
|
|
defutil,
|
|
cgutils,cgobj;
|
|
|
|
type
|
|
tparasupregs = array[0..5] of tsuperregister;
|
|
pparasupregs = ^tparasupregs;
|
|
const
|
|
paraoutsupregs : tparasupregs = (RS_O0,RS_O1,RS_O2,RS_O3,RS_O4,RS_O5);
|
|
parainsupregs : tparasupregs = (RS_I0,RS_I1,RS_I2,RS_I3,RS_I4,RS_I5);
|
|
|
|
|
|
function TSparcParaManager.get_volatile_registers_int(calloption : tproccalloption):TCpuRegisterSet;
|
|
begin
|
|
result:=[RS_G1,RS_O0,RS_O1,RS_O2,RS_O3,RS_O4,RS_O5,RS_O6,RS_O7];
|
|
end;
|
|
|
|
|
|
function tsparcparamanager.get_volatile_registers_fpu(calloption : tproccalloption):TCpuRegisterSet;
|
|
begin
|
|
result:=[RS_F0..RS_F31];
|
|
end;
|
|
|
|
|
|
procedure TSparcParaManager.GetIntParaLoc(calloption : tproccalloption; nr : longint;var cgpara : tcgpara);
|
|
var
|
|
paraloc : pcgparalocation;
|
|
begin
|
|
if nr<1 then
|
|
InternalError(2002100806);
|
|
cgpara.reset;
|
|
cgpara.size:=OS_ADDR;
|
|
cgpara.intsize:=sizeof(pint);
|
|
cgpara.alignment:=std_param_align;
|
|
paraloc:=cgpara.add_location;
|
|
with paraloc^ do
|
|
begin
|
|
{ The six first parameters are passed into registers }
|
|
dec(nr);
|
|
if nr<6 then
|
|
begin
|
|
loc:=LOC_REGISTER;
|
|
register:=newreg(R_INTREGISTER,(RS_O0+nr),R_SUBWHOLE);
|
|
end
|
|
else
|
|
begin
|
|
{ The other parameters are passed on the stack }
|
|
loc:=LOC_REFERENCE;
|
|
reference.index:=NR_STACK_POINTER_REG;
|
|
reference.offset:=92+(nr-6)*4;
|
|
end;
|
|
size:=OS_INT;
|
|
end;
|
|
end;
|
|
|
|
|
|
{ true if a parameter is too large to copy and only the address is pushed }
|
|
function tsparcparamanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
|
|
begin
|
|
result:=false;
|
|
{ var,out always require address }
|
|
if varspez in [vs_var,vs_out] 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,
|
|
variantdef,
|
|
formaldef :
|
|
result:=true;
|
|
objectdef :
|
|
result:=is_object(def);
|
|
stringdef :
|
|
result:=(tstringdef(def).stringtype in [st_shortstring,st_longstring]);
|
|
procvardef :
|
|
result:=(po_methodpointer in tprocvardef(def).procoptions);
|
|
setdef :
|
|
result:=(tsetdef(def).settype<>smallset);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure tsparcparamanager.create_funcretloc_info(p : tabstractprocdef; side: tcallercallee);
|
|
var
|
|
retcgsize : tcgsize;
|
|
begin
|
|
{ Constructors return self instead of a boolean }
|
|
if (p.proctypeoption=potype_constructor) then
|
|
retcgsize:=OS_ADDR
|
|
else
|
|
retcgsize:=def_cgsize(p.returndef);
|
|
|
|
location_reset(p.funcretloc[side],LOC_INVALID,OS_NO);
|
|
p.funcretloc[side].size:=retcgsize;
|
|
{ void has no location }
|
|
if is_void(p.returndef) then
|
|
begin
|
|
p.funcretloc[side].loc:=LOC_VOID;
|
|
exit;
|
|
end;
|
|
{ Return is passed as var parameter }
|
|
if ret_in_param(p.returndef,p.proccalloption) then
|
|
begin
|
|
p.funcretloc[side].loc:=LOC_REFERENCE;
|
|
p.funcretloc[side].size:=retcgsize;
|
|
exit;
|
|
end;
|
|
{ Return in FPU register? }
|
|
if p.returndef.typ=floatdef then
|
|
begin
|
|
p.funcretloc[side].loc:=LOC_FPUREGISTER;
|
|
p.funcretloc[side].register:=NR_FPU_RESULT_REG;
|
|
if retcgsize=OS_F64 then
|
|
setsubreg(p.funcretloc[side].register,R_SUBFD);
|
|
p.funcretloc[side].size:=retcgsize;
|
|
end
|
|
else
|
|
{ Return in register }
|
|
begin
|
|
{$ifndef cpu64bitaddr}
|
|
if retcgsize in [OS_64,OS_S64] then
|
|
begin
|
|
p.funcretloc[side].loc:=LOC_REGISTER;
|
|
{ high }
|
|
if (side=callerside) or (po_inline in p.procoptions) then
|
|
p.funcretloc[side].register64.reghi:=NR_FUNCTION_RESULT64_HIGH_REG
|
|
else
|
|
p.funcretloc[side].register64.reghi:=NR_FUNCTION_RETURN64_HIGH_REG;
|
|
{ low }
|
|
if (side=callerside) or (po_inline in p.procoptions) then
|
|
p.funcretloc[side].register64.reglo:=NR_FUNCTION_RESULT64_LOW_REG
|
|
else
|
|
p.funcretloc[side].register64.reglo:=NR_FUNCTION_RETURN64_LOW_REG;
|
|
end
|
|
else
|
|
{$endif not cpu64bitaddr}
|
|
begin
|
|
p.funcretloc[side].loc:=LOC_REGISTER;
|
|
p.funcretloc[side].size:=retcgsize;
|
|
if (side=callerside) then
|
|
p.funcretloc[side].register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,cgsize2subreg(retcgsize))
|
|
else
|
|
p.funcretloc[side].register:=newreg(R_INTREGISTER,RS_FUNCTION_RETURN_REG,cgsize2subreg(retcgsize));
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure tsparcparamanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee;paras:tparalist;
|
|
var intparareg,parasize:longint);
|
|
var
|
|
paraloc : pcgparalocation;
|
|
i : integer;
|
|
hp : tparavarsym;
|
|
paracgsize : tcgsize;
|
|
hparasupregs : pparasupregs;
|
|
paralen : longint;
|
|
begin
|
|
if side=callerside then
|
|
hparasupregs:=@paraoutsupregs
|
|
else
|
|
hparasupregs:=@parainsupregs;
|
|
for i:=0 to paras.count-1 do
|
|
begin
|
|
hp:=tparavarsym(paras[i]);
|
|
{ currently only support C-style array of const,
|
|
there should be no location assigned to the vararg array itself }
|
|
if (p.proccalloption in [pocall_cdecl,pocall_cppdecl]) and
|
|
is_array_of_const(hp.vardef) 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_G0;
|
|
paraloc^.size:=OS_ADDR;
|
|
break;
|
|
end;
|
|
|
|
if push_addr_param(hp.varspez,hp.vardef,p.proccalloption) then
|
|
paracgsize:=OS_ADDR
|
|
else
|
|
begin
|
|
paracgsize:=def_cgSize(hp.vardef);
|
|
if paracgsize=OS_NO then
|
|
paracgsize:=OS_ADDR;
|
|
end;
|
|
hp.paraloc[side].reset;
|
|
hp.paraloc[side].size:=paracgsize;
|
|
if (side = callerside) then
|
|
hp.paraloc[side].Alignment:=std_param_align
|
|
else
|
|
hp.paraloc[side].Alignment:=hp.vardef.alignment;
|
|
paralen:=tcgsize2size[paracgsize];
|
|
hp.paraloc[side].intsize:=paralen;
|
|
while paralen>0 do
|
|
begin
|
|
paraloc:=hp.paraloc[side].add_location;
|
|
{ Floats are passed in int registers,
|
|
We can allocate at maximum 32 bits per register }
|
|
if paracgsize in [OS_64,OS_S64,OS_F32,OS_F64] then
|
|
paraloc^.size:=OS_32
|
|
else
|
|
paraloc^.size:=paracgsize;
|
|
{ ret in param? }
|
|
if vo_is_funcret in hp.varoptions then
|
|
begin
|
|
paraloc^.loc:=LOC_REFERENCE;
|
|
if side=callerside then
|
|
paraloc^.reference.index:=NR_STACK_POINTER_REG
|
|
else
|
|
paraloc^.reference.index:=NR_FRAME_POINTER_REG;
|
|
paraloc^.reference.offset:=64;
|
|
end
|
|
else if (intparareg<=high(tparasupregs)) then
|
|
begin
|
|
paraloc^.loc:=LOC_REGISTER;
|
|
paraloc^.register:=newreg(R_INTREGISTER,hparasupregs^[intparareg],R_SUBWHOLE);
|
|
inc(intparareg);
|
|
end
|
|
else
|
|
begin
|
|
paraloc^.loc:=LOC_REFERENCE;
|
|
if side=callerside then
|
|
paraloc^.reference.index:=NR_STACK_POINTER_REG
|
|
else
|
|
paraloc^.reference.index:=NR_FRAME_POINTER_REG;
|
|
paraloc^.reference.offset:=target_info.first_parm_offset+parasize;
|
|
{ Parameters are aligned at 4 bytes }
|
|
inc(parasize,align(tcgsize2size[paraloc^.size],sizeof(pint)));
|
|
end;
|
|
dec(paralen,tcgsize2size[paraloc^.size]);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
function TSparcParaManager.create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;
|
|
var
|
|
intparareg,
|
|
parasize : longint;
|
|
begin
|
|
intparareg:=0;
|
|
parasize:=0;
|
|
{ calculate the registers for the normal parameters }
|
|
create_paraloc_info_intern(p,callerside,p.paras,intparareg,parasize);
|
|
{ append the varargs }
|
|
create_paraloc_info_intern(p,callerside,varargspara,intparareg,parasize);
|
|
result:=parasize;
|
|
end;
|
|
|
|
|
|
|
|
function tsparcparamanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
|
|
var
|
|
intparareg,
|
|
parasize : longint;
|
|
begin
|
|
intparareg:=0;
|
|
parasize:=0;
|
|
create_paraloc_info_intern(p,side,p.paras,intparareg,parasize);
|
|
{ Create Function result paraloc }
|
|
create_funcretloc_info(p,side);
|
|
{ We need to return the size allocated on the stack }
|
|
result:=parasize;
|
|
end;
|
|
|
|
|
|
begin
|
|
ParaManager:=TSparcParaManager.create;
|
|
end.
|