Przeglądaj źródła

* hopefully the final fix for x86-64 sysv calling conventions

git-svn-id: trunk@10304 -
florian 17 lat temu
rodzic
commit
1a2a4af773
3 zmienionych plików z 86 dodań i 7 usunięć
  1. 14 3
      compiler/ncgcal.pas
  2. 53 0
      compiler/ncgutil.pas
  3. 19 4
      compiler/x86_64/cpupara.pas

+ 14 - 3
compiler/ncgcal.pas

@@ -507,6 +507,7 @@ implementation
 
     procedure tcgcallnode.handle_return_value;
       var
+        tmpcgsize,
         cgsize    : tcgsize;
         retloc    : tlocation;
         ref       : treference;
@@ -583,10 +584,20 @@ implementation
                         getregister was done for the full register
                         def_cgsize(resultdef) is used here because
                         it could be a constructor call }
+
                       if getsupreg(procdefinition.funcretloc[callerside].register)<first_int_imreg then
                         cg.ungetcpuregister(current_asmdata.CurrAsmList,procdefinition.funcretloc[callerside].register);
-                      location.register:=cg.getintregister(current_asmdata.CurrAsmList,def_cgsize(resultdef));
-                      cg.a_load_reg_reg(current_asmdata.CurrAsmList,cgsize,def_cgsize(resultdef),procdefinition.funcretloc[callerside].register,location.register);
+
+                      { but use def_size only if it returns something valid because in
+                        case of odd sized structured results in registers def_cgsize(resultdef)
+                        could return OS_NO }
+                      if def_cgsize(resultdef)<>OS_NO then
+                        tmpcgsize:=def_cgsize(resultdef)
+                      else
+                        tmpcgsize:=cgsize;
+
+                      location.register:=cg.getintregister(current_asmdata.CurrAsmList,tmpcgsize);
+                      cg.a_load_reg_reg(current_asmdata.CurrAsmList,cgsize,tmpcgsize,procdefinition.funcretloc[callerside].register,location.register);
                     end;
 {$ifdef arm}
                   if (resultdef.typ=floatdef) and (current_settings.fputype in [fpu_fpa,fpu_fpa10,fpu_fpa11]) then
@@ -1085,7 +1096,7 @@ implementation
              cgpara.init;
              paramanager.getintparaloc(pocall_default,1,cgpara);
              cg.a_param_reg(current_asmdata.CurrAsmList,OS_ADDR,NR_RAX,cgpara);
-             cgpara.done;          
+             cgpara.done;
 {$endif x86_64}
              cg.allocallcpuregisters(current_asmdata.CurrAsmList);
              cg.a_call_name(current_asmdata.CurrAsmList,'FPC_SAFECALLCHECK');

+ 53 - 0
compiler/ncgutil.pas

@@ -1376,6 +1376,32 @@ implementation
                       end;
                     end
                   else
+                    { this code is for structures etc. being returned in registers and having odd sizes }
+                    if (current_procinfo.procdef.funcretloc[calleeside].size=OS_64) and
+                      (restmploc.size<>OS_64) 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;
+                              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;
+                      end
+                    else
 {$else cpu64bit}
                   if current_procinfo.procdef.funcretloc[calleeside].size in [OS_64,OS_S64] then
                     begin
@@ -1421,6 +1447,33 @@ implementation
                     end
                   else
 {$endif cpu64bit}
+                  { this code is for structures etc. being returned in registers and having odd sizes }
+                  if (current_procinfo.procdef.funcretloc[calleeside].size=OS_32) and
+                    not(restmploc.size in [OS_S32,OS_32]) 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;
+                            resloc.register:=cg.makeregsize(list,resloc.register,OS_32);
+                            cg.a_load_ref_reg(list,OS_32,OS_32,href,resloc.register);
+                          end;
+                        LOC_CREGISTER :
+                          cg.a_load_reg_reg(list,OS_32,OS_32,restmploc.register,resloc.register);
+                        else
+                          internalerror(200409203);
+                      end;
+                    end
+                  else
                     begin
                       hreg:=cg.makeregsize(list,funcretloc.register,funcretloc.size);
                       if getsupreg(funcretloc.register)<first_int_imreg then

+ 19 - 4
compiler/x86_64/cpupara.pas

@@ -436,11 +436,26 @@ unit cpupara;
          { Return in register }
           begin
             p.funcretloc[side].loc:=LOC_REGISTER;
-            if p.returndef.size>8 then
+            if retcgsize=OS_NO 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);
+                case p.returndef.size of
+                  0..4:
+                    begin
+                      p.funcretloc[side].size:=OS_32;
+                      p.funcretloc[side].register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,R_SUBD);
+                    end;
+                  5..8:
+                    begin
+                      p.funcretloc[side].size:=OS_64;
+                      p.funcretloc[side].register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,R_SUBQ);
+                    end;
+                  9..16:
+                    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;
+                end;
               end
             else
               begin