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
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;

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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,