2
0
Эх сурвалжийг харах

* fixed sysv x86-64 function results for records and arrays with sizes 9..16 bytes

git-svn-id: trunk@10285 -
florian 17 жил өмнө
parent
commit
4592402529

+ 2 - 0
compiler/cgutils.pas

@@ -97,6 +97,8 @@ unit cgutils;
             LOC_CREGISTER : (
               case longint of
                 1 : (register : tregister;
+                     { some x86_64 targets require two function result registers }
+                     registerhi : tregister;
 {$ifdef m68k}
                      { some m68k OSes require that the result is returned in d0 and a0
                        the second location must be stored here }

+ 15 - 1
compiler/ncgcal.pas

@@ -509,6 +509,7 @@ implementation
       var
         cgsize    : tcgsize;
         retloc    : tlocation;
+        ref       : treference;
 {$ifndef x86}
         hregister : tregister;
 {$endif not x86}
@@ -546,7 +547,20 @@ implementation
                if cgsize<>OS_NO then
                 begin
                   location_reset(location,LOC_REGISTER,cgsize);
-{$ifndef cpu64bit}
+{$ifdef cpu64bit}
+                  { x86-64 system v abi:
+                    structs with up to 16 bytes are returned in registers }
+                  if cgsize in [OS_128,OS_S128] then
+                    begin
+                      tg.GetTemp(current_asmdata.CurrAsmList,16,tt_normal,ref);
+                      location_reset(location,LOC_REFERENCE,OS_NO);
+                      location.reference:=ref;
+                      cg.a_load_reg_ref(current_asmdata.CurrAsmList,OS_64,OS_64,procdefinition.funcretloc[callerside].register,ref);
+                      inc(ref.offset,8);
+                      cg.a_load_reg_ref(current_asmdata.CurrAsmList,OS_64,OS_64,procdefinition.funcretloc[callerside].registerhi,ref);
+                    end
+                  else
+{$else cpu64bit}
                   if cgsize in [OS_64,OS_S64] then
                     begin
                       retloc:=procdefinition.funcretloc[callerside];

+ 45 - 3
compiler/ncgutil.pas

@@ -1267,9 +1267,7 @@ implementation
 
     procedure gen_load_return_value(list:TAsmList);
       var
-{$ifndef cpu64bit}
         href   : treference;
-{$endif cpu64bit}
         ressym : tabstractnormalvarsym;
         resloc,
         restmploc : tlocation;
@@ -1334,7 +1332,51 @@ implementation
             case funcretloc.loc of
               LOC_REGISTER:
                 begin
-{$ifndef cpu64bit}
+{$ifdef cpu64bit}
+                  if current_procinfo.procdef.funcretloc[calleeside].size in [OS_128,OS_S128] then
+                    begin
+                      resloc:=current_procinfo.procdef.funcretloc[calleeside];
+                      if resloc.loc<>LOC_REGISTER then
+                        internalerror(200409141);
+                      { Load low and high register separate to generate better register
+                        allocation info }
+                      if getsupreg(resloc.register)<first_int_imreg then
+                        begin
+                          cg.getcpuregister(list,resloc.register);
+                        end;
+                      case restmploc.loc of
+                        LOC_REFERENCE :
+                          begin
+                            href:=restmploc.reference;
+                            if target_info.endian=ENDIAN_BIG then
+                              inc(href.offset,8);
+                            cg.a_load_ref_reg(list,OS_64,OS_64,href,resloc.register);
+                          end;
+                        LOC_CREGISTER :
+                          cg.a_load_reg_reg(list,OS_64,OS_64,restmploc.register,resloc.register);
+                        else
+                          internalerror(200409203);
+                      end;
+                      if getsupreg(resloc.registerhi)<first_int_imreg then
+                        begin
+                          cg.getcpuregister(list,resloc.registerhi);
+                        end;
+                      case restmploc.loc of
+                        LOC_REFERENCE :
+                          begin
+                            href:=restmploc.reference;
+                            if target_info.endian=ENDIAN_LITTLE then
+                              inc(href.offset,8);
+                            cg.a_load_ref_reg(list,OS_64,OS_64,href,resloc.registerhi);
+                          end;
+                        LOC_CREGISTER :
+                          cg.a_load_reg_reg(list,OS_64,OS_64,restmploc.registerhi,resloc.registerhi);
+                        else
+                          internalerror(200409204);
+                      end;
+                    end
+                  else
+{$else cpu64bit}
                   if current_procinfo.procdef.funcretloc[calleeside].size in [OS_64,OS_S64] then
                     begin
                       resloc:=current_procinfo.procdef.funcretloc[calleeside];

+ 54 - 9
compiler/x86_64/cpupara.pas

@@ -193,12 +193,48 @@ unit cpupara;
 
 
     function tx86_64paramanager.ret_in_param(def : tdef;calloption : tproccalloption) : boolean;
+      var
+        l,loc1,loc2 : tcgloc;
+        i : longint;
       begin
-        if target_info.system=system_x86_64_win64 then
-          result:=(calloption=pocall_safecall) or
-            (def.size>8) or not(def.size in [1,2,4,8])
-        else
-          result:=inherited ret_in_param(def,calloption);
+        case target_info.system of
+          system_x86_64_win64:
+            result:=(calloption=pocall_safecall) or
+              (def.size>8) or not(def.size in [1,2,4,8])
+          else
+            { handle objectdefs by the default code because they have no equivalence in C }
+            if (def.typ in [recorddef {,arraydef }]) and (def.size<=16) then
+              begin
+                case def.typ of
+                  recorddef:
+                    begin
+                      l:=LOC_MMREGISTER;
+                      for i:=0 to tabstractrecorddef(def).symtable.SymList.count-1 do
+                        begin
+                          getvalueparaloc(vs_value,tfieldvarsym(tabstractrecorddef(def).symtable.SymList[i]).vardef,loc1,loc2);
+                          case loc1 of
+                            LOC_REGISTER:
+                              if l<>LOC_REFERENCE then
+                                l:=LOC_REGISTER;
+                            LOC_MMREGISTER:
+                              ;
+                            else
+                              l:=LOC_REFERENCE;
+                          end;
+                        end;
+                    end;
+                  arraydef:
+                    begin
+                      getvalueparaloc(vs_value,tarraydef(def).elementdef,l,loc2);
+                      if not(l in [LOC_MMREGISTER,LOC_REGISTER]) then
+                        l:=LOC_REFERENCE;
+                    end;
+                end;
+                result:=l=LOC_REFERENCE;
+              end
+            else
+              result:=inherited ret_in_param(def,calloption);
+        end;
       end;
 
 
@@ -400,11 +436,20 @@ unit cpupara;
          { Return in register }
           begin
             p.funcretloc[side].loc:=LOC_REGISTER;
-            p.funcretloc[side].size:=retcgsize;
-            if side=callerside then
-              p.funcretloc[side].register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,cgsize2subreg(retcgsize))
+            if p.returndef.size>8 then
+              begin
+                p.funcretloc[side].size:=OS_128;
+                p.funcretloc[side].register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,R_SUBWHOLE);
+                p.funcretloc[side].registerhi:=newreg(R_INTREGISTER,RS_RDX,R_SUBWHOLE);
+              end
             else
-              p.funcretloc[side].register:=newreg(R_INTREGISTER,RS_FUNCTION_RETURN_REG,cgsize2subreg(retcgsize));
+              begin
+                p.funcretloc[side].size:=retcgsize;
+                if side=callerside then
+                  p.funcretloc[side].register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,cgsize2subreg(retcgsize))
+                else
+                  p.funcretloc[side].register:=newreg(R_INTREGISTER,RS_FUNCTION_RETURN_REG,cgsize2subreg(retcgsize));
+              end;
           end;
       end;