Browse Source

m68k: basic 68881 FPU register save/restore support. probably still needs some work here and there.

git-svn-id: trunk@29644 -
Károly Balogh 10 years ago
parent
commit
a99c9c29b6

+ 2 - 1
compiler/aasmtai.pas

@@ -276,7 +276,7 @@ interface
           top_shifterop : (shifterop : pshifterop);
       {$endif defined(arm) or defined(aarch64)}
       {$ifdef m68k}
-          top_regset : (dataregset,addrregset:^tcpuregisterset);
+          top_regset : (dataregset,addrregset,fpuregset:^tcpuregisterset);
       {$endif m68k}
       {$ifdef jvm}
           top_single : (sval:single);
@@ -2653,6 +2653,7 @@ implementation
                 begin
                   dispose(dataregset);
                   dispose(addrregset);
+                  dispose(fpuregset);
                 end;
 {$endif m68k}
 {$ifdef jvm}

+ 21 - 14
compiler/m68k/aasmcpu.pas

@@ -41,7 +41,7 @@ type
   taicpu = class(tai_cpu_abstract_sym)
      opsize : topsize;
 
-     procedure loadregset(opidx:longint; const dataregs,addrregs:tcpuregisterset);
+     procedure loadregset(opidx:longint; const dataregs,addrregs,fpuregs:tcpuregisterset);
 
      constructor op_none(op : tasmop);
      constructor op_none(op : tasmop;_size : topsize);
@@ -68,11 +68,11 @@ type
      constructor op_reg_reg_ref(op : tasmop;_size : topsize;_op1,_op2 : tregister; _op3 : treference);
      constructor op_const_reg_ref(op : tasmop;_size : topsize;_op1 : longint;_op2 : tregister;_op3 : treference);
 
-     constructor op_reg_regset(op: tasmop; _size : topsize; _op1: tregister;const _op2data,_op2addr: tcpuregisterset);
-     constructor op_regset_reg(op: tasmop; _size : topsize;const _op1data,_op1addr: tcpuregisterset; _op2: tregister);
+     constructor op_reg_regset(op: tasmop; _size : topsize; _op1: tregister;const _op2data,_op2addr,_op2fpu: tcpuregisterset);
+     constructor op_regset_reg(op: tasmop; _size : topsize;const _op1data,_op1addr,_op1fpu: tcpuregisterset; _op2: tregister);
 
-     constructor op_ref_regset(op: tasmop; _size : topsize; _op1: treference;const _op2data,_op2addr: tcpuregisterset);
-     constructor op_regset_ref(op: tasmop; _size : topsize;const _op1data,_op1addr: tcpuregisterset; _op2: treference);
+     constructor op_ref_regset(op: tasmop; _size : topsize; _op1: treference;const _op2data,_op2addr,_op2fpu: tcpuregisterset);
+     constructor op_regset_ref(op: tasmop; _size : topsize;const _op1data,_op1addr,_op1fpu: tcpuregisterset; _op2: treference);
 
      { this is for Jmp instructions }
      constructor op_cond_sym(op : tasmop;cond:TAsmCond;_size : topsize;_op1 : tasmsymbol);
@@ -116,7 +116,7 @@ type
 
 
 
-    procedure taicpu.loadregset(opidx:longint; const dataregs,addrregs:tcpuregisterset);
+    procedure taicpu.loadregset(opidx:longint; const dataregs,addrregs,fpuregs:tcpuregisterset);
       var
         i : byte;
       begin
@@ -127,8 +127,10 @@ type
              clearop(opidx);
            new(dataregset);
            new(addrregset);
+           new(fpuregset);
            dataregset^:=dataregs;
            addrregset^:=addrregs;
+           fpuregset^:=fpuregs;
            typ:=top_regset;
            for i:=RS_D0 to RS_D7 do
              begin
@@ -140,6 +142,11 @@ type
                if assigned(add_reg_instruction_hook) and (i in addrregset^) then
                  add_reg_instruction_hook(self,newreg(R_ADDRESSREGISTER,i,R_SUBWHOLE));
              end;
