From f0ee1a9ee3b204f6b030e0cd6109713929b62442 Mon Sep 17 00:00:00 2001 From: Jonas Maebe Date: Sat, 14 Mar 2015 18:35:38 +0000 Subject: [PATCH] * pass records that (recursively) only contain floating point values of the same type (even in other records or in arrays), with 8 or less such values, as if those values were passed individually on ppc64/ELFv2 git-svn-id: trunk@30200 - --- compiler/powerpc64/cpupara.pas | 19 +++++++++++--- compiler/powerpc64/symcpu.pas | 48 ++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/compiler/powerpc64/cpupara.pas b/compiler/powerpc64/cpupara.pas index b95b175f4d..d36e008587 100644 --- a/compiler/powerpc64/cpupara.pas +++ b/compiler/powerpc64/cpupara.pas @@ -60,7 +60,7 @@ implementation uses verbose, systems, - defutil,symtable, + defutil,symtable,symcpu, procinfo, cpupi; function tppcparamanager.get_volatile_registers_int(calloption: @@ -262,6 +262,7 @@ var stack_offset: longint; paralen: aint; nextintreg, nextfloatreg, nextmmreg : tsuperregister; + tmpdef, locdef, paradef: tdef; paraloc: pcgparalocation; @@ -291,6 +292,7 @@ begin hp := tparavarsym(paras[i]); paradef := hp.vardef; + locdef := nil; { Syscall for Morphos can have already a paraloc set; not supported on ppc64 } if (vo_has_explicit_paraloc in hp.varoptions) then begin internalerror(200412153); @@ -329,7 +331,17 @@ begin (fsym.vardef.typ in [orddef, enumdef]))) then begin paradef := fsym.vardef; loc := getparaloc(paradef); - paracgsize := def_cgsize(paradef); + paracgsize := def_cgsize(paradef) + { With the new ABI, so-called "homogeneous" aggregates, i.e. struct, arrays, + or unions that (recursively) contain only elements of the same floating- + point or vector type are passed as if those elements were passed as + separate arguments. (This is done for up to 8 such elements.) } + end else if (target_info.abi=abi_powerpc_elfv2) and + tcpurecorddef(paradef).has_single_type_elfv2(tmpdef) and + ((8*tmpdef.size)<=paradef.size) then begin + locdef := tmpdef; + loc := getparaloc(locdef); + paracgsize := def_cgsize(locdef); end else begin loc := LOC_REGISTER; paracgsize := int_cgsize(paralen); @@ -369,7 +381,8 @@ begin end else internalerror(2005011310); adjusttail:=paralen>8; - locdef:=paradef; + if not assigned(locdef) then + locdef:=paradef; firstparaloc:=true; { can become < 0 for e.g. 3-byte records } while (paralen > 0) do begin diff --git a/compiler/powerpc64/symcpu.pas b/compiler/powerpc64/symcpu.pas index d252b9897a..12e14ca87f 100644 --- a/compiler/powerpc64/symcpu.pas +++ b/compiler/powerpc64/symcpu.pas @@ -59,6 +59,10 @@ type tcpupointerdefclass = class of tcpupointerdef; tcpurecorddef = class(trecorddef) + { returns whether the record's elements (including arrays) all have + the same floating point or vector type; returns that type in the "def" + parameter if so } + function has_single_type_elfv2(out def: tdef): boolean; end; tcpurecorddefclass = class of tcpurecorddef; @@ -170,6 +174,50 @@ const implementation + uses + symconst, defutil, defcmp; + +{ tcpurecorddef } + + function tcpurecorddef.has_single_type_elfv2(out def: tdef): boolean; + var + i: longint; + checkdef, tmpdef: tdef; + begin + def:=nil; + tmpdef:=nil; + result:=false; + for i:=0 to symtable.SymList.Count-1 do + begin + if tsym(symtable.symlist[i]).typ=fieldvarsym then + begin + checkdef:=tfieldvarsym(symtable.symlist[i]).vardef; + repeat + case checkdef.typ of + floatdef: + ; + arraydef: + if not is_special_array(checkdef) then + checkdef:=tarraydef(checkdef).elementdef + else + exit; + recorddef: + if not tcpurecorddef(checkdef).has_single_type_elfv2(checkdef) then + exit; + else + exit; + end; + until checkdef.typ=floatdef; + if not assigned(def) then + def:=checkdef + else if not equal_defs(def,checkdef) then + exit; + end; + end; + if assigned(def) then + result:=true; + end; + begin { used tdef classes } cfiledef:=tcpufiledef;