This patch gets GCC support for native TLS on AIX working and passing most tests.
The patch shifts the creation of the qualified symbol name from output_toc() to rs6000_legitimize_tls_address_aix(). I was hoping that the separate SYMBOL_REF would prevent RTL fwprop from becoming confused about the symbols, but no such luck. The re-write still makes things a little cleaner. Also, private TLS data (static variables with non-zero initializers) are not decorated with the TLS CSECT qualifier so that the AIX assembler and linker resolve it correctly. To prevent fwprop from breaking things, I need to prevent rs6000_delegitimize_address from associating TLS TOC references with the original symbol. The rs6000 port uses the constant pool to manage the TOC. However, for TLS symbols, the value in the TOC is not equivalent to the symbol itself. The RTL fwprop pass thinks that it can associate the result of a TLS access, which materializes the symbol in a register, with the value in the constant pool and avoid re-loading the TOC value. This does not work and passes a garbage value to subsequent TLS calls, which produce garbage results. The two solutions are either "hide" the TLS constant pool values by not delegitmizing them or completely re-writing the TOC support to use a pool separate from the constant pool. I chose the former because TLS is a scarce resource and its usage should be minimal anyway. Bootstrapped on powerpc-ibm-aix7.1.0.0. Thanks, David * config/rs6000/rs6000.c (rs6000_deligitimze_address): Do not delegitimize TLS addresses on AIX. (rs6000_legitimize_tls_address_aix): Append TLS symbol qualifier. Set SYMBOL_FLAG_LOCAL on module symbol. (output_toc): Do not append TLS symbol qualifier here. * config/rs6000/rs6000.md (tls_get_addr_internal): Add GPR 4 to clobbers. Index: rs6000.c =================================================================== --- rs6000.c (revision 194725) +++ rs6000.c (working copy) @@ -5826,6 +5826,15 @@ rs6000_delegitimize_address (rtx orig_x) } #endif y = XVECEXP (y, 0, 0); + +#ifdef HAVE_AS_TLS + /* Do not associate thread-local symbols with the original + constant pool symbol. */ + if (TARGET_XCOFF + && SYMBOL_REF_TLS_MODEL (get_pool_constant (y)) >= TLS_MODEL_REAL) + return orig_x; +#endif + if (offset != NULL_RTX) y = gen_rtx_PLUS (Pmode, y, offset); if (!MEM_P (orig_x)) @@ -5899,10 +5908,29 @@ rs6000_got_sym (void) static rtx rs6000_legitimize_tls_address_aix (rtx addr, enum tls_model model) { - rtx sym, mem, tocref, tlsreg, tmpreg, dest; + rtx sym, mem, tocref, tlsreg, tmpreg, dest, tlsaddr; + const char *name; + char *tlsname; + name = XSTR (addr, 0); + /* Append TLS CSECT qualifier, unless the symbol already is qualified + or the symbol will be in TLS private data section. */ + if (name[strlen (name) - 1] != ']' + && (TREE_PUBLIC (SYMBOL_REF_DECL (addr)) + || bss_initializer_p (SYMBOL_REF_DECL (addr)))) + { + tlsname = XALLOCAVEC (char, strlen (name) + 4); + strcpy (tlsname, name); + strcat (tlsname, + bss_initializer_p (SYMBOL_REF_DECL (addr)) ? "[UL]" : "[TL]"); + tlsaddr = copy_rtx (addr); + XSTR (tlsaddr, 0) = ggc_strdup (tlsname); + } + else + tlsaddr = addr; + /* Place addr into TOC constant pool. */ - sym = force_const_mem (GET_MODE (addr), addr); + sym = force_const_mem (GET_MODE (tlsaddr), tlsaddr); /* Output the TOC entry and create the MEM referencing the value. */ if (constant_pool_expr_p (XEXP (sym, 0)) @@ -5919,27 +5947,28 @@ rs6000_legitimize_tls_address_aix (rtx addr, enum 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 ()); + name = XSTR (XVECEXP (XEXP (mem, 0), 0, 0), 0); + tlsname = XALLOCAVEC (char, strlen (name) + 1); + strcpy (tlsname, "*LCM"); + strcat (tlsname, name + 3); + rtx modaddr = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (tlsname)); + SYMBOL_REF_FLAGS (modaddr) |= SYMBOL_FLAG_LOCAL; + tocref = create_TOC_reference (modaddr, NULL_RTX); + rtx modmem = gen_const_mem (Pmode, tocref); + set_mem_alias_set (modmem, get_TOC_alias_set ()); - dest = gen_reg_rtx (Pmode); + rtx modreg = gen_reg_rtx (Pmode); + emit_insn (gen_rtx_SET (VOIDmode, modreg, modmem)); + tmpreg = gen_reg_rtx (Pmode); emit_insn (gen_rtx_SET (VOIDmode, tmpreg, mem)); - emit_insn (gen_rtx_SET (VOIDmode, module, mem2)); + + dest = gen_reg_rtx (Pmode); if (TARGET_32BIT) - emit_insn (gen_tls_get_addrsi (dest, module, tmpreg)); + emit_insn (gen_tls_get_addrsi (dest, modreg, tmpreg)); else - emit_insn (gen_tls_get_addrdi (dest, module, tmpreg)); + emit_insn (gen_tls_get_addrdi (dest, modreg, tmpreg)); return dest; } /* Obtain TLS pointer: 32 bit call or 64 bit GPR 13. */ @@ -22320,12 +22349,6 @@ output_toc (FILE *file, rtx x, int labelno, enum m if (TARGET_XCOFF && GET_CODE (base) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (base) != 0) { - tree decl = SYMBOL_REF_DECL (base); - if (bss_initializer_p (decl)) - fputs ("[UL]", file); - else - fputs ("[TL]", file); - if (SYMBOL_REF_TLS_MODEL (base) == TLS_MODEL_LOCAL_EXEC) fputs ("@le", file); else if (SYMBOL_REF_TLS_MODEL (base) == TLS_MODEL_INITIAL_EXEC) @@ -22340,10 +22363,7 @@ output_toc (FILE *file, rtx x, int labelno, enum m RS6000_OUTPUT_BASENAME (file, name); fputs ("[TC],", file); output_addr_const (file, x); - if (TREE_PUBLIC (SYMBOL_REF_DECL (base))) - fputs ("[TL]@m", file); - else - fputs ("[UL]@m", file); + fputs ("@m", file); } } #endif Index: rs6000.md =================================================================== --- rs6000.md (revision 194725) +++ rs6000.md (working copy) @@ -10022,6 +10022,7 @@ [(set (reg:P 3) (unspec:P [(reg:P 3) (reg:P 4)] UNSPEC_TLSTLS)) (clobber (reg:P 0)) + (clobber (reg:P 4)) (clobber (reg:P 5)) (clobber (reg:P 11)) (clobber (reg:CC CR0_REGNO))