[RS6000] Use standard call patterns for __tls_get_addr calls

The current code handling __tls_get_addr calls for powerpc*-linux
generates a call then overwrites the call insn with a special
tls_{gd,ld}_{aix,sysv} pattern.  It's done that way to support
!TARGET_TLS_MARKERS, where the arg setup insns need to be emitted
immediately before the branch and link.  When TARGET_TLS_MARKERS, the
arg setup insns are split from the actual call, but we then have a
non-standard call pattern that needs to be carried through to output.

This patch changes that scheme, to instead use the standard call
patterns for __tls_get_addr calls, except for the now rare
!TARGET_TLS_MARKERS case.  Doing it this way should be better for
maintenance as the !TARGET_TLS_MARKERS code can eventually disappear.
It also makes it possible to support longcalls (and in following
patches, inline plt calls) for __tls_get_addr without introducing yet
more special call patterns.

__tls_get_addr calls do however need to be different to standard
calls, because when TARGET_TLS_MARKERS the calls are decorated with an
argument specifier, eg. "bl __tls_get_addr(thread_var@tlsgd)" that
causes a reloc to be emitted by the assembler tying the call to its
arg setup insns.  I chose to smuggle the arg in the currently unused
stack size rtl.

I've also introduced rs6000_call_sysv to generate rtl for sysv calls,
as rs6000_call_aix does for aix and elfv2 calls.  This allows
rs6000_longcall_ref to be local to rs6000.c since the calls in the
expanders never did anything for darwin.

	* config/rs6000/predicates.md (unspec_tls): New.
	* config/rs6000/rs6000-protos.h (rs6000_call_template),
	(rs6000_sibcall_template): Update prototype.
	(rs6000_longcall_ref): Delete.
	(rs6000_call_sysv): Declare.
	* config/rs6000/rs6000.c (edit_tls_call_insn): New function.
	(global_tlsarg): New variable.
	(rs6000_legitimize_tls_address): Rewrite __tls_get_addr call
	handling.
	(print_operand): Extract UNSPEC_TLSGD address operand.
	(rs6000_call_template, rs6000_sibcall_template): Remove arg
	parameter, extract from second call operand instead.
	(rs6000_longcall_ref): Make static, localize vars.
	(rs6000_call_aix): Rename parameter to reflect new usage.  Take
	tlsarg from global_tlsarg.  Don't create unused rtl or nop insns.
	(rs6000_sibcall_aix): Rename parameter to reflect new usage.  Take
	tlsarg from global_tlsarg.
	(rs6000_call_sysv): New function.
	* config/rs6000/rs6000.md: Adjust rs6000_call_template and
	rs6000_sibcall_template throughout.
	(tls_gd_aix, tls_gd_sysv, tls_gd_call_aix, tls_gd_call_sysv): Delete.
	(tls_ld_aix, tls_ld_sysv, tls_ld_call_aix, tls_ld_call_sysv): Delete.
	(tls_gdld_nomark): New insn.
	(tls_gd): Swap operand order.  Simplify mode selection.
	(tls_gd_high, tls_gd_low): Swap operand order.
	(tls_ld): Remove const_int 0 vector element from UNSPEC_TLSLD.
	Simplify mode selection.
	(tls_ld_high, tls_ld_low): Similarly adjust UNSPEC_TLSLD.
	(call, call_value): Don't assert for second call operand.
	Use rs6000_call_sysv.

From-SVN: r266604
This commit is contained in:
Alan Modra 2018-11-29 15:17:51 +10:30 committed by Alan Modra
parent 7a24893b2e
commit ece3bca2bd
5 changed files with 262 additions and 301 deletions

View File

@ -1,3 +1,36 @@
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.
(rs6000_longcall_ref): Delete.
(rs6000_call_sysv): Declare.
* config/rs6000/rs6000.c (edit_tls_call_insn): New function.
(global_tlsarg): New variable.
(rs6000_legitimize_tls_address): Rewrite __tls_get_addr call
handling.
(print_operand): Extract UNSPEC_TLSGD address operand.
(rs6000_call_template, rs6000_sibcall_template): Remove arg
parameter, extract from second call operand instead.
(rs6000_longcall_ref): Make static, localize vars.
(rs6000_call_aix): Rename parameter to reflect new usage. Take
tlsarg from global_tlsarg. Don't create unused rtl or nop insns.
(rs6000_sibcall_aix): Rename parameter to reflect new usage. Take
tlsarg from global_tlsarg.
(rs6000_call_sysv): New function.
* config/rs6000/rs6000.md: Adjust rs6000_call_template and
rs6000_sibcall_template throughout.
(tls_gd_aix, tls_gd_sysv, tls_gd_call_aix, tls_gd_call_sysv): Delete.
(tls_ld_aix, tls_ld_sysv, tls_ld_call_aix, tls_ld_call_sysv): Delete.
(tls_gdld_nomark): New insn.
(tls_gd): Swap operand order. Simplify mode selection.
(tls_gd_high, tls_gd_low): Swap operand order.
(tls_ld): Remove const_int 0 vector element from UNSPEC_TLSLD.
Simplify mode selection.
(tls_ld_high, tls_ld_low): Similarly adjust UNSPEC_TLSLD.
(call, call_value): Don't assert for second call operand.
Use rs6000_call_sysv.
2018-11-29 Alan Modra <amodra@gmail.com>
* config/rs6000/darwin.md (call_indirect_nonlocal_darwin64),

