mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-27 00:30:33 +02:00
m68k: basic 68881 FPU register save/restore support. probably still needs some work here and there.
git-svn-id: trunk@29644 -
This commit is contained in:
parent
82fd859a19
commit
a99c9c29b6
@ -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}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user