From patchwork Thu Nov 29 02:55:24 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Edelsohn X-Patchwork-Id: 202649 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 7C4472C0085 for ; Thu, 29 Nov 2012 13:55:38 +1100 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1354762539; h=Comment: DomainKey-Signature:Received:Received:Received:Received: MIME-Version:Received:Received:Date:Message-ID:Subject:From:To: Content-Type:Content-Transfer-Encoding:Mailing-List:Precedence: List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender: Delivered-To; bh=iGqnzSEeRcgQxMs4lrEgZuTbhRU=; b=SUf9sdmMkc8TN73 wG8vvnJi/f1CAeXcbRqHP5lQXuxeM36LN8Jr5F12vLPkplfD0FkriRMWHNZvxyfb BkdLcsUiQ8nJLgul7Za6509qWVyqcjNxiDxsuGYgRvjgnbdGx+9ZHo3MHgQRA3Da 8MY3ZMcMCMBKf7XrU67OR2rJhmIo= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:MIME-Version:Received:Received:Date:Message-ID:Subject:From:To:Content-Type:Content-Transfer-Encoding:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=w+zOqfXrHeGE0PS7GuIP81Os0dPgX3maYFt3V5GZhIEaDB/0beGJMVc+7tdX4w 2PsHGdnFYCGO0zypLiYDWag1ZKR3WQ4gPwz8F75WQTY/igp/L/44KeX9J3zxgkJR g6HkDVnvkDGBm1zysSFH1V5ZZuZT3PSMwRDMl4Xw08d80=; Received: (qmail 17926 invoked by alias); 29 Nov 2012 02:55:33 -0000 Received: (qmail 17917 invoked by uid 22791); 29 Nov 2012 02:55:32 -0000 X-SWARE-Spam-Status: No, hits=-3.5 required=5.0 tests=AWL, BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, KAM_STOCKGEN, KHOP_RCVD_TRUST, RCVD_IN_DNSWL_LOW, RCVD_IN_HOSTKARMA_YE, TW_CP X-Spam-Check-By: sourceware.org Received: from mail-vc0-f175.google.com (HELO mail-vc0-f175.google.com) (209.85.220.175) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 29 Nov 2012 02:55:26 +0000 Received: by mail-vc0-f175.google.com with SMTP id m8so11179680vcd.20 for ; Wed, 28 Nov 2012 18:55:25 -0800 (PST) MIME-Version: 1.0 Received: by 10.220.220.18 with SMTP id hw18mr30439732vcb.59.1354157724904; Wed, 28 Nov 2012 18:55:24 -0800 (PST) Received: by 10.58.235.232 with HTTP; Wed, 28 Nov 2012 18:55:24 -0800 (PST) Date: Wed, 28 Nov 2012 21:55:24 -0500 Message-ID: Subject: [PATCH] AIX native TLS support From: David Edelsohn To: GCC Patches Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Below is a first attempt at native TLS support on AIX. It produces the correct syntax and works for small testcases. All of GCC can build with it enabled, but libstdc++ and libgomp do not run correctly, so I am not enabling it by default. The implementation treats local-dynamic as general-dynamic because AIX local-dynamic is a mess to implement for not much gain. Unlike PPC64 Linux, AIX requires TLS symbols to be placed in a special CSECT mapping class and referenced with special TOC symbol decorations, not assembler decorations left to the linker. The patch leaves PPC64 Linux behavior unchanged. Thanks, David * xcoffout.c (xcoff_tls_data_section_name): Define. * xcoffout.h (xcoff_tls_data_section_name): Declare. * config/rs6000/rs6000.c (tls_data_section): Define. (TARGET_USE_BLOCKS_FOR_DECL_P): Define. (rs6000_legitimize_tls_address_aix): New function. (rs6000_legitimize_tls_address): Use new function for AIX. (rs6000_cannot_force_const_mem): No sum in TLS TOC symbols. Allow TLS symbol in constant pool other than ELF. (rs6000_legitimate_address_p): Allow TLS symbol other than ELF. (rs6000_assemble_visibility): Do not emit anything on AIX. (output_toc): Handle alias of TLS general-dynamic symbols. Emit TLS decorations on symbols. (rs6000_use_blocks_for_decl_p): New function. (rs6000_xcoff_output_tls_section_asm_op): New function. (rs6000_xcoff_asm_init_sections): Initialize tls_data_section. (rs6000_xcoff_select_section): Choose tls_data_section for thread-local storage. (rs6000_xcoff_file_start): Generate xcoff_tls_data_section_name. (rs6000_legitimate_constant_p): Allow TLS symbol other than ELF. * config/rs6000/rs6000.md (tls_tls_): Restrict to ELF. (tls_get_tpointer): New. (tle_get_tpointer_internal): New. (tls_get_addr): New. (tls_get_addr_internal): New. Index: xcoffout.c =================================================================== --- xcoffout.c (revision 193917) +++ xcoffout.c (working copy) @@ -66,6 +66,7 @@ char *xcoff_bss_section_name; char *xcoff_private_data_section_name; +char *xcoff_tls_data_section_name; char *xcoff_read_only_section_name; /* Last source file name mentioned in a NOTE insn. */ Index: xcoffout.h =================================================================== --- xcoffout.h (revision 193917) +++ xcoffout.h (working copy) @@ -126,6 +126,7 @@ extern char *xcoff_bss_section_name; extern char *xcoff_private_data_section_name; +extern char *xcoff_tls_data_section_name; extern char *xcoff_read_only_section_name; /* Last source file name mentioned in a NOTE insn. */ Index: config/rs6000/rs6000.c =================================================================== --- config/rs6000/rs6000.c (revision 193917) +++ config/rs6000/rs6000.c (working copy) @@ -208,6 +208,7 @@ static GTY(()) section *read_only_data_section; static GTY(()) section *private_data_section; +static GTY(()) section *tls_data_section; static GTY(()) section *read_only_private_data_section; static GTY(()) section *sdata2_section; static GTY(()) section *toc_section; @@ -1405,6 +1406,8 @@ #define TARGET_MAX_ANCHOR_OFFSET 0x7fffffff #undef TARGET_USE_BLOCKS_FOR_CONSTANT_P #define TARGET_USE_BLOCKS_FOR_CONSTANT_P rs6000_use_blocks_for_constant_p +#undef TARGET_USE_BLOCKS_FOR_DECL_P +#define TARGET_USE_BLOCKS_FOR_DECL_P rs6000_use_blocks_for_decl_p #undef TARGET_BUILTIN_RECIPROCAL #define TARGET_BUILTIN_RECIPROCAL rs6000_builtin_reciprocal @@ -5882,6 +5885,75 @@ return rs6000_got_symbol; } +/* AIX Thread-Local Address support. */ + +static rtx +rs6000_legitimize_tls_address_aix (rtx addr, enum tls_model model) +{ + rtx sym, mem, tocref, tlsreg, tmpreg, dest; + + /* Place addr into TOC constant pool. */ + sym = force_const_mem (GET_MODE (addr), addr); + + /* Output the TOC entry and create the MEM referencing the value. */ + if (constant_pool_expr_p (XEXP (sym, 0)) + && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (XEXP (sym, 0)), Pmode)) + { + tocref = create_TOC_reference (XEXP (sym, 0), NULL_RTX); + mem = gen_const_mem (Pmode, tocref); + set_mem_alias_set (mem, get_TOC_alias_set ()); + } + else + return sym; + + /* Use global-dynamic for local-dynamic. */ + if (model == TLS_MODEL_GLOBAL_DYNAMIC + || model == TLS_MODEL_LOCAL_DYNAMIC) + { + rtx module = gen_reg_rtx (Pmode); + /* Create new TOC reference for @m symbol. */ + const char *name = XSTR (XVECEXP (XEXP (mem, 0), 0, 0), 0); + char *name2 = XALLOCAVEC (char, strlen (name) + 1); + strcpy (name2, "*LCM"); + strcat (name2, name + 3); + tocref = create_TOC_reference (gen_rtx_SYMBOL_REF (Pmode, + ggc_alloc_string (name2, + strlen (name2))), + NULL_RTX); + rtx mem2 = gen_const_mem (Pmode, tocref); + set_mem_alias_set (mem2, get_TOC_alias_set ()); + + dest = gen_reg_rtx (Pmode); + tmpreg = gen_reg_rtx (Pmode); + emit_insn (gen_rtx_SET (VOIDmode, tmpreg, mem)); + emit_insn (gen_rtx_SET (VOIDmode, module, mem2)); + if (TARGET_32BIT) + emit_insn (gen_tls_get_addrsi (dest, module, tmpreg)); + else + emit_insn (gen_tls_get_addrdi (dest, module, tmpreg)); + return dest; + } + /* Obtain TLS pointer: 32 bit call or 64 bit GPR 13. */ + else if (TARGET_32BIT) + { + tlsreg = gen_reg_rtx (SImode); + emit_insn (gen_tls_get_tpointer (tlsreg)); + } + else + tlsreg = gen_rtx_REG (DImode, 13); + + /* Load the TOC value into temporary register. */ + tmpreg = gen_reg_rtx (Pmode); + emit_insn (gen_rtx_SET (VOIDmode, tmpreg, mem)); + set_unique_reg_note (get_last_insn (), REG_EQUAL, + gen_rtx_MINUS (Pmode, addr, tlsreg)); + + /* Add TOC symbol value to TLS pointer. */ + dest = force_reg (Pmode, gen_rtx_PLUS (Pmode, tmpreg, tlsreg)); + + return dest; +} + /* ADDR contains a thread-local SYMBOL_REF. Generate code to compute this (thread-local) address. */ @@ -5890,6 +5962,9 @@ { rtx dest, insn; + if (TARGET_XCOFF) + return rs6000_legitimize_tls_address_aix (addr, model); + dest = gen_reg_rtx (Pmode); if (model == TLS_MODEL_LOCAL_EXEC && rs6000_tls_size == 16) { @@ -6085,7 +6160,15 @@ && GET_CODE (XEXP (x, 0)) == UNSPEC) return true; - return rs6000_tls_referenced_p (x); + /* A TLS symbol in the TOC cannot contain a sum. */ + if (GET_CODE (x) == CONST + && GET_CODE (XEXP (x, 0)) == PLUS + && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF + && SYMBOL_REF_TLS_MODEL (XEXP (XEXP (x, 0), 0)) != 0) + return true; + + /* Do not place an ELF TLS symbol in the constant pool. */ + return TARGET_ELF && rs6000_tls_referenced_p (x); } /* Return 1 if *X is a thread-local symbol. This is the same as @@ -6380,7 +6463,7 @@ && INTVAL (XEXP (x, 1)) == -16) x = XEXP (x, 0); - if (RS6000_SYMBOL_REF_TLS_P (x)) + if (TARGET_ELF && RS6000_SYMBOL_REF_TLS_P (x)) return 0; if (legitimate_indirect_address_p (x, reg_ok_strict)) return 1; @@ -15486,6 +15569,9 @@ static void rs6000_assemble_visibility (tree decl, int vis) { + if (TARGET_XCOFF) + return; + /* Functions need to have their entry point symbol visibility set as well as their descriptor symbol visibility. */ if (DEFAULT_ABI == ABI_AIX @@ -21934,6 +22020,20 @@ ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LC"); fprintf (file, "%d\n", ((*(const struct toc_hash_struct **) found)->labelno)); + +#ifdef HAVE_AS_TLS + if (TARGET_XCOFF && GET_CODE (x) == SYMBOL_REF + && (SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_GLOBAL_DYNAMIC + || SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_LOCAL_DYNAMIC)) + { + fputs ("\t.set ", file); + ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LCM"); + fprintf (file, "%d,", labelno); + ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LCM"); + fprintf (file, "%d\n", ((*(const struct toc_hash_struct **) + found)->labelno)); + } +#endif return; } } @@ -22206,6 +22306,29 @@ } else output_addr_const (file, x); + +#if HAVE_AS_TLS + if (TARGET_XCOFF && GET_CODE (base) == SYMBOL_REF) + { + if (SYMBOL_REF_TLS_MODEL (base) == TLS_MODEL_LOCAL_EXEC) + fputs ("[TL]@le", file); + else if (SYMBOL_REF_TLS_MODEL (base) == TLS_MODEL_INITIAL_EXEC) + fputs ("[TL]@ie", file); + /* Use global-dynamic for local-dynamic. */ + else if (SYMBOL_REF_TLS_MODEL (base) == TLS_MODEL_GLOBAL_DYNAMIC + || SYMBOL_REF_TLS_MODEL (base) == TLS_MODEL_LOCAL_DYNAMIC) + { + fputs ("[TL]\n", file); + (*targetm.asm_out.internal_label) (file, "LCM", labelno); + fputs ("\t.tc .", file); + RS6000_OUTPUT_BASENAME (file, name); + fputs ("[TC],", file); + output_addr_const (file, x); + fputs ("[TL]@m", file); + } + } +#endif + putc ('\n', file); } @@ -24884,6 +25007,14 @@ { return !ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (x, mode); } + +/* Do not place thread-local symbols refs in the object blocks. */ + +static bool +rs6000_use_blocks_for_decl_p (const_tree decl) +{ + return !DECL_THREAD_LOCAL_P (decl); +} /* Return a REG that occurs in ADDR with coefficient 1. ADDR can be effectively incremented by incrementing REG. @@ -25516,6 +25647,14 @@ XCOFF_CSECT_DEFAULT_ALIGNMENT_STR); } +static void +rs6000_xcoff_output_tls_section_asm_op (const void *directive) +{ + fprintf (asm_out_file, "\t.csect %s[TL],%s\n", + *(const char *const *) directive, + XCOFF_CSECT_DEFAULT_ALIGNMENT_STR); +} + /* A get_unnamed_section callback, used for switching to toc_section. */ static void @@ -25553,6 +25692,11 @@ rs6000_xcoff_output_readwrite_section_asm_op, &xcoff_private_data_section_name); + tls_data_section + = get_unnamed_section (SECTION_TLS, + rs6000_xcoff_output_tls_section_asm_op, + &xcoff_tls_data_section_name); + read_only_private_data_section = get_unnamed_section (0, rs6000_xcoff_output_readonly_section_asm_op, &xcoff_private_data_section_name); @@ -25604,7 +25748,12 @@ } else { - if (TREE_PUBLIC (decl)) +#if HAVE_AS_TLS + if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl)) + return tls_data_section; + else +#endif + if (TREE_PUBLIC (decl)) return data_section; else return private_data_section; @@ -25700,6 +25849,8 @@ main_input_filename, ".bss_"); rs6000_gen_section_name (&xcoff_private_data_section_name, main_input_filename, ".rw_"); + rs6000_gen_section_name (&xcoff_tls_data_section_name, + main_input_filename, ".tls_"); rs6000_gen_section_name (&xcoff_read_only_section_name, main_input_filename, ".ro_"); @@ -28164,7 +28315,7 @@ static bool rs6000_legitimate_constant_p (enum machine_mode mode, rtx x) { - if (rs6000_tls_referenced_p (x)) + if (TARGET_ELF && rs6000_tls_referenced_p (x)) return false; return ((GET_CODE (x) != CONST_DOUBLE && GET_CODE (x) != CONST_VECTOR) Index: config/rs6000/rs6000.md =================================================================== --- config/rs6000/rs6000.md (revision 193917) +++ config/rs6000/rs6000.md (working copy) @@ -9983,8 +9983,51 @@ (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b") (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] UNSPEC_TLSTLS))] - "HAVE_AS_TLS" + "TARGET_ELF && HAVE_AS_TLS" "add %0,%1,%2@tls") + +(define_expand "tls_get_tpointer" + [(set (match_operand:SI 0 "gpc_reg_operand" "") + (unspec:SI [(const_int 0)] UNSPEC_TLSTLS))] + "TARGET_XCOFF && HAVE_AS_TLS" + " +{ + emit_insn (gen_tls_get_tpointer_internal ()); + emit_move_insn (operands[0], gen_rtx_REG (SImode, 3)); + DONE; +}") + +(define_insn "tls_get_tpointer_internal" + [(set (reg:SI 3) + (unspec:SI [(const_int 0)] UNSPEC_TLSTLS)) + (clobber (reg:SI LR_REGNO))] + "TARGET_XCOFF && HAVE_AS_TLS" + "bla __get_tpointer") + +(define_expand "tls_get_addr" + [(set (match_operand:P 0 "gpc_reg_operand" "") + (unspec:P [(match_operand:P 1 "gpc_reg_operand" "") + (match_operand:P 2 "gpc_reg_operand" "")] UNSPEC_TLSTLS))] + "TARGET_XCOFF && HAVE_AS_TLS" + " +{ + emit_move_insn (gen_rtx_REG (Pmode, 3), operands[1]); + emit_move_insn (gen_rtx_REG (Pmode, 4), operands[2]); + emit_insn (gen_tls_get_addr_internal ()); + emit_move_insn (operands[0], gen_rtx_REG (Pmode, 3)); + DONE; +}") + +(define_insn "tls_get_addr_internal" + [(set (reg:P 3) + (unspec:P [(reg:P 3) (reg:P 4)] UNSPEC_TLSTLS)) + (clobber (reg:P 0)) + (clobber (reg:P 5)) + (clobber (reg:P 11)) + (clobber (reg:CC CR0_REGNO)) + (clobber (reg:P LR_REGNO))] + "TARGET_XCOFF && HAVE_AS_TLS" + "bla __tls_get_addr") ;; Next come insns related to the calling sequence. ;;