Browse Source

Partial merge of 21562 by Foxsen, adapted.

git-svn-id: trunk@21613 -
pierre 13 years ago
parent
commit
72d310a8a4
1 changed files with 180 additions and 69 deletions
  1. 180 69
      compiler/mips/cpupara.pas

+ 180 - 69
compiler/mips/cpupara.pas

@@ -33,15 +33,38 @@ interface
     const
     const
       MIPS_MAX_OFFSET = 20;
       MIPS_MAX_OFFSET = 20;
       MIPS_MAX_REGISTERS_USED_IN_CALL = 6;
       MIPS_MAX_REGISTERS_USED_IN_CALL = 6;
+
+      { All ABI seem to start with $4 i.e. $a0 }
       MIPS_FIRST_REGISTER_USED_IN_CALL = RS_R4;
       MIPS_FIRST_REGISTER_USED_IN_CALL = RS_R4;
+      { O32 ABI uses $a0 to $a3, i.e R4 to R7 }
+      MIPS_LAST_REGISTER_USED_IN_CALL_ABI_O32 = RS_R7;
+      { N32 ABI uses also R8 and R9 }
+      MIPS_LAST_REGISTER_USED_IN_CALL_ABI_N32 = RS_R9;
+      { The calculation below is based on the assumption
+        that all registers used for ABI calls are
+        ordered and follow each other }
+      MIPS_NB_REGISTERS_USED_IN_CALL_O32 =
+        MIPS_LAST_REGISTER_USED_IN_CALL_ABI_O32
+        - MIPS_FIRST_REGISTER_USED_IN_CALL + 1;
+      MIPS_NB_REGISTERS_USED_IN_CALL_N32 =
+        MIPS_LAST_REGISTER_USED_IN_CALL_ABI_N32
+        - MIPS_FIRST_REGISTER_USED_IN_CALL + 1;
+
+
+      { Set O32 ABI as default }
+    const
+      mips_nb_used_registers = MIPS_NB_REGISTERS_USED_IN_CALL_O32;
+
+      { Might need to be changed if we support N64 ABI later }
+      mips_sizeof_register_param = 4;
+
     type
     type
       tparasupregs = array[0..MIPS_MAX_REGISTERS_USED_IN_CALL-1] of tsuperregister;
       tparasupregs = array[0..MIPS_MAX_REGISTERS_USED_IN_CALL-1] of tsuperregister;
       tparasupregsused = array[0..MIPS_MAX_REGISTERS_USED_IN_CALL-1] of boolean;
       tparasupregsused = array[0..MIPS_MAX_REGISTERS_USED_IN_CALL-1] of boolean;
       tparasupregsoffset = array[0..MIPS_MAX_REGISTERS_USED_IN_CALL-1] of longint;
       tparasupregsoffset = array[0..MIPS_MAX_REGISTERS_USED_IN_CALL-1] of longint;
-      pparasupregs = ^tparasupregs;
+
     const
     const
-      paraoutsupregs : tparasupregs = (RS_R4, RS_R5, RS_R6, RS_R7, RS_R8, RS_R9);
-      parainsupregs  : tparasupregs = (RS_R4, RS_R5, RS_R6, RS_R7, RS_R8, RS_R9);
+      parasupregs : tparasupregs = (RS_R4, RS_R5, RS_R6, RS_R7, RS_R8, RS_R9);
 
 
     type
     type
       TMIPSParaManager=class(TParaManager)
       TMIPSParaManager=class(TParaManager)
@@ -75,13 +98,15 @@ implementation
 
 
     function TMIPSParaManager.get_volatile_registers_int(calloption : tproccalloption):TCpuRegisterSet;
     function TMIPSParaManager.get_volatile_registers_int(calloption : tproccalloption):TCpuRegisterSet;
       begin
       begin
+        { O32 ABI values }
         result:=[RS_R1..RS_R15,RS_R24..RS_R25,RS_R31];
         result:=[RS_R1..RS_R15,RS_R24..RS_R25,RS_R31];
       end;
       end;
 
 
 
 
     function TMIPSParaManager.get_volatile_registers_fpu(calloption : tproccalloption):TCpuRegisterSet;
     function TMIPSParaManager.get_volatile_registers_fpu(calloption : tproccalloption):TCpuRegisterSet;
       begin
       begin
