Commit 3f79c0ad by Alan Modra Committed by Alan Modra

[RS6000] inline plt call sequences

Finally, the point of the previous patches in this series, support for
inline PLT calls, keyed off -fno-plt.  This emits code using new
relocations that tie all insns in the sequence together, so that the
linker can edit the sequence back to a direct call should the call
target turn out to be local.  An example of ELFv2 code to call puts is
as follows:

     .reloc .,R_PPC64_PLTSEQ,puts
        std 2,24(1)
     .reloc .,R_PPC64_PLT16_HA,puts
        addis 12,2,0
     .reloc .,R_PPC64_PLT16_LO_DS,puts
        ld 12,0(12)
     .reloc .,R_PPC64_PLTSEQ,puts
        mtctr 12
     .reloc .,R_PPC64_PLTCALL,puts
        bctrl
        ld 2,24(1)

"addis 12,2,puts@plt@ha" and "ld 12,puts@plt@l(12)" are also supported
by the assembler.  gcc instead uses the explicit R_PPC64_PLT16_HA and
R_PPC64_PLT16_LO_DS relocs because when the call is to __tls_get_addr
an extra reloc is emitted at every place where one is shown above, to
specify the __tls_get_addr arg.  The linker expects the extra reloc to
come first.  .reloc enforces that ordering.

The patch also changes code emitted for longcalls if the assembler
supports the new marker relocs, so that these too can be edited.  One
side effect of longcalls using PLT16 relocs is that they can now be
resolved lazily by ld.so.

I don't support lazy inline PLT calls for ELFv1, because ELFv1 would
need barriers to reliably load both the function address and toc
pointer from the PLT.  ELFv1 -fno-plt uses the longcall sequence
instead, which isn't edited by GNU ld.

	* config.in (HAVE_AS_PLTSEQ): Add.
	* config/rs6000/predicates.md (indirect_call_operand): New.
	* config/rs6000/rs6000-protos.h (rs6000_pltseq_template),
	(rs6000_sibcall_sysv): Declare.
	* config/rs6000/rs6000.c (init_cumulative_args): Set cookie
	CALL_LONG for -fno-plt.
	(print_operand <T, z, 0>): Handle UNSPEC_PLTSEQ.
	(rs6000_indirect_call_template_1): Emit .reloc directives for
	UNSPEC_PLTSEQ calls.
	(rs6000_pltseq_template): New function.
	(rs6000_longcall_ref): Add arg parameter.  Use PLT16 insns if
	relocs supported by assembler.  Move SYMBOL_REF test to callers.
	(rs6000_call_aix): Adjust rs6000_longcall_ref call.  Package
	insns in UNSPEC_PLTSEQ, preserving original func_desc.
	(rs6000_call_sysv): Likewise.
	(rs6000_sibcall_sysv): New function.
	* config/rs6000/rs6000.h (HAVE_AS_PLTSEQ): Provide default.
	* config/rs6000/rs6000.md (UNSPEC_PLTSEQ, UNSPEC_PLT16_HA,
	UNSPEC_PLT16_LO): New.
	(pltseq_tocsave, pltseq_plt16_ha, pltseq_plt16_lo, pltseq_mtctr): New.
	(call_indirect_nonlocal_sysv): Don't differentiate zero from non-zero
	cookie in constraints.  Test explicitly for flags in length attr.
	Handle unspec operand 1.
	(call_value_indirect_nonlocal_sysv): Likewise.
	(call_indirect_aix, call_value_indirect_aix): Handle unspec operand 1.
	(call_indirect_elfv2, call_value_indirect_elfv2): Likewise.
	(sibcall, sibcall_value): Use rs6000_sibcall_sysv.
	(sibcall_indirect_nonlocal_sysv): New pattern.
	(sibcall_value_indirect_nonlocal_sysv): Likewise.
	(sibcall_nonlocal_sysv, sibcall_value_nonlocal_sysv): Remove indirect
	call alternatives.
	* configure.ac: Check for gas plt sequence marker support.
	* configure: Regenerate.

