diff --git a/compiler/ncgvmt.pas b/compiler/ncgvmt.pas index c049ac1f28..b855f7fae2 100644 --- a/compiler/ncgvmt.pas +++ b/compiler/ncgvmt.pas @@ -1234,7 +1234,7 @@ implementation between code fragments that use a different TOC (which has to be executed when that "branch" returns). So we can't use tail call branches to routines potentially using a different TOC there } - if target_info.system in systems_ppc_toc then + if target_info.abi in abis_ppc_toc then usehighlevelwrapper:=true else usehighlevelwrapper:=false; diff --git a/compiler/powerpc/cgcpu.pas b/compiler/powerpc/cgcpu.pas index b3f7a656d8..850e92a08a 100644 --- a/compiler/powerpc/cgcpu.pas +++ b/compiler/powerpc/cgcpu.pas @@ -911,9 +911,17 @@ const end; end; - { save the CR if necessary ( !!! never done currently ) } -{ still need to find out where this has to be done for SystemV - a_reg_alloc(list,R_0); + { save current RTOC for restoration after calls if necessary } + if (pi_do_call in current_procinfo.flags) and + (target_info.abi in abis_ppc_toc) then + begin + reference_reset_base(href,NR_STACK_POINTER_REG,get_rtoc_offset,ctempposinvalid,target_info.stackalign,[]); + a_load_reg_ref(list,OS_ADDR,OS_ADDR,NR_RTOC,href); + end; + + { save the CR if/when we ever start using caller-save portions of that + register} +{ a_reg_alloc(list,R_0); list.concat(taicpu.op_reg_reg(A_MFSPR,R_0,R_CR); list.concat(taicpu.op_reg_ref(A_STW,scratch_register, new_reference(STACK_POINTER_REG,LA_CR))); @@ -1306,6 +1314,14 @@ const a_reg_dealloc(list,href.index); end; end; + + { save current RTOC for restoration after calls if necessary } + if pi_do_call in current_procinfo.flags then + begin + reference_reset_base(href,NR_STACK_POINTER_REG,get_rtoc_offset,ctempposinvalid,target_info.stackalign,[]); + a_load_reg_ref(list,OS_ADDR,OS_ADDR,NR_RTOC,href); + end; + end; procedure tcgppc.g_return_from_proc_mac(list : TAsmList;parasize : tcgint); diff --git a/compiler/powerpc64/cgcpu.pas b/compiler/powerpc64/cgcpu.pas index 7f77f6a3be..ea5fdadce8 100644 --- a/compiler/powerpc64/cgcpu.pas +++ b/compiler/powerpc64/cgcpu.pas @@ -305,22 +305,6 @@ begin end; -function get_rtoc_offset: longint; -begin - result:=0; - case target_info.abi of - abi_powerpc_aix, - abi_powerpc_darwin: - result:=LA_RTOC_AIX; - abi_powerpc_elfv1: - result:=LA_RTOC_SYSV; - abi_powerpc_elfv2: - result:=LA_RTOC_ELFV2; - else - internalerror(2015021001); - end; -end; - { calling a procedure by address } procedure tcgppc.a_call_reg(list: TAsmList; reg: tregister); @@ -330,40 +314,44 @@ var begin if (target_info.abi<>abi_powerpc_sysv) then inherited a_call_reg(list,reg) - else if (not (cs_opt_size in current_settings.optimizerswitches)) then begin - tempreg := getintregister(list, OS_INT); - { load actual function entry (reg contains the reference to the function descriptor) - into tempreg } - reference_reset_base(tmpref, reg, 0, ctempposinvalid, sizeof(pint), []); - a_load_ref_reg(list, OS_ADDR, OS_ADDR, tmpref, tempreg); + else + begin + if (not (cs_opt_size in current_settings.optimizerswitches)) then + begin + tempreg := getintregister(list, OS_INT); + { load actual function entry (reg contains the reference to the function descriptor) + into tempreg } + reference_reset_base(tmpref, reg, 0, ctempposinvalid, sizeof(pint), []); + a_load_ref_reg(list, OS_ADDR, OS_ADDR, tmpref, tempreg); - { move actual function pointer to CTR register } - list.concat(taicpu.op_reg(A_MTCTR, tempreg)); + { move actual function pointer to CTR register } + list.concat(taicpu.op_reg(A_MTCTR, tempreg)); - { load new TOC pointer from function descriptor into RTOC register } - reference_reset_base(tmpref, reg, tcgsize2size[OS_ADDR], ctempposinvalid, 8, []); + { load new TOC pointer from function descriptor into RTOC register } + reference_reset_base(tmpref, reg, tcgsize2size[OS_ADDR], ctempposinvalid, 8, []); + a_load_ref_reg(list, OS_ADDR, OS_ADDR, tmpref, NR_RTOC); + + { load new environment pointer from function descriptor into R11 register } + reference_reset_base(tmpref, reg, 2*tcgsize2size[OS_ADDR], ctempposinvalid, 8, []); + a_reg_alloc(list, NR_R11); + a_load_ref_reg(list, OS_ADDR, OS_ADDR, tmpref, NR_R11); + { call function } + list.concat(taicpu.op_none(A_BCTRL)); + a_reg_dealloc(list, NR_R11); + end + else + begin + { call ptrgl helper routine which expects the pointer to the function descriptor + in R11 } + a_reg_alloc(list, NR_R11); + a_load_reg_reg(list, OS_ADDR, OS_ADDR, reg, NR_R11); + a_call_name_direct(list, A_BL, '.ptrgl', false, false, false); + a_reg_dealloc(list, NR_R11); + end; + { we need to load the old RTOC from stackframe because we changed it} + reference_reset_base(tmpref, NR_STACK_POINTER_REG, get_rtoc_offset, ctempposinvalid, 8, []); a_load_ref_reg(list, OS_ADDR, OS_ADDR, tmpref, NR_RTOC); - - { load new environment pointer from function descriptor into R11 register } - reference_reset_base(tmpref, reg, 2*tcgsize2size[OS_ADDR], ctempposinvalid, 8, []); - a_reg_alloc(list, NR_R11); - a_load_ref_reg(list, OS_ADDR, OS_ADDR, tmpref, NR_R11); - { call function } - list.concat(taicpu.op_none(A_BCTRL)); - a_reg_dealloc(list, NR_R11); - end else begin - { call ptrgl helper routine which expects the pointer to the function descriptor - in R11 } - a_reg_alloc(list, NR_R11); - a_load_reg_reg(list, OS_ADDR, OS_ADDR, reg, NR_R11); - a_call_name_direct(list, A_BL, '.ptrgl', false, false, false); - a_reg_dealloc(list, NR_R11); end; - - { we need to load the old RTOC from stackframe because we changed it} - reference_reset_base(tmpref, NR_STACK_POINTER_REG, get_rtoc_offset, ctempposinvalid, 8, []); - a_load_ref_reg(list, OS_ADDR, OS_ADDR, tmpref, NR_RTOC); - include(current_procinfo.flags, pi_do_call); end; @@ -1270,7 +1258,8 @@ begin end; { save current RTOC for restoration after calls if necessary } - if pi_do_call in current_procinfo.flags then + if (pi_do_call in current_procinfo.flags) and + (target_info.abi in abis_ppc_toc) then begin reference_reset_base(href,NR_STACK_POINTER_REG,get_rtoc_offset,ctempposinvalid,target_info.stackalign,[]); a_load_reg_ref(list,OS_ADDR,OS_ADDR,NR_RTOC,href); diff --git a/compiler/ppcgen/cgppc.pas b/compiler/ppcgen/cgppc.pas index 1d1543c989..2fa1115240 100644 --- a/compiler/ppcgen/cgppc.pas +++ b/compiler/ppcgen/cgppc.pas @@ -89,6 +89,8 @@ unit cgppc; procedure a_jmp(list: TAsmList; op: tasmop; c: tasmcondflag; crval: longint; l: tasmlabel); + function get_rtoc_offset: longint; + function save_lr_in_prologue: boolean; function load_got_symbol(list : TAsmList; const symbol : string; const flags: tindsymflags) : tregister; @@ -123,7 +125,6 @@ unit cgppc; C_LT,C_GE,C_LE,C_NE,C_LE,C_LT,C_GE,C_GT); TocSecBaseName = 'toc_table'; - {$ifdef extdebug} function ref2string(const ref : treference) : string; function cgop2string(const op : TOpCg) : String; @@ -473,9 +474,6 @@ unit cgppc; { no need to allocate/free R0, is already allocated by call node because it's a volatile register } reg:=NR_R0; - { save current TOC } - reference_reset_base(tmpref,NR_STACK_POINTER_REG,LA_RTOC_AIX,ctempposinvalid,sizeof(pint),[]); - a_load_reg_ref(list,OS_ADDR,OS_ADDR,NR_RTOC,tmpref); end; list.concat(taicpu.op_reg(A_MTCTR,reg)); if target_info.system in systems_aix then @@ -488,9 +486,6 @@ unit cgppc; end else if target_info.abi=abi_powerpc_elfv2 then begin - { save current TOC } - reference_reset_base(tmpref,NR_STACK_POINTER_REG,LA_RTOC_ELFV2,ctempposinvalid,sizeof(pint),[]); - a_load_reg_ref(list,OS_ADDR,OS_ADDR,NR_RTOC,tmpref); { functions must be called via R12 for this ABI } if reg<>NR_R12 then begin @@ -499,17 +494,13 @@ unit cgppc; end; end; list.concat(taicpu.op_none(A_BCTRL)); - if (target_info.system in systems_aix) or - (target_info.abi=abi_powerpc_elfv2) then + if target_info.abi in abis_ppc_toc then begin if (target_info.abi=abi_powerpc_elfv2) and (reg<>NR_R12) then ungetcpuregister(list,NR_R12); { restore our TOC } - if target_info.system in systems_aix then - toc_offset:=LA_RTOC_AIX - else - toc_offset:=LA_RTOC_ELFV2; + toc_offset:=get_rtoc_offset; reference_reset_base(tmpref,NR_STACK_POINTER_REG,toc_offset,ctempposinvalid,sizeof(pint),[]); a_load_ref_reg(list,OS_ADDR,OS_ADDR,tmpref,NR_RTOC); end; @@ -743,6 +734,23 @@ unit cgppc; list.concat(p) end; + function tcgppcgen.get_rtoc_offset: longint; + begin + case target_info.abi of + abi_powerpc_aix: + result:=LA_RTOC_AIX; +{$ifdef powerpc64} + { no TOC on Linux/ppc32 } + abi_powerpc_elfv1: + result:=LA_RTOC_SYSV; +{$endif} + abi_powerpc_elfv2: + result:=LA_RTOC_ELFV2; + else + internalerror(2015021001); + end; + end; + function tcgppcgen.load_got_symbol(list: TAsmList; const symbol : string; const flags: tindsymflags) : tregister; diff --git a/compiler/systems.pas b/compiler/systems.pas index 7acb05f158..9e220be6a3 100644 --- a/compiler/systems.pas +++ b/compiler/systems.pas @@ -448,14 +448,9 @@ interface on the caller side rather than on the callee side } systems_caller_copy_addr_value_para = [system_aarch64_ios,system_aarch64_darwin,system_aarch64_linux,system_aarch64_win64,system_aarch64_freebsd]; - { all PPC systems that use a TOC register to address globals } - { TODO: not used by Darwin, but don't know about others (JM) } - systems_ppc_toc = [ - system_powerpc_linux, - system_powerpc64_linux, - system_powerpc_aix, - system_powerpc64_aix, - system_powerpc_macosclassic + { all PPC ABIs that use a TOC register to address globals } + abis_ppc_toc = [ + abi_powerpc_sysv,abi_powerpc_aix,abi_powerpc_elfv2 ]; { pointer checking (requires special code in FPC_CHECKPOINTER,