-        result:=[RS_F0..RS_F19,RS_F31];
+        { O32 ABI values }
+        result:=[RS_F0..RS_F19];
       end;
       end;
 
 
 
 
@@ -98,16 +123,17 @@ implementation
         paraloc:=cgpara.add_location;
         paraloc:=cgpara.add_location;
         with paraloc^ do
         with paraloc^ do
           begin
           begin
-            { The six first parameters are passed into registers } {MIPS first four}
+            { MIPS: ABI dependent number of first parameters
+              are passed into registers }
             dec(nr);
             dec(nr);
-            if nr<MIPS_MAX_REGISTERS_USED_IN_CALL then //MIPSEL nr<6
+            if nr<mips_nb_used_registers then
               begin
               begin
                 loc:=LOC_REGISTER;
                 loc:=LOC_REGISTER;
-                register:=newreg(R_INTREGISTER,paraoutsupregs[nr],R_SUBWHOLE);
+                register:=newreg(R_INTREGISTER,parasupregs[nr],R_SUBWHOLE);
                 if assigned(current_procinfo) then
                 if assigned(current_procinfo) then
                   begin
                   begin
                     TMIPSProcInfo(current_procinfo).register_used[nr]:=true;
                     TMIPSProcInfo(current_procinfo).register_used[nr]:=true;
-                    TMIPSProcInfo(current_procinfo).register_offset[nr]:=nr*4;
+                    TMIPSProcInfo(current_procinfo).register_offset[nr]:=nr*mips_sizeof_register_param;
                   end;
                   end;
               end
               end
             else
             else
@@ -115,7 +141,7 @@ implementation
                 { The other parameters are passed on the stack }
                 { The other parameters are passed on the stack }
                 loc:=LOC_REFERENCE;
                 loc:=LOC_REFERENCE;
                 reference.index:=NR_STACK_POINTER_REG;
                 reference.index:=NR_STACK_POINTER_REG;
-                reference.offset:={92+(nr-6)*4;} nr*4;
+                reference.offset:=nr*mips_sizeof_register_param;
               end;
               end;
             size:=OS_INT;
             size:=OS_INT;
           end;
           end;
@@ -132,11 +158,18 @@ implementation
             exit;
             exit;
           end;
           end;
         case def.typ of
         case def.typ of
-          recorddef,
-          arraydef,
+          recorddef:
+            result:=true;
+            { According to 032 ABI we should have
+              result:=false; buut this cmpletely fails }
+          arraydef:
+            result:=true; {(tarraydef(def).highrange>=tarraydef(def).lowrange) or
+                            is_open_array(def) or
+                            is_array_of_const(def) or
+                            is_array_constructor(def);}
           variantdef,
           variantdef,
           formaldef :
           formaldef :
-            push_addr_param:=true;
+            result:=true;
           objectdef :
           objectdef :
             result:=is_object(def);
             result:=is_object(def);
           stringdef :
           stringdef :
@@ -220,7 +253,7 @@ implementation
         else
         else
          { Return in register }
          { Return in register }
           begin
           begin
-{$ifndef cpu64bitaddr}
+{$ifndef cpu64bitalu}
             if retcgsize in [OS_64,OS_S64] then
             if retcgsize in [OS_64,OS_S64] then
              begin
              begin
                { low }
                { low }
@@ -240,7 +273,7 @@ implementation
                paraloc^.size:=OS_32;
                paraloc^.size:=OS_32;
              end
              end
             else
             else
-{$endif cpu64bitaddr}
+{$endif cpu64bitalu}
              begin
              begin
                paraloc^.loc:=LOC_REGISTER;
                paraloc^.loc:=LOC_REGISTER;
                paraloc^.size:=retcgsize;
                paraloc^.size:=retcgsize;
@@ -259,22 +292,26 @@ implementation
         i            : integer;
         i            : integer;
         hp           : tparavarsym;
         hp           : tparavarsym;
         paracgsize   : tcgsize;
         paracgsize   : tcgsize;
-        hparasupregs : pparasupregs;
         paralen      : longint;
         paralen      : longint;
+	paradef      : tdef;
+	fpparareg    : integer;
+	can_use_float : boolean;
+	reg           : tsuperregister;
+	alignment     : longint;
+	tmp	      : longint;
       begin
       begin
