* 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:
florian 2008-02-10 22:28:07 +00:00
parent c35e0bf712
commit 4592402529
4 changed files with 116 additions and 13 deletions

View File

@ -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 }

View File

@ -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];

View File

@ -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];

View File

@ -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;