* has_single_field() now looks recursively into fields that are aggregate

types until it finds a non-aggregate type, and then returns "true" if
    that aggregate (record or array) contains one element
  * it now also returns the type of that element directly rather than a
    tfieldvarsym, since we only care about the type and in case of an array
    there is no field

git-svn-id: trunk@30205 -
This commit is contained in:
Jonas Maebe 2015-03-14 18:35:53 +00:00
parent 2e126bb723
commit 3d9713b9c8
5 changed files with 68 additions and 35 deletions

View File

@ -292,7 +292,7 @@ unit cpupara;
var var
retcgsize : tcgsize; retcgsize : tcgsize;
paraloc : pcgparalocation; paraloc : pcgparalocation;
sym: tfieldvarsym; fdef,
usedef: tdef; usedef: tdef;
handled: boolean; handled: boolean;
begin begin
@ -307,10 +307,10 @@ unit cpupara;
system_i386_os2,system_i386_emx]) and system_i386_os2,system_i386_emx]) and
((usedef.typ=recorddef) or ((usedef.typ=recorddef) or
is_object(usedef)) and is_object(usedef)) and
tabstractrecordsymtable(tabstractrecorddef(usedef).symtable).has_single_field(sym) and tabstractrecordsymtable(tabstractrecorddef(usedef).symtable).has_single_field(fdef) and
(sym.vardef.typ=floatdef) and (fdef.typ=floatdef) and
(tfloatdef(sym.vardef).floattype in [s32real,s64real]) then (tfloatdef(fdef).floattype in [s32real,s64real]) then
usedef:=sym.vardef; usedef:=fdef;
handled:=set_common_funcretloc_info(p,usedef,retcgsize,result); handled:=set_common_funcretloc_info(p,usedef,retcgsize,result);
{ normally forcetempdef is passed straight through to { normally forcetempdef is passed straight through to

View File

@ -330,13 +330,13 @@ unit cpupara;
paralen: aint; paralen: aint;
nextintreg,nextfloatreg,nextmmreg, maxfpureg : tsuperregister; nextintreg,nextfloatreg,nextmmreg, maxfpureg : tsuperregister;
locdef, locdef,
fdef,
paradef : tdef; paradef : tdef;
paraloc : pcgparalocation; paraloc : pcgparalocation;
i : integer; i : integer;
hp : tparavarsym; hp : tparavarsym;
loc : tcgloc; loc : tcgloc;
paracgsize: tcgsize; paracgsize: tcgsize;
sym: tfieldvarsym;
firstparaloc: boolean; firstparaloc: boolean;
begin begin
@ -404,13 +404,12 @@ unit cpupara;
{ if a record has only one field and that field is } { if a record has only one field and that field is }
{ non-composite (not array or record), it must be } { non-composite (not array or record), it must be }
{ passed according to the rules of that type. } { passed according to the rules of that type. }
sym:=nil; if tabstractrecordsymtable(tabstractrecorddef(paradef).symtable).has_single_field(fdef) and
if tabstractrecordsymtable(tabstractrecorddef(paradef).symtable).has_single_field(sym) and ((fdef.typ=floatdef) or
((sym.vardef.typ=floatdef) or
((target_info.system=system_powerpc_darwin) and ((target_info.system=system_powerpc_darwin) and
(sym.vardef.typ in [orddef,enumdef]))) then (fdef.typ in [orddef,enumdef]))) then
begin begin
paradef:=sym.vardef; paradef:=fdef;
paracgsize:=def_cgsize(paradef); paracgsize:=def_cgsize(paradef);
end end
else else

View File

@ -320,7 +320,6 @@ var
locdef, locdef,
tmpdef: tdef; tmpdef: tdef;
paralen: aint; paralen: aint;
fsym: tfieldvarsym;
parashift: byte; parashift: byte;
tailpadding, tailpadding,
firstparaloc, firstparaloc,
@ -422,10 +421,10 @@ implemented
{ AIX/ELFv1 b) } { AIX/ELFv1 b) }
else if (target_info.abi in [abi_powerpc_aix,abi_powerpc_sysv]) and else if (target_info.abi in [abi_powerpc_aix,abi_powerpc_sysv]) and
(paradef.typ=recorddef) and (paradef.typ=recorddef) and
tabstractrecordsymtable(tabstractrecorddef(paradef).symtable).has_single_field(fsym) and tabstractrecordsymtable(tabstractrecorddef(paradef).symtable).has_single_field(tmpdef) and
(fsym.vardef.typ=floatdef) then (tmpdef.typ=floatdef) then
begin begin
paradef:=fsym.vardef; paradef:=tmpdef;
loc:=getparaloc(paradef); loc:=getparaloc(paradef);
paracgsize:=def_cgsize(paradef) paracgsize:=def_cgsize(paradef)
end end