View File

@ -997,6 +997,13 @@
(and (match_code "symbol_ref")
(match_test "RS6000_SYMBOL_REF_TLS_P (op)")))
;; Return 1 for the UNSPEC used in TLS call operands
(define_predicate "unspec_tls"
(match_code "unspec")
{
return XINT (op, 1) == UNSPEC_TLSGD || XINT (op, 1) == UNSPEC_TLSLD;
})
;; Return 1 if the operand, used inside a MEM, is a valid first argument
;; to CALL. This is a SYMBOL_REF, a pseudo-register, LR or CTR.
(define_predicate "call_operand"

View File

@ -105,8 +105,8 @@ extern int ccr_bit (rtx, int);
extern void rs6000_output_function_entry (FILE *, const char *);
extern void print_operand (FILE *, rtx, int);
extern void print_operand_address (FILE *, rtx);
extern const char *rs6000_call_template (rtx *, unsigned int, const char *);
extern const char *rs6000_sibcall_template (rtx *, unsigned int, const char *);
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 enum rtx_code rs6000_reverse_condition (machine_mode,
@ -130,7 +130,6 @@ extern void rs6000_expand_atomic_op (enum rtx_code, rtx, rtx, rtx, rtx, rtx);
extern void rs6000_emit_swdiv (rtx, rtx, rtx, bool);
extern void rs6000_emit_swsqrt (rtx, rtx, bool);
extern void output_toc (FILE *, rtx, int, machine_mode);
extern rtx rs6000_longcall_ref (rtx);
extern void rs6000_fatal_bad_address (rtx);
extern rtx create_TOC_reference (rtx, rtx);
extern void rs6000_split_multireg_move (rtx, rtx);
@ -198,6 +197,7 @@ extern void rs6000_split_stack_space_check (rtx, rtx);
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_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);

View File

@ -8566,6 +8566,43 @@ rs6000_legitimize_tls_address_aix (rtx addr, enum tls_model model)
return dest;
}
/* Mess with a call, to make it look like the tls_gdld insns when
!TARGET_TLS_MARKERS. These insns have an extra unspec to
differentiate them from standard calls, because they need to emit
the arg setup insns as well as the actual call. That keeps the
arg setup insns immediately adjacent to the branch and link. */
static void
edit_tls_call_insn (rtx arg)
{
rtx call_insn = last_call_insn ();
if (!TARGET_TLS_MARKERS)
{
rtx patt = PATTERN (call_insn);
gcc_assert (GET_CODE (patt) == PARALLEL);
rtvec orig = XVEC (patt, 0);
rtvec v = rtvec_alloc (GET_NUM_ELEM (orig) + 1);
gcc_assert (GET_NUM_ELEM (orig) > 0);
/* The (set (..) (call (mem ..))). */
RTVEC_ELT (v, 0) = RTVEC_ELT (orig, 0);
/* The extra unspec. */
RTVEC_ELT (v, 1) = arg;
/* All other assorted call pattern pieces. */
for (int i = 1; i < GET_NUM_ELEM (orig); i++)
RTVEC_ELT (v, i + 1) = RTVEC_ELT (orig, i);
XVEC (patt, 0) = v;
}
if (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT && flag_pic)
use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn),
pic_offset_table_rtx);
}
/* Passes the tls arg value for global dynamic and local dynamic
emit_library_call_value in rs6000_legitimize_tls_address to
rs6000_call_aix and rs6000_call_sysv. This is used to emit the
marker relocs put on __tls_get_addr calls. */
static rtx global_tlsarg;
/* ADDR contains a thread-local SYMBOL_REF. Generate code to compute
this (thread-local) address. */
@ -8618,7 +8655,7 @@ rs6000_legitimize_tls_address (rtx addr, enum tls_model model)
}
else
{
rtx r3, got, tga, tmp1, tmp2, call_insn;
rtx got, tga, tmp1, tmp2;
/* We currently use relocations like @got@tlsgd for tls, which
means the linker will handle allocation of tls entries, placing
@ -8658,52 +8695,42 @@ rs6000_legitimize_tls_address (rtx addr, enum tls_model model)
if (model == TLS_MODEL_GLOBAL_DYNAMIC)
{
rtx arg = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, addr, got),
UNSPEC_TLSGD);
global_tlsarg = arg;
rtx argreg = const0_rtx;
if (TARGET_TLS_MARKERS)
{
argreg = gen_rtx_REG (Pmode, 3);
emit_insn (gen_rtx_SET (argreg, arg));
}
tga = rs6000_tls_get_addr ();
emit_library_call_value (tga, dest, LCT_CONST, Pmode,
const0_rtx, Pmode);
argreg, Pmode);
global_tlsarg = NULL_RTX;
r3 = gen_rtx_REG (Pmode, 3);
if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
{
if (TARGET_64BIT)
insn = gen_tls_gd_aix64 (r3, got, addr, tga, const0_rtx);
else
insn = gen_tls_gd_aix32 (r3, got, addr, tga, const0_rtx);
}
else if (DEFAULT_ABI == ABI_V4)
insn = gen_tls_gd_sysvsi (r3, got, addr, tga, const0_rtx);
else
gcc_unreachable ();
call_insn = last_call_insn ();
PATTERN (call_insn) = insn;
if (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT && flag_pic)
use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn),
pic_offset_table_rtx);
edit_tls_call_insn (arg);
}
else if (model == TLS_MODEL_LOCAL_DYNAMIC)
{
rtx arg = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, got),
UNSPEC_TLSLD);
global_tlsarg = arg;
rtx argreg = const0_rtx;
if (TARGET_TLS_MARKERS)
{
argreg = gen_rtx_REG (Pmode, 3);
emit_insn (gen_rtx_SET (argreg, arg));
}
tga = rs6000_tls_get_addr ();
tmp1 = gen_reg_rtx (Pmode);
emit_library_call_value (tga, tmp1, LCT_CONST, Pmode,
const0_rtx, Pmode);
argreg, Pmode);
global_tlsarg = NULL_RTX;
r3 = gen_rtx_REG (Pmode, 3);
if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
{
if (TARGET_64BIT)
insn = gen_tls_ld_aix64 (r3, got, tga, const0_rtx);
else
insn = gen_tls_ld_aix32 (r3, got, tga, const0_rtx);
}
else if (DEFAULT_ABI == ABI_V4)
insn = gen_tls_ld_sysvsi (r3, got, tga, const0_rtx);
else
gcc_unreachable ();
call_insn = last_call_insn ();
PATTERN (call_insn) = insn;
if (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT && flag_pic)
use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn),
pic_offset_table_rtx);
edit_tls_call_insn (arg);
if (rs6000_tls_size == 16)
{
@ -21170,19 +21197,19 @@ print_operand (FILE *file, rtx x, int code)
else
output_address (GET_MODE (x), XEXP (x, 0));
}
else if (toc_relative_expr_p (x, false,
&tocrel_base_oac, &tocrel_offset_oac))
/* This hack along with a corresponding hack in
rs6000_output_addr_const_extra arranges to output addends
where the assembler expects to find them. eg.
(plus (unspec [(symbol_ref ("x")) (reg 2)] tocrel) 4)
without this hack would be output as "x@toc+4". We
want "x+4@toc". */
output_addr_const (file, CONST_CAST_RTX (tocrel_base_oac));
else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLSGD)
output_addr_const (file, XVECEXP (x, 0, 0));
else
{
if (toc_relative_expr_p (x, false, &tocrel_base_oac, &tocrel_offset_oac))
/* This hack along with a corresponding hack in
rs6000_output_addr_const_extra arranges to output addends
where the assembler expects to find them. eg.
(plus (unspec [(symbol_ref ("x")) (reg 2)] tocrel) 4)
without this hack would be output as "x@toc+4". We
want "x+4@toc". */
output_addr_const (file, CONST_CAST_RTX (tocrel_base_oac));
else
output_addr_const (file, x);
}
output_addr_const (file, x);
return;
case '&':
@ -21368,18 +21395,27 @@ rs6000_assemble_integer (rtx x, unsigned int size, int aligned_p)
}
/* Return a template string for assembly to emit when making an
external call. FUNOP is the call mem argument operand number,
ARG is either NULL or a @TLSGD or @TLSLD __tls_get_addr argument
specifier. */
external call. FUNOP is the call mem argument operand number. */
static const char *
rs6000_call_template_1 (rtx *operands ATTRIBUTE_UNUSED, unsigned int funop,
bool sibcall, const char *arg)
rs6000_call_template_1 (rtx *operands, unsigned int funop, bool sibcall)
{
/* -Wformat-overflow workaround, without which gcc thinks that %u
might produce 10 digits. */
gcc_assert (funop <= MAX_RECOG_OPERANDS);
char arg[12];
arg[0] = 0;
if (TARGET_TLS_MARKERS && GET_CODE (operands[funop + 1]) == UNSPEC)
{
if (XINT (operands[funop + 1], 1) == UNSPEC_TLSGD)
sprintf (arg, "(%%%u@tlsgd)", funop + 1);
else if (XINT (operands[funop + 1], 1) == UNSPEC_TLSLD)
sprintf (arg, "(%%&@tlsld)");
else
gcc_unreachable ();
}
/* The magic 32768 offset here corresponds to the offset of
r30 in .got2, as given by LCTOC1. See sysv4.h:toc_section. */
char z[11];
@ -21387,7 +21423,7 @@ rs6000_call_template_1 (rtx *operands ATTRIBUTE_UNUSED, unsigned int funop,
(DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT && flag_pic == 2
? "+32768" : ""));
static char str[32]; /* 4 spare */
static char str[32]; /* 2 spare */
if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
sprintf (str, "b%s %s%s%s", sibcall ? "" : "l", z, arg,
sibcall ? "" : "\n\tnop");
@ -21400,15 +21436,15 @@ rs6000_call_template_1 (rtx *operands ATTRIBUTE_UNUSED, unsigned int funop,
}
const char *
rs6000_call_template (rtx *operands, unsigned int funop, const char *arg)
rs6000_call_template (rtx *operands, unsigned int funop)
{
return rs6000_call_template_1 (operands, funop, false, arg);
return rs6000_call_template_1 (operands, funop, false);
}
const char *
rs6000_sibcall_template (rtx *operands, unsigned int funop, const char *arg)
rs6000_sibcall_template (rtx *operands, unsigned int funop)
{
return rs6000_call_template_1 (operands, funop, true, arg);
return rs6000_call_template_1 (operands, funop, true);
}
/* As above, for indirect calls. */
@ -32498,23 +32534,20 @@ rs6000_set_default_type_attributes (tree type)
/* Return a reference suitable for calling a function with the
longcall attribute. */
rtx
static rtx
rs6000_longcall_ref (rtx call_ref)
{
const char *call_name;
tree node;
if (GET_CODE (call_ref) != SYMBOL_REF)
return call_ref;
/* System V adds '.' to the internal name, so skip them. */
call_name = XSTR (call_ref, 0);
const char *call_name = XSTR (call_ref, 0);
if (*call_name == '.')
{
while (*call_name == '.')
call_name++;
node = get_identifier (call_name);
tree node = get_identifier (call_name);
call_ref = gen_rtx_SYMBOL_REF (VOIDmode, IDENTIFIER_POINTER (node));
}
@ -37485,7 +37518,7 @@ chain_already_loaded (rtx_insn *last)
/* Expand code to perform a call under the AIX or ELFv2 ABI. */
void
rs6000_call_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
rs6000_call_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
{
const bool direct_call_p
= GET_CODE (func_desc) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (func_desc);
@ -37498,6 +37531,9 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
int n_call;
rtx insn;
if (global_tlsarg)
tlsarg = global_tlsarg;
/* Handle longcall attributes. */
if (INTVAL (cookie) & CALL_LONG)
func_desc = rs6000_longcall_ref (func_desc);
@ -37508,11 +37544,7 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
{
/* Save the TOC into its reserved slot before the call,
and prepare to restore it after the call. */
rtx stack_ptr = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
rtx stack_toc_offset = GEN_INT (RS6000_TOC_SAVE_SLOT);
rtx stack_toc_mem = gen_frame_mem (Pmode,
gen_rtx_PLUS (Pmode, stack_ptr,
stack_toc_offset));
rtx stack_toc_unspec = gen_rtx_UNSPEC (Pmode,
gen_rtvec (1, stack_toc_offset),
UNSPEC_TOCSLOT);
@ -37524,6 +37556,10 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
cfun->machine->save_toc_in_prologue = true;
else
{
rtx stack_ptr = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
rtx stack_toc_mem = gen_frame_mem (Pmode,
gen_rtx_PLUS (Pmode, stack_ptr,
stack_toc_offset));
MEM_VOLATILE_P (stack_toc_mem) = 1;
emit_move_insn (stack_toc_mem, toc_reg);
}
@ -37533,7 +37569,8 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
/* A function pointer in the ELFv2 ABI is just a plain address, but
the ABI requires it to be loaded into r12 before the call. */
func_addr = gen_rtx_REG (Pmode, 12);
emit_move_insn (func_addr, func_desc);
if (!rtx_equal_p (func_addr, func_desc))
emit_move_insn (func_addr, func_desc);
abi_reg = func_addr;
}
else
@ -37588,7 +37625,7 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
}
/* Create the call. */
call[0] = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (SImode, func_addr), flag);
call[0] = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (SImode, func_addr), tlsarg);
if (value != NULL_RTX)
call[0] = gen_rtx_SET (value, call[0]);
n_call = 1;
@ -37612,15 +37649,18 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
/* Expand code to perform a sibling call under the AIX or ELFv2 ABI. */
void
rs6000_sibcall_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
rs6000_sibcall_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
{
rtx call[2];
rtx insn;
gcc_assert (INTVAL (cookie) == 0);
if (global_tlsarg)
tlsarg = global_tlsarg;
/* Create the call. */
call[0] = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (SImode, func_desc), flag);
call[0] = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (SImode, func_desc), tlsarg);
if (value != NULL_RTX)
call[0] = gen_rtx_SET (value, call[0]);
@ -37633,6 +37673,42 @@ rs6000_sibcall_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
use_reg (&CALL_INSN_FUNCTION_USAGE (insn), gen_rtx_REG (Pmode, TOC_REGNUM));
}
/* Expand code to perform a call under the SYSV4 ABI. */
void
rs6000_call_sysv (rtx value, rtx func, rtx tlsarg, rtx cookie)
{
rtx func_addr;
rtx call[3];
rtx insn;
if (global_tlsarg)
tlsarg = global_tlsarg;
/* Handle longcall attributes. */
if (INTVAL (cookie) & CALL_LONG)
func = rs6000_longcall_ref (func);
/* Handle indirect calls. */
if (GET_CODE (func) != SYMBOL_REF)
func_addr = force_reg (Pmode, func);
else
func_addr = func;
/* Create the call. */
call[0] = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (SImode, func_addr), tlsarg);
if (value != NULL_RTX)
call[0] = gen_rtx_SET (value, call[0]);
unsigned int mask = CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS;
call[1] = gen_rtx_USE (VOIDmode, GEN_INT (INTVAL (cookie) & mask));
call[2] = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, LR_REGNO));
insn = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (3, call));
insn = emit_call_insn (insn);
}
/* Return whether we need to always update the saved TOC pointer when we update
the stack pointer. */

