Browse Source

+ ppc64le/ELFv2 ret_in_param implementation
* fixed ret_in_param for other ppc64 ABIs

git-svn-id: trunk@30221 -

Jonas Maebe 10 years ago
parent
commit
3d6fcd8815
1 changed files with 105 additions and 25 deletions
  1. 105 25
      compiler/powerpc64/cpupara.pas

+ 105 - 25
compiler/powerpc64/cpupara.pas

@@ -39,6 +39,7 @@ type
       tcpuregisterset; override;
     function push_addr_param(varspez: tvarspez; def: tdef; calloption:
       tproccalloption): boolean; override;
+    function ret_in_param(def: tdef; pd: tabstractprocdef): boolean; override;
 
     procedure getintparaloc(pd : tabstractprocdef; nr: longint; var cgpara: tcgpara); override;
     function create_paraloc_info(p: tabstractprocdef; side: tcallercallee): longint; override;
@@ -54,7 +55,7 @@ type
       var curintreg, curfloatreg, curmmreg: tsuperregister; var
         cur_stack_offset: aword; isVararg : boolean): longint;
     function parseparaloc(p: tparavarsym; const s: string): boolean; override;
-    procedure create_paraloc_for_def(var para: TCGPara; varspez: tvarspez; paradef: tdef; var nextfloatreg, nextintreg: tsuperregister; var stack_offset: longint; const isVararg, forceintmem: boolean; const side: tcallercallee; const p: tabstractprocdef);
+    procedure create_paraloc_for_def(var para: TCGPara; varspez: tvarspez; paradef: tdef; var nextfloatreg, nextintreg: tsuperregister; var stack_offset: aword; const isVararg, forceintmem: boolean; const side: tcallercallee; const p: tabstractprocdef);
   end;
 
 implementation
@@ -200,6 +201,74 @@ begin
   end;
 end;
 
+function tppcparamanager.ret_in_param(def: tdef; pd: tabstractprocdef): boolean;
+  var
+    tmpdef: tdef;
+  begin
+    if handle_common_ret_in_param(def,pd,result) then
+      exit;
+
+    { general rule: passed in registers -> returned in registers }
+    result:=push_addr_param(vs_value,def,pd.proccalloption);
+
+    case target_info.abi of
+      { elfv2: non-homogeneous aggregate larger than 2 doublewords or a
+        homogeneous aggregate with more than eight registers are returned by
+        reference }
+      abi_powerpc_elfv2:
+        begin
+          if not result then
+            begin
+              if (def.typ=recorddef) then
+                begin
+                  if tcpurecorddef(def).has_single_type_elfv2(tmpdef) then
+                    begin
+                      if def.size>8*tmpdef.size then
+                        result:=true
+                    end
+                  else if def.size>2*sizeof(aint) then
+                    result:=true;
+                end
+              else if (def.typ=arraydef) then
+                begin
+                  if tcpuarraydef(def).has_single_type_elfv2(tmpdef) then
+                    begin
+                      if def.size>8*tmpdef.size then
+                        result:=true
+                    end
+                  else if def.size>2*sizeof(aint) then
+                    result:=true;
+                end;
+            end;
+        end;
+      { sysv/aix: any non-scalar/non-floating point is returned by reference }
+      abi_powerpc_sysv,
+      abi_powerpc_aix:
+        begin
+          case def.typ of
+            procvardef:
+              result:=def.size>8;
+            recorddef:
+              result:=true;
+          end;
+        end;
+      { Darwin: if completely passed in registers -> returned by registers;
+        i.e., if part is passed via memory because there are not enough
+        registers, return via memory }
+      abi_powerpc_darwin:
+        begin
+          case def.typ of
+            recorddef:
+              { todo: fix once the Darwin/ppc64 abi is fully implemented, as it
+                requires individual fields to be passed in individual registers,
+                so a record with 9 bytes may need to be passed via memory }
+              if def.size>8*sizeof(aint) then
+                result:=true;
+          end;
+        end;
+    end;
+  end;
+
 procedure tppcparamanager.init_values(var curintreg, curfloatreg, curmmreg:
   tsuperregister; var cur_stack_offset: aword);
 begin
@@ -213,32 +282,45 @@ end;
 function tppcparamanager.get_funcretloc(p : tabstractprocdef; side:
   tcallercallee; forcetempdef: tdef): tcgpara;
 var
