m68k: introduce a register calling convention, inspired by VBCC. volatile registers are used to pass arguments

git-svn-id: trunk@34821 -
This commit is contained in:
Károly Balogh 2016-11-06 18:00:29 +00:00
parent f8a7708741
commit 4ee4099fca
3 changed files with 237 additions and 9 deletions

View File

@ -165,6 +165,7 @@
{$define cpurefshaveindexreg}
{$define cpucapabilities}
{$define cpuneedsdivhelper}
{$define cpu_uses_separate_address_registers}
{$endif m68k}
{$ifdef avr}

View File

@ -53,7 +53,9 @@ unit cpupara;
function get_volatile_registers_fpu(calloption:tproccalloption):tcpuregisterset;override;
private
function parse_loc_string_to_register(var locreg: tregister; const s : string): boolean;
function create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
function create_stdcall_paraloc_info(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
var cur_stack_offset: aword):longint;
function create_register_paraloc_info(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
var cur_stack_offset: aword):longint;
end;
@ -64,7 +66,14 @@ unit cpupara;
globals,
systems,
cpuinfo,
defutil;
defutil,
cutils,
hlcgobj;
const
intparasupregs : array[0..1] of tsuperregister = (RS_D0,RS_D1);
addrparasupregs : array[0..1] of tsuperregister = (RS_A0,RS_A1);
floatparasupregs : array[0..1] of tsuperregister = (RS_FP0,RS_FP1);
function tcpuparamanager.get_volatile_registers_int(calloption:tproccalloption):tcpuregisterset;
@ -227,12 +236,17 @@ unit cpupara;
cur_stack_offset: aword;
begin
cur_stack_offset:=0;
result:=create_paraloc_info_intern(p,side,p.paras,cur_stack_offset);
case p.proccalloption of
pocall_register :
result:=create_register_paraloc_info(p,side,p.paras,cur_stack_offset);
else
result:=create_stdcall_paraloc_info(p,side,p.paras,cur_stack_offset);
end;
create_funcretloc_info(p,side);
end;
function tcpuparamanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
function tcpuparamanager.create_stdcall_paraloc_info(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
var cur_stack_offset: aword):longint;
var
paraloc : pcgparalocation;
@ -342,10 +356,216 @@ unit cpupara;
result:=cur_stack_offset;
end;
function tcpuparamanager.create_register_paraloc_info(p : tabstractprocdef; side: tcallercallee;paras:tparalist;
var cur_stack_offset: aword): longint;
var
hp : tparavarsym;
paradef : tdef;
paraloc : pcgparalocation;
paracgsize : tcgsize;
i : integer;
l,
paralen,
parareg: longint;
addrparareg: longint;
floatparareg: longint;
varalign : longint;
paraalign : shortint;
pass : byte;
firstparaloc,
pushaddr : boolean;
rt: tregistertype;
begin
result:=0;
parareg:=0;
addrparareg:=0;
floatparareg:=0;
if paras.count=0 then
exit;
paraalign:=get_para_align(p.proccalloption);
{ clean up here so we can later detect properly if a parameter has been
assigned or not
}
for i:=0 to paras.count-1 do
tparavarsym(paras[i]).paraloc[side].reset;
{ Register parameters are assigned from left to right,
stack parameters from right to left so assign first the
register parameters in a first pass, in the second
pass all unhandled parameters are done }
for pass:=1 to 2 do
begin
if pass=1 then
i:=0
else
i:=paras.count-1;
while true do
begin
hp:=tparavarsym(paras[i]);
paradef:=hp.vardef;
if not(assigned(hp.paraloc[side].location)) then
begin
pushaddr:=push_addr_param(hp.varspez,hp.vardef,p.proccalloption);
if pushaddr then
begin
paralen:=sizeof(aint);
paracgsize:=OS_ADDR;
paradef:=cpointerdef.getreusable_no_free(paradef);
end
else
begin
paralen:=push_size(hp.varspez,hp.vardef,p.proccalloption);
paracgsize:=def_cgsize(hp.vardef);
end;
hp.paraloc[side].size:=paracgsize;
hp.paraloc[side].intsize:=paralen;
hp.paraloc[side].Alignment:=paraalign;
hp.paraloc[side].def:=paradef;
{
In case of po_delphi_nested_cc, the parent frame pointer
is also always passed on the stack.
}
rt:=chlcgobj.def2regtyp(paradef);
if (rt=R_FPUREGISTER) and
(floatparareg<=high(floatparasupregs)) and
(not pushaddr) then
begin
if pass=1 then
begin
paraloc:=hp.paraloc[side].add_location;
paraloc^.size:=paracgsize;
paraloc^.def:=paradef;
paraloc^.loc:=LOC_FPUREGISTER;
paraloc^.register:=newreg(R_FPUREGISTER,floatparasupregs[floatparareg],R_SUBWHOLE);
inc(floatparareg);
end;
end
else
if (((rt=R_INTREGISTER) and (parareg<=high(intparasupregs))) or
((rt=R_ADDRESSREGISTER) and (addrparareg<=high(addrparasupregs)))) and
(paralen<=sizeof(aint)) and
(not(hp.vardef.typ in [floatdef,recorddef,arraydef]) or
pushaddr or
is_dynamic_array(hp.vardef)) and
(not(vo_is_parentfp in hp.varoptions) or
not(po_delphi_nested_cc in p.procoptions)) then
begin
if pass=1 then
begin
paraloc:=hp.paraloc[side].add_location;
paraloc^.size:=paracgsize;
paraloc^.def:=paradef;
paraloc^.loc:=LOC_REGISTER;
if (rt=R_ADDRESSREGISTER) and (addrparareg<=high(addrparasupregs)) then
begin
paraloc^.register:=newreg(R_ADDRESSREGISTER,addrparasupregs[addrparareg],R_SUBWHOLE);
inc(addrparareg);
end
else
if (rt=R_INTREGISTER) and (parareg<=high(intparasupregs)) then
begin
paraloc^.register:=newreg(R_INTREGISTER,intparasupregs[parareg],cgsize2subreg(R_INTREGISTER,paracgsize));
inc(parareg);
end
else
internalerror(2016051801);
end;
end
else
if pass=2 then
begin
{ Copy to stack? }
if (use_fixed_stack) or
(paracgsize=OS_NO) then
begin
paraloc:=hp.paraloc[side].add_location;
paraloc^.loc:=LOC_REFERENCE;
paraloc^.size:=paracgsize;
paraloc^.def:=paradef;
if side=callerside then
paraloc^.reference.index:=NR_STACK_POINTER_REG
else
paraloc^.reference.index:=NR_FRAME_POINTER_REG;
varalign:=used_align(size_2_align(paralen),paraalign,paraalign);
paraloc^.reference.offset:=cur_stack_offset;
if side=calleeside then
inc(paraloc^.reference.offset,target_info.first_parm_offset);
cur_stack_offset:=align(cur_stack_offset+paralen,varalign);
end
else
begin
if paralen=0 then
internalerror(200501163);
firstparaloc:=true;
while (paralen>0) do
begin
paraloc:=hp.paraloc[side].add_location;
paraloc^.loc:=LOC_REFERENCE;
{ Extended and double need a single location }
if (paracgsize in [OS_F64,OS_F32]) then
begin
paraloc^.size:=paracgsize;
paraloc^.def:=paradef;
l:=paralen;
end
else
begin
{ We can allocate at maximum 32 bits per location }
if paralen>sizeof(aint) then
begin
l:=sizeof(aint);
paraloc^.def:=uinttype;
end
else
begin
l:=paralen;
paraloc^.def:=get_paraloc_def(paradef,l,firstparaloc);
end;
paraloc^.size:=int_cgsize(l);
end;
if side=callerside then
paraloc^.reference.index:=NR_STACK_POINTER_REG
else
paraloc^.reference.index:=NR_FRAME_POINTER_REG;
varalign:=used_align(size_2_align(l),paraalign,paraalign);
paraloc^.reference.offset:=cur_stack_offset;
{ M68K is a big-endian target }
if (paralen<tcgsize2size[OS_INT]) then
inc(paraloc^.reference.offset,4-paralen);
if side=calleeside then
inc(paraloc^.reference.offset,target_info.first_parm_offset);
cur_stack_offset:=align(cur_stack_offset+l,varalign);
dec(paralen,l);
firstparaloc:=false;
end;
end;
end;
end;
case pass of
1:
begin
if i=paras.count-1 then
break;
inc(i);
end;
2:
begin
if i=0 then
break;
dec(i);
end;
end;
end;
end;
result:=cur_stack_offset;
end;
function tcpuparamanager.parse_loc_string_to_register(var locreg: tregister; const s : string): boolean;
begin
locreg:=std_regnum_search(lowercase(s));
locreg:=std_regnum_search(lower(s));
result:=(locreg <> NR_NO) and (locreg <> NR_SP);
end;
@ -401,10 +621,10 @@ unit cpupara;
begin
cur_stack_offset:=0;
result:=create_paraloc_info_intern(p,callerside,p.paras,cur_stack_offset);
result:=create_stdcall_paraloc_info(p,callerside,p.paras,cur_stack_offset);
if (p.proccalloption in cstylearrayofconst) then
{ just continue loading the parameters in the registers }
result:=create_paraloc_info_intern(p,callerside,varargspara,cur_stack_offset)
result:=create_stdcall_paraloc_info(p,callerside,varargspara,cur_stack_offset)
else
internalerror(200410231);
end;

View File

@ -166,7 +166,7 @@ implementation
uses
systems,
cgobj,tgobj,
cgobj,hlcgobj,tgobj,
defutil,verbose;
{ true if the location in paraloc can be reused as localloc }
@ -427,7 +427,14 @@ implementation
if (vo_has_explicit_paraloc in parasym.varoptions) and (paraloc^.loc = LOC_REGISTER) then
newparaloc^.register:=paraloc^.register
else
newparaloc^.register:=cg.getintregister(list,paraloc^.size);
begin
{$ifdef cpu_uses_separate_address_registers}
if hlcg.def2regtyp(paraloc^.def) = R_ADDRESSREGISTER then
newparaloc^.register:=hlcg.getaddressregister(list,paraloc^.def)
else
{$endif}
newparaloc^.register:=cg.getintregister(list,paraloc^.size);
end;
end;
LOC_FPUREGISTER :
newparaloc^.register:=cg.getfpuregister(list,paraloc^.size);