View File

@ -86,7 +86,7 @@ interface
procedure addalignmentpadding; procedure addalignmentpadding;
procedure insertdef(def:TDefEntry);override; procedure insertdef(def:TDefEntry);override;
function is_packed: boolean; function is_packed: boolean;
function has_single_field(out sym:tfieldvarsym): boolean; function has_single_field(out def:tdef): boolean;
function get_unit_symtable: tsymtable; function get_unit_symtable: tsymtable;
protected protected
{ size in bytes including padding } { size in bytes including padding }
@ -1238,9 +1238,12 @@ implementation
end; end;
function tabstractrecordsymtable.has_single_field(out sym: tfieldvarsym): boolean; function tabstractrecordsymtable.has_single_field(out def:tdef): boolean;
var var
i: longint; i: longint;
currentsymlist: TFPHashObjectList;
currentdef: tdef;
sym: tfieldvarsym;
begin begin
result:=false; result:=false;
{ If a record contains a union, it does not contain a "single { If a record contains a union, it does not contain a "single
@ -1250,7 +1253,12 @@ implementation
trecorddef(defowner).isunion then trecorddef(defowner).isunion then
exit; exit;
{ a record/object can contain other things than fields } { a record/object can contain other things than fields }
for i:=0 to SymList.Count-1 do currentsymlist:=symlist;
{ recurse in arrays and records }
sym:=nil;
repeat
{ record has one field? }
for i:=0 to currentsymlist.Count-1 do
begin begin
if tsym(symlist[i]).typ=fieldvarsym then if tsym(symlist[i]).typ=fieldvarsym then
begin begin
@ -1263,6 +1271,33 @@ implementation
sym:=tfieldvarsym(symlist[i]) sym:=tfieldvarsym(symlist[i])
end; end;
end; end;
if assigned(sym) then
begin
{ if the field is an array, does it contain one element? }
currentdef:=sym.vardef;
while (currentdef.typ=arraydef) and
not is_special_array(currentdef) do
begin
if tarraydef(currentdef).elecount<>1 then
begin
result:=false;
exit;
end;
currentdef:=tarraydef(currentdef).elementdef;
end;
{ if the array element is again a record, continue descending }
if currentdef.typ=recorddef then
currentsymlist:=trecorddef(currentdef).symtable.SymList
else
begin
{ otherwise we found the type of the single element }
def:=currentdef;
exit;
end;
end
else
exit
until false;
end; end;
function tabstractrecordsymtable.get_unit_symtable: tsymtable; function tabstractrecordsymtable.get_unit_symtable: tsymtable;

View File

@ -1069,6 +1069,7 @@ unit cpupara;
var intparareg,mmparareg,parasize:longint;varargsparas: boolean); var intparareg,mmparareg,parasize:longint;varargsparas: boolean);
var var
hp : tparavarsym; hp : tparavarsym;
fdef,
paradef : tdef; paradef : tdef;
paraloc : pcgparalocation; paraloc : pcgparalocation;
subreg : tsubregister; subreg : tsubregister;
@ -1082,7 +1083,6 @@ unit cpupara;
i, i,
varalign, varalign,
paraalign : longint; paraalign : longint;
sym: tfieldvarsym;
begin begin
paraalign:=get_para_align(p.proccalloption); paraalign:=get_para_align(p.proccalloption);
{ Register parameters are assigned from left to right } { Register parameters are assigned from left to right }
@ -1095,10 +1095,10 @@ unit cpupara;
if (target_info.system=system_x86_64_win64) and if (target_info.system=system_x86_64_win64) and
((paradef.typ=recorddef) {or ((paradef.typ=recorddef) {or
is_object(paradef)}) and is_object(paradef)}) and
tabstractrecordsymtable(tabstractrecorddef(paradef).symtable).has_single_field(sym) and tabstractrecordsymtable(tabstractrecorddef(paradef).symtable).has_single_field(fdef) and
(sym.vardef.typ=floatdef) and (fdef.typ=floatdef) and
(tfloatdef(sym.vardef).floattype in [s32real,s64real]) then (tfloatdef(fdef).floattype in [s32real,s64real]) then
paradef:=sym.vardef; paradef:=fdef;
pushaddr:=push_addr_param(hp.varspez,paradef,p.proccalloption); pushaddr:=push_addr_param(hp.varspez,paradef,p.proccalloption);
if pushaddr then if pushaddr then