Pārlūkot izejas kodu

m68k: for cdecls with the SVR4 ABI return results both in A0 and D0

git-svn-id: trunk@36588 -
Károly Balogh 8 gadi atpakaļ
vecāks
revīzija
b481129f4e

+ 3 - 3
compiler/m68k/cgcpu.pas

@@ -1876,11 +1876,11 @@ unit cgcpu;
                     { point to nowhere!                                   }
 
                     { Instead of doing a slow copy of the return address while trying    }
-                    { to feed it to the RTS instruction, load the PC to A0 (scratch reg) }
-                    { then free up the stack allocated for paras, then use a JMP (A0) to }
+                    { to feed it to the RTS instruction, load the PC to A1 (scratch reg) }
+                    { then free up the stack allocated for paras, then use a JMP (A1) to }
                     { return to the caller with the paras freed. (KB) }
 
-                    hregister:=NR_A0;
+                    hregister:=NR_A1;
                     cg.a_reg_alloc(list,hregister);
                     reference_reset_base(ref,NR_STACK_POINTER_REG,0,4,[]);
                     list.concat(taicpu.op_ref_reg(A_MOVE,S_L,ref,hregister));

+ 1 - 1
compiler/m68k/cpubase.pas

@@ -279,8 +279,8 @@ unit cpubase;
 { TODO: FIX ME!!! pic offset reg conflicts with frame pointer?}
       NR_PIC_OFFSET_REG = NR_A5;
       { Return address for DWARF }
-{ TODO: just a guess!}
       NR_RETURN_ADDRESS_REG = NR_A0;
+      RS_RETURN_ADDRESS_REG = RS_A0;
       { Results are returned in this register (32-bit values) }
       NR_FUNCTION_RETURN_REG = NR_D0;
       RS_FUNCTION_RETURN_REG = RS_D0;

+ 34 - 4
compiler/m68k/cpupara.pas

@@ -168,8 +168,9 @@ unit cpupara;
 
     function tcpuparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
       var
-        paraloc : pcgparalocation;
+        paraloc    : pcgparalocation;
         retcgsize  : tcgsize;
+        retregtype : tregistertype;
       begin
         if set_common_funcretloc_info(p,forcetempdef,retcgsize,result) then
           exit;
@@ -223,10 +224,39 @@ unit cpupara;
                paraloc^.loc:=LOC_REGISTER;
                paraloc^.size:=retcgsize;
                paraloc^.def:=result.def;
-               if side=callerside then
-                 paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,cgsize2subreg(R_INTREGISTER,retcgsize))
+
+               { GCC (and SVR4 in general maybe?) requires a pointer result on the A0
+                 register, as well as D0. So we init the result to be A0, then copy
+                 it also to D0 in hlcg.gen_load_loc_function_result. This is not pretty,
+                 but we don't really have an architecture for funcretlocs in two
+                 separate locations.
+
+                 We also have to figure out a better switch for this, because this is
+                 now compiler and platform specific... (KB) }
+
+               if (tprocdef(p).proccalloption in [pocall_cdecl,pocall_cppdecl]) and
+                  (target_info.system in [system_m68k_linux]) and
+                  assigned(result.def) and
+                  (result.def.typ in [stringdef,pointerdef,classrefdef,objectdef,
+                                      procvardef,procdef,arraydef,formaldef]) then
+                 retregtype:=R_ADDRESSREGISTER
+               else
+                 retregtype:=R_INTREGISTER;
+
+               if retregtype = R_ADDRESSREGISTER then
+                 begin
+                   if side=callerside then
+                     paraloc^.register:=newreg(R_ADDRESSREGISTER,RS_RETURN_ADDRESS_REG,cgsize2subreg(R_ADDRESSREGISTER,retcgsize))
+                   else
+                     paraloc^.register:=newreg(R_ADDRESSREGISTER,RS_RETURN_ADDRESS_REG,cgsize2subreg(R_ADDRESSREGISTER,retcgsize));
+                 end
                else
-                 paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RETURN_REG,cgsize2subreg(R_INTREGISTER,retcgsize));
+                 begin
+                   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));
+                 end;
              end;
           end;
       end;

+ 24 - 1
compiler/m68k/hlcgcpu.pas

@@ -43,6 +43,8 @@ interface
       procedure a_bit_set_reg_ref(list: TAsmList; doset: boolean; fromsize, tosize: tdef; bitnumber: tregister; const ref: treference); override;
       procedure a_bit_set_const_ref(list: TAsmList; doset: boolean; destsize: tdef; bitnumber: tcgint; const ref: treference); override;
       procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
+
+      procedure gen_load_loc_function_result(list: TAsmList; vardef: tdef; const l: tlocation);override;
     end;
 
   procedure create_hlcodegen;
@@ -55,7 +57,8 @@ implementation
     aasmtai, aasmcpu,
     defutil,
     hlcgobj,
-    cpuinfo, cgobj, cpubase, cgcpu;
+    cpuinfo, cgobj, cpubase, cgcpu,
+    parabase, procinfo;
 
 
 
@@ -241,6 +244,26 @@ implementation
     end;
 
 
+  procedure thlcgcpu.gen_load_loc_function_result(list: TAsmList; vardef: tdef; const l: tlocation);
+    var
+      cgpara: tcgpara;
+    begin
+      inherited;
+
+      { Kludge:
+        GCC (and SVR4 in general maybe?) requires a pointer
+        result on the A0 register, as well as D0. So when we
+        have a result in A0, also copy it to D0. See the decision
+        making code in tcpuparamanager.get_funcretloc (KB) }
+      cgpara:=current_procinfo.procdef.funcretloc[calleeside];
+      if ((cgpara.location^.loc = LOC_REGISTER) and
+          (isaddressregister(cgpara.location^.register))) then
+        begin
+          cg.a_load_reg_reg(list,OS_ADDR,OS_ADDR,NR_RETURN_ADDRESS_REG,NR_FUNCTION_RESULT_REG);
+        end;
+    end;
+
+
   procedure create_hlcodegen;
     begin
       hlcg:=thlcgcpu.create;