* add support for HFA parameter passing for ARM hardfloat

(fixes test/cg/tcalext6)

git-svn-id: trunk@41421 -
This commit is contained in:
Jonas Maebe 2019-02-23 15:42:48 +00:00
parent 8b9e90dc7a
commit 4e5f48a25e

View File

@ -45,6 +45,8 @@ unit cpupara;
function create_varargs_paraloc_info(p : tabstractprocdef; side: tcallercallee; varargspara:tvarargsparalist):longint;override;
function get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;override;
private
function usemmpararegs(calloption: tproccalloption; variadic: boolean): boolean;
function getparaloc(calloption : tproccalloption; p : tdef; isvariadic: boolean) : tcgloc;
procedure init_values(p: tabstractprocdef; side: tcallercallee; var curintreg,
curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword;
var sparesinglereg: tregister);
@ -131,7 +133,9 @@ unit cpupara;
end;
function getparaloc(calloption : tproccalloption; p : tdef; isvariadic: boolean) : tcgloc;
function tcpuparamanager.getparaloc(calloption : tproccalloption; p : tdef; isvariadic: boolean) : tcgloc;
var
basedef: tdef;
begin
{ Later, the LOC_REFERENCE is in most cases changed into LOC_REGISTER
if push_addr_param for the def is true
@ -161,7 +165,11 @@ unit cpupara;
classrefdef:
getparaloc:=LOC_REGISTER;
recorddef:
getparaloc:=LOC_REGISTER;
if usemmpararegs(calloption,isvariadic) and
is_hfa(p,basedef) then
getparaloc:=LOC_MMREGISTER
else
getparaloc:=LOC_REGISTER;
objectdef:
getparaloc:=LOC_REGISTER;
stringdef:
@ -176,6 +184,9 @@ unit cpupara;
arraydef:
if is_dynamic_array(p) then
getparaloc:=LOC_REGISTER
else if usemmpararegs(calloption,isvariadic) and
is_hfa(p,basedef) then
getparaloc:=LOC_MMREGISTER
else
getparaloc:=LOC_REFERENCE;
setdef:
@ -229,12 +240,19 @@ unit cpupara;
var
i: longint;
sym: tsym;
basedef: tdef;
begin
if handle_common_ret_in_param(def,pd,result) then
exit;
case def.typ of
recorddef:
begin
if usemmpararegs(pd.proccalloption,is_c_variadic(pd)) and
is_hfa(def,basedef) then
begin
result:=false;
exit;
end;
result:=def.size>4;
if not result and
(target_info.abi in [abi_default,abi_armeb]) then
@ -327,11 +345,13 @@ unit cpupara;
var
nextintreg,nextfloatreg,nextmmreg : tsuperregister;
paradef : tdef;
paradef,
hfabasedef : tdef;
paraloc : pcgparalocation;
stack_offset : aword;
hp : tparavarsym;
loc : tcgloc;
hfabasesize : tcgsize;
paracgsize : tcgsize;
paralen : longint;
i : integer;
@ -359,6 +379,31 @@ unit cpupara;
end;
procedure updatemmregs(paradef, basedef: tdef);
var
regsavailable,
regsneeded: longint;
basesize: asizeint;
begin
basesize:=basedef.size;
regsneeded:=paradef.size div basesize;
regsavailable:=ord(RS_D7)-ord(nextmmreg)+1;
case basesize of
4:
regsavailable:=regsavailable*2+ord(sparesinglereg<>NR_NO);
8:
;
else
internalerror(2019022301);
end;
if regsavailable<regsneeded then
begin
nextmmreg:=succ(RS_D7);
sparesinglereg:=NR_NO;
end;
end;
begin
result:=0;
nextintreg:=curintreg;
@ -429,6 +474,18 @@ unit cpupara;
hp.paraloc[side].def:=paradef;
firstparaloc:=true;
if (loc=LOC_MMREGISTER) and
is_hfa(paradef,hfabasedef) then
begin
updatemmregs(paradef,hfabasedef);
hfabasesize:=def_cgsize(hfabasedef);
end
else
begin
hfabasedef:=nil;
hfabasesize:=OS_NO;
end;
{$ifdef EXTDEBUG}
if paralen=0 then
internalerror(200410311);
@ -514,10 +571,18 @@ unit cpupara;
end;
LOC_MMREGISTER:
begin
paraloc^.size:=paracgsize;
paraloc^.def:=paradef;
if assigned(hfabasedef) then
begin
paraloc^.def:=hfabasedef;
paraloc^.size:=hfabasesize;
end
else
begin
paraloc^.size:=paracgsize;
paraloc^.def:=paradef;
end;
if (nextmmreg<=RS_D7) or
((paraloc^.size = OS_F32) and
((paraloc^.size=OS_F32) and
(sparesinglereg<>NR_NO)) then
begin
paraloc^.loc:=LOC_MMREGISTER;
@ -642,35 +707,53 @@ unit cpupara;
function tcpuparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
var
paraloc : pcgparalocation;
paraloc: pcgparalocation;
retcgsize : tcgsize;
basedef: tdef;
i: longint;
mmreg: tregister;
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
basedef:=nil;
if (result.def.typ=floatdef) or
is_hfa(result.def,basedef) then
begin
if (target_info.abi=abi_eabihf) or (p.proccalloption=pocall_hardfloat) then
if usemmpararegs(p.proccalloption,is_c_variadic(p)) then
begin
paraloc^.loc:=LOC_MMREGISTER;
if assigned(basedef) then
begin
for i:=2 to result.def.size div basedef.size do
result.add_location;
retcgsize:=def_cgsize(basedef);
end
else
basedef:=result.def;
case retcgsize of
OS_64,
OS_F64:
begin
paraloc^.register:=NR_MM_RESULT_REG;
mmreg:=NR_MM_RESULT_REG
end;
OS_32,
OS_F32:
begin
paraloc^.register:=NR_S0;
mmreg:=NR_S0;
end;
else
internalerror(2012032501);
end;
paraloc^.size:=retcgsize;
paraloc^.def:=result.def;
repeat
paraloc^.loc:=LOC_MMREGISTER;
paraloc^.register:=mmreg;
inc(mmreg);
paraloc^.size:=retcgsize;
paraloc^.def:=basedef;
paraloc:=paraloc^.next;
until not assigned(paraloc);
end
else if (p.proccalloption in [pocall_softfloat]) or
(cs_fp_emulation in current_settings.moduleswitches) or
@ -764,6 +847,14 @@ unit cpupara;
end;
function tcpuparamanager.usemmpararegs(calloption: tproccalloption; variadic: boolean): boolean;
begin
result:=
((target_info.abi=abi_eabihf) or (calloption=pocall_hardfloat)) and
(not variadic);
end;
function tcpuparamanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
var
cur_stack_offset: aword;