瀏覽代碼

* 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 -

Jonas Maebe 10 年之前
父節點
當前提交
f0ee1a9ee3
共有 2 個文件被更改,包括 64 次插入3 次删除
  1. 16 3
      compiler/powerpc64/cpupara.pas
  2. 48 0
      compiler/powerpc64/symcpu.pas

+ 16 - 3
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

+ 48 - 0
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;