+           for i:=RS_FP0 to RS_FP7 do
+             begin
+               if assigned(add_reg_instruction_hook) and (i in fpuregset^) then
+                 add_reg_instruction_hook(self,newreg(R_FPUREGISTER,i,R_SUBWHOLE));
+             end;
          end;
       end;
 
@@ -327,43 +334,43 @@ type
       end;
 
 
-   constructor taicpu.op_ref_regset(op: tasmop; _size : topsize; _op1: treference;const _op2data,_op2addr: tcpuregisterset);
+   constructor taicpu.op_ref_regset(op: tasmop; _size : topsize; _op1: treference;const _op2data,_op2addr,_op2fpu: tcpuregisterset);
      Begin
         inherited create(op);
         init(_size);
         ops:=2;
         loadref(0,_op1);
-        loadregset(1,_op2data,_op2addr);
+        loadregset(1,_op2data,_op2addr,_op2fpu);
      end;
 
 
-   constructor taicpu.op_regset_ref(op: tasmop; _size : topsize;const _op1data,_op1addr: tcpuregisterset; _op2: treference);
+   constructor taicpu.op_regset_ref(op: tasmop; _size : topsize;const _op1data,_op1addr,_op1fpu: tcpuregisterset; _op2: treference);
      Begin
         inherited create(op);
         init(_size);
         ops:=2;
-        loadregset(0,_op1data,_op1addr);
+        loadregset(0,_op1data,_op1addr,_op1fpu);
         loadref(1,_op2);
      End;
 
 
 
-   constructor taicpu.op_reg_regset(op: tasmop; _size : topsize; _op1: tregister;const _op2data,_op2addr: tcpuregisterset);
+   constructor taicpu.op_reg_regset(op: tasmop; _size : topsize; _op1: tregister;const _op2data,_op2addr,_op2fpu: tcpuregisterset);
      Begin
         inherited create(op);
         init(_size);
         ops:=2;
         loadreg(0,_op1);
-        loadregset(1,_op2data,_op2addr);
+        loadregset(1,_op2data,_op2addr,_op2fpu);
      end;
 
 
-   constructor taicpu.op_regset_reg(op: tasmop; _size : topsize;const _op1data,_op1addr: tcpuregisterset; _op2: tregister);
+   constructor taicpu.op_regset_reg(op: tasmop; _size : topsize;const _op1data,_op1addr,_op1fpu: tcpuregisterset; _op2: tregister);
      Begin
         inherited create(op);
         init(_size);
         ops:=2;
-        loadregset(0,_op1data,_op1addr);
+        loadregset(0,_op1data,_op1addr,_op1fpu);
         loadreg(1,_op2);
      End;
 

+ 5 - 0
compiler/m68k/ag68kgas.pas

@@ -173,6 +173,11 @@ interface
                   if i in o.addrregset^ then
                    hs:=hs+gas_regname(newreg(R_ADDRESSREGISTER,i,R_SUBWHOLE))+'/';
                 end;
+              for i:=RS_FP0 to RS_FP7 do
+                begin
+                  if i in o.fpuregset^ then
+                   hs:=hs+gas_regname(newreg(R_FPUREGISTER,i,R_SUBWHOLE))+'/';
+                end;
               delete(hs,length(hs),1);
               getopstr := hs;
             end;

+ 65 - 10
compiler/m68k/cgcpu.pas

@@ -1753,9 +1753,12 @@ unit cgcpu;
       var
         dataregs: tcpuregisterset;
         addrregs: tcpuregisterset;
+        fpuregs: tcpuregisterset;
         href : treference;
         hreg : tregister;
+        hfreg : tregister;
         size : longint;
+        fsize : longint;
         r : integer;
       begin
         { The code generated by the section below, particularly the movem.l
@@ -1766,10 +1769,13 @@ unit cgcpu;
           AS version instead. (KB) }
         dataregs:=[];
         addrregs:=[];
+        fpuregs:=[];
 
         { calculate temp. size }
         size:=0;