-        if side=callerside then
-          hparasupregs:=@paraoutsupregs
-        else
-          hparasupregs:=@parainsupregs;
+        fpparareg := 0;
+	can_use_float := true;
         for i:=0 to paras.count-1 do
         for i:=0 to paras.count-1 do
           begin
           begin
             if i<=MIPS_MAX_OFFSET then
             if i<=MIPS_MAX_OFFSET then
               param_offset[i] := Nil;
               param_offset[i] := Nil;
             hp:=tparavarsym(paras[i]);
             hp:=tparavarsym(paras[i]);
-            { currently only support C-style array of const,
-              there should be no location assigned to the vararg array itself }
-            if (p.proccalloption in [pocall_cdecl,pocall_cppdecl]) and
-               is_array_of_const(hp.vardef) then
+            paradef := hp.vardef;
+
+            { currently only support C-style array of const }
+             if (p.proccalloption in [pocall_cdecl,pocall_cppdecl]) and
+               is_array_of_const(paradef) then
               begin
               begin
                 paraloc:=hp.paraloc[side].add_location;
                 paraloc:=hp.paraloc[side].add_location;
                 { hack: the paraloc must be valid, but is not actually used }
                 { hack: the paraloc must be valid, but is not actually used }
@@ -284,25 +321,56 @@ implementation
                 break;
                 break;
               end;
               end;
 
 
-            if push_addr_param(hp.varspez,hp.vardef,p.proccalloption) then
-              paracgsize:=OS_ADDR
+            if (push_addr_param(hp.varspez,paradef,p.proccalloption)) then
+              begin
+                paracgsize := OS_ADDR;
+	    	paralen := tcgsize2size[paracgsize];
+              end
             else
             else
               begin
               begin
-                paracgsize:=def_cgSize(hp.vardef);
-                if paracgsize=OS_NO then
-                  paracgsize:=OS_ADDR;
+                paracgsize := def_cgsize(paradef);
+                { for things like formaldef }
+                if (paracgsize=OS_NO) then
+                  begin
+                    paracgsize:=OS_ADDR;
+                  end;
+
+                if not is_special_array(paradef) then
+                  paralen := paradef.size
+                else
+                  paralen := tcgsize2size[paracgsize];
               end;
               end;
+
+            if (paracgsize in [OS_64, OS_S64, OS_F64]) or (hp.vardef.alignment = 8) then
+	      alignment := 8
+            else
+	      alignment := 4;
             hp.paraloc[side].reset;
             hp.paraloc[side].reset;
-            hp.paraloc[side].size:=paracgsize;
-            hp.paraloc[side].Alignment:=std_param_align;
+            hp.paraloc[side].Alignment:=alignment;
             paralen:=tcgsize2size[paracgsize];
             paralen:=tcgsize2size[paracgsize];
             hp.paraloc[side].intsize:=paralen;
             hp.paraloc[side].intsize:=paralen;
+            hp.paraloc[side].size:=paracgsize;
+	    { check the alignment, mips O32ABI require a nature alignment  }
+	    tmp := align(parasize, alignment) - parasize;
+	    while tmp > 0 do
+              begin
+                inc(intparareg);
+	        inc(parasize,4);
+                dec(tmp,4);
+              end;
+
+	    { any non-float args will disable the use the floating regs }
+	    { up to two fp args }
+	    if (not(paracgsize in [OS_F32, OS_F64])) or (fpparareg = 2) then
+              can_use_float := false;
+
             while paralen>0 do
             while paralen>0 do
               begin
               begin
                 paraloc:=hp.paraloc[side].add_location;
                 paraloc:=hp.paraloc[side].add_location;
-                { Floats are passed in int registers,
-                  We can allocate at maximum 32 bits per register }
-                if paracgsize in [OS_64,OS_S64,OS_F32,OS_F64] then
+                { We can allocate at maximum 32 bits per register }
+                if (paracgsize in [OS_64,OS_S64]) or
+                   ((paracgsize in [OS_F32,OS_F64]) and
+                     not(can_use_float)) then
                   paraloc^.size:=OS_32
                   paraloc^.size:=OS_32
                 else
                 else
                   paraloc^.size:=paracgsize;
                   paraloc^.size:=paracgsize;
