Browse Source

* m68k: Fixed parameter passing to conform to ABI:
* records are passed by value
* records with size of 1,2 or 4 are returned in registers
* parameters with size<4 are justified on the stack according to big-endian target

Now everything except floating-point parameters is compatible with C code compiled with "-malign-int -mrtd".
Compatibility with "-mno-align-int" is achievable by changing target_info.maxCrecordalign to 2, but doings so causes a lot more troubles because RTL (incorrectly) assumes that records declared with {$PACKRECORDS C} are aligned to pointer size.

+ Reuse parameter locations. Since everything is passed on stack, it reduces code size quite a bit.
- tm68kparamanager.getintparaloc removed, generic implementation has been tested and works as expected.

git-svn-id: trunk@28083 -

sergei 11 years ago
parent
commit
acd3ea8750
3 changed files with 57 additions and 66 deletions
  1. 5 23
      compiler/m68k/cgcpu.pas
  2. 50 37
      compiler/m68k/cpupara.pas
  3. 2 6
      rtl/m68k/m68k.inc

+ 5 - 23
compiler/m68k/cgcpu.pas

@@ -815,17 +815,14 @@ unit cgcpu;
 
     procedure tcg68k.a_load_reg_ref(list : TAsmList;fromsize,tosize : tcgsize;register : tregister;const ref : treference);
       var
-       href : treference;
-        size : tcgsize;
+        href : treference;
       begin
         href := ref;
         fixref(list,href);
         if tcgsize2size[fromsize]<tcgsize2size[tosize] then
-          size:=fromsize
-        else
-          size:=tosize;
+          a_load_reg_reg(list,fromsize,tosize,register,register);
         { move to destination reference }
-        list.concat(taicpu.op_reg_ref(A_MOVE,TCGSize2OpSize[size],register,href));
+        list.concat(taicpu.op_reg_ref(A_MOVE,TCGSize2OpSize[tosize],register,href));
       end;
 
 
@@ -1506,7 +1503,6 @@ unit cgcpu;
          hp2 : treference;
          hl : tasmlabel;
          srcref,dstref : treference;
-         alignsize : tcgsize;
          orglen : tcgint;
       begin
          hregister := getintregister(list,OS_INT);
@@ -1530,14 +1526,7 @@ unit cgcpu;
               { move a word }
               if len>1 then
                 begin
-                   if (orglen<sizeof(aint)) and
-                       (source.base=NR_FRAME_POINTER_REG) and
-                       (source.offset>0) then
-                     { copy of param to local location }
-                     alignsize:=OS_INT
-                   else
-                     alignsize:=OS_16;
-                   a_load_ref_reg(list,alignsize,alignsize,srcref,hregister);
+                   a_load_ref_reg(list,OS_16,OS_16,srcref,hregister);
                    a_load_reg_ref(list,OS_16,OS_16,hregister,dstref);
                    inc(srcref.offset,2);
                    inc(dstref.offset,2);
@@ -1546,14 +1535,7 @@ unit cgcpu;
               { move a single byte }
               if len>0 then
                 begin
-                   if (orglen<sizeof(aint)) and
-                       (source.base=NR_FRAME_POINTER_REG) and
-                       (source.offset>0) then
-                     { copy of param to local location }
-                     alignsize:=OS_INT
-                   else
-                     alignsize:=OS_8;
-                   a_load_ref_reg(list,alignsize,alignsize,srcref,hregister);
+                   a_load_ref_reg(list,OS_8,OS_8,srcref,hregister);
                    a_load_reg_ref(list,OS_8,OS_8,hregister,dstref);
                 end
            end

+ 50 - 37
compiler/m68k/cpupara.pas

@@ -39,7 +39,8 @@ unit cpupara;
          rtl are used.
        }
        tm68kparamanager = class(tparamanager)
-          procedure getintparaloc(pd : tabstractprocdef; nr : longint; var cgpara : tcgpara);override;
+          function ret_in_param(def:tdef;pd:tabstractprocdef):boolean;override;
+          function param_use_paraloc(const cgpara:tcgpara):boolean;override;
           function create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;override;
           function push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override;
           function get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;override;
@@ -80,35 +81,24 @@ unit cpupara;
       end;
 
 
-    procedure tm68kparamanager.getintparaloc(pd : tabstractprocdef; nr : longint; var cgpara : tcgpara);
+    function tm68kparamanager.param_use_paraloc(const cgpara:tcgpara):boolean;
       var
         paraloc : pcgparalocation;
-        psym: tparavarsym;
-        pdef: tdef;
       begin
