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. */
+/* Output arg setup instructions for a !TARGET_TLS_MARKERS
+ __tls_get_addr call. */
-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);
+void
+rs6000_output_tlsargs (rtx *operands)
+{
+ /* Set up operands for output_asm_insn, without modifying OPERANDS. */
+ rtx op[3];
+
+ /* The set dest of the call, ie. r3, which is also the first arg reg. */
+ op[0] = operands[0];
+ /* The TLS symbol from global_tlsarg stashed as CALL operand 2. */
+ op[1] = XVECEXP (operands[2], 0, 0);
+ if (XINT (operands[2], 1) == UNSPEC_TLSGD)
+ {
+ /* The GOT register. */
+ op[2] = XVECEXP (operands[2], 0, 1);
+ if (TARGET_CMODEL != CMODEL_SMALL)
+ output_asm_insn ("addis %0,%2,%1@got@tlsgd@ha\n\t"
+ "addi %0,%0,%1@got@tlsgd@l", op);
+ else
+ output_asm_insn ("addi %0,%2,%1@got@tlsgd", op);
+ }
+ else if (XINT (operands[2], 1) == UNSPEC_TLSLD)
+ {
+ if (TARGET_CMODEL != CMODEL_SMALL)
+ output_asm_insn ("addis %0,%1,%&@got@tlsld@ha\n\t"
+ "addi %0,%0,%&@got@tlsld@l", op);
+ else
+ output_asm_insn ("addi %0,%1,%&@got@tlsld", op);
+ }
+ else
+ gcc_unreachable ();
}
/* Passes the tls arg value for global dynamic and local dynamic
{
rtx arg = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, addr, got),
UNSPEC_TLSGD);
+ tga = rs6000_tls_get_addr ();
global_tlsarg = arg;
- rtx argreg = const0_rtx;
if (TARGET_TLS_MARKERS)
{
- argreg = gen_rtx_REG (Pmode, 3);
+ rtx argreg = gen_rtx_REG (Pmode, 3);
emit_insn (gen_rtx_SET (argreg, arg));
+ emit_library_call_value (tga, dest, LCT_CONST, Pmode,
+ argreg, Pmode);
}
-
- tga = rs6000_tls_get_addr ();
- emit_library_call_value (tga, dest, LCT_CONST, Pmode,
- argreg, Pmode);
+ else
+ emit_library_call_value (tga, dest, LCT_CONST, Pmode);
global_tlsarg = NULL_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);
+ rtx arg = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, got), UNSPEC_TLSLD);
+ tga = rs6000_tls_get_addr ();
+ tmp1 = gen_reg_rtx (Pmode);
global_tlsarg = arg;
- rtx argreg = const0_rtx;
if (TARGET_TLS_MARKERS)
{
- argreg = gen_rtx_REG (Pmode, 3);
+ rtx argreg = gen_rtx_REG (Pmode, 3);
emit_insn (gen_rtx_SET (argreg, arg));
+ emit_library_call_value (tga, tmp1, LCT_CONST, Pmode,
+ argreg, Pmode);
}
-
- tga = rs6000_tls_get_addr ();
- tmp1 = gen_reg_rtx (Pmode);
- emit_library_call_value (tga, tmp1, LCT_CONST, Pmode,
- argreg, Pmode);
+ else
+ emit_library_call_value (tga, tmp1, LCT_CONST, Pmode);
global_tlsarg = NULL_RTX;
- edit_tls_call_insn (arg);
-
if (rs6000_tls_size == 16)
{
if (TARGET_64BIT)
{
rtx func = func_desc;
rtx func_addr;
- rtx call[3];
+ rtx call[4];
rtx insn;
rtx abi_reg = NULL_RTX;
+ int n;
if (global_tlsarg)
tlsarg = global_tlsarg;
call[0] = gen_rtx_SET (value, call[0]);
call[1] = gen_rtx_USE (VOIDmode, cookie);
- call[2] = gen_hard_reg_clobber (Pmode, LR_REGNO);
+ n = 2;
+ if (TARGET_SECURE_PLT
+ && flag_pic
+ && GET_CODE (func_addr) == SYMBOL_REF
+ && !SYMBOL_REF_LOCAL_P (func_addr))
+ call[n++] = gen_rtx_USE (VOIDmode, pic_offset_table_rtx);
- insn = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (3, call));
+ call[n++] = gen_hard_reg_clobber (Pmode, LR_REGNO);
+
+ insn = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (n, call));
insn = emit_call_insn (insn);
if (abi_reg)
use_reg (&CALL_INSN_FUNCTION_USAGE (insn), abi_reg);
\f
;; TLS support.
-(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"
-{
- 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
- {
- 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);
-}
- [(set_attr "type" "two")
- (set (attr "length")
- (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 "rs6000_tls_symbol_ref" "")
(match_operand 2)))
(use (match_operand:SI 3 "immediate_operand" "O,n"))
(clobber (reg:SI LR_REGNO))]
- "(INTVAL (operands[3]) & CALL_LONG) == 0"
+ "(INTVAL (operands[3]) & CALL_LONG) == 0
+ && !IS_NOMARK_TLSGETADDR (operands[2])"
{
if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS)
output_asm_insn ("crxor 6,6,6", operands);
(match_operand 2)))
(use (match_operand:SI 3 "immediate_operand" "O,n"))
(clobber (reg:DI LR_REGNO))]
- "TARGET_64BIT && (INTVAL (operands[3]) & CALL_LONG) == 0"
+ "TARGET_64BIT && (INTVAL (operands[3]) & CALL_LONG) == 0
+ && !IS_NOMARK_TLSGETADDR (operands[2])"
{
if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS)
output_asm_insn ("crxor 6,6,6", operands);
(const_string "8")]
(const_string "4")))])
-(define_insn_and_split "*call_nonlocal_sysv<mode>"
+(define_insn "*call_nonlocal_sysv<mode>"
[(call (mem:SI (match_operand:P 0 "symbol_ref_operand" "s,s"))
(match_operand 1))
(use (match_operand:SI 2 "immediate_operand" "O,n"))
output_asm_insn ("creqv 6,6,6", operands);
return rs6000_call_template (operands, 0);
-}
- "DEFAULT_ABI == ABI_V4
- && TARGET_SECURE_PLT && flag_pic && !SYMBOL_REF_LOCAL_P (operands[0])
- && (INTVAL (operands[2]) & CALL_LONG) == 0"
- [(parallel [(call (mem:SI (match_dup 0))
- (match_dup 1))
- (use (match_dup 2))
- (use (match_dup 3))
- (clobber (reg:SI LR_REGNO))])]
-{
- operands[3] = pic_offset_table_rtx;
}
[(set_attr "type" "branch,branch")
(set_attr "length" "4,8")])
(define_insn "*call_value_indirect_nonlocal_sysv<mode>"
[(set (match_operand 0 "" "")
(call (mem:SI (match_operand:P 1 "indirect_call_operand" "c,*l,X"))
- (match_operand 2)))
+ (match_operand:P 2 "unspec_tls" "")))
(use (match_operand:SI 3 "immediate_operand" "n,n,n"))
(clobber (reg:P LR_REGNO))]
"DEFAULT_ABI == ABI_V4
|| DEFAULT_ABI == ABI_DARWIN"
{
- if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS)
+ if (IS_NOMARK_TLSGETADDR (operands[2]))
+ rs6000_output_tlsargs (operands);
+
+ else if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS)
output_asm_insn ("crxor 6,6,6", operands);
else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
}
[(set_attr "type" "jmpreg")
(set (attr "length")
- (cond [(and (and (match_test "!rs6000_speculate_indirect_jumps")
- (match_test "which_alternative != 1"))
- (match_test "(INTVAL (operands[3]) & (CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS))"))
- (const_string "12")
- (ior (and (match_test "!rs6000_speculate_indirect_jumps")
- (match_test "which_alternative != 1"))
- (match_test "(INTVAL (operands[3]) & (CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS))"))
- (const_string "8")]
- (const_string "4")))])
-
-(define_insn_and_split "*call_value_nonlocal_sysv<mode>"
+ (plus
+ (if_then_else (ior (match_test "IS_NOMARK_TLSGETADDR (operands[2])")
+ (match_test "IS_V4_FP_ARGS (operands[3])"))
+ (const_int 4)
+ (const_int 0))
+ (if_then_else (and (match_test "!rs6000_speculate_indirect_jumps")
+ (match_test "which_alternative != 1"))
+ (const_int 8)
+ (const_int 4))))])
+
+(define_insn "*call_value_nonlocal_sysv<mode>"
[(set (match_operand 0 "" "")
- (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s,s"))
- (match_operand 2)))
- (use (match_operand:SI 3 "immediate_operand" "O,n"))
+ (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
+ (match_operand:P 2 "unspec_tls" "")))
+ (use (match_operand:SI 3 "immediate_operand" "n"))
(clobber (reg:P LR_REGNO))]
"(DEFAULT_ABI == ABI_DARWIN
- || (DEFAULT_ABI == ABI_V4
- && (INTVAL (operands[3]) & CALL_LONG) == 0))"
+ || (DEFAULT_ABI == ABI_V4
+ && (INTVAL (operands[3]) & CALL_LONG) == 0))"
{
- if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS)
+ if (IS_NOMARK_TLSGETADDR (operands[2]))
+ rs6000_output_tlsargs (operands);
+
+ else if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS)
output_asm_insn ("crxor 6,6,6", operands);
else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
return rs6000_call_template (operands, 1);
}
- "DEFAULT_ABI == ABI_V4
- && TARGET_SECURE_PLT && flag_pic && !SYMBOL_REF_LOCAL_P (operands[1])
- && (INTVAL (operands[3]) & CALL_LONG) == 0"
- [(parallel [(set (match_dup 0)
- (call (mem:SI (match_dup 1))
- (match_dup 2)))
- (use (match_dup 3))
- (use (match_dup 4))
- (clobber (reg:SI LR_REGNO))])]
-{
- operands[4] = pic_offset_table_rtx;
-}
- [(set_attr "type" "branch,branch")
- (set_attr "length" "4,8")])
+ [(set_attr "type" "branch")
+ (set (attr "length")
+ (if_then_else (ior (match_test "IS_NOMARK_TLSGETADDR (operands[2])")
+ (match_test "IS_V4_FP_ARGS (operands[3])"))
+ (const_int 8)
+ (const_int 4)))])
(define_insn "*call_value_nonlocal_sysv_secure<mode>"
[(set (match_operand 0 "" "")
- (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s,s"))
- (match_operand 2)))
- (use (match_operand:SI 3 "immediate_operand" "O,n"))
- (use (match_operand:SI 4 "register_operand" "r,r"))
+ (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
+ (match_operand:P 2 "unspec_tls" "")))
+ (use (match_operand:SI 3 "immediate_operand" "n"))
+ (use (match_operand:SI 4 "register_operand" "r"))
(clobber (reg:P LR_REGNO))]
"(DEFAULT_ABI == ABI_V4
&& TARGET_SECURE_PLT && flag_pic && !SYMBOL_REF_LOCAL_P (operands[1])
&& (INTVAL (operands[3]) & CALL_LONG) == 0)"
{
- if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS)
+ if (IS_NOMARK_TLSGETADDR (operands[2]))
+ rs6000_output_tlsargs (operands);
+
+ else if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS)
output_asm_insn ("crxor 6,6,6", operands);
else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
return rs6000_call_template (operands, 1);
}
- [(set_attr "type" "branch,branch")
- (set_attr "length" "4,8")])
-
+ [(set_attr "type" "branch")
+ (set (attr "length")
+ (if_then_else (ior (match_test "IS_NOMARK_TLSGETADDR (operands[2])")
+ (match_test "IS_V4_FP_ARGS (operands[3])"))
+ (const_int 8)
+ (const_int 4)))])
;; Call to AIX abi function in the same module.
(call (mem:SI (match_operand:P 1 "current_file_function_operand" "s"))
(match_operand 2)))
(clobber (reg:P LR_REGNO))]
- "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
+ "(DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
+ && !IS_NOMARK_TLSGETADDR (operands[2])"
"bl %z1"
[(set_attr "type" "branch")])
(define_insn "*call_value_nonlocal_aix<mode>"
[(set (match_operand 0 "" "")
(call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
- (match_operand 2)))
+ (match_operand:P 2 "unspec_tls" "")))
(clobber (reg:P LR_REGNO))]
"DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
{
+ if (IS_NOMARK_TLSGETADDR (operands[2]))
+ rs6000_output_tlsargs (operands);
+
return rs6000_call_template (operands, 1);
}
[(set_attr "type" "branch")
- (set_attr "length" "8")])
+ (set (attr "length")
+ (if_then_else (match_test "IS_NOMARK_TLSGETADDR (operands[2])")
+ (if_then_else (match_test "TARGET_CMODEL != CMODEL_SMALL")
+ (const_int 16)
+ (const_int 12))
+ (const_int 8)))])
;; Call to indirect functions with the AIX abi using a 3 word descriptor.
;; Operand0 is the addresss of the function to call
(define_insn "*call_value_indirect_aix<mode>"
[(set (match_operand 0 "" "")
(call (mem:SI (match_operand:P 1 "indirect_call_operand" "c,*l,X"))
- (match_operand 2)))
+ (match_operand:P 2 "unspec_tls" "")))
(use (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>,<ptrm>"))
- (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 4 "const_int_operand" "n,n,n")] UNSPEC_TOCSLOT))
+ (set (reg:P TOC_REGNUM)
+ (unspec:P [(match_operand:P 4 "const_int_operand" "n,n,n")]
+ UNSPEC_TOCSLOT))
(clobber (reg:P LR_REGNO))]
"DEFAULT_ABI == ABI_AIX"
{
+ if (IS_NOMARK_TLSGETADDR (operands[2]))
+ rs6000_output_tlsargs (operands);
+
return rs6000_indirect_call_template (operands, 1);
}
[(set_attr "type" "jmpreg")
(set (attr "length")
- (if_then_else (and (match_test "!rs6000_speculate_indirect_jumps")
- (match_test "which_alternative != 1"))
- (const_string "16")
- (const_string "12")))])
+ (plus
+ (if_then_else (match_test "IS_NOMARK_TLSGETADDR (operands[2])")
+ (if_then_else (match_test "TARGET_CMODEL != CMODEL_SMALL")
+ (const_int 8)
+ (const_int 4))
+ (const_int 0))
+ (if_then_else (and (match_test "!rs6000_speculate_indirect_jumps")
+ (match_test "which_alternative != 1"))
+ (const_string "16")
+ (const_string "12"))))])
;; Call to indirect functions with the ELFv2 ABI.
;; Operand0 is the addresss of the function to call
(define_insn "*call_value_indirect_elfv2<mode>"
[(set (match_operand 0 "" "")
(call (mem:SI (match_operand:P 1 "indirect_call_operand" "c,*l,X"))
- (match_operand 2)))
- (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n,n")] UNSPEC_TOCSLOT))
+ (match_operand:P 2 "unspec_tls" "")))
+ (set (reg:P TOC_REGNUM)
+ (unspec:P [(match_operand:P 3 "const_int_operand" "n,n,n")]
+ UNSPEC_TOCSLOT))
(clobber (reg:P LR_REGNO))]
"DEFAULT_ABI == ABI_ELFv2"
{
+ if (IS_NOMARK_TLSGETADDR (operands[2]))
+ rs6000_output_tlsargs (operands);
+
return rs6000_indirect_call_template (operands, 1);
}
[(set_attr "type" "jmpreg")
(set (attr "length")
- (if_then_else (and (match_test "!rs6000_speculate_indirect_jumps")
- (match_test "which_alternative != 1"))
- (const_string "12")
- (const_string "8")))])
+ (plus
+ (if_then_else (match_test "IS_NOMARK_TLSGETADDR (operands[2])")
+ (if_then_else (match_test "TARGET_CMODEL != CMODEL_SMALL")
+ (const_int 8)
+ (const_int 4))
+ (const_int 0))
+ (if_then_else (and (match_test "!rs6000_speculate_indirect_jumps")
+ (match_test "which_alternative != 1"))
+ (const_string "12")
+ (const_string "8"))))])
;; Call subroutine returning any type.
(define_expand "untyped_call"