diff --git a/compiler/aarch64/cpubase.pas b/compiler/aarch64/cpubase.pas index 7b3afd309f..05f8c89c68 100644 --- a/compiler/aarch64/cpubase.pas +++ b/compiler/aarch64/cpubase.pas @@ -305,25 +305,6 @@ unit cpubase; NR_DEFAULTFLAGS = NR_NZCV; RS_DEFAULTFLAGS = RS_NZCV; -{***************************************************************************** - GCC /ABI linking information -*****************************************************************************} - - const - { Registers which must be saved when calling a routine declared as - cppdecl, cdecl, stdcall, safecall, palmossyscall. The registers - saved should be the ones as defined in the target ABI and / or GCC. - - This value can be deduced from the CALLED_USED_REGISTERS array in the - GCC source. - } - saved_standard_registers : array[0..9] of tsuperregister = - (RS_X19,RS_X20,RS_X21,RS_X22,RS_X23,RS_X24,RS_X25,RS_X26,RS_X27,RS_X28); - saved_mm_registers : array[0..7] of tsuperregister = (RS_D8,RS_D9,RS_D10,RS_D11,RS_D12,RS_D13,RS_D14,RS_D15); - - { this is only for the generic code which is not used for this architecture } - saved_address_registers : array[0..0] of tsuperregister = (RS_INVALID); - {***************************************************************************** Helpers *****************************************************************************} diff --git a/compiler/aarch64/cpupara.pas b/compiler/aarch64/cpupara.pas index 21423daa4d..c0f811aaab 100644 --- a/compiler/aarch64/cpupara.pas +++ b/compiler/aarch64/cpupara.pas @@ -37,6 +37,8 @@ unit cpupara; function get_volatile_registers_int(calloption: tproccalloption): tcpuregisterset; override; function get_volatile_registers_fpu(calloption: tproccalloption): tcpuregisterset; override; function get_volatile_registers_mm(calloption: tproccalloption): tcpuregisterset; override; + function get_saved_registers_int(calloption: tproccalloption): tcpuregisterarray; override; + function get_saved_registers_mm(calloption: tproccalloption): tcpuregisterarray; override; function push_addr_param(varspez: tvarspez; def: tdef; calloption: tproccalloption): boolean; override; function ret_in_param(def: tdef; pd: tabstractprocdef):boolean;override; function create_paraloc_info(p: tabstractprocdef; side: tcallercallee):longint;override; @@ -87,6 +89,23 @@ unit cpupara; end; + function tcpuparamanager.get_saved_registers_int(calloption: tproccalloption): tcpuregisterarray; + const + saved_regs : array[0..9] of tsuperregister = + (RS_X19,RS_X20,RS_X21,RS_X22,RS_X23,RS_X24,RS_X25,RS_X26,RS_X27,RS_X28); + begin + result:=saved_regs; + end; + + + function tcpuparamanager.get_saved_registers_mm(calloption: tproccalloption): tcpuregisterarray; + const + saved_mm_regs : array[0..7] of tsuperregister = (RS_D8,RS_D9,RS_D10,RS_D11,RS_D12,RS_D13,RS_D14,RS_D15); + begin + result:=saved_mm_regs; + end; + + function is_hfa_internal(p: tdef; var basedef: tdef; var elecount: longint): boolean; var i: longint; diff --git a/compiler/arm/cpubase.pas b/compiler/arm/cpubase.pas index fca256f431..0dde9d2835 100644 --- a/compiler/arm/cpubase.pas +++ b/compiler/arm/cpubase.pas @@ -341,20 +341,6 @@ unit cpubase; *****************************************************************************} const - { Registers which must be saved when calling a routine declared as - cppdecl, cdecl, stdcall, safecall, palmossyscall. The registers - saved should be the ones as defined in the target ABI and / or GCC. - - This value can be deduced from the CALLED_USED_REGISTERS array in the - GCC source. - } - saved_standard_registers : array[0..6] of tsuperregister = - (RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,RS_R9,RS_R10); - - { this is only for the generic code which is not used for this architecture } - saved_address_registers : array[0..0] of tsuperregister = (RS_INVALID); - saved_mm_registers : array[0..0] of tsuperregister = (RS_INVALID); - { Required parameter alignment when calling a routine declared as stdcall and cdecl. The alignment value should be the one defined by GCC or the target ABI. diff --git a/compiler/arm/cpupara.pas b/compiler/arm/cpupara.pas index d679bbc5cb..088a8215ae 100644 --- a/compiler/arm/cpupara.pas +++ b/compiler/arm/cpupara.pas @@ -37,6 +37,7 @@ unit cpupara; function get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;override; function get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;override; function get_volatile_registers_mm(calloption : tproccalloption):tcpuregisterset;override; + function get_saved_registers_int(calloption : tproccalloption):tcpuregisterarray;override; function push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override; function ret_in_param(def:tdef;pd:tabstractprocdef):boolean;override; procedure getintparaloc(list: TAsmList; pd : tabstractprocdef; nr : longint; var cgpara : tcgpara);override; @@ -81,6 +82,15 @@ unit cpupara; end; + function tcpuparamanager.get_saved_registers_int(calloption : tproccalloption):tcpuregisterarray; + const + saved_regs : array[0..6] of tsuperregister = + (RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,RS_R9,RS_R10); + begin + result:=saved_regs; + end; + + procedure tcpuparamanager.getintparaloc(list: TAsmList; pd : tabstractprocdef; nr : longint; var cgpara : tcgpara); var paraloc : pcgparalocation; diff --git a/compiler/avr/cpubase.pas b/compiler/avr/cpubase.pas index 91ecf6ef79..955e18484a 100644 --- a/compiler/avr/cpubase.pas +++ b/compiler/avr/cpubase.pas @@ -278,17 +278,6 @@ unit cpubase; *****************************************************************************} const - { Registers which must be saved when calling a routine declared as - cppdecl, cdecl, stdcall, safecall, palmossyscall. The registers - saved should be the ones as defined in the target ABI and / or GCC. - - This value can be deduced from the CALLED_USED_REGISTERS array in the - GCC source. - } - { on avr, gen_entry/gen_exit code saves/restores registers, so - we don't need this array } - saved_standard_registers : array[0..0] of tsuperregister = - (RS_INVALID); { Required parameter alignment when calling a routine declared as stdcall and cdecl. The alignment value should be the one defined by GCC or the target ABI. @@ -298,9 +287,6 @@ unit cpubase; } std_param_align = 4; - saved_address_registers : array[0..0] of tsuperregister = (RS_INVALID); - saved_mm_registers : array[0..0] of tsuperregister = (RS_INVALID); - {***************************************************************************** Helpers *****************************************************************************} diff --git a/compiler/cgobj.pas b/compiler/cgobj.pas index cd82da0e88..6b30cfb0a1 100644 --- a/compiler/cgobj.pas +++ b/compiler/cgobj.pas @@ -2523,15 +2523,21 @@ implementation href : treference; size : longint; r : integer; + regs_to_save_int, + regs_to_save_address, + regs_to_save_mm : tcpuregisterarray; begin + regs_to_save_int:=paramanager.get_saved_registers_int(current_procinfo.procdef.proccalloption); + regs_to_save_address:=paramanager.get_saved_registers_address(current_procinfo.procdef.proccalloption); + regs_to_save_mm:=paramanager.get_saved_registers_mm(current_procinfo.procdef.proccalloption); { calculate temp. size } size:=0; - 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 + for r:=low(regs_to_save_int) to high(regs_to_save_int) do + if regs_to_save_int[r] in rg[R_INTREGISTER].used_in_proc then inc(size,sizeof(aint)); if uses_registers(R_ADDRESSREGISTER) then - for r:=low(saved_address_registers) to high(saved_address_registers) do - if saved_address_registers[r] in rg[R_ADDRESSREGISTER].used_in_proc then + for r:=low(regs_to_save_int) to high(regs_to_save_int) do + if regs_to_save_int[r] in rg[R_ADDRESSREGISTER].used_in_proc then inc(size,sizeof(aint)); { mm registers } @@ -2542,8 +2548,8 @@ implementation of the temp is smaller than needed for an OS_VECTOR } inc(size,tcgsize2size[OS_VECTOR]); - for r:=low(saved_mm_registers) to high(saved_mm_registers) do - if saved_mm_registers[r] in rg[R_MMREGISTER].used_in_proc then + for r:=low(regs_to_save_mm) to high(regs_to_save_mm) do + if regs_to_save_mm[r] in rg[R_MMREGISTER].used_in_proc then inc(size,tcgsize2size[OS_VECTOR]); end; @@ -2554,25 +2560,25 @@ implementation { Copy registers to temp } href:=current_procinfo.save_regs_ref; - for r:=low(saved_standard_registers) to high(saved_standard_registers) do + for r:=low(regs_to_save_int) to high(regs_to_save_int) do begin - if saved_standard_registers[r] in rg[R_INTREGISTER].used_in_proc then + if regs_to_save_int[r] in rg[R_INTREGISTER].used_in_proc then begin - a_load_reg_ref(list,OS_ADDR,OS_ADDR,newreg(R_INTREGISTER,saved_standard_registers[r],R_SUBWHOLE),href); + a_load_reg_ref(list,OS_ADDR,OS_ADDR,newreg(R_INTREGISTER,regs_to_save_int[r],R_SUBWHOLE),href); inc(href.offset,sizeof(aint)); end; - include(rg[R_INTREGISTER].preserved_by_proc,saved_standard_registers[r]); + include(rg[R_INTREGISTER].preserved_by_proc,regs_to_save_int[r]); end; if uses_registers(R_ADDRESSREGISTER) then - for r:=low(saved_address_registers) to high(saved_address_registers) do + for r:=low(regs_to_save_address) to high(regs_to_save_address) do begin - if saved_address_registers[r] in rg[R_ADDRESSREGISTER].used_in_proc then + if regs_to_save_address[r] in rg[R_ADDRESSREGISTER].used_in_proc then begin - a_load_reg_ref(list,OS_ADDR,OS_ADDR,newreg(R_ADDRESSREGISTER,saved_address_registers[r],R_SUBWHOLE),href); + a_load_reg_ref(list,OS_ADDR,OS_ADDR,newreg(R_ADDRESSREGISTER,regs_to_save_address[r],R_SUBWHOLE),href); inc(href.offset,sizeof(aint)); end; - include(rg[R_ADDRESSREGISTER].preserved_by_proc,saved_address_registers[r]); + include(rg[R_ADDRESSREGISTER].preserved_by_proc,regs_to_save_address[r]); end; if uses_registers(R_MMREGISTER) then @@ -2580,20 +2586,20 @@ implementation if (href.offset mod tcgsize2size[OS_VECTOR])<>0 then inc(href.offset,tcgsize2size[OS_VECTOR]-(href.offset mod tcgsize2size[OS_VECTOR])); - for r:=low(saved_mm_registers) to high(saved_mm_registers) do + for r:=low(regs_to_save_mm) to high(regs_to_save_mm) do begin { the array has to be declared even if no MM registers are saved (such as with SSE on i386), and since 0-element arrays don't exist, they contain a single RS_INVALID element in that case } - if saved_mm_registers[r]<>RS_INVALID then + if regs_to_save_mm[r]<>RS_INVALID then begin - if saved_mm_registers[r] in rg[R_MMREGISTER].used_in_proc then + if regs_to_save_mm[r] in rg[R_MMREGISTER].used_in_proc then begin - a_loadmm_reg_ref(list,OS_VECTOR,OS_VECTOR,newreg(R_MMREGISTER,saved_mm_registers[r],R_SUBMMWHOLE),href,nil); + a_loadmm_reg_ref(list,OS_VECTOR,OS_VECTOR,newreg(R_MMREGISTER,regs_to_save_mm[r],R_SUBMMWHOLE),href,nil); inc(href.offset,tcgsize2size[OS_VECTOR]); end; - include(rg[R_MMREGISTER].preserved_by_proc,saved_mm_registers[r]); + include(rg[R_MMREGISTER].preserved_by_proc,regs_to_save_mm[r]); end; end; end; @@ -2606,15 +2612,21 @@ implementation href : treference; r : integer; hreg : tregister; + regs_to_save_int, + regs_to_save_address, + regs_to_save_mm : tcpuregisterarray; begin if not(pi_has_saved_regs in current_procinfo.flags) then exit; + regs_to_save_int:=paramanager.get_saved_registers_int(current_procinfo.procdef.proccalloption); + regs_to_save_address:=paramanager.get_saved_registers_address(current_procinfo.procdef.proccalloption); + regs_to_save_mm:=paramanager.get_saved_registers_mm(current_procinfo.procdef.proccalloption); { Copy registers from temp } href:=current_procinfo.save_regs_ref; - 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 + for r:=low(regs_to_save_int) to high(regs_to_save_int) do + if regs_to_save_int[r] in rg[R_INTREGISTER].used_in_proc then begin - hreg:=newreg(R_INTREGISTER,saved_standard_registers[r],R_SUBWHOLE); + hreg:=newreg(R_INTREGISTER,regs_to_save_int[r],R_SUBWHOLE); { Allocate register so the optimizer does not remove the load } a_reg_alloc(list,hreg); a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,hreg); @@ -2622,10 +2634,10 @@ implementation end; if uses_registers(R_ADDRESSREGISTER) then - for r:=low(saved_address_registers) to high(saved_address_registers) do - if saved_address_registers[r] in rg[R_ADDRESSREGISTER].used_in_proc then + for r:=low(regs_to_save_address) to high(regs_to_save_address) do + if regs_to_save_address[r] in rg[R_ADDRESSREGISTER].used_in_proc then begin - hreg:=newreg(R_ADDRESSREGISTER,saved_address_registers[r],R_SUBWHOLE); + hreg:=newreg(R_ADDRESSREGISTER,regs_to_save_address[r],R_SUBWHOLE); { Allocate register so the optimizer does not remove the load } a_reg_alloc(list,hreg); a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,hreg); @@ -2637,11 +2649,11 @@ implementation if (href.offset mod tcgsize2size[OS_VECTOR])<>0 then inc(href.offset,tcgsize2size[OS_VECTOR]-(href.offset mod tcgsize2size[OS_VECTOR])); - for r:=low(saved_mm_registers) to high(saved_mm_registers) do + for r:=low(regs_to_save_mm) to high(regs_to_save_mm) do begin - if saved_mm_registers[r] in rg[R_MMREGISTER].used_in_proc then + if regs_to_save_mm[r] in rg[R_MMREGISTER].used_in_proc then begin - hreg:=newreg(R_MMREGISTER,saved_mm_registers[r],R_SUBMMWHOLE); + hreg:=newreg(R_MMREGISTER,regs_to_save_mm[r],R_SUBMMWHOLE); { Allocate register so the optimizer does not remove the load } a_reg_alloc(list,hreg); a_loadmm_ref_reg(list,OS_VECTOR,OS_VECTOR,href,hreg,nil); diff --git a/compiler/cgutils.pas b/compiler/cgutils.pas index 124ca4016f..50485fe688 100644 --- a/compiler/cgutils.pas +++ b/compiler/cgutils.pas @@ -42,6 +42,7 @@ unit cgutils; type { Set type definition for cpuregisters } tcpuregisterset = set of 0..maxcpuregister; + tcpuregisterarray = array of tsuperregister; {$packset 1} { a reference may be volatile for reading, writing, or both. E.g., local variables diff --git a/compiler/i386/cpubase.inc b/compiler/i386/cpubase.inc index b604845055..de3cb7ec61 100644 --- a/compiler/i386/cpubase.inc +++ b/compiler/i386/cpubase.inc @@ -131,17 +131,6 @@ *****************************************************************************} const - {# Registers which must be saved when calling a routine declared as - cppdecl, cdecl, stdcall, safecall, palmossyscall. The registers - saved should be the ones as defined in the target ABI and / or GCC. - - This value can be deduced from the CALLED_USED_REGISTERS array in the - GCC source. - } - saved_standard_registers : array[0..3] of tsuperregister = (RS_EBX,RS_ESI,RS_EDI,RS_EBP); - - saved_address_registers : array[0..0] of tsuperregister = (RS_INVALID); - saved_mm_registers : array[0..0] of tsuperregister = (RS_INVALID); {# Required parameter alignment when calling a routine declared as stdcall and cdecl. The alignment value should be the one defined by GCC or the target ABI. diff --git a/compiler/i386/cpupara.pas b/compiler/i386/cpupara.pas index 62a493dc13..05b9abd1a0 100644 --- a/compiler/i386/cpupara.pas +++ b/compiler/i386/cpupara.pas @@ -40,6 +40,7 @@ unit cpupara; function get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;override; function get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;override; function get_volatile_registers_mm(calloption : tproccalloption):tcpuregisterset;override; + function get_saved_registers_int(calloption : tproccalloption):tcpuregisterarray;override; function create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;override; function create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;override; procedure createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;can_use_final_stack_loc : boolean;var cgpara:TCGPara);override; @@ -286,6 +287,14 @@ unit cpupara; end; + function tcpuparamanager.get_saved_registers_int(calloption : tproccalloption):tcpuregisterarray; + const + saveregs : array[0..3] of tsuperregister = (RS_EBX,RS_ESI,RS_EDI,RS_EBP); + begin + result:=saveregs; + end; + + function tcpuparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): TCGPara; var retcgsize : tcgsize; diff --git a/compiler/i8086/cpubase.inc b/compiler/i8086/cpubase.inc index 733c0a6346..950d0029f5 100644 --- a/compiler/i8086/cpubase.inc +++ b/compiler/i8086/cpubase.inc @@ -150,17 +150,6 @@ *****************************************************************************} const - {# Registers which must be saved when calling a routine declared as - cppdecl, cdecl, stdcall, safecall, palmossyscall. The registers - saved should be the ones as defined in the target ABI and / or GCC. - - This value can be deduced from the CALLED_USED_REGISTERS array in the - GCC source. - } - saved_standard_registers : array[0..0] of tsuperregister = (RS_BP); - - saved_address_registers : array[0..0] of tsuperregister = (RS_INVALID); - saved_mm_registers : array[0..0] of tsuperregister = (RS_INVALID); {# Required parameter alignment when calling a routine declared as stdcall and cdecl. The alignment value should be the one defined by GCC or the target ABI. diff --git a/compiler/i8086/cpupara.pas b/compiler/i8086/cpupara.pas index 3171c3af65..1b4a1aeb73 100644 --- a/compiler/i8086/cpupara.pas +++ b/compiler/i8086/cpupara.pas @@ -41,6 +41,7 @@ unit cpupara; function get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;override; function get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;override; function get_volatile_registers_mm(calloption : tproccalloption):tcpuregisterset;override; + function get_saved_registers_int(calloption : tproccalloption):tcpuregisterarray;override; { Returns the location for the nr-st 16 Bit int parameter if every parameter before is an 16 Bit int parameter as well and if the calling conventions for the helper routines of the @@ -236,6 +237,14 @@ unit cpupara; end; + function tcpuparamanager.get_saved_registers_int(calloption : tproccalloption):tcpuregisterarray; + const + saveregs_pascal: array [0..0] of tsuperregister = (RS_BP); + begin + result:=saveregs_pascal; + end; + + procedure tcpuparamanager.getintparaloc(list: TAsmList; pd : tabstractprocdef; nr : longint; var cgpara : tcgpara); var paraloc : pcgparalocation; diff --git a/compiler/jvm/cpubase.pas b/compiler/jvm/cpubase.pas index a4cb80b49c..e880bf76a7 100644 --- a/compiler/jvm/cpubase.pas +++ b/compiler/jvm/cpubase.pas @@ -255,17 +255,6 @@ uses { dummies, not used for JVM } - {# Registers which must be saved when calling a routine - - } - saved_standard_registers : array[0..0] of tsuperregister = ( - RS_NO - ); - - { this is only for the generic code which is not used for this architecture } - saved_address_registers : array[0..0] of tsuperregister = (RS_INVALID); - saved_mm_registers : array[0..0] of tsuperregister = (RS_INVALID); - {# Required parameter alignment when calling a routine } std_param_align = 1; diff --git a/compiler/jvm/cpupara.pas b/compiler/jvm/cpupara.pas index 4c7eb718f3..929abfe184 100644 --- a/compiler/jvm/cpupara.pas +++ b/compiler/jvm/cpupara.pas @@ -35,6 +35,7 @@ interface { tcpuparamanager } tcpuparamanager=class(TParaManager) + function get_saved_registers_int(calloption: tproccalloption): tcpuregisterarray;override; function push_high_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override; function keep_para_array_range(varspez: tvarspez; def: tdef; calloption: tproccalloption): boolean; override; function push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override; @@ -70,6 +71,14 @@ implementation internalerror(2010121001); end; + function tcpuparamanager.get_saved_registers_int(calloption: tproccalloption): tcpuregisterarray; + const + { dummy, not used for JVM } + saved_regs: array [0..0] of tsuperregister = (RS_NO); + begin + result:=saved_regs; + end; + function tcpuparamanager.push_high_param(varspez: tvarspez; def: tdef; calloption: tproccalloption): boolean; begin { we don't need a separate high parameter, since all arrays in Java diff --git a/compiler/m68k/cgcpu.pas b/compiler/m68k/cgcpu.pas index bd0f511c0c..4b49e99c19 100644 --- a/compiler/m68k/cgcpu.pas +++ b/compiler/m68k/cgcpu.pas @@ -1963,6 +1963,9 @@ unit cgcpu; size : longint; fsize : longint; r : integer; + regs_to_save_int, + regs_to_save_address, + regs_to_save_fpu: tcpuregisterarray; begin { The code generated by the section below, particularly the movem.l instruction is known to cause an issue when compiled by some GNU @@ -1974,33 +1977,36 @@ unit cgcpu; addrregs:=[]; fpuregs:=[]; + regs_to_save_int:=paramanager.get_saved_registers_int(current_procinfo.procdef.proccalloption); + regs_to_save_address:=paramanager.get_saved_registers_address(current_procinfo.procdef.proccalloption); + regs_to_save_fpu:=paramanager.get_saved_registers_fpu(current_procinfo.procdef.proccalloption); { 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 + for r:=low(regs_to_save_int) to high(regs_to_save_int) do + if regs_to_save_int[r] in rg[R_INTREGISTER].used_in_proc then begin - hreg:=newreg(R_INTREGISTER,saved_address_registers[r],R_SUBWHOLE); + hreg:=newreg(R_INTREGISTER,regs_to_save_int[r],R_SUBWHOLE); inc(size,sizeof(aint)); - dataregs:=dataregs + [saved_standard_registers[r]]; + dataregs:=dataregs + [regs_to_save_int[r]]; end; if uses_registers(R_ADDRESSREGISTER) then - for r:=low(saved_address_registers) to high(saved_address_registers) do - if saved_address_registers[r] in rg[R_ADDRESSREGISTER].used_in_proc then + for r:=low(regs_to_save_address) to high(regs_to_save_address) do + if regs_to_save_address[r] in rg[R_ADDRESSREGISTER].used_in_proc then begin - hreg:=newreg(R_ADDRESSREGISTER,saved_address_registers[r],R_SUBWHOLE); + hreg:=newreg(R_ADDRESSREGISTER,regs_to_save_address[r],R_SUBWHOLE); inc(size,sizeof(aint)); - addrregs:=addrregs + [saved_address_registers[r]]; + addrregs:=addrregs + [regs_to_save_address[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 + for r:=low(regs_to_save_fpu) to high(regs_to_save_fpu) do + if regs_to_save_fpu[r] in rg[R_FPUREGISTER].used_in_proc then begin - hfreg:=newreg(R_FPUREGISTER,saved_fpu_registers[r],R_SUBNONE); + hfreg:=newreg(R_FPUREGISTER,regs_to_save_fpu[r],R_SUBNONE); inc(fsize,fpuregsize); - fpuregs:=fpuregs + [saved_fpu_registers[r]]; + fpuregs:=fpuregs + [regs_to_save_fpu[r]]; end; { 68k has no MM registers } @@ -2052,6 +2058,9 @@ unit cgcpu; hfreg : tregister; size : longint; fsize : longint; + regs_to_save_int, + regs_to_save_address, + regs_to_save_fpu: tcpuregisterarray; begin { see the remark about buggy GNU AS versions in g_save_registers() (KB) } dataregs:=[]; @@ -2060,41 +2069,44 @@ unit cgcpu; if not(pi_has_saved_regs in current_procinfo.flags) then exit; + regs_to_save_int:=paramanager.get_saved_registers_int(current_procinfo.procdef.proccalloption); + regs_to_save_address:=paramanager.get_saved_registers_address(current_procinfo.procdef.proccalloption); + regs_to_save_fpu:=paramanager.get_saved_registers_fpu(current_procinfo.procdef.proccalloption); { 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 + for r:=low(regs_to_save_int) to high(regs_to_save_int) do + if regs_to_save_int[r] in rg[R_INTREGISTER].used_in_proc then begin inc(size,sizeof(aint)); - hreg:=newreg(R_INTREGISTER,saved_standard_registers[r],R_SUBWHOLE); + hreg:=newreg(R_INTREGISTER,regs_to_save_int[r],R_SUBWHOLE); { Allocate register so the optimizer does not remove the load } a_reg_alloc(list,hreg); - dataregs:=dataregs + [saved_standard_registers[r]]; + dataregs:=dataregs + [regs_to_save_int[r]]; end; if uses_registers(R_ADDRESSREGISTER) then - for r:=low(saved_address_registers) to high(saved_address_registers) do - if saved_address_registers[r] in rg[R_ADDRESSREGISTER].used_in_proc then + for r:=low(regs_to_save_address) to high(regs_to_save_address) do + if regs_to_save_address[r] in rg[R_ADDRESSREGISTER].used_in_proc then begin inc(size,sizeof(aint)); - hreg:=newreg(R_ADDRESSREGISTER,saved_address_registers[r],R_SUBWHOLE); + hreg:=newreg(R_ADDRESSREGISTER,regs_to_save_address[r],R_SUBWHOLE); { Allocate register so the optimizer does not remove the load } a_reg_alloc(list,hreg); - addrregs:=addrregs + [saved_address_registers[r]]; + addrregs:=addrregs + [regs_to_save_address[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 + for r:=low(regs_to_save_fpu) to high(regs_to_save_fpu) do + if regs_to_save_fpu[r] in rg[R_FPUREGISTER].used_in_proc then begin inc(fsize,fpuregsize); - hfreg:=newreg(R_FPUREGISTER,saved_fpu_registers[r],R_SUBNONE); + hfreg:=newreg(R_FPUREGISTER,regs_to_save_fpu[r],R_SUBNONE); { Allocate register so the optimizer does not remove the load } a_reg_alloc(list,hfreg); - fpuregs:=fpuregs + [saved_fpu_registers[r]]; + fpuregs:=fpuregs + [regs_to_save_fpu[r]]; end; { 68k has no MM registers } diff --git a/compiler/m68k/cpubase.pas b/compiler/m68k/cpubase.pas index ebf4e1856e..b74ee580b7 100644 --- a/compiler/m68k/cpubase.pas +++ b/compiler/m68k/cpubase.pas @@ -320,20 +320,6 @@ unit cpubase; GCC /ABI linking information *****************************************************************************} - {# Registers which must be saved when calling a routine declared as - cppdecl, cdecl, stdcall, safecall, palmossyscall. The registers - saved should be the ones as defined in the target ABI and / or GCC. - - This value can be deduced from CALLED_USED_REGISTERS array in the - GCC source. - } - saved_standard_registers : array[0..5] of tsuperregister = (RS_D2,RS_D3,RS_D4,RS_D5,RS_D6,RS_D7); - saved_address_registers : array[0..4] of tsuperregister = (RS_A2,RS_A3,RS_A4,RS_A5,RS_A6); - saved_fpu_registers : array[0..5] of tsuperregister = (RS_FP2,RS_FP3,RS_FP4,RS_FP5,RS_FP6,RS_FP7); - - { this is only for the generic code which is not used for this architecture } - saved_mm_registers : array[0..0] of tsuperregister = (RS_INVALID); - {# Required parameter alignment when calling a routine declared as stdcall and cdecl. The alignment value should be the one defined by GCC or the target ABI. diff --git a/compiler/m68k/cpupara.pas b/compiler/m68k/cpupara.pas index 5e74472c71..a6915f842c 100644 --- a/compiler/m68k/cpupara.pas +++ b/compiler/m68k/cpupara.pas @@ -50,6 +50,9 @@ unit cpupara; 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; + function get_saved_registers_int(calloption:tproccalloption):tcpuregisterarray;override; + function get_saved_registers_address(calloption:tproccalloption):tcpuregisterarray;override; + function get_saved_registers_fpu(calloption:tproccalloption):tcpuregisterarray;override; function get_para_align(calloption : tproccalloption):byte;override; private function parse_loc_string_to_register(var locreg: tregister; const s : string): boolean; @@ -99,6 +102,27 @@ unit cpupara; Result:=VOLATILE_FPUREGISTERS; end; + function tcpuparamanager.get_saved_registers_int(calloption:tproccalloption):tcpuregisterarray; + const + saved_regs: array[0..5] of tsuperregister = (RS_D2,RS_D3,RS_D4,RS_D5,RS_D6,RS_D7); + begin + result:=saved_regs; + end; + + function tcpuparamanager.get_saved_registers_address(calloption:tproccalloption):tcpuregisterarray; + const + saved_addr_regs: array[0..4] of tsuperregister = (RS_A2,RS_A3,RS_A4,RS_A5,RS_A6); + begin + result:=saved_addr_regs; + end; + + function tcpuparamanager.get_saved_registers_fpu(calloption:tproccalloption):tcpuregisterarray; + const + saved_fpu_regs: array[0..5] of tsuperregister = (RS_FP2,RS_FP3,RS_FP4,RS_FP5,RS_FP6,RS_FP7); + begin + result:=saved_fpu_regs; + end; + function tcpuparamanager.get_para_align(calloption : tproccalloption):byte; begin result:=target_info.stackalign; diff --git a/compiler/mips/cpubase.pas b/compiler/mips/cpubase.pas index d57b2d8195..70f368463c 100644 --- a/compiler/mips/cpubase.pas +++ b/compiler/mips/cpubase.pas @@ -238,20 +238,6 @@ unit cpubase; *****************************************************************************} const - { Registers which must be saved when calling a routine declared as - cppdecl, cdecl, stdcall, safecall, palmossyscall. The registers - saved should be the ones as defined in the target ABI and / or GCC. - - This value can be deduced from the CALLED_USED_REGISTERS array in the - GCC source. - } - saved_standard_registers : array[0..0] of tsuperregister = - (RS_NO); - - { this is only for the generic code which is not used for this architecture } - saved_address_registers : array[0..0] of tsuperregister = (RS_INVALID); - saved_mm_registers : array[0..0] of tsuperregister = (RS_INVALID); - { Required parameter alignment when calling a routine declared as stdcall and cdecl. The alignment value should be the one defined by GCC or the target ABI. diff --git a/compiler/mips/cpupara.pas b/compiler/mips/cpupara.pas index cf666ea979..d3c1ef12c6 100644 --- a/compiler/mips/cpupara.pas +++ b/compiler/mips/cpupara.pas @@ -71,6 +71,7 @@ interface function push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override; function get_volatile_registers_int(calloption : tproccalloption):TCpuRegisterSet;override; function get_volatile_registers_fpu(calloption : tproccalloption):TCpuRegisterSet;override; + function get_saved_registers_int(calloption : tproccalloption):TCpuRegisterArray;override; function create_paraloc_info(p : TAbstractProcDef; side: tcallercallee):longint;override; function create_varargs_paraloc_info(p : TAbstractProcDef; varargspara:tvarargsparalist):longint;override; function get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;override; @@ -106,6 +107,15 @@ implementation end; + function tcpuparamanager.get_saved_registers_int(calloption : tproccalloption):TCpuRegisterArray; + const + saved_regs : array[0..0] of tsuperregister = + (RS_NO); + begin + result:=saved_regs; + end; + + { whether "def" must be treated as record when used as function result, i.e. its address passed in a0 } function tcpuparamanager.is_abi_record(def: tdef): boolean; diff --git a/compiler/paramgr.pas b/compiler/paramgr.pas index e28fb15e5a..898b7d5a98 100644 --- a/compiler/paramgr.pas +++ b/compiler/paramgr.pas @@ -82,6 +82,17 @@ unit paramgr; function get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;virtual; function get_volatile_registers_flags(calloption : tproccalloption):tcpuregisterset;virtual; function get_volatile_registers_mm(calloption : tproccalloption):tcpuregisterset;virtual; + {# Registers which must be saved when calling a routine declared as + cppdecl, cdecl, stdcall, safecall, palmossyscall. The registers + saved should be the ones as defined in the target ABI and / or GCC. + + This value can be deduced from the CALLED_USED_REGISTERS array in the + GCC source. + } + function get_saved_registers_int(calloption : tproccalloption):tcpuregisterarray;virtual; + function get_saved_registers_address(calloption : tproccalloption):tcpuregisterarray;virtual; + function get_saved_registers_fpu(calloption : tproccalloption):tcpuregisterarray;virtual; + function get_saved_registers_mm(calloption : tproccalloption):tcpuregisterarray;virtual; procedure getintparaloc(list: TAsmList; pd: tabstractprocdef; nr : longint; var cgpara: tcgpara);virtual; @@ -299,6 +310,38 @@ implementation result:=[]; end; + + function tparamanager.get_saved_registers_int(calloption : tproccalloption):tcpuregisterarray; + const + inv: array [0..0] of tsuperregister = (RS_INVALID); + begin + result:=inv; + end; + + + function tparamanager.get_saved_registers_address(calloption : tproccalloption):tcpuregisterarray; + const + inv: array [0..0] of tsuperregister = (RS_INVALID); + begin + result:=inv; + end; + + + function tparamanager.get_saved_registers_fpu(calloption : tproccalloption):tcpuregisterarray; + const + inv: array [0..0] of tsuperregister = (RS_INVALID); + begin + result:=inv; + end; + + + function tparamanager.get_saved_registers_mm(calloption : tproccalloption):tcpuregisterarray; + const + inv: array [0..0] of tsuperregister = (RS_INVALID); + begin + result:=inv; + end; + {$if first_mm_imreg = 0} {$WARN 4044 OFF} { Comparison might be always false ... } {$endif} diff --git a/compiler/powerpc/cpubase.pas b/compiler/powerpc/cpubase.pas index c97318f663..e569e13423 100644 --- a/compiler/powerpc/cpubase.pas +++ b/compiler/powerpc/cpubase.pas @@ -338,23 +338,6 @@ uses GCC /ABI linking information *****************************************************************************} - {# Registers which must be saved when calling a routine declared as - cppdecl, cdecl, stdcall, safecall, palmossyscall. The registers - saved should be the ones as defined in the target ABI and / or GCC. - - This value can be deduced from CALLED_USED_REGISTERS array in the - GCC source. - } - saved_standard_registers : array[0..18] of tsuperregister = ( - RS_R13,RS_R14,RS_R15,RS_R16,RS_R17,RS_R18,RS_R19, - RS_R20,RS_R21,RS_R22,RS_R23,RS_R24,RS_R25,RS_R26,RS_R27,RS_R28,RS_R29, - RS_R30,RS_R31 - ); - - { this is only for the generic code which is not used for this architecture } - saved_address_registers : array[0..0] of tsuperregister = (RS_INVALID); - saved_mm_registers : array[0..0] of tsuperregister = (RS_INVALID); - {# Required parameter alignment when calling a routine declared as stdcall and cdecl. The alignment value should be the one defined by GCC or the target ABI. diff --git a/compiler/powerpc/cpupara.pas b/compiler/powerpc/cpupara.pas index b20f59cdb6..1edfaafa94 100644 --- a/compiler/powerpc/cpupara.pas +++ b/compiler/powerpc/cpupara.pas @@ -35,6 +35,7 @@ unit cpupara; tcpuparamanager = class(tparamanager) function get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;override; function get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;override; + function get_saved_registers_int(calloption : tproccalloption):tcpuregisterarray;override; function push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override; procedure getintparaloc(list: TAsmList; pd : tabstractprocdef; nr : longint; var cgpara : tcgpara);override; @@ -78,6 +79,18 @@ unit cpupara; end; + function tcpuparamanager.get_saved_registers_int(calloption : tproccalloption):tcpuregisterarray; + const + saved_regs : array[0..18] of tsuperregister = ( + RS_R13,RS_R14,RS_R15,RS_R16,RS_R17,RS_R18,RS_R19, + RS_R20,RS_R21,RS_R22,RS_R23,RS_R24,RS_R25,RS_R26,RS_R27,RS_R28,RS_R29, + RS_R30,RS_R31 + ); + begin + result:=saved_regs; + end; + + procedure tcpuparamanager.getintparaloc(list: TAsmList; pd : tabstractprocdef; nr : longint; var cgpara : tcgpara); var paraloc : pcgparalocation; diff --git a/compiler/powerpc64/cpubase.pas b/compiler/powerpc64/cpubase.pas index 7c847c1260..1a4d672399 100644 --- a/compiler/powerpc64/cpubase.pas +++ b/compiler/powerpc64/cpubase.pas @@ -332,23 +332,6 @@ const GCC /ABI linking information *****************************************************************************} - {# Registers which must be saved when calling a routine declared as - cppdecl, cdecl, stdcall, safecall, palmossyscall. The registers - saved should be the ones as defined in the target ABI and / or GCC. - - This value can be deduced from CALLED_USED_REGISTERS array in the - GCC source. - } - saved_standard_registers: array[0..17] of tsuperregister = ( - RS_R14, RS_R15, RS_R16, RS_R17, RS_R18, RS_R19, - RS_R20, RS_R21, RS_R22, RS_R23, RS_R24, RS_R25, - RS_R26, RS_R27, RS_R28, RS_R29, RS_R30, RS_R31 - ); - - { this is only for the generic code which is not used for this architecture } - saved_address_registers : array[0..0] of tsuperregister = (RS_INVALID); - saved_mm_registers : array[0..0] of tsuperregister = (RS_INVALID); - {# Required parameter alignment when calling a routine declared as stdcall and cdecl. The alignment value should be the one defined by GCC or the target ABI. diff --git a/compiler/powerpc64/cpupara.pas b/compiler/powerpc64/cpupara.pas index adfce8efdc..5ac2d9dd68 100644 --- a/compiler/powerpc64/cpupara.pas +++ b/compiler/powerpc64/cpupara.pas @@ -37,6 +37,8 @@ type tcpuregisterset; override; function get_volatile_registers_fpu(calloption: tproccalloption): tcpuregisterset; override; + function get_saved_registers_int(calloption: tproccalloption): + tcpuregisterarray; override; function push_addr_param(varspez: tvarspez; def: tdef; calloption: tproccalloption): boolean; override; function ret_in_param(def: tdef; pd: tabstractprocdef): boolean; override; @@ -79,6 +81,18 @@ begin result := [RS_F0..RS_F13]; end; +function tcpuparamanager.get_saved_registers_int(calloption: tproccalloption): + tcpuregisterarray; +const + saved_regs: array[0..17] of tsuperregister = ( + RS_R14, RS_R15, RS_R16, RS_R17, RS_R18, RS_R19, + RS_R20, RS_R21, RS_R22, RS_R23, RS_R24, RS_R25, + RS_R26, RS_R27, RS_R28, RS_R29, RS_R30, RS_R31 + ); +begin + result:=saved_regs; +end; + procedure tcpuparamanager.getintparaloc(list: TAsmList; pd : tabstractprocdef; nr: longint; var cgpara: tcgpara); var paraloc: pcgparalocation; diff --git a/compiler/sparcgen/cpubase.pas b/compiler/sparcgen/cpubase.pas index be5944eacc..43b1a91d31 100644 --- a/compiler/sparcgen/cpubase.pas +++ b/compiler/sparcgen/cpubase.pas @@ -305,19 +305,6 @@ uses GCC /ABI linking information *****************************************************************************} - {# Registers which must be saved when calling a routine declared as - cppdecl, cdecl, stdcall, safecall, palmossyscall. The registers - saved should be the ones as defined in the target ABI and / or GCC. - - This value can be deduced from CALLED_USED_REGISTERS array in the - GCC source. - } - saved_standard_registers : array[0..0] of tsuperregister = (RS_INVALID); - - { this is only for the generic code which is not used for this architecture } - saved_address_registers : array[0..0] of tsuperregister = (RS_INVALID); - saved_mm_registers : array[0..0] of tsuperregister = (RS_INVALID); - {# Required parameter alignment when calling a routine declared as stdcall and cdecl. The alignment value should be the one defined by GCC or the target ABI. diff --git a/compiler/x86/cgx86.pas b/compiler/x86/cgx86.pas index 5e9b4182f9..7707936fdd 100644 --- a/compiler/x86/cgx86.pas +++ b/compiler/x86/cgx86.pas @@ -3294,14 +3294,16 @@ unit cgx86; var r: longint; usedregs: tcpuregisterset; + regs_to_save_int: tcpuregisterarray; begin regsize:=0; usedregs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(current_procinfo.procdef.proccalloption); - for r := low(saved_standard_registers) to high(saved_standard_registers) do - if saved_standard_registers[r] in usedregs then + regs_to_save_int:=paramanager.get_saved_registers_int(current_procinfo.procdef.proccalloption); + for r := low(regs_to_save_int) to high(regs_to_save_int) do + if regs_to_save_int[r] in usedregs then begin inc(regsize,sizeof(aint)); - list.concat(Taicpu.Op_reg(A_PUSH,tcgsize2opsize[OS_ADDR],newreg(R_INTREGISTER,saved_standard_registers[r],R_SUBWHOLE))); + list.concat(Taicpu.Op_reg(A_PUSH,tcgsize2opsize[OS_ADDR],newreg(R_INTREGISTER,regs_to_save_int[r],R_SUBWHOLE))); end; end; @@ -3572,13 +3574,15 @@ unit cgx86; hreg: tregister; href: treference; usedregs: tcpuregisterset; + regs_to_save_int: tcpuregisterarray; begin href:=current_procinfo.save_regs_ref; usedregs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(current_procinfo.procdef.proccalloption); - for r:=high(saved_standard_registers) downto low(saved_standard_registers) do - if saved_standard_registers[r] in usedregs then + regs_to_save_int:=paramanager.get_saved_registers_int(current_procinfo.procdef.proccalloption); + for r:=high(regs_to_save_int) downto low(regs_to_save_int) do + if regs_to_save_int[r] in usedregs then begin - hreg:=newreg(R_INTREGISTER,saved_standard_registers[r],R_SUBWHOLE); + hreg:=newreg(R_INTREGISTER,regs_to_save_int[r],R_SUBWHOLE); { Allocate register so the optimizer does not remove the load } a_reg_alloc(list,hreg); if use_pop then diff --git a/compiler/x86_64/cgcpu.pas b/compiler/x86_64/cgcpu.pas index 7dda93406a..d36b8ce2b5 100644 --- a/compiler/x86_64/cgcpu.pas +++ b/compiler/x86_64/cgcpu.pas @@ -65,42 +65,12 @@ unit cgcpu; procedure Tcgx86_64.init_register_allocators; - const - win64_saved_std_regs : array[0..7] of tsuperregister = (RS_RBX,RS_RDI,RS_RSI,RS_R12,RS_R13,RS_R14,RS_R15,RS_RBP); - others_saved_std_regs : array[0..4] of tsuperregister = (RS_RBX,RS_R12,RS_R13,RS_R14,RS_R15); - saved_regs_length : array[boolean] of longint = (5,7); - - win64_saved_xmm_regs : array[0..9] of tsuperregister = (RS_XMM6,RS_XMM7, - RS_XMM8,RS_XMM9,RS_XMM10,RS_XMM11,RS_XMM12,RS_XMM13,RS_XMM14,RS_XMM15); var - i : longint; ms_abi: boolean; begin inherited init_register_allocators; ms_abi:=use_ms_abi; - if (length(saved_standard_registers)<>saved_regs_length[ms_abi]) then - begin - if ms_abi then - begin - SetLength(saved_standard_registers,Length(win64_saved_std_regs)); - SetLength(saved_mm_registers,Length(win64_saved_xmm_regs)); - - for i:=low(win64_saved_std_regs) to high(win64_saved_std_regs) do - saved_standard_registers[i]:=win64_saved_std_regs[i]; - - for i:=low(win64_saved_xmm_regs) to high(win64_saved_xmm_regs) do - saved_mm_registers[i]:=win64_saved_xmm_regs[i]; - end - else - begin - SetLength(saved_standard_registers,Length(others_saved_std_regs)); - SetLength(saved_mm_registers,0); - - for i:=low(others_saved_std_regs) to high(others_saved_std_regs) do - saved_standard_registers[i]:=others_saved_std_regs[i]; - end; - end; if ms_abi then begin if (cs_userbp in current_settings.optimizerswitches) and assigned(current_procinfo) and (current_procinfo.framepointer=NR_STACK_POINTER_REG) then @@ -156,14 +126,16 @@ unit cgcpu; function tcgx86_64.saved_xmm_reg_size: longint; var i: longint; + regs_to_save_mm: tcpuregisterarray; begin result:=0; if (target_info.system<>system_x86_64_win64) or (not uses_registers(R_MMREGISTER)) then exit; - for i:=low(saved_mm_registers) to high(saved_mm_registers) do + regs_to_save_mm:=paramanager.get_saved_registers_mm(current_procinfo.procdef.proccalloption); + for i:=low(regs_to_save_mm) to high(regs_to_save_mm) do begin - if (saved_mm_registers[i] in rg[R_MMREGISTER].used_in_proc) then + if (regs_to_save_mm[i] in rg[R_MMREGISTER].used_in_proc) then inc(result,tcgsize2size[OS_VECTOR]); end; end; @@ -180,6 +152,8 @@ unit cgcpu; suppress_endprologue: boolean; stackmisalignment: longint; xmmsize: longint; + regs_to_save_int, + regs_to_save_mm: tcpuregisterarray; procedure push_one_reg(reg: tregister); begin @@ -197,15 +171,17 @@ unit cgcpu; usedregs: tcpuregisterset; begin usedregs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(current_procinfo.procdef.proccalloption); - for r := low(saved_standard_registers) to high(saved_standard_registers) do - if saved_standard_registers[r] in usedregs then + for r := low(regs_to_save_int) to high(regs_to_save_int) do + if regs_to_save_int[r] in usedregs then begin inc(stackmisalignment,sizeof(pint)); - push_one_reg(newreg(R_INTREGISTER,saved_standard_registers[r],R_SUBWHOLE)); + push_one_reg(newreg(R_INTREGISTER,regs_to_save_int[r],R_SUBWHOLE)); end; end; begin + regs_to_save_int:=paramanager.get_saved_registers_int(current_procinfo.procdef.proccalloption); + regs_to_save_mm:=paramanager.get_saved_registers_mm(current_procinfo.procdef.proccalloption); hitem:=list.last; { pi_has_unwind_info may already be set at this point if there are SEH directives in assembler body. In this case, .seh_endprologue @@ -282,10 +258,10 @@ unit cgcpu; if use_push and (xmmsize<>0) then begin href:=current_procinfo.save_regs_ref; - for r:=low(saved_mm_registers) to high(saved_mm_registers) do - if saved_mm_registers[r] in rg[R_MMREGISTER].used_in_proc then + for r:=low(regs_to_save_mm) to high(regs_to_save_mm) do + if regs_to_save_mm[r] in rg[R_MMREGISTER].used_in_proc then begin - a_loadmm_reg_ref(list,OS_VECTOR,OS_VECTOR,newreg(R_MMREGISTER,saved_mm_registers[r],R_SUBMMWHOLE),href,nil); + a_loadmm_reg_ref(list,OS_VECTOR,OS_VECTOR,newreg(R_MMREGISTER,regs_to_save_mm[r],R_SUBMMWHOLE),href,nil); inc(href.offset,tcgsize2size[OS_VECTOR]); end; end; @@ -316,11 +292,11 @@ unit cgcpu; href:=current_procinfo.save_regs_ref; if (not use_push) then begin - 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 + for r:=low(regs_to_save_int) to high(regs_to_save_int) do + if regs_to_save_int[r] in rg[R_INTREGISTER].used_in_proc then begin templist.concat(cai_seh_directive.create_reg_offset(ash_savereg, - newreg(R_INTREGISTER,saved_standard_registers[r],R_SUBWHOLE), + newreg(R_INTREGISTER,regs_to_save_int[r],R_SUBWHOLE), href.offset+frame_offset)); inc(href.offset,sizeof(aint)); end; @@ -330,12 +306,12 @@ unit cgcpu; if (href.offset mod tcgsize2size[OS_VECTOR])<>0 then inc(href.offset,tcgsize2size[OS_VECTOR]-(href.offset mod tcgsize2size[OS_VECTOR])); - for r:=low(saved_mm_registers) to high(saved_mm_registers) do + for r:=low(regs_to_save_mm) to high(regs_to_save_mm) do begin - if saved_mm_registers[r] in rg[R_MMREGISTER].used_in_proc then + if regs_to_save_mm[r] in rg[R_MMREGISTER].used_in_proc then begin templist.concat(cai_seh_directive.create_reg_offset(ash_savexmm, - newreg(R_MMREGISTER,saved_mm_registers[r],R_SUBMMWHOLE), + newreg(R_MMREGISTER,regs_to_save_mm[r],R_SUBMMWHOLE), href.offset+frame_offset)); inc(href.offset,tcgsize2size[OS_VECTOR]); end; @@ -366,7 +342,9 @@ unit cgcpu; href : treference; hreg : tregister; r : longint; + regs_to_save_mm: tcpuregisterarray; begin + regs_to_save_mm:=paramanager.get_saved_registers_mm(current_procinfo.procdef.proccalloption);; { Prevent return address from a possible call from ending up in the epilogue } { (restoring registers happens before epilogue, providing necessary padding) } if (current_procinfo.flags*[pi_has_unwind_info,pi_do_call,pi_has_saved_regs])=[pi_has_unwind_info,pi_do_call] then @@ -379,11 +357,11 @@ unit cgcpu; if (saved_xmm_reg_size<>0) then begin href:=current_procinfo.save_regs_ref; - for r:=low(saved_mm_registers) to high(saved_mm_registers) do - if saved_mm_registers[r] in rg[R_MMREGISTER].used_in_proc then + for r:=low(regs_to_save_mm) to high(regs_to_save_mm) do + if regs_to_save_mm[r] in rg[R_MMREGISTER].used_in_proc then begin { Allocate register so the optimizer does not remove the load } - hreg:=newreg(R_MMREGISTER,saved_mm_registers[r],R_SUBMMWHOLE); + hreg:=newreg(R_MMREGISTER,regs_to_save_mm[r],R_SUBMMWHOLE); a_reg_alloc(list,hreg); a_loadmm_ref_reg(list,OS_VECTOR,OS_VECTOR,href,hreg,nil); inc(href.offset,tcgsize2size[OS_VECTOR]); diff --git a/compiler/x86_64/cpubase.inc b/compiler/x86_64/cpubase.inc index 44c92397f3..816fba50be 100644 --- a/compiler/x86_64/cpubase.inc +++ b/compiler/x86_64/cpubase.inc @@ -126,11 +126,6 @@ const *****************************************************************************} const - { these arrays differ between unix and win64 } - saved_standard_registers : array of tsuperregister = nil; - saved_mm_registers : array of tsuperregister = nil; - - saved_address_registers : array[0..0] of tsuperregister = (RS_INVALID); { Required parameter alignment when calling a routine declared as stdcall and cdecl. The alignment value should be the one defined by GCC or the target ABI. diff --git a/compiler/x86_64/cpupara.pas b/compiler/x86_64/cpupara.pas index fca7b8382a..c268072c61 100644 --- a/compiler/x86_64/cpupara.pas +++ b/compiler/x86_64/cpupara.pas @@ -43,6 +43,8 @@ unit cpupara; function get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;override; function get_volatile_registers_mm(calloption : tproccalloption):tcpuregisterset;override; function get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;override; + function get_saved_registers_int(calloption : tproccalloption):tcpuregisterarray;override; + function get_saved_registers_mm(calloption: tproccalloption):tcpuregisterarray;override; function create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;override; function create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;override; function get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;override; @@ -56,7 +58,7 @@ unit cpupara; defutil, symtable, cpupi, - cgx86; + cgx86,cgobj,cgcpu; const paraintsupregs : array[0..5] of tsuperregister = (RS_RDI,RS_RSI,RS_RDX,RS_RCX,RS_R8,RS_R9); @@ -1364,6 +1366,30 @@ unit cpupara; end; + function tcpuparamanager.get_saved_registers_int(calloption : tproccalloption):tcpuregisterarray; + const + win64_saved_std_regs : array[0..7] of tsuperregister = (RS_RBX,RS_RDI,RS_RSI,RS_R12,RS_R13,RS_R14,RS_R15,RS_RBP); + others_saved_std_regs : array[0..4] of tsuperregister = (RS_RBX,RS_R12,RS_R13,RS_R14,RS_R15); + begin + if tcgx86_64(cg).use_ms_abi then + result:=win64_saved_std_regs + else + result:=others_saved_std_regs; + end; + + + function tcpuparamanager.get_saved_registers_mm(calloption: tproccalloption):tcpuregisterarray; + const + win64_saved_xmm_regs : array[0..9] of tsuperregister = (RS_XMM6,RS_XMM7, + RS_XMM8,RS_XMM9,RS_XMM10,RS_XMM11,RS_XMM12,RS_XMM13,RS_XMM14,RS_XMM15); + begin + if tcgx86_64(cg).use_ms_abi then + result:=win64_saved_xmm_regs + else + SetLength(result,0); + end; + + function tcpuparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara; const intretregs: array[0..1] of tregister = (NR_FUNCTION_RETURN_REG,NR_FUNCTION_RETURN_REG_HIGH);