View File

@ -9422,74 +9422,51 @@
;; TLS support.
(define_insn_and_split "tls_gd_aix<bits>"
[(set (match_operand:P 0 "gpc_reg_operand" "=b")
(call (mem:SI (match_operand:P 3 "symbol_ref_operand" "s"))
(match_operand 4)))
(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
(match_operand:P 2 "rs6000_tls_symbol_ref" "")]
UNSPEC_TLSGD)
(clobber (reg:SI LR_REGNO))]
"HAVE_AS_TLS && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
(define_insn "*tls_gdld_nomark<bits>"
[(match_parallel 3 ""
[(set (match_operand:P 0 "gpc_reg_operand" "=b")
(call (mem:SI (match_operand:P 1))
(match_operand:P 2 "unspec_tls")))
(match_dup 2)])]
"HAVE_AS_TLS && !TARGET_TLS_MARKERS && DEFAULT_ABI != ABI_DARWIN"
{
if (TARGET_CMODEL != CMODEL_SMALL)
output_asm_insn ("addis %0,%1,%2@got@tlsgd@ha\;"
"addi %0,%0,%2@got@tlsgd@l", operands);
rtx op[3];
op[0] = operands[0];
op[1] = XVECEXP (operands[2], 0, 0);
if (XINT (operands[2], 1) == UNSPEC_TLSGD)
{
op[2] = XVECEXP (operands[2], 0, 1);
if (TARGET_CMODEL != CMODEL_SMALL)
output_asm_insn ("addis %0,%2,%1@got@tlsgd@ha\;"
"addi %0,%0,%1@got@tlsgd@l", op);
else
output_asm_insn ("addi %0,%2,%1@got@tlsgd", op);
}
else
output_asm_insn ("addi %0,%1,%2@got@tlsgd", operands);
return rs6000_call_template (operands, 3, "");
{
if (TARGET_CMODEL != CMODEL_SMALL)
output_asm_insn ("addis %0,%1,%&@got@tlsld@ha\;"
"addi %0,%0,%&@got@tlsld@l", op);
else
output_asm_insn ("addi %0,%1,%&@got@tlsld", op);
}
return rs6000_call_template (operands, 1);
}
"&& TARGET_TLS_MARKERS"
[(set (match_dup 0)
(unspec:P [(match_dup 1)
(match_dup 2)]
UNSPEC_TLSGD))
(parallel [(set (match_dup 0)
(call (mem:SI (match_dup 3))
(match_dup 4)))
(unspec:P [(match_dup 2)] UNSPEC_TLSGD)
(clobber (reg:SI LR_REGNO))])]
""
[(set_attr "type" "two")
(set (attr "length")
(if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
(const_int 16)
(const_int 12)))])
(define_insn_and_split "tls_gd_sysv<mode>"
[(set (match_operand:P 0 "gpc_reg_operand" "=b")
(call (mem:SI (match_operand:P 3 "symbol_ref_operand" "s"))
(match_operand 4)))
(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
(match_operand:P 2 "rs6000_tls_symbol_ref" "")]
UNSPEC_TLSGD)
(clobber (reg:SI LR_REGNO))]
"HAVE_AS_TLS && DEFAULT_ABI == ABI_V4"
{
output_asm_insn ("addi %0,%1,%2@got@tlsgd", operands);
return rs6000_call_template (operands, 3, "");
}
"&& TARGET_TLS_MARKERS"
[(set (match_dup 0)
(unspec:P [(match_dup 1)
(match_dup 2)]
UNSPEC_TLSGD))
(parallel [(set (match_dup 0)
(call (mem:SI (match_dup 3))
(match_dup 4)))
(unspec:P [(match_dup 2)] UNSPEC_TLSGD)
(clobber (reg:SI LR_REGNO))])]
""
[(set_attr "type" "two")
(set_attr "length" "8")])
(cond [(match_test "TARGET_CMODEL != CMODEL_SMALL")
(const_int 16)
(match_test "DEFAULT_ABI != ABI_V4")
(const_int 12)]
(const_int 8)))])
(define_insn_and_split "*tls_gd<bits>"
[(set (match_operand:P 0 "gpc_reg_operand" "=b")
(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
(match_operand:P 2 "rs6000_tls_symbol_ref" "")]
(unspec:P [(match_operand:P 1 "rs6000_tls_symbol_ref" "")
(match_operand:P 2 "gpc_reg_operand" "b")]
UNSPEC_TLSGD))]
"HAVE_AS_TLS && TARGET_TLS_MARKERS"
"addi %0,%1,%2@got@tlsgd"
"addi %0,%2,%1@got@tlsgd"
"&& TARGET_CMODEL != CMODEL_SMALL"
[(set (match_dup 3)
(high:P
@ -9498,7 +9475,7 @@
(lo_sum:P (match_dup 3)
(unspec:P [(match_dup 1) (match_dup 2)] UNSPEC_TLSGD)))]
{
operands[3] = gen_reg_rtx (TARGET_64BIT ? DImode : SImode);
operands[3] = gen_reg_rtx (<MODE>mode);
}
[(set (attr "length")
(if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
@ -9508,105 +9485,21 @@
(define_insn "*tls_gd_high<bits>"
[(set (match_operand:P 0 "gpc_reg_operand" "=b")
(high:P
(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
(match_operand:P 2 "rs6000_tls_symbol_ref" "")]
(unspec:P [(match_operand:P 1 "rs6000_tls_symbol_ref" "")
(match_operand:P 2 "gpc_reg_operand" "b")]
UNSPEC_TLSGD)))]
"HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
"addis %0,%1,%2@got@tlsgd@ha")
"addis %0,%2,%1@got@tlsgd@ha")
(define_insn "*tls_gd_low<bits>"
[(set (match_operand:P 0 "gpc_reg_operand" "=b")
(lo_sum:P (match_operand:P 1 "gpc_reg_operand" "b")
(unspec:P [(match_operand:P 3 "gpc_reg_operand" "b")
(match_operand:P 2 "rs6000_tls_symbol_ref" "")]
(unspec:P [(match_operand:P 2 "rs6000_tls_symbol_ref" "")
(match_operand:P 3 "gpc_reg_operand" "b")]
UNSPEC_TLSGD)))]
"HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
"addi %0,%1,%2@got@tlsgd@l")
(define_insn "*tls_gd_call_aix<bits>"
[(set (match_operand:P 0 "gpc_reg_operand" "=b")
(call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
(match_operand 2)))
(unspec:P [(match_operand:P 3 "rs6000_tls_symbol_ref" "")]
UNSPEC_TLSGD)
(clobber (reg:SI LR_REGNO))]
"HAVE_AS_TLS && TARGET_TLS_MARKERS
&& (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
{
return rs6000_call_template (operands, 1, "(%3@tlsgd)");
}
[(set_attr "type" "branch")
(set_attr "length" "8")])
(define_insn "*tls_gd_call_sysv<bits>"
[(set (match_operand:P 0 "gpc_reg_operand" "=b")
(call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
(match_operand 2)))
(unspec:P [(match_operand:P 3 "rs6000_tls_symbol_ref" "")]
UNSPEC_TLSGD)
(clobber (reg:SI LR_REGNO))]
"HAVE_AS_TLS && DEFAULT_ABI == ABI_V4 && TARGET_TLS_MARKERS"
{
return rs6000_call_template (operands, 1, "(%3@tlsgd)");
}
[(set_attr "type" "branch")])
(define_insn_and_split "tls_ld_aix<bits>"
[(set (match_operand:P 0 "gpc_reg_operand" "=b")
(call (mem:SI (match_operand:P 2 "symbol_ref_operand" "s"))
(match_operand 3)))
(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")]
UNSPEC_TLSLD)
(clobber (reg:SI LR_REGNO))]
"HAVE_AS_TLS && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
{
if (TARGET_CMODEL != CMODEL_SMALL)
output_asm_insn ("addis %0,%1,%&@got@tlsld@ha\;"
"addi %0,%0,%&@got@tlsld@l", operands);
else
output_asm_insn ("addi %0,%1,%&@got@tlsld", operands);
return rs6000_call_template (operands, 2, "");
}
"&& TARGET_TLS_MARKERS"
[(set (match_dup 0)
(unspec:P [(match_dup 1)]
UNSPEC_TLSLD))
(parallel [(set (match_dup 0)
(call (mem:SI (match_dup 2))
(match_dup 3)))
(unspec:P [(const_int 0)] UNSPEC_TLSLD)
(clobber (reg:SI LR_REGNO))])]
""
[(set_attr "type" "two")
(set (attr "length")
(if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
(const_int 16)
(const_int 12)))])
(define_insn_and_split "tls_ld_sysv<mode>"
[(set (match_operand:P 0 "gpc_reg_operand" "=b")
(call (mem:SI (match_operand:P 2 "symbol_ref_operand" "s"))
(match_operand 3)))
(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")]
UNSPEC_TLSLD)
(clobber (reg:SI LR_REGNO))]
"HAVE_AS_TLS && DEFAULT_ABI == ABI_V4"
{
output_asm_insn ("addi %0,%1,%&@got@tlsld", operands);
return rs6000_call_template (operands, 2, "");
}
"&& TARGET_TLS_MARKERS"
[(set (match_dup 0)
(unspec:P [(match_dup 1)]
UNSPEC_TLSLD))
(parallel [(set (match_dup 0)
(call (mem:SI (match_dup 2))
(match_dup 3)))
(unspec:P [(const_int 0)] UNSPEC_TLSLD)
(clobber (reg:SI LR_REGNO))])]
""
[(set_attr "length" "8")])
(define_insn_and_split "*tls_ld<bits>"
[(set (match_operand:P 0 "gpc_reg_operand" "=b")
(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")]
@ -9616,12 +9509,12 @@
"&& TARGET_CMODEL != CMODEL_SMALL"
[(set (match_dup 2)
(high:P
(unspec:P [(const_int 0) (match_dup 1)] UNSPEC_TLSLD)))
(unspec:P [(match_dup 1)] UNSPEC_TLSLD)))
(set (match_dup 0)
(lo_sum:P (match_dup 2)
(unspec:P [(const_int 0) (match_dup 1)] UNSPEC_TLSLD)))]
(unspec:P [(match_dup 1)] UNSPEC_TLSLD)))]
{
operands[2] = gen_reg_rtx (TARGET_64BIT ? DImode : SImode);
operands[2] = gen_reg_rtx (<MODE>mode);
}
[(set (attr "length")
(if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
@ -9631,8 +9524,7 @@
(define_insn "*tls_ld_high<bits>"
[(set (match_operand:P 0 "gpc_reg_operand" "=b")
(high:P
(unspec:P [(const_int 0)
(match_operand:P 1 "gpc_reg_operand" "b")]
(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")]
UNSPEC_TLSLD)))]
"HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
"addis %0,%1,%&@got@tlsld@ha")
@ -9640,38 +9532,11 @@
(define_insn "*tls_ld_low<bits>"
[(set (match_operand:P 0 "gpc_reg_operand" "=b")
(lo_sum:P (match_operand:P 1 "gpc_reg_operand" "b")
(unspec:P [(const_int 0)
(match_operand:P 2 "gpc_reg_operand" "b")]
(unspec:P [(match_operand:P 2 "gpc_reg_operand" "b")]
UNSPEC_TLSLD)))]
"HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
"addi %0,%1,%&@got@tlsld@l")
(define_insn "*tls_ld_call_aix<bits>"
[(set (match_operand:P 0 "gpc_reg_operand" "=b")
(call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
(match_operand 2)))
(unspec:P [(const_int 0)] UNSPEC_TLSLD)
(clobber (reg:SI LR_REGNO))]
"HAVE_AS_TLS && TARGET_TLS_MARKERS
&& (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
{
return rs6000_call_template (operands, 1, "(%&@tlsld)");
}
[(set_attr "type" "branch")
(set_attr "length" "8")])
(define_insn "*tls_ld_call_sysv<bits>"
[(set (match_operand:P 0 "gpc_reg_operand" "=b")
(call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
(match_operand 2)))
(unspec:P [(const_int 0)] UNSPEC_TLSLD)
(clobber (reg:SI LR_REGNO))]
"HAVE_AS_TLS && DEFAULT_ABI == ABI_V4 && TARGET_TLS_MARKERS"
{
return rs6000_call_template (operands, 1, "(%&@tlsld)");
}
[(set_attr "type" "branch")])
(define_insn "tls_dtprel_<bits>"
[(set (match_operand:P 0 "gpc_reg_operand" "=r")
(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
@ -10345,7 +10210,6 @@
#endif
gcc_assert (GET_CODE (operands[0]) == MEM);
gcc_assert (GET_CODE (operands[1]) == CONST_INT);
operands[0] = XEXP (operands[0], 0);
@ -10355,23 +10219,14 @@
DONE;
}
if (GET_CODE (operands[0]) != SYMBOL_REF
|| (DEFAULT_ABI != ABI_DARWIN && (INTVAL (operands[2]) & CALL_LONG) != 0))
if (DEFAULT_ABI == ABI_V4)
{
if (INTVAL (operands[2]) & CALL_LONG)
operands[0] = rs6000_longcall_ref (operands[0]);
switch (DEFAULT_ABI)
{
case ABI_V4:
case ABI_DARWIN:
operands[0] = force_reg (Pmode, operands[0]);
break;
default:
gcc_unreachable ();
}
rs6000_call_sysv (NULL_RTX, operands[0], operands[1], operands[2]);
DONE;
}
if (GET_CODE (operands[0]) != SYMBOL_REF)
operands[0] = force_reg (Pmode, operands[0]);
})
(define_expand "call_value"
@ -10388,7 +10243,6 @@
#endif
gcc_assert (GET_CODE (operands[1]) == MEM);
gcc_assert (GET_CODE (operands[2]) == CONST_INT);
operands[1] = XEXP (operands[1], 0);
@ -10398,23 +10252,14 @@
DONE;
}
if (GET_CODE (operands[1]) != SYMBOL_REF
|| (DEFAULT_ABI != ABI_DARWIN && (INTVAL (operands[3]) & CALL_LONG) != 0))
if (DEFAULT_ABI == ABI_V4)
{
if (INTVAL (operands[3]) & CALL_LONG)
operands[1] = rs6000_longcall_ref (operands[1]);
switch (DEFAULT_ABI)
{
case ABI_V4:
case ABI_DARWIN:
operands[1] = force_reg (Pmode, operands[1]);
break;
default:
gcc_unreachable ();
}
rs6000_call_sysv (operands[0], operands[1], operands[2], operands[3]);
DONE;
}
if (GET_CODE (operands[1]) != SYMBOL_REF)
operands[1] = force_reg (Pmode, operands[1]);
})
;; Call to function in current module. No TOC pointer reload needed.
@ -10501,7 +10346,7 @@
;; A function pointer under System V is just a normal pointer
;; operands[0] is the function pointer
;; operands[1] is the stack size to clean up
;; operands[1] is the tls call arg
;; operands[2] is the value FUNCTION_ARG returns for the VOID argument
;; which indicates how to set cr1
@ -10552,7 +10397,7 @@
#if TARGET_MACHO
return macho_call_template (insn, operands, 0, 2);
#else
return rs6000_call_template (operands, 0, "");
return rs6000_call_template (operands, 0);
#endif
}
"DEFAULT_ABI == ABI_V4
@ -10585,7 +10430,7 @@
else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
output_asm_insn ("creqv 6,6,6", operands);
return rs6000_call_template (operands, 0, "");
return rs6000_call_template (operands, 0);
}
[(set_attr "type" "branch,branch")
(set_attr "length" "4,8")])
@ -10639,7 +10484,7 @@
#if TARGET_MACHO
return macho_call_template (insn, operands, 1, 3);
#else
return rs6000_call_template (operands, 1, "");
return rs6000_call_template (operands, 1);
#endif
}
"DEFAULT_ABI == ABI_V4
@ -10674,7 +10519,7 @@
else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
output_asm_insn ("creqv 6,6,6", operands);
return rs6000_call_template (operands, 1, "");
return rs6000_call_template (operands, 1);
}
[(set_attr "type" "branch,branch")
(set_attr "length" "4,8")])
@ -10708,7 +10553,7 @@
(clobber (reg:P LR_REGNO))]
"DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
{
return rs6000_call_template (operands, 0, "");
return rs6000_call_template (operands, 0);
}
[(set_attr "type" "branch")
(set_attr "length" "8")])
@ -10720,7 +10565,7 @@
(clobber (reg:P LR_REGNO))]
"DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
{
return rs6000_call_template (operands, 1, "");
return rs6000_call_template (operands, 1);
}
[(set_attr "type" "branch")
(set_attr "length" "8")])
@ -10971,7 +10816,7 @@
if (which_alternative >= 2)
return rs6000_indirect_sibcall_template (operands, 0);
else
return rs6000_sibcall_template (operands, 0, "");
return rs6000_sibcall_template (operands, 0);
}
[(set_attr "type" "branch")
(set_attr_alternative "length"
@ -11011,7 +10856,7 @@
return "crset 2\;beq%T1-\;b $";
}
else
return rs6000_sibcall_template (operands, 1, "");
return rs6000_sibcall_template (operands, 1);
}
[(set_attr "type" "branch")
(set_attr_alternative "length"
@ -11035,7 +10880,7 @@
"DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
{
if (which_alternative == 0)
return rs6000_sibcall_template (operands, 0, "");
return rs6000_sibcall_template (operands, 0);
else
return "b%T0";
}
@ -11049,7 +10894,7 @@
"DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
{
if (which_alternative == 0)
return rs6000_sibcall_template (operands, 1, "");
return rs6000_sibcall_template (operands, 1);
else
return "b%T1";
}