TOC handling: clean up

Also fix on 32 bits PowerPC
This commit is contained in:
Jonas Maebe 2022-02-06 20:50:00 +01:00
parent d42f577a3f
commit 629c1de460
5 changed files with 80 additions and 72 deletions

View File

@ -1234,7 +1234,7 @@ implementation
between code fragments that use a different TOC (which has to be between code fragments that use a different TOC (which has to be
executed when that "branch" returns). So we can't use tail call executed when that "branch" returns). So we can't use tail call
branches to routines potentially using a different TOC there } 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 usehighlevelwrapper:=true
else else
usehighlevelwrapper:=false; usehighlevelwrapper:=false;

View File

@ -911,9 +911,17 @@ const
end; end;
end; end;
{ save the CR if necessary ( !!! never done currently ) } { save current RTOC for restoration after calls if necessary }
{ still need to find out where this has to be done for SystemV if (pi_do_call in current_procinfo.flags) and
a_reg_alloc(list,R_0); (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_reg(A_MFSPR,R_0,R_CR);
list.concat(taicpu.op_reg_ref(A_STW,scratch_register, list.concat(taicpu.op_reg_ref(A_STW,scratch_register,
new_reference(STACK_POINTER_REG,LA_CR))); new_reference(STACK_POINTER_REG,LA_CR)));
@ -1306,6 +1314,14 @@ const
a_reg_dealloc(list,href.index); a_reg_dealloc(list,href.index);
end; end;
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; end;
procedure tcgppc.g_return_from_proc_mac(list : TAsmList;parasize : tcgint); procedure tcgppc.g_return_from_proc_mac(list : TAsmList;parasize : tcgint);

View File

@ -305,22 +305,6 @@ begin
end; 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 } { calling a procedure by address }
procedure tcgppc.a_call_reg(list: TAsmList; reg: tregister); procedure tcgppc.a_call_reg(list: TAsmList; reg: tregister);
@ -330,40 +314,44 @@ var
begin begin
if (target_info.abi<>abi_powerpc_sysv) then if (target_info.abi<>abi_powerpc_sysv) then
inherited a_call_reg(list,reg) inherited a_call_reg(list,reg)
else if (not (cs_opt_size in current_settings.optimizerswitches)) then begin else
tempreg := getintregister(list, OS_INT); begin
{ load actual function entry (reg contains the reference to the function descriptor) if (not (cs_opt_size in current_settings.optimizerswitches)) then
into tempreg } begin
reference_reset_base(tmpref, reg, 0, ctempposinvalid, sizeof(pint), []); tempreg := getintregister(list, OS_INT);
a_load_ref_reg(list, OS_ADDR, OS_ADDR, tmpref, tempreg); { 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 } { move actual function pointer to CTR register }
list.concat(taicpu.op_reg(A_MTCTR, tempreg)); list.concat(taicpu.op_reg(A_MTCTR, tempreg));
{ load new TOC pointer from function descriptor into RTOC register } { load new TOC pointer from function descriptor into RTOC register }
reference_reset_base(tmpref, reg, tcgsize2size[OS_ADDR], ctempposinvalid, 8, []); 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); 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; 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); include(current_procinfo.flags, pi_do_call);
end; end;
@ -1270,7 +1258,8 @@ begin
end; end;
{ save current RTOC for restoration after calls if necessary } { 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 begin
reference_reset_base(href,NR_STACK_POINTER_REG,get_rtoc_offset,ctempposinvalid,target_info.stackalign,[]); 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); a_load_reg_ref(list,OS_ADDR,OS_ADDR,NR_RTOC,href);

View File

@ -89,6 +89,8 @@ unit cgppc;
procedure a_jmp(list: TAsmList; op: tasmop; procedure a_jmp(list: TAsmList; op: tasmop;
c: tasmcondflag; crval: longint; l: tasmlabel); c: tasmcondflag; crval: longint; l: tasmlabel);
function get_rtoc_offset: longint;
function save_lr_in_prologue: boolean; function save_lr_in_prologue: boolean;
function load_got_symbol(list : TAsmList; const symbol : string; const flags: tindsymflags) : tregister; 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); C_LT,C_GE,C_LE,C_NE,C_LE,C_LT,C_GE,C_GT);
TocSecBaseName = 'toc_table'; TocSecBaseName = 'toc_table';
{$ifdef extdebug} {$ifdef extdebug}
function ref2string(const ref : treference) : string; function ref2string(const ref : treference) : string;
function cgop2string(const op : TOpCg) : 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 { no need to allocate/free R0, is already allocated by call node
because it's a volatile register } because it's a volatile register }
reg:=NR_R0; 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; end;
list.concat(taicpu.op_reg(A_MTCTR,reg)); list.concat(taicpu.op_reg(A_MTCTR,reg));
if target_info.system in systems_aix then if target_info.system in systems_aix then
@ -488,9 +486,6 @@ unit cgppc;
end end
else if target_info.abi=abi_powerpc_elfv2 then else if target_info.abi=abi_powerpc_elfv2 then
begin 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 } { functions must be called via R12 for this ABI }
if reg<>NR_R12 then if reg<>NR_R12 then
begin begin
@ -499,17 +494,13 @@ unit cgppc;
end; end;
end; end;
list.concat(taicpu.op_none(A_BCTRL)); list.concat(taicpu.op_none(A_BCTRL));
if (target_info.system in systems_aix) or if target_info.abi in abis_ppc_toc then
(target_info.abi=abi_powerpc_elfv2) then
begin begin
if (target_info.abi=abi_powerpc_elfv2) and if (target_info.abi=abi_powerpc_elfv2) and
(reg<>NR_R12) then (reg<>NR_R12) then
ungetcpuregister(list,NR_R12); ungetcpuregister(list,NR_R12);
{ restore our TOC } { restore our TOC }
if target_info.system in systems_aix then toc_offset:=get_rtoc_offset;
toc_offset:=LA_RTOC_AIX
else
toc_offset:=LA_RTOC_ELFV2;
reference_reset_base(tmpref,NR_STACK_POINTER_REG,toc_offset,ctempposinvalid,sizeof(pint),[]); 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); a_load_ref_reg(list,OS_ADDR,OS_ADDR,tmpref,NR_RTOC);
end; end;
@ -743,6 +734,23 @@ unit cgppc;
list.concat(p) list.concat(p)
end; 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; function tcgppcgen.load_got_symbol(list: TAsmList; const symbol : string; const flags: tindsymflags) : tregister;

View File

@ -448,14 +448,9 @@ interface
on the caller side rather than on the callee side } 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]; 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 } { all PPC ABIs that use a TOC register to address globals }
{ TODO: not used by Darwin, but don't know about others (JM) } abis_ppc_toc = [
systems_ppc_toc = [ abi_powerpc_sysv,abi_powerpc_aix,abi_powerpc_elfv2
system_powerpc_linux,
system_powerpc64_linux,
system_powerpc_aix,
system_powerpc64_aix,
system_powerpc_macosclassic
]; ];
{ pointer checking (requires special code in FPC_CHECKPOINTER, { pointer checking (requires special code in FPC_CHECKPOINTER,