-         if nr<1 then
-           internalerror(2002070801);
-         psym:=tparavarsym(pd.paras[nr-1]);
-         pdef:=psym.vardef;
-         if push_addr_param(psym.varspez,pdef,pd.proccalloption) then
-           pdef:=getpointerdef(pdef);
-         cgpara.reset;
-         cgpara.size:=def_cgsize(pdef);
-         cgpara.intsize:=tcgsize2size[cgpara.size];
-         cgpara.alignment:=std_param_align;
-         cgpara.def:=pdef;
-         paraloc:=cgpara.add_location;
-         with paraloc^ do
-           begin
-              { warning : THIS ONLY WORKS WITH INTERNAL ROUTINES,
-                WHICH MUST ALWAYS PASS 4-BYTE PARAMETERS!!
-              }
-              loc:=LOC_REFERENCE;
-              reference.index:=NR_STACK_POINTER_REG;
-              reference.offset:=target_info.first_parm_offset+nr*4;
-              size:=def_cgsize(pdef);
-              def:=pdef;
-           end;
+        if not assigned(cgpara.location) then
+          internalerror(200410102);
+        result:=true;
+        { All locations are LOC_REFERENCE }
+        paraloc:=cgpara.location;
+        while assigned(paraloc) do
+          begin
+            if (paraloc^.loc<>LOC_REFERENCE) then
+              begin
+                result:=false;
+                exit;
+              end;
+            paraloc:=paraloc^.next;
+          end;
       end;
 
 
@@ -127,7 +117,7 @@ unit cpupara;
           formaldef :
             result:=true;
           recorddef:
-            result:=true;
+            result:=false;
           arraydef:
             result:=(tarraydef(def).highrange>=tarraydef(def).lowrange) or
                              is_open_array(def) or
@@ -140,7 +130,8 @@ unit cpupara;
           stringdef :
             result:=tstringdef(def).stringtype in [st_shortstring,st_longstring];
           procvardef :
-            result:=po_methodpointer in tprocvardef(def).procoptions;
+            { Handling of methods must match that of records }
+            result:=false;
         end;
       end;
 
@@ -151,6 +142,24 @@ unit cpupara;
         curfloatreg:=RS_FP0;
       end;
 
+
+    function tm68kparamanager.ret_in_param(def:tdef;pd:tabstractprocdef):boolean;
+      begin
+        if handle_common_ret_in_param(def,pd,result) then
+          exit;
+
+        case def.typ of
+          recorddef:
+            if def.size in [1,2,4] then
+              begin
+                result:=false;
+                exit;
+              end;
+        end;
+        result:=inherited ret_in_param(def,pd);
+      end;
+
+
     function tm68kparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
       var
         paraloc : pcgparalocation;
@@ -286,7 +295,7 @@ unit cpupara;
 
                 paracgsize:=def_cgsize(paradef);
                 { for things like formaldef }
-                if (paracgsize=OS_NO) then
+                if (paracgsize=OS_NO) and (paradef.typ<>recorddef) then
                   begin
                     paracgsize:=OS_ADDR;
                     paralen := tcgsize2size[OS_ADDR];
@@ -314,17 +323,21 @@ unit cpupara;
 
                 paraloc^.loc:=LOC_REFERENCE;
                 paraloc^.def:=get_paraloc_def(paradef,paralen,firstparaloc);
-                if paradef.typ<>orddef then
-                  paracgsize:=int_cgsize(paralen);
-                if paracgsize=OS_NO then
-                  paraloc^.size:=OS_INT
+                if (paradef.typ=floatdef) then
+                  paraloc^.size:=int_float_cgsize(paralen)
                 else
-                  paraloc^.size:=paracgsize;
+                  paraloc^.size:=int_cgsize(paralen);
+
+                paraloc^.reference.offset:=stack_offset;
                 if (side = callerside) then
                   paraloc^.reference.index:=NR_STACK_POINTER_REG
                 else
-                  paraloc^.reference.index:=NR_FRAME_POINTER_REG;
-                paraloc^.reference.offset:=stack_offset;
+                  begin
+                    paraloc^.reference.index:=NR_FRAME_POINTER_REG;
+                    { M68K is a big-endian target }
+                    if (paralen<tcgsize2size[OS_INT]) then
+                      inc(paraloc^.reference.offset,4-paralen);
+                  end;
                 inc(stack_offset,align(paralen,4));
                 paralen := 0;
 

+ 2 - 6
rtl/m68k/m68k.inc

@@ -91,9 +91,7 @@ procedure FillChar(var x; count : longint; value : byte); assembler;
 asm
   move.l x, a0          { destination                   }
   move.l count, d1      { number of bytes to fill       }
-{ FIXME: this should be move.b, but everything is pushed as long on
-         the stack ATM (KB) }
-  move.l value, d0      { fill data                     }
+  move.b value, d0      { fill data                     }
   tst.l  d1             { anything to fill at all?      }
   ble    @LMEMSET5
 {$ifdef CPUM68K_HAS_DBRA}
@@ -321,9 +319,7 @@ procedure FillWord(var x; count : longint; value : word); assembler;
 asm
   move.l x, a0         { destination              }
   move.l count, d1     { number of bytes to fill  }
-{ FIXME: this should be move.w, but everything is pushed as long on
-         the stack ATM (KB) }
-  move.l value, d0     { fill data                }
+  move.w value, d0     { fill data                }
   tst.l  d1            { anything to fill at all? }
   ble @LMEMSET3
   bra @LMEMSET21