+        fsize:=0;
         hreg:=NR_NO;
+        hfreg:=NR_NO;
         for r:=low(saved_standard_registers) to high(saved_standard_registers) do
           if saved_standard_registers[r] in rg[R_INTREGISTER].used_in_proc then
             begin
@@ -1785,14 +1791,22 @@ unit cgcpu;
                 inc(size,sizeof(aint));
                 addrregs:=addrregs + [saved_address_registers[r]];
               end;
+        if uses_registers(R_FPUREGISTER) then
+          for r:=low(saved_fpu_registers) to high(saved_fpu_registers) do
+            if saved_fpu_registers[r] in rg[R_FPUREGISTER].used_in_proc then
+              begin
+                hfreg:=newreg(R_FPUREGISTER,saved_fpu_registers[r],R_SUBWHOLE);
+                inc(fsize,10{sizeof(extended)});
+                fpuregs:=fpuregs + [saved_fpu_registers[r]];
+              end;
 
         { 68k has no MM registers }
         if uses_registers(R_MMREGISTER) then
           internalerror(2014030201);
 
-        if size>0 then
+        if (size+fsize) > 0 then
           begin
-            tg.GetTemp(list,size,sizeof(aint),tt_noreuse,current_procinfo.save_regs_ref);
+            tg.GetTemp(list,size+fsize,sizeof(aint),tt_noreuse,current_procinfo.save_regs_ref);
             include(current_procinfo.flags,pi_has_saved_regs);
 
             { Copy registers to temp }
@@ -1804,10 +1818,22 @@ unit cgcpu;
                 list.concat(taicpu.op_const_reg(A_ADDA,S_L,href.offset,NR_A0));
                 reference_reset_base(href,NR_A0,0,sizeof(pint));
               end;
-            if size = sizeof(aint) then
-              list.concat(taicpu.op_reg_ref(A_MOVE,S_L,hreg,href))
-            else
-              list.concat(taicpu.op_regset_ref(A_MOVEM,S_L,dataregs,addrregs,href));
+
+            if size > 0 then
+              if size = sizeof(aint) then
+                list.concat(taicpu.op_reg_ref(A_MOVE,S_L,hreg,href))
+              else
+                list.concat(taicpu.op_regset_ref(A_MOVEM,S_L,dataregs,addrregs,[],href));
+
+            if fsize > 0 then
+              begin
+                { size is always longword aligned, while fsize is not }
+                inc(href.offset,size);
+                if fsize = 10{sizeof(extended)} then
+                  list.concat(taicpu.op_reg_ref(A_FMOVE,S_FX,hfreg,href))
+                else
+                  list.concat(taicpu.op_regset_ref(A_FMOVEM,S_FX,[],[],fpuregs,href));
+              end;
           end;
       end;
 
@@ -1816,20 +1842,26 @@ unit cgcpu;
       var
         dataregs: tcpuregisterset;
         addrregs: tcpuregisterset;
+        fpuregs : tcpuregisterset;
         href    : treference;
         r       : integer;
         hreg    : tregister;
+        hfreg   : tregister;
         size    : longint;
+        fsize   : longint;
       begin
         { see the remark about buggy GNU AS versions in g_save_registers() (KB) }
         dataregs:=[];
         addrregs:=[];
+        fpuregs:=[];
 
         if not(pi_has_saved_regs in current_procinfo.flags) then
           exit;
         { Copy registers from temp }
         size:=0;
+        fsize:=0;
         hreg:=NR_NO;
+        hfreg:=NR_NO;
         for r:=low(saved_standard_registers) to high(saved_standard_registers) do
           if saved_standard_registers[r] in rg[R_INTREGISTER].used_in_proc then
             begin
@@ -1851,6 +1883,17 @@ unit cgcpu;
                 addrregs:=addrregs + [saved_address_registers[r]];
               end;
 