@@ -320,12 +388,19 @@ implementation
                     if side=callerside then
                     if side=callerside then
                     begin
                     begin
                       paraloc^.loc:=LOC_REGISTER;
                       paraloc^.loc:=LOC_REGISTER;
-                      paraloc^.register:=newreg(R_INTREGISTER,hparasupregs^[0],R_SUBWHOLE);
+                      paraloc^.register:=newreg(R_INTREGISTER,parasupregs[0],R_SUBWHOLE);
                     end
                     end
                     else
                     else
                     begin
                     begin
                       paraloc^.loc:=LOC_REFERENCE;
                       paraloc^.loc:=LOC_REFERENCE;
-                      paraloc^.reference.index := NR_FRAME_POINTER_REG;
+                      if (po_nostackframe in p.procoptions) then
+                        paraloc^.reference.index := NR_STACK_POINTER_REG
+                      else
+                        begin
+                          paraloc^.reference.index := NR_FRAME_POINTER_REG;
+                          if assigned(current_procinfo) then
+                            TMIPSProcinfo(current_procinfo).needs_frame_pointer := true;
+                        end;
                       paraloc^.reference.offset:=0;
                       paraloc^.reference.offset:=0;
                       if i<=MIPS_MAX_OFFSET then
                       if i<=MIPS_MAX_OFFSET then
                         param_offset[i] := @paraloc^.reference.offset;
                         param_offset[i] := @paraloc^.reference.offset;
@@ -334,63 +409,89 @@ implementation
                   end
                   end
                 { In case of po_delphi_nested_cc, the parent frame pointer
                 { In case of po_delphi_nested_cc, the parent frame pointer
                   is always passed on the stack. }
                   is always passed on the stack. }
-                else if (intparareg<=high(tparasupregs)) and
+                else if (intparareg<mips_nb_used_registers) and
                    (not(vo_is_parentfp in hp.varoptions) or
                    (not(vo_is_parentfp in hp.varoptions) or
                     not(po_delphi_nested_cc in p.procoptions)) then
                     not(po_delphi_nested_cc in p.procoptions)) then
                   begin
                   begin
-                    if assigned(current_procinfo) then
-                      begin
-                        TMIPSProcInfo(current_procinfo).register_used[intparareg]:=true;
-                        TMIPSProcInfo(current_procinfo).register_offset[intparareg]:=intparareg*4;
-                      end;
-                    if side=callerside then
+                    if (can_use_float) then
                       begin
                       begin
-                        paraloc^.loc:=LOC_REGISTER;
-                        paraloc^.register:=newreg(R_INTREGISTER,hparasupregs^[intparareg],R_SUBWHOLE);
+                        paraloc^.loc:=LOC_FPUREGISTER;
+                        if (fpparareg = 0) then
+                          reg := RS_F12
+                        else
+                          reg := RS_F14;
+                        if (paraloc^.size = OS_F64) then
+                          begin
+                            paraloc^.register:=newreg(R_FPUREGISTER, reg, R_SUBFD);
+			    inc(fpparareg);
+			    inc(intparareg);
+			    inc(intparareg);
+			    inc(parasize,8);
+                          end
+                        else
+                          begin
+                            paraloc^.register:=newreg(R_FPUREGISTER, reg, R_SUBFS);
+			    inc(fpparareg);
+			    inc(intparareg);
+			    inc(parasize,sizeof(aint));
+                          end;
                       end
                       end