-  paraloc : pcgparalocation;
-  retcgsize  : tcgsize;
+  paraloc: pcgparalocation;
+  retcgsize: tcgsize;
+  nextfloatreg, nextintreg, nextmmreg: tsuperregister;
+  stack_offset: aword;
 begin
   if set_common_funcretloc_info(p,forcetempdef,retcgsize,result) then
     exit;
 
-  paraloc:=result.add_location;
-  { Return in FPU register? }
-  if result.def.typ=floatdef then
+  { on Darwin and with ELFv2, results are returned the same way as they are
+    passed }
+  if target_info.abi in [abi_powerpc_elfv2,abi_powerpc_darwin] then
     begin
-      paraloc^.loc:=LOC_FPUREGISTER;
-      paraloc^.register:=NR_FPU_RESULT_REG;
-      paraloc^.size:=retcgsize;
-      paraloc^.def:=result.def;
+      init_values(nextintreg,nextfloatreg,nextmmreg,stack_offset);
+      create_paraloc_for_def(result,vs_value,result.def,nextfloatreg,nextintreg,stack_offset,false,false,side,p);
     end
   else
-   { Return in register }
     begin
-       paraloc^.loc:=LOC_REGISTER;
-       if side=callerside then
-         paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,cgsize2subreg(R_INTREGISTER,retcgsize))
-       else
-         paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RETURN_REG,cgsize2subreg(R_INTREGISTER,retcgsize));
-       paraloc^.size:=retcgsize;
-       paraloc^.def:=result.def;
-     end;
+      { for AIX and ELFv1, the situation is simpler: always just one register }
+      paraloc:=result.add_location;
+      { Return in FPU register? }
+      if result.def.typ=floatdef then
+        begin
+          paraloc^.loc:=LOC_FPUREGISTER;
+          paraloc^.register:=NR_FPU_RESULT_REG;
+          paraloc^.size:=retcgsize;
+          paraloc^.def:=result.def;
+        end
+      else
+       { Return in register }
+        begin
+           paraloc^.loc:=LOC_REGISTER;
+           if side=callerside then
+             paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,cgsize2subreg(R_INTREGISTER,retcgsize))
+           else
+             paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RETURN_REG,cgsize2subreg(R_INTREGISTER,retcgsize));
+           paraloc^.size:=retcgsize;
+           paraloc^.def:=result.def;
+         end;
+    end;
 end;
 
 function tppcparamanager.create_paraloc_info(p: tabstractprocdef; side:
@@ -260,7 +342,6 @@ function tppcparamanager.create_paraloc_info_intern(p: tabstractprocdef; side:
   var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset:
   aword; isVararg : boolean): longint;
 var
-  stack_offset: longint;
   nextintreg, nextfloatreg, nextmmreg : tsuperregister;
   i: integer;
   hp: tparavarsym;
@@ -277,7 +358,6 @@ begin
   nextintreg := curintreg;
   nextfloatreg := curfloatreg;
   nextmmreg := curmmreg;
-  stack_offset := cur_stack_offset;
 
   for i := 0 to paras.count - 1 do begin
     hp := tparavarsym(paras[i]);
@@ -300,17 +380,17 @@ begin
     end;
     delphi_nestedfp:=(vo_is_parentfp in hp.varoptions) and (po_delphi_nested_cc in p.procoptions);
     create_paraloc_for_def(hp.paraloc[side], hp.varspez, hp.vardef,
-      nextfloatreg, nextintreg, stack_offset, isVararg, delphi_nestedfp, side, p);
+      nextfloatreg, nextintreg, cur_stack_offset, isVararg, delphi_nestedfp, side, p);
   end;
 
   curintreg := nextintreg;
   curfloatreg := nextfloatreg;
   curmmreg := nextmmreg;
-  cur_stack_offset := stack_offset;
-  result := stack_offset;
+  cur_stack_offset := cur_stack_offset;
+  result := cur_stack_offset;
 end;
 
-procedure tppcparamanager.create_paraloc_for_def(var para: TCGPara; varspez: tvarspez; paradef: tdef; var nextfloatreg, nextintreg: tsuperregister; var stack_offset: longint; const isVararg, forceintmem: boolean; const side: tcallercallee; const p: tabstractprocdef);
+procedure tppcparamanager.create_paraloc_for_def(var para: TCGPara; varspez: tvarspez; paradef: tdef; var nextfloatreg, nextintreg: tsuperregister; var stack_offset: aword; const isVararg, forceintmem: boolean; const side: tcallercallee; const p: tabstractprocdef);
 var
   paracgsize: tcgsize;
   loc: tcgloc;