+        if uses_registers(R_FPUREGISTER) then
+          for r:=low(saved_address_registers) to high(saved_address_registers) do
+            if saved_fpu_registers[r] in rg[R_FPUREGISTER].used_in_proc then
+              begin
+                inc(fsize,10{sizeof(extended)});
+                hfreg:=newreg(R_FPUREGISTER,saved_address_registers[r],R_SUBWHOLE);
+                { Allocate register so the optimizer does not remove the load }
+                a_reg_alloc(list,hfreg);
+                fpuregs:=fpuregs + [saved_fpu_registers[r]];
+              end;
+
         { 68k has no MM registers }
         if uses_registers(R_MMREGISTER) then
           internalerror(2014030202);
@@ -1863,10 +1906,22 @@ unit cgcpu;
             list.concat(taicpu.op_const_reg(A_ADDA,S_L,href.offset,NR_A0));
             reference_reset_base(href,NR_A0,0,sizeof(pint));
           end;
-        if size = sizeof(aint) then
-          list.concat(taicpu.op_ref_reg(A_MOVE,S_L,href,hreg))
-        else
-          list.concat(taicpu.op_ref_regset(A_MOVEM,S_L,href,dataregs,addrregs));
+
+        if size > 0 then
+          if size = sizeof(aint) then
+            list.concat(taicpu.op_ref_reg(A_MOVE,S_L,href,hreg))
+          else
+            list.concat(taicpu.op_ref_regset(A_MOVEM,S_L,href,dataregs,addrregs,[]));
+
+        if fsize > 0 then
+          begin
+            { size is always longword aligned, while fsize is not }
+            inc(href.offset,size);
+            if fsize = 10{sizeof(extended)} then
+              list.concat(taicpu.op_ref_reg(A_FMOVE,S_FX,href,hfreg))
+            else
+              list.concat(taicpu.op_ref_regset(A_FMOVEM,S_FX,href,[],[],fpuregs));
+          end;
 
         tg.UnGetTemp(list,current_procinfo.save_regs_ref);
       end;

+ 6 - 0
compiler/m68k/cpupara.pas

@@ -50,6 +50,7 @@ unit cpupara;
           function parsefuncretloc(p : tabstractprocdef; const s : string) : boolean;override;
           function get_volatile_registers_int(calloption:tproccalloption):tcpuregisterset;override;
           function get_volatile_registers_address(calloption:tproccalloption):tcpuregisterset;override;
+          function get_volatile_registers_fpu(calloption:tproccalloption):tcpuregisterset;override;
          private
           function parse_loc_string_to_register(var locreg: tregister; const s : string): boolean;
           function create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
@@ -79,6 +80,11 @@ unit cpupara;
         Result:=VOLATILE_ADDRESSREGISTERS;
       end;
 
+    function tm68kparamanager.get_volatile_registers_fpu(calloption:tproccalloption):tcpuregisterset;
+      begin
+        { fp0 and fp1 are considered volatile }
+        Result:=VOLATILE_FPUREGISTERS;
+      end;
 
     function tm68kparamanager.param_use_paraloc(const cgpara:tcgpara):boolean;
       var

+ 2 - 2
compiler/rautils.pas

@@ -54,7 +54,7 @@ type
       OPR_LOCAL     : (localvarsize, localconstoffset: asizeint;localsym:tabstractnormalvarsym;localsymofs:aint;localindexreg:tregister;localscale:byte;localgetoffset,localforceref:boolean);
       OPR_REGISTER  : (reg:tregister);
 {$ifdef m68k}
-      OPR_REGSET   : (regsetdata,regsetaddr : tcpuregisterset);
+      OPR_REGSET   : (regsetdata,regsetaddr,regsetfpu : tcpuregisterset);
 {$endif m68k}
 {$ifdef powerpc}
       OPR_COND      : (cond : tasmcond);
@@ -1057,7 +1057,7 @@ end;
                 ai.loadref(i-1,ref);
 {$ifdef m68k}
               OPR_REGSET:
-                ai.loadregset(i-1,regsetdata,regsetaddr);
+                ai.loadregset(i-1,regsetdata,regsetaddr,regsetfpu);
 {$endif}
 {$ifdef ARM}
               OPR_REGSET: