From 3d9713b9c808e329b5a819faa2a351d5780c7114 Mon Sep 17 00:00:00 2001 From: Jonas Maebe Date: Sat, 14 Mar 2015 18:35:53 +0000 Subject: [PATCH] * 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 - --- compiler/i386/cpupara.pas | 10 +++--- compiler/powerpc/cpupara.pas | 11 +++--- compiler/powerpc64/cpupara.pas | 7 ++-- compiler/symtable.pas | 65 ++++++++++++++++++++++++++-------- compiler/x86_64/cpupara.pas | 10 +++--- 5 files changed, 68 insertions(+), 35 deletions(-) diff --git a/compiler/i386/cpupara.pas b/compiler/i386/cpupara.pas index d310fb5279..f33c2ffc27 100644 --- a/compiler/i386/cpupara.pas +++ b/compiler/i386/cpupara.pas @@ -292,7 +292,7 @@ unit cpupara; var retcgsize : tcgsize; paraloc : pcgparalocation; - sym: tfieldvarsym; + fdef, usedef: tdef; handled: boolean; begin @@ -307,10 +307,10 @@ unit cpupara; system_i386_os2,system_i386_emx]) and ((usedef.typ=recorddef) or is_object(usedef)) and - tabstractrecordsymtable(tabstractrecorddef(usedef).symtable).has_single_field(sym) and - (sym.vardef.typ=floatdef) and - (tfloatdef(sym.vardef).floattype in [s32real,s64real]) then - usedef:=sym.vardef; + tabstractrecordsymtable(tabstractrecorddef(usedef).symtable).has_single_field(fdef) and + (fdef.typ=floatdef) and + (tfloatdef(fdef).floattype in [s32real,s64real]) then + usedef:=fdef; handled:=set_common_funcretloc_info(p,usedef,retcgsize,result); { normally forcetempdef is passed straight through to diff --git a/compiler/powerpc/cpupara.pas b/compiler/powerpc/cpupara.pas index 8855333573..b260af97e9 100644 --- a/compiler/powerpc/cpupara.pas +++ b/compiler/powerpc/cpupara.pas @@ -330,13 +330,13 @@ unit cpupara; paralen: aint; nextintreg,nextfloatreg,nextmmreg, maxfpureg : tsuperregister; locdef, + fdef, paradef : tdef; paraloc : pcgparalocation; i : integer; hp : tparavarsym; loc : tcgloc; paracgsize: tcgsize; - sym: tfieldvarsym; firstparaloc: boolean; begin @@ -404,13 +404,12 @@ unit cpupara; { if a record has only one field and that field is } { non-composite (not array or record), it must be } { passed according to the rules of that type. } - sym:=nil; - if tabstractrecordsymtable(tabstractrecorddef(paradef).symtable).has_single_field(sym) and - ((sym.vardef.typ=floatdef) or + if tabstractrecordsymtable(tabstractrecorddef(paradef).symtable).has_single_field(fdef) and + ((fdef.typ=floatdef) or ((target_info.system=system_powerpc_darwin) and - (sym.vardef.typ in [orddef,enumdef]))) then + (fdef.typ in [orddef,enumdef]))) then begin - paradef:=sym.vardef; + paradef:=fdef; paracgsize:=def_cgsize(paradef); end else diff --git a/compiler/powerpc64/cpupara.pas b/compiler/powerpc64/cpupara.pas index 65f06490cd..51f8c4e378 100644 --- a/compiler/powerpc64/cpupara.pas +++ b/compiler/powerpc64/cpupara.pas @@ -320,7 +320,6 @@ var locdef, tmpdef: tdef; paralen: aint; - fsym: tfieldvarsym; parashift: byte; tailpadding, firstparaloc, @@ -422,10 +421,10 @@ implemented { AIX/ELFv1 b) } else if (target_info.abi in [abi_powerpc_aix,abi_powerpc_sysv]) and (paradef.typ=recorddef) and - tabstractrecordsymtable(tabstractrecorddef(paradef).symtable).has_single_field(fsym) and - (fsym.vardef.typ=floatdef) then + tabstractrecordsymtable(tabstractrecorddef(paradef).symtable).has_single_field(tmpdef) and + (tmpdef.typ=floatdef) then begin - paradef:=fsym.vardef; + paradef:=tmpdef; loc:=getparaloc(paradef); paracgsize:=def_cgsize(paradef) end diff --git a/compiler/symtable.pas b/compiler/symtable.pas index 89aeed0668..b8204bb508 100644 --- a/compiler/symtable.pas +++ b/compiler/symtable.pas @@ -86,7 +86,7 @@ interface procedure addalignmentpadding; procedure insertdef(def:TDefEntry);override; 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; protected { size in bytes including padding } @@ -1238,9 +1238,12 @@ implementation end; - function tabstractrecordsymtable.has_single_field(out sym: tfieldvarsym): boolean; + function tabstractrecordsymtable.has_single_field(out def:tdef): boolean; var i: longint; + currentsymlist: TFPHashObjectList; + currentdef: tdef; + sym: tfieldvarsym; begin result:=false; { If a record contains a union, it does not contain a "single @@ -1250,19 +1253,51 @@ implementation trecorddef(defowner).isunion then exit; { a record/object can contain other things than fields } - for i:=0 to SymList.Count-1 do - begin - if tsym(symlist[i]).typ=fieldvarsym then - begin - if result then - begin - result:=false; - exit; - end; - result:=true; - sym:=tfieldvarsym(symlist[i]) - end; - end; + currentsymlist:=symlist; + { recurse in arrays and records } + sym:=nil; + repeat + { record has one field? } + for i:=0 to currentsymlist.Count-1 do + begin + if tsym(symlist[i]).typ=fieldvarsym then + begin + if result then + begin + result:=false; + exit; + end; + result:=true; + sym:=tfieldvarsym(symlist[i]) + 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; function tabstractrecordsymtable.get_unit_symtable: tsymtable; diff --git a/compiler/x86_64/cpupara.pas b/compiler/x86_64/cpupara.pas index c61712b10b..7c72164511 100644 --- a/compiler/x86_64/cpupara.pas +++ b/compiler/x86_64/cpupara.pas @@ -1069,6 +1069,7 @@ unit cpupara; var intparareg,mmparareg,parasize:longint;varargsparas: boolean); var hp : tparavarsym; + fdef, paradef : tdef; paraloc : pcgparalocation; subreg : tsubregister; @@ -1082,7 +1083,6 @@ unit cpupara; i, varalign, paraalign : longint; - sym: tfieldvarsym; begin paraalign:=get_para_align(p.proccalloption); { Register parameters are assigned from left to right } @@ -1095,10 +1095,10 @@ unit cpupara; if (target_info.system=system_x86_64_win64) and ((paradef.typ=recorddef) {or is_object(paradef)}) and - tabstractrecordsymtable(tabstractrecorddef(paradef).symtable).has_single_field(sym) and - (sym.vardef.typ=floatdef) and - (tfloatdef(sym.vardef).floattype in [s32real,s64real]) then - paradef:=sym.vardef; + tabstractrecordsymtable(tabstractrecorddef(paradef).symtable).has_single_field(fdef) and + (fdef.typ=floatdef) and + (tfloatdef(fdef).floattype in [s32real,s64real]) then + paradef:=fdef; pushaddr:=push_addr_param(hp.varspez,paradef,p.proccalloption); if pushaddr then