mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-22 10:49:29 +02:00
* fixed sysv x86-64 function results for records and arrays with sizes 9..16 bytes
git-svn-id: trunk@10285 -
This commit is contained in:
parent
c35e0bf712
commit
4592402529
@ -97,6 +97,8 @@ unit cgutils;
|
||||
LOC_CREGISTER : (
|
||||
case longint of
|
||||
1 : (register : tregister;
|
||||
{ some x86_64 targets require two function result registers }
|
||||
registerhi : tregister;
|
||||
{$ifdef m68k}
|
||||
{ some m68k OSes require that the result is returned in d0 and a0
|
||||
the second location must be stored here }
|
||||
|
@ -509,6 +509,7 @@ implementation
|
||||
var
|
||||
cgsize : tcgsize;
|
||||
retloc : tlocation;
|
||||
ref : treference;
|
||||
{$ifndef x86}
|
||||
hregister : tregister;
|
||||
{$endif not x86}
|
||||
@ -546,7 +547,20 @@ implementation
|
||||
if cgsize<>OS_NO then
|
||||
begin
|
||||
location_reset(location,LOC_REGISTER,cgsize);
|
||||
{$ifndef cpu64bit}
|
||||
{$ifdef cpu64bit}
|
||||
{ x86-64 system v abi:
|
||||
structs with up to 16 bytes are returned in registers }
|
||||
if cgsize in [OS_128,OS_S128] then
|
||||
begin
|
||||
tg.GetTemp(current_asmdata.CurrAsmList,16,tt_normal,ref);
|
||||
location_reset(location,LOC_REFERENCE,OS_NO);
|
||||
location.reference:=ref;
|
||||
cg.a_load_reg_ref(current_asmdata.CurrAsmList,OS_64,OS_64,procdefinition.funcretloc[callerside].register,ref);
|
||||
inc(ref.offset,8);
|
||||
cg.a_load_reg_ref(current_asmdata.CurrAsmList,OS_64,OS_64,procdefinition.funcretloc[callerside].registerhi,ref);
|
||||
end
|
||||
else
|
||||
{$else cpu64bit}
|
||||
if cgsize in [OS_64,OS_S64] then
|
||||
begin
|
||||
retloc:=procdefinition.funcretloc[callerside];
|
||||
|
@ -1267,9 +1267,7 @@ implementation
|
||||
|
||||
procedure gen_load_return_value(list:TAsmList);
|
||||
var
|
||||
{$ifndef cpu64bit}
|
||||
href : treference;
|
||||
{$endif cpu64bit}
|
||||
ressym : tabstractnormalvarsym;
|
||||
resloc,
|
||||
restmploc : tlocation;
|
||||
@ -1334,7 +1332,51 @@ implementation
|
||||
case funcretloc.loc of
|
||||
LOC_REGISTER:
|
||||
begin
|
||||
{$ifndef cpu64bit}
|
||||
{$ifdef cpu64bit}
|
||||
if current_procinfo.procdef.funcretloc[calleeside].size in [OS_128,OS_S128] then
|
||||
begin
|
||||
resloc:=current_procinfo.procdef.funcretloc[calleeside];
|
||||
if resloc.loc<>LOC_REGISTER then
|
||||
internalerror(200409141);
|
||||
{ Load low and high register separate to generate better register
|
||||
allocation info }
|
||||
if getsupreg(resloc.register)<first_int_imreg then
|
||||
begin
|
||||
cg.getcpuregister(list,resloc.register);
|
||||
end;
|
||||
case restmploc.loc of
|
||||
LOC_REFERENCE :
|
||||
begin
|
||||
href:=restmploc.reference;
|
||||
if target_info.endian=ENDIAN_BIG then
|
||||
inc(href.offset,8);
|
||||
cg.a_load_ref_reg(list,OS_64,OS_64,href,resloc.register);
|
||||
end;
|
||||
LOC_CREGISTER :
|
||||
cg.a_load_reg_reg(list,OS_64,OS_64,restmploc.register,resloc.register);
|
||||
else
|
||||
internalerror(200409203);
|
||||
end;
|
||||
if getsupreg(resloc.registerhi)<first_int_imreg then
|
||||
begin
|
||||
cg.getcpuregister(list,resloc.registerhi);
|
||||
end;
|
||||
case restmploc.loc of
|
||||
LOC_REFERENCE :
|
||||
begin
|
||||
href:=restmploc.reference;
|
||||
if target_info.endian=ENDIAN_LITTLE then
|
||||
inc(href.offset,8);
|
||||
cg.a_load_ref_reg(list,OS_64,OS_64,href,resloc.registerhi);
|
||||
end;
|
||||
LOC_CREGISTER :
|
||||
cg.a_load_reg_reg(list,OS_64,OS_64,restmploc.registerhi,resloc.registerhi);
|
||||
else
|
||||
internalerror(200409204);
|
||||
end;
|
||||
end
|
||||
else
|
||||
{$else cpu64bit}
|
||||
if current_procinfo.procdef.funcretloc[calleeside].size in [OS_64,OS_S64] then
|
||||
begin
|
||||
resloc:=current_procinfo.procdef.funcretloc[calleeside];
|
||||
|
@ -193,12 +193,48 @@ unit cpupara;
|
||||
|
||||
|
||||
function tx86_64paramanager.ret_in_param(def : tdef;calloption : tproccalloption) : boolean;
|
||||
var
|
||||
l,loc1,loc2 : tcgloc;
|
||||
i : longint;
|
||||
begin
|
||||
if target_info.system=system_x86_64_win64 then
|
||||
result:=(calloption=pocall_safecall) or
|
||||
(def.size>8) or not(def.size in [1,2,4,8])
|
||||
else
|
||||
result:=inherited ret_in_param(def,calloption);
|
||||
case target_info.system of
|
||||
system_x86_64_win64:
|
||||
result:=(calloption=pocall_safecall) or
|
||||
(def.size>8) or not(def.size in [1,2,4,8])
|
||||
else
|
||||
{ handle objectdefs by the default code because they have no equivalence in C }
|
||||
if (def.typ in [recorddef {,arraydef }]) and (def.size<=16) then
|
||||
begin
|
||||
case def.typ of
|
||||
recorddef:
|
||||
begin
|
||||
l:=LOC_MMREGISTER;
|
||||
for i:=0 to tabstractrecorddef(def).symtable.SymList.count-1 do
|
||||
begin
|
||||
getvalueparaloc(vs_value,tfieldvarsym(tabstractrecorddef(def).symtable.SymList[i]).vardef,loc1,loc2);
|
||||
case loc1 of
|
||||
LOC_REGISTER:
|
||||
if l<>LOC_REFERENCE then
|
||||
l:=LOC_REGISTER;
|
||||
LOC_MMREGISTER:
|
||||
;
|
||||
else
|
||||
l:=LOC_REFERENCE;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
arraydef:
|
||||
begin
|
||||
getvalueparaloc(vs_value,tarraydef(def).elementdef,l,loc2);
|
||||
if not(l in [LOC_MMREGISTER,LOC_REGISTER]) then
|
||||
l:=LOC_REFERENCE;
|
||||
end;
|
||||
end;
|
||||
result:=l=LOC_REFERENCE;
|
||||
end
|
||||
else
|
||||
result:=inherited ret_in_param(def,calloption);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
@ -400,11 +436,20 @@ unit cpupara;
|
||||
{ Return in register }
|
||||
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))
|
||||
if p.returndef.size>8 then
|
||||
begin
|
||||
p.funcretloc[side].size:=OS_128;
|
||||
p.funcretloc[side].register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,R_SUBWHOLE);
|
||||
p.funcretloc[side].registerhi:=newreg(R_INTREGISTER,RS_RDX,R_SUBWHOLE);
|
||||
end
|
||||
else
|
||||
p.funcretloc[side].register:=newreg(R_INTREGISTER,RS_FUNCTION_RETURN_REG,cgsize2subreg(retcgsize));
|
||||
begin
|
||||
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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user