diff --git a/compiler/aasmtai.pas b/compiler/aasmtai.pas index 841ce2555f..7b788697b1 100644 --- a/compiler/aasmtai.pas +++ b/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} diff --git a/compiler/m68k/aasmcpu.pas b/compiler/m68k/aasmcpu.pas index cb59c976d4..723a70aacf 100644 --- a/compiler/m68k/aasmcpu.pas +++ b/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; diff --git a/compiler/m68k/ag68kgas.pas b/compiler/m68k/ag68kgas.pas index 28d38c92ab..d77d9c48e3 100644 --- a/compiler/m68k/ag68kgas.pas +++ b/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; diff --git a/compiler/m68k/cgcpu.pas b/compiler/m68k/cgcpu.pas index 2d0220c16a..43b0755400 100644 --- a/compiler/m68k/cgcpu.pas +++ b/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; diff --git a/compiler/m68k/cpupara.pas b/compiler/m68k/cpupara.pas index 2751dbea90..9070a2d506 100644 --- a/compiler/m68k/cpupara.pas +++ b/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 diff --git a/compiler/rautils.pas b/compiler/rautils.pas index 8fd7981550..9ac136e76d 100644 --- a/compiler/rautils.pas +++ b/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: