Message ID | 20181113125243.GU29784@bubble.grove.modra.org |
---|---|
State | New |
Headers | show |
Series | [1/6,RS6000] rs6000_call_template for external call insn assembly output | expand |
Hi! On Tue, Nov 13, 2018 at 11:22:43PM +1030, Alan Modra wrote: > Version 2. > > 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_aix, tls_gdld_sysv): New insns, replacing above. > (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. > +/* 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; Typo (s/_Tls/_tls/). > +(define_insn "*tls_gdld_aix<P:bits>" > + [(match_parallel 3 "" A match_parallel without predicate... Does this work?! Does this not accidentally pick up the wrong things? Do you think we should to deprecate -mtls-markers in GCC 9? Please test with -mtls-markers, too, if you can, and test on AIX. Looks fine. Thank you for the cleanup! Okay for trunk, but please do the extra testing. Segher
On Tue, Nov 27, 2018 at 10:29:29AM -0600, Segher Boessenkool wrote: > Hi! Thanks for the review! > > +(define_insn "*tls_gdld_aix<P:bits>" > > + [(match_parallel 3 "" > > A match_parallel without predicate... Does this work?! Yes. In fact, rs6000/predicates.md any_parallel_operand is useless except as documentation. The only thing it checks is that its operand is a parallel, but that has already been checked. > Does this not > accidentally pick up the wrong things? No. The purpose of the predicate is to match anything beyond the vector of expressions. So tls_gdld_aix* matches insns that look like: (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) ... This is sufficiently different from other calls, by virtue of the "(match_dup 2)". Incidentally, I think tls_gdld_aix and tls_gdld_sysv could be merged at the expense of complicating the length attribute expression. > Do you think we should to deprecate -mtls-markers in GCC 9? Support for the TLS marker relocs was added to binutils in 2009 (git commit 727fc41e077), so yes, the option is not likely to be useful nowadays. > Please test with -mtls-markers, too, if you can, and test on AIX. Presumably you mean -mno-tls-markers. -mtls-markers is the default. > Looks fine. Thank you for the cleanup! Okay for trunk, but please do the > extra testing. Huh, local testing of -mno-tls-markers showed a lack of a TARGET_TLS_MARKERS check in rs6000_call_template_1. Likely this would blow up on AIX. I'll test with the following delta. diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 56ca117a0a0..5f4fcee3b33 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -8622,7 +8622,7 @@ edit_tls_call_insn (rtx arg) } /* Passes the tls arg value for global dynamic and local dynamic - emit_library_call_value in rs6000_legitimize_Tls_address to + 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; @@ -21429,7 +21429,7 @@ rs6000_call_template_1 (rtx *operands, unsigned int funop, bool sibcall) char arg[12]; arg[0] = 0; - if (GET_CODE (operands[funop + 1]) == UNSPEC) + if (TARGET_TLS_MARKERS && GET_CODE (operands[funop + 1]) == UNSPEC) { if (XINT (operands[funop + 1], 1) == UNSPEC_TLSGD) sprintf (arg, "(%%%u@tlsgd)", funop + 1);
On Wed, Nov 28, 2018 at 11:37:42AM +1030, Alan Modra wrote: > On Tue, Nov 27, 2018 at 10:29:29AM -0600, Segher Boessenkool wrote: > > Hi! > > Thanks for the review! > > > > +(define_insn "*tls_gdld_aix<P:bits>" > > > + [(match_parallel 3 "" > > > > A match_parallel without predicate... Does this work?! > > Yes. In fact, rs6000/predicates.md any_parallel_operand is useless > except as documentation. The only thing it checks is that its operand > is a parallel, but that has already been checked. Right. I grepped if there were other parallels without predicate, not finding any, but I did not notice that half of the predicates used are any_parallel_operand. > > Does this not > > accidentally pick up the wrong things? > > No. The purpose of the predicate is to match anything beyond the > vector of expressions. So tls_gdld_aix* matches insns that look like: > > (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) > ... > > This is sufficiently different from other calls, by virtue of the > "(match_dup 2)". And the "unspec_tls". Right. > Incidentally, I think tls_gdld_aix and tls_gdld_sysv could be merged > at the expense of complicating the length attribute expression. > > > Do you think we should to deprecate -mtls-markers in GCC 9? > > Support for the TLS marker relocs was added to binutils in 2009 (git > commit 727fc41e077), so yes, the option is not likely to be useful > nowadays. Well, but do we gain anything if it is eventually deleted? Simpler code? > > Please test with -mtls-markers, too, if you can, and test on AIX. > > Presumably you mean -mno-tls-markers. -mtls-markers is the default. Yeah, the ! case. > > Looks fine. Thank you for the cleanup! Okay for trunk, but please do the > > extra testing. > > Huh, local testing of -mno-tls-markers showed a lack of a > TARGET_TLS_MARKERS check in rs6000_call_template_1. Likely this would > blow up on AIX. I'll test with the following delta. Sounds good. Segher
On Wed, Nov 28, 2018 at 07:32:50AM -0600, Segher Boessenkool wrote: > On Wed, Nov 28, 2018 at 11:37:42AM +1030, Alan Modra wrote: > > On Tue, Nov 27, 2018 at 10:29:29AM -0600, Segher Boessenkool wrote: > > > Do you think we should to deprecate -mtls-markers in GCC 9? > > > > Support for the TLS marker relocs was added to binutils in 2009 (git > > commit 727fc41e077), so yes, the option is not likely to be useful > > nowadays. > > Well, but do we gain anything if it is eventually deleted? Simpler code? Not much. Unfortunately we still need to keep TARGET_TLS_MARKERS (or replace throughout with !HAVE_AS_TLS_MARKERS) for AIX. Deprecate AIX perhaps? :-)
On Wed, Nov 28, 2018 at 07:32:50AM -0600, Segher Boessenkool wrote: > On Wed, Nov 28, 2018 at 11:37:42AM +1030, Alan Modra wrote: > > On Tue, Nov 27, 2018 at 10:29:29AM -0600, Segher Boessenkool wrote: > > > Looks fine. Thank you for the cleanup! Okay for trunk, but please do the > > > extra testing. > > > > Huh, local testing of -mno-tls-markers showed a lack of a > > TARGET_TLS_MARKERS check in rs6000_call_template_1. Likely this would > > blow up on AIX. I'll test with the following delta. > > Sounds good. For the record, this is the patch I committed. Besides the delta posted previously, I managed to combine the tls_gdld_aix and tls_gdld_sysv insns into a single insn, tls_gdld_nomark. * 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. 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 @@ (define_predicate "rs6000_tls_symbol_ref" (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 @@ (define_peephole2 ;; 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)" -{ - 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<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 - 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 @@ (define_insn_and_split "*tls_gd<bits>" (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_and_split "*tls_gd<bits>" (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 @@ (define_insn_and_split "*tls_ld<bits>" "&& 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_and_split "*tls_ld<bits>" (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_high<bits>" (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 @@ (define_expand "call" #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 @@ (define_expand "call" 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 @@ (define_expand "call_value" #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 @@ (define_expand "call_value" 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 @@ (define_insn "*call_value_local64" ;; 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 @@ (define_insn_and_split "*call_nonlocal_sysv<mode>" #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 @@ (define_insn "*call_nonlocal_sysv_secure<mode>" 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 @@ (define_insn_and_split "*call_value_nonlocal_sysv<mode>" #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 @@ (define_insn "*call_value_nonlocal_sysv_secure<mode>" 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 @@ (define_insn "*call_nonlocal_aix<mode>" (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 @@ (define_insn "*call_value_nonlocal_aix<mode>" (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 @@ (define_insn "*sibcall_nonlocal_sysv<mode>" 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 @@ (define_insn "*sibcall_value_nonlocal_sysv<mode>" 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 @@ (define_insn "*sibcall_aix<mode>" "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 @@ (define_insn "*sibcall_value_aix<mode>" "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"; }
diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md index b80c278d742..7e45d2f0371 100644 --- a/gcc/config/rs6000/predicates.md +++ b/gcc/config/rs6000/predicates.md @@ -1039,6 +1039,13 @@ (define_predicate "rs6000_tls_symbol_ref" (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 967f65e2d94..3fd89dc20db 100644 --- a/gcc/config/rs6000/rs6000-protos.h +++ b/gcc/config/rs6000/rs6000-protos.h @@ -111,8 +111,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, @@ -136,7 +136,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); @@ -204,6 +203,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 cd1ab95166e..5fd6e17bdda 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -8583,6 +8583,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. */ @@ -8635,7 +8672,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 @@ -8675,52 +8712,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) { @@ -21175,19 +21202,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 '&': @@ -21373,18 +21400,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 (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]; @@ -21392,7 +21428,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"); @@ -21405,15 +21441,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. */ @@ -32503,23 +32539,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)); } @@ -37491,7 +37524,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); @@ -37504,6 +37537,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); @@ -37514,11 +37550,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); @@ -37530,6 +37562,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); } @@ -37539,7 +37575,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 @@ -37594,7 +37631,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; @@ -37618,15 +37655,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]); @@ -37639,6 +37679,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 c261c8bb9c1..336d42335cb 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -9436,74 +9436,73 @@ (define_peephole2 ;; TLS support. -(define_insn_and_split "tls_gd_aix<P: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_aix<P: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_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); + 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<P: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" +(define_insn "*tls_gdld_sysv<P: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_V4" { - output_asm_insn ("addi %0,%1,%2@got@tlsgd", operands); - return rs6000_call_template (operands, 3, ""); + 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); + output_asm_insn ("addi %0,%2,%1@got@tlsgd", 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" "8")]) (define_insn_and_split "*tls_gd<P: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 @@ -9512,7 +9511,7 @@ (define_insn_and_split "*tls_gd<P:bits>" (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")) @@ -9522,105 +9521,21 @@ (define_insn_and_split "*tls_gd<P:bits>" (define_insn "*tls_gd_high<P: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<P: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<P: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<P: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<P: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<P: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<P:bits>" [(set (match_operand:P 0 "gpc_reg_operand" "=b") (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")] @@ -9630,12 +9545,12 @@ (define_insn_and_split "*tls_ld<P:bits>" "&& 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")) @@ -9645,8 +9560,7 @@ (define_insn_and_split "*tls_ld<P:bits>" (define_insn "*tls_ld_high<P: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") @@ -9654,38 +9568,11 @@ (define_insn "*tls_ld_high<P:bits>" (define_insn "*tls_ld_low<P: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<P: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<P: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_<P:bits>" [(set (match_operand:P 0 "gpc_reg_operand" "=r") (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b") @@ -10359,7 +10246,6 @@ (define_expand "call" #endif gcc_assert (GET_CODE (operands[0]) == MEM); - gcc_assert (GET_CODE (operands[1]) == CONST_INT); operands[0] = XEXP (operands[0], 0); @@ -10369,23 +10255,14 @@ (define_expand "call" 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" @@ -10402,7 +10279,6 @@ (define_expand "call_value" #endif gcc_assert (GET_CODE (operands[1]) == MEM); - gcc_assert (GET_CODE (operands[2]) == CONST_INT); operands[1] = XEXP (operands[1], 0); @@ -10412,23 +10288,14 @@ (define_expand "call_value" 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. @@ -10515,7 +10382,7 @@ (define_insn "*call_value_local64" ;; 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 @@ -10566,7 +10433,7 @@ (define_insn_and_split "*call_nonlocal_sysv<mode>" #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 @@ -10599,7 +10466,7 @@ (define_insn "*call_nonlocal_sysv_secure<mode>" 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")]) @@ -10653,7 +10520,7 @@ (define_insn_and_split "*call_value_nonlocal_sysv<mode>" #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 @@ -10688,7 +10555,7 @@ (define_insn "*call_value_nonlocal_sysv_secure<mode>" 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")]) @@ -10722,7 +10589,7 @@ (define_insn "*call_nonlocal_aix<mode>" (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")]) @@ -10734,7 +10601,7 @@ (define_insn "*call_value_nonlocal_aix<mode>" (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")]) @@ -10985,7 +10852,7 @@ (define_insn "*sibcall_nonlocal_sysv<mode>" 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" @@ -11025,7 +10892,7 @@ (define_insn "*sibcall_value_nonlocal_sysv<mode>" 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" @@ -11049,7 +10916,7 @@ (define_insn "*sibcall_aix<mode>" "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"; } @@ -11063,7 +10930,7 @@ (define_insn "*sibcall_value_aix<mode>" "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"; }