-                    else
-                      begin
-                        paraloc^.loc:=LOC_REFERENCE;
-                        //if assigned(current_procinfo) then
-                        //  paraloc^.reference.index := current_procinfo.framepointer
-                        //else
-                          paraloc^.reference.index := NR_FRAME_POINTER_REG;
-                        paraloc^.reference.offset:=intparareg*sizeof(aint);
-                      end;
-                    inc(intparareg);
-                    inc(parasize,align(tcgsize2size[paraloc^.size],sizeof(aint)));
+                    else { not can use float }
+                     begin
+                       if assigned(current_procinfo) then
+                         begin
+                           TMIPSProcInfo(current_procinfo).register_used[intparareg]:=true;
+                           TMIPSProcInfo(current_procinfo).register_offset[intparareg]:=intparareg*mips_sizeof_register_param;
+                         end;
+                       if side=callerside then
+                         begin
+                           paraloc^.loc:=LOC_REGISTER;
+                           paraloc^.register:=newreg(R_INTREGISTER,parasupregs[intparareg],R_SUBWHOLE);
+                         end
+                       else
+                         begin
+                           paraloc^.loc:=LOC_REFERENCE;
+                           if (po_nostackframe in p.procoptions) then
+                             paraloc^.reference.index := NR_STACK_POINTER_REG
+                           else
+                             begin
+                               paraloc^.reference.index := NR_FRAME_POINTER_REG;
+                               if assigned(current_procinfo) then
+                                 TMIPSProcinfo(current_procinfo).needs_frame_pointer := true;
+                             end;
+                           paraloc^.reference.offset:=intparareg*mips_sizeof_register_param;
+                         end;
+                       inc(intparareg);
+                       inc(parasize,align(tcgsize2size[paraloc^.size],mips_sizeof_register_param));
+                     end;
                   end
                   end
                 else
                 else
                   begin
                   begin
                     paraloc^.loc:=LOC_REFERENCE;
                     paraloc^.loc:=LOC_REFERENCE;
                     if side=callerside then
                     if side=callerside then
                       begin
                       begin
-                        paraloc^.reference.index := {NR_R17;//}NR_STACK_POINTER_REG;
+                        paraloc^.reference.index := NR_STACK_POINTER_REG;
                         paraloc^.reference.offset:=parasize;
                         paraloc^.reference.offset:=parasize;
                       end
                       end
                     else
                     else
                       begin
                       begin
-                        //if assigned(current_procinfo) then
-                        //  paraloc^.reference.index := current_procinfo.framepointer
-                        //else
-                          paraloc^.reference.index := {NR_R18;//}NR_FRAME_POINTER_REG;
+                        if (po_nostackframe in p.procoptions) then
+                          paraloc^.reference.index := NR_STACK_POINTER_REG
+                        else
+                          begin
+                            paraloc^.reference.index := NR_FRAME_POINTER_REG;
+                            if assigned(current_procinfo) then
+                              TMIPSProcinfo(current_procinfo).needs_frame_pointer := true;
+                          end;
                         paraloc^.reference.offset:=parasize;
                         paraloc^.reference.offset:=parasize;
                         if i<=MIPS_MAX_OFFSET then
                         if i<=MIPS_MAX_OFFSET then
                           param_offset[i] := @paraloc^.reference.offset;
                           param_offset[i] := @paraloc^.reference.offset;
                       end;
                       end;
-                    { Parameters are aligned at 4 bytes }
-                    inc(parasize,align(tcgsize2size[paraloc^.size],sizeof(aint)));
+                    inc(parasize,align(tcgsize2size[paraloc^.size],mips_sizeof_register_param));
                   end;
                   end;
                 dec(paralen,tcgsize2size[paraloc^.size]);
                 dec(paralen,tcgsize2size[paraloc^.size]);
               end;
               end;
           end;
           end;
-        {
-        for i:=0 to paras.count-1 do
-        begin
-          if (side = calleeside) and (param_offset[i] <> nil) then
-            param_offset[i]^ := param_offset[i]^ + parasize - 8;
-        end;
-        }
       end;
       end;
 
 
 
 
@@ -404,6 +505,11 @@ implementation
         create_paraloc_info_intern(p,callerside,p.paras);
         create_paraloc_info_intern(p,callerside,p.paras);
         { append the varargs }
         { append the varargs }
         create_paraloc_info_intern(p,callerside,varargspara);
         create_paraloc_info_intern(p,callerside,varargspara);
+        { At least 16 bytes must be reserved for parameter
+          area in O32 ABI, this can be used by called function,
+          even if it has less parameter }
+        if (parasize < 16) then
+          parasize := 16;
         result:=parasize;
         result:=parasize;
       end;
       end;
 
 
@@ -417,6 +523,11 @@ implementation
         create_funcretloc_info(p,side);
         create_funcretloc_info(p,side);
         create_paraloc_info_intern(p,side,p.paras);
         create_paraloc_info_intern(p,side,p.paras);
         { We need to return the size allocated on the stack }
         { We need to return the size allocated on the stack }
+        { At least 16 bytes must be reserved for parameter
+          area in O32 ABI, this can be used by called function,
+          even if it has less parameter }
+        if (parasize < 16) then
+          parasize := 16;
         result:=parasize;
         result:=parasize;
       end;
       end;