From-SVN: r266605
parent ece3bca2
2018-11-29 Alan Modra <amodra@gmail.com>
* config.in (HAVE_AS_PLTSEQ): Add.
* config/rs6000/predicates.md (indirect_call_operand): New.
* config/rs6000/rs6000-protos.h (rs6000_pltseq_template),
(rs6000_sibcall_sysv): Declare.
* config/rs6000/rs6000.c (init_cumulative_args): Set cookie
CALL_LONG for -fno-plt.
(print_operand <T, z, 0>): Handle UNSPEC_PLTSEQ.
(rs6000_indirect_call_template_1): Emit .reloc directives for
UNSPEC_PLTSEQ calls.
(rs6000_pltseq_template): New function.
(rs6000_longcall_ref): Add arg parameter. Use PLT16 insns if
relocs supported by assembler. Move SYMBOL_REF test to callers.
(rs6000_call_aix): Adjust rs6000_longcall_ref call. Package
insns in UNSPEC_PLTSEQ, preserving original func_desc.
(rs6000_call_sysv): Likewise.
(rs6000_sibcall_sysv): New function.
* config/rs6000/rs6000.h (HAVE_AS_PLTSEQ): Provide default.
* config/rs6000/rs6000.md (UNSPEC_PLTSEQ, UNSPEC_PLT16_HA,
UNSPEC_PLT16_LO): New.
(pltseq_tocsave, pltseq_plt16_ha, pltseq_plt16_lo, pltseq_mtctr): New.
(call_indirect_nonlocal_sysv): Don't differentiate zero from non-zero
cookie in constraints. Test explicitly for flags in length attr.
Handle unspec operand 1.
(call_value_indirect_nonlocal_sysv): Likewise.
(call_indirect_aix, call_value_indirect_aix): Handle unspec operand 1.
(call_indirect_elfv2, call_value_indirect_elfv2): Likewise.
(sibcall, sibcall_value): Use rs6000_sibcall_sysv.
(sibcall_indirect_nonlocal_sysv): New pattern.
(sibcall_value_indirect_nonlocal_sysv): Likewise.
(sibcall_nonlocal_sysv, sibcall_value_nonlocal_sysv): Remove indirect
call alternatives.
* configure.ac: Check for gas plt sequence marker support.
* configure: Regenerate.
2018-11-29 Alan Modra <amodra@gmail.com>
* config/rs6000/predicates.md (unspec_tls): New.
* config/rs6000/rs6000-protos.h (rs6000_call_template),
(rs6000_sibcall_template): Update prototype.
......@@ -577,6 +577,12 @@
#endif
/* Define if your assembler supports R_PPC*_PLTSEQ relocations. */
#ifndef USED_FOR_TARGET
#undef HAVE_AS_PLTSEQ
#endif
/* Define if your assembler supports .ref */
#ifndef USED_FOR_TARGET
#undef HAVE_AS_REF
......
......@@ -1013,6 +1013,24 @@
|| REGNO (op) >= FIRST_PSEUDO_REGISTER")
(match_code "symbol_ref")))
;; Return 1 if the operand, used inside a MEM, is a valid first argument
;; to an indirect CALL. This is LR, CTR, or a PLTSEQ unspec using CTR.
(define_predicate "indirect_call_operand"
(match_code "reg,unspec")
{
if (REG_P (op))
return (REGNO (op) == LR_REGNO
|| REGNO (op) == CTR_REGNO);
if (GET_CODE (op) == UNSPEC)
{
if (XINT (op, 1) != UNSPEC_PLTSEQ)
return false;
op = XVECEXP (op, 0, 0);
return REG_P (op) && REGNO (op) == CTR_REGNO;
}
return false;
})
;; Return 1 if the operand is a SYMBOL_REF for a function known to be in
;; this file.
(define_predicate "current_file_function_operand"
......
......@@ -109,6 +109,7 @@ extern const char *rs6000_call_template (rtx *, unsigned int);
extern const char *rs6000_sibcall_template (rtx *, unsigned int);
extern const char *rs6000_indirect_call_template (rtx *, unsigned int);
extern const char *rs6000_indirect_sibcall_template (rtx *, unsigned int);
extern const char *rs6000_pltseq_template (rtx *, int);
extern enum rtx_code rs6000_reverse_condition (machine_mode,
enum rtx_code);
extern rtx rs6000_emit_eqne (machine_mode, rtx, rtx, rtx);
......@@ -198,6 +199,7 @@ extern void rs6000_emit_eh_reg_restore (rtx, rtx);
extern void rs6000_call_aix (rtx, rtx, rtx, rtx);
extern void rs6000_sibcall_aix (rtx, rtx, rtx, rtx);
extern void rs6000_call_sysv (rtx, rtx, rtx, rtx);
extern void rs6000_sibcall_sysv (rtx, rtx, rtx, rtx);
extern void rs6000_aix_asm_output_dwarf_table_ref (char *);
extern void get_ppc476_thunk_name (char name[32]);
extern bool rs6000_overloaded_builtin_p (enum rs6000_builtins);
......
......@@ -220,6 +220,10 @@ extern const char *host_detect_local_cpu (int argc, const char **argv);
#define HAVE_AS_TLS 0
#endif
#ifndef HAVE_AS_PLTSEQ
#define HAVE_AS_PLTSEQ 0
#endif
#ifndef TARGET_LINK_STACK
#define TARGET_LINK_STACK 0
#endif
......
......@@ -24393,12 +24393,12 @@ foo: .long 25
;;
or1k*-*-*)
conftest_s='
.section ".tdata","awT",@progbits
foo: .long 25
.text
l.movhi r3, tpoffha(foo)
l.add r3, r3, r10
l.lwz r4, tpofflo(foo)(r3)'
.section ".tdata","awT",@progbits
foo: .long 25
.text
l.movhi r3, tpoffha(foo)
l.add r3, r3, r10
l.lwz r4, tpofflo(foo)(r3)'
tls_first_major=2
tls_first_minor=30
tls_as_opt=--fatal-warnings
......@@ -26942,6 +26942,42 @@ $as_echo "#define HAVE_AS_ENTRY_MARKERS 1" >>confdefs.h
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for plt sequence marker support" >&5
$as_echo_n "checking assembler for plt sequence marker support... " >&6; }
if ${gcc_cv_as_powerpc_pltseq_markers+:} false; then :
$as_echo_n "(cached) " >&6
else
gcc_cv_as_powerpc_pltseq_markers=no
if test $in_tree_gas = yes; then
if test $gcc_cv_gas_vers -ge `expr \( \( 2 \* 1000 \) + 31 \) \* 1000 + 0`
then gcc_cv_as_powerpc_pltseq_markers=yes
fi
elif test x$gcc_cv_as != x; then
$as_echo ' .reloc .,R_PPC_PLTSEQ; nop' > conftest.s
if { ac_try='$gcc_cv_as $gcc_cv_as_flags -a32 --fatal-warnings -o conftest.o conftest.s >&5'
{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
(eval $ac_try) 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; }
then
gcc_cv_as_powerpc_pltseq_markers=yes
else
echo "configure: failed program was" >&5
cat conftest.s >&5
fi
rm -f conftest.o conftest.s
fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_powerpc_pltseq_markers" >&5
$as_echo "$gcc_cv_as_powerpc_pltseq_markers" >&6; }
if test $gcc_cv_as_powerpc_pltseq_markers = yes; then
$as_echo "#define HAVE_AS_PLTSEQ 1" >>confdefs.h
fi
case $target in
*-*-aix*)
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for AIX .ref support" >&5
......
......@@ -4648,6 +4648,12 @@ LCF0:
[AC_DEFINE(HAVE_AS_ENTRY_MARKERS, 1,
[Define if your assembler supports the R_PPC64_ENTRY relocation.])])
gcc_GAS_CHECK_FEATURE([plt sequence marker support],
gcc_cv_as_powerpc_pltseq_markers, [2,31,0],-a32 --fatal-warnings,
[ .reloc .,R_PPC_PLTSEQ; nop],,
[AC_DEFINE(HAVE_AS_PLTSEQ, 1,
[Define if your assembler supports R_PPC*_PLTSEQ relocations.])])
case $target in
*-*-aix*)
gcc_GAS_CHECK_FEATURE([AIX .ref support],
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment