From: Alan Modra Date: Thu, 29 Nov 2018 04:47:51 +0000 (+1030) Subject: [RS6000] Use standard call patterns for __tls_get_addr calls X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=ece3bca2bd08bd02028f9ac6b0a2b6b8fa111305;p=gcc.git [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 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 560fb9b29ea..50148302f19 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,36 @@ +2018-11-29 Alan Modra + + * 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 * config/rs6000/darwin.md (call_indirect_nonlocal_darwin64), diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md index 5589ea19519..2c297fc45e8 100644 --- a/gcc/config/rs6000/predicates.md +++ b/gcc/config/rs6000/predicates.md @@ -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" diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h index f1a294a3617..dd930bb2da6 100644 --- a/gcc/config/rs6000/rs6000-protos.h +++ b/gcc/config/rs6000/rs6000-protos.h @@ -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); diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 497a157b89c..f3376065ee1 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -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. */ diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index b223e0b266d..ac87bb96436 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -9422,74 +9422,51 @@ ;; TLS support. -(define_insn_and_split "tls_gd_aix" - [(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)" -{ - if (TARGET_CMODEL != CMODEL_SMALL) - output_asm_insn ("addis %0,%1,%2@got@tlsgd@ha\;" - "addi %0,%0,%2@got@tlsgd@l", operands); +(define_insn "*tls_gdld_nomark" + [(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 - 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" - [(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" [(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); } [(set (attr "length") (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL")) @@ -9508,105 +9485,21 @@ (define_insn "*tls_gd_high" [(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" [(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" - [(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" - [(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" - [(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" - [(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" [(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); } [(set (attr "length") (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL")) @@ -9631,8 +9524,7 @@ (define_insn "*tls_ld_high" [(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" [(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" - [(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" - [(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_" [(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"; }