From patchwork Fri Jul 23 23:11:31 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 59843 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 32EC3B6EF7 for ; Sat, 24 Jul 2010 09:12:04 +1000 (EST) Received: (qmail 20514 invoked by alias); 23 Jul 2010 23:12:02 -0000 Received: (qmail 20493 invoked by uid 22791); 23 Jul 2010 23:11:52 -0000 X-SWARE-Spam-Status: No, hits=-3.5 required=5.0 tests=AWL, BAYES_40, KAM_STOCKGEN, RCVD_IN_DNSWL_HI, SPF_HELO_PASS, TW_CF, TW_CP, TW_TM, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 23 Jul 2010 23:11:37 +0000 Received: from int-mx05.intmail.prod.int.phx2.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.18]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id o6NNBXQZ028603 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Fri, 23 Jul 2010 19:11:34 -0400 Received: from anchor.twiddle.home (ovpn-113-55.phx2.redhat.com [10.3.113.55]) by int-mx05.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id o6NNBWGU021937; Fri, 23 Jul 2010 19:11:32 -0400 Message-ID: <4C4A21A3.2010504@redhat.com> Date: Fri, 23 Jul 2010 16:11:31 -0700 From: Richard Henderson User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.7) Gecko/20100720 Fedora/3.1.1-1.fc13 Thunderbird/3.1.1 MIME-Version: 1.0 To: Jack Howarth CC: Richard Guenther , IainS , GCC Patches , Jakub Jelinek , jh@suse.cz Subject: [RFA, Fortran, try 11] Emulated tls rewrite References: <4C3E4D3C.1030205@redhat.com> <4C44AA95.9000505@redhat.com> <4C45CBEC.7020400@redhat.com> <4C47212E.70005@redhat.com> <4C474CB6.9080303@redhat.com> <20100722023203.GA19394@bromo.med.uc.edu> In-Reply-To: <20100722023203.GA19394@bromo.med.uc.edu> X-IsSubscribed: yes 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 On 07/21/2010 07:32 PM, Jack Howarth wrote: > FAIL: gfortran.dg/gomp/appendix-a/a.22.6.f90 -O (test for excess errors) > Excess errors: > .../testsuite/gfortran.dg/gomp/appendix-a/a.22.6.f90:4:0: sorry, unimplemented: thread-local COMMON data not implemented I managed to reproduce this problem reliably. It has to do with the Fortran front end (indirectly) invoking varpool_finalize_decl much later than the C front ends do. Without the decls being finalized, the IPA pass doesn't get to see them and they don't get lowered. I talked to Richi about this ordering problem on IRC, and changing the generic ordering of decls vs compilation unit finalization appears to run into problems with C++ and Java and their aliases. An acceptable solution appears to be to hack the Fortran front end to do it by hand. An incremental diff, excluding the testsuite, from #9 is below and the full patch from HEAD is attached. Ok? r~ diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 22e4ee8..e4b6452 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1354,6 +1354,7 @@ OBJS-common = \ tree-diagnostic.o \ tree-dump.o \ tree-eh.o \ + tree-emutls.o \ tree-if-conv.o \ tree-into-ssa.o \ tree-iterator.o \ @@ -3142,6 +3143,9 @@ tree-switch-conversion.o : tree-switch-conversion.c $(CONFIG_H) $(SYSTEM_H) \ tree-complex.o : tree-complex.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \ $(TM_H) $(FLAGS_H) $(TREE_FLOW_H) $(GIMPLE_H) \ tree-iterator.h $(TREE_PASS_H) tree-ssa-propagate.h $(DIAGNOSTIC_H) +tree-emutls.o : tree-emutls.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \ + $(GIMPLE_H) $(TREE_PASS_H) $(TREE_FLOW_H) $(CGRAPH_H) langhooks.h \ + $(TARGET_H) targhooks.h tree-iterator.h tree-vect-generic.o : tree-vect-generic.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) \ $(TM_H) $(TREE_FLOW_H) $(GIMPLE_H) tree-iterator.h $(TREE_PASS_H) \ $(FLAGS_H) $(OPTABS_H) $(MACHMODE_H) $(EXPR_H) \ diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index d9dc571..8b6fe51 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -4355,9 +4355,6 @@ x86_64_elf_select_section (tree decl, int reloc, /* We don't split these for medium model. Place them into default sections and hope for best. */ break; - case SECCAT_EMUTLS_VAR: - case SECCAT_EMUTLS_TMPL: - gcc_unreachable (); } if (sname) { @@ -4415,12 +4412,6 @@ x86_64_elf_unique_section (tree decl, int reloc) /* We don't split these for medium model. Place them into default sections and hope for best. */ break; - case SECCAT_EMUTLS_VAR: - prefix = targetm.emutls.var_section; - break; - case SECCAT_EMUTLS_TMPL: - prefix = targetm.emutls.tmpl_section; - break; } if (prefix) { diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 183bbd3..6abeb9c 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -15103,7 +15103,11 @@ loc_list_from_tree (tree loc, int want_address) if (!targetm.emutls.debug_form_tls_address || !(dwarf_version >= 3 || !dwarf_strict)) return 0; - loc = emutls_decl (loc); + /* We stuffed the control variable into the DECL_VALUE_EXPR + to signal (via DECL_HAS_VALUE_EXPR_P) that the decl should + no longer appear in gimple code. We used the control + variable in specific so that we could pick it up here. */ + loc = DECL_VALUE_EXPR (loc); first_op = DW_OP_addr; second_op = DW_OP_form_tls_address; } diff --git a/gcc/expr.c b/gcc/expr.c index 3e5d18b..57f9eff 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -6818,19 +6818,6 @@ highest_pow2_factor_for_target (const_tree target, const_tree exp) return MAX (factor, talign); } -/* Return &VAR expression for emulated thread local VAR. */ - -static tree -emutls_var_address (tree var) -{ - tree emuvar = emutls_decl (var); - tree fn = built_in_decls [BUILT_IN_EMUTLS_GET_ADDRESS]; - tree arg = build_fold_addr_expr_with_type (emuvar, ptr_type_node); - tree call = build_call_expr (fn, 1, arg); - return fold_convert (build_pointer_type (TREE_TYPE (var)), call); -} - - /* Subroutine of expand_expr. Expand the two operands of a binary expression EXP0 and EXP1 placing the results in OP0 and OP1. The value may be stored in TARGET if TARGET is nonzero. The @@ -6933,18 +6920,6 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode, inner = TREE_OPERAND (exp, 0); break; - case VAR_DECL: - /* TLS emulation hook - replace __thread VAR's &VAR with - __emutls_get_address (&_emutls.VAR). */ - if (! targetm.have_tls - && TREE_CODE (exp) == VAR_DECL - && DECL_THREAD_LOCAL_P (exp)) - { - exp = emutls_var_address (exp); - return expand_expr (exp, target, tmode, modifier); - } - /* Fall through. */ - default: /* If the object is a DECL, then expand it for its rtl. Don't bypass expand_expr, as that can have various side effects; LABEL_DECLs for @@ -8382,16 +8357,6 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, && (TREE_STATIC (exp) || DECL_EXTERNAL (exp))) layout_decl (exp, 0); - /* TLS emulation hook - replace __thread vars with - *__emutls_get_address (&_emutls.var). */ - if (! targetm.have_tls - && TREE_CODE (exp) == VAR_DECL - && DECL_THREAD_LOCAL_P (exp)) - { - exp = build_fold_indirect_ref_loc (loc, emutls_var_address (exp)); - return expand_expr_real_1 (exp, target, tmode, modifier, NULL); - } - /* ... fall through ... */ case FUNCTION_DECL: diff --git a/gcc/fortran/f95-lang.c b/gcc/fortran/f95-lang.c index 5b67621..9d0bf44 100644 --- a/gcc/fortran/f95-lang.c +++ b/gcc/fortran/f95-lang.c @@ -88,6 +88,7 @@ static void gfc_init_builtin_functions (void); /* Each front end provides its own. */ static bool gfc_init (void); static void gfc_finish (void); +static void gfc_write_global_declarations (void); static void gfc_print_identifier (FILE *, tree, int); void do_function_end (void); int global_bindings_p (void); @@ -99,6 +100,7 @@ static void gfc_init_ts (void); #undef LANG_HOOKS_NAME #undef LANG_HOOKS_INIT #undef LANG_HOOKS_FINISH +#undef LANG_HOOKS_WRITE_GLOBALS #undef LANG_HOOKS_INIT_OPTIONS #undef LANG_HOOKS_HANDLE_OPTION #undef LANG_HOOKS_POST_OPTIONS @@ -127,6 +129,7 @@ static void gfc_init_ts (void); #define LANG_HOOKS_NAME "GNU Fortran" #define LANG_HOOKS_INIT gfc_init #define LANG_HOOKS_FINISH gfc_finish +#define LANG_HOOKS_WRITE_GLOBALS gfc_write_global_declarations #define LANG_HOOKS_INIT_OPTIONS gfc_init_options #define LANG_HOOKS_HANDLE_OPTION gfc_handle_option #define LANG_HOOKS_POST_OPTIONS gfc_post_options @@ -282,6 +285,33 @@ gfc_finish (void) return; } +/* ??? This is something of a hack. + + Emulated tls lowering needs to see all TLS variables before we call + cgraph_finalize_compilation_unit. The C/C++ front ends manage this + by calling decl_rest_of_compilation on each global and static variable + as they are seen. The Fortran front end waits until this hook. + + A Correct solution is for cgraph_finalize_compilation_unit not to be + called during the WRITE_GLOBALS langhook, and have that hook only do what + its name suggests and write out globals. But the C++ and Java front ends + have (unspecified) problems with aliases that gets in the way. It has + been suggested that these problems would be solved by completing the + conversion to cgraph-based aliases. */ + +static void +gfc_write_global_declarations (void) +{ + tree decl; + + /* Finalize all of the globals. */ + for (decl = getdecls(); decl ; decl = DECL_CHAIN (decl)) + rest_of_decl_compilation (decl, true, true); + + write_global_declarations (); +} + + static void gfc_print_identifier (FILE * file ATTRIBUTE_UNUSED, tree node ATTRIBUTE_UNUSED, diff --git a/gcc/gimple-iterator.c b/gcc/gimple-iterator.c index 1402c0d..064b7fe 100644 --- a/gcc/gimple-iterator.c +++ b/gcc/gimple-iterator.c @@ -65,6 +65,35 @@ update_bb_for_stmts (gimple_seq_node first, basic_block bb) gimple_set_bb (n->stmt, bb); } +/* Set the frequencies for the cgraph_edges for each of the calls + starting at FIRST for their new position within BB. */ + +static void +update_call_edge_frequencies (gimple_seq_node first, basic_block bb) +{ + struct cgraph_node *cfun_node = NULL; + int bb_freq = 0; + gimple_seq_node n; + + for (n = first; n ; n = n->next) + if (is_gimple_call (n->stmt)) + { + struct cgraph_edge *e; + + /* These function calls are expensive enough that we want + to avoid calling them if we never see any calls. */ + if (cfun_node == NULL) + { + cfun_node = cgraph_node (current_function_decl); + bb_freq = (compute_call_stmt_bb_frequency + (current_function_decl, bb)); + } + + e = cgraph_edge (cfun_node, n->stmt); + if (e != NULL) + e->frequency = bb_freq; + } +} /* Insert the sequence delimited by nodes FIRST and LAST before iterator I. M specifies how to update iterator I after insertion @@ -696,11 +725,19 @@ basic_block gsi_insert_on_edge_immediate (edge e, gimple stmt) { gimple_stmt_iterator gsi; + struct gimple_seq_node_d node; basic_block new_bb = NULL; + bool ins_after; gcc_assert (!PENDING_STMT (e)); - if (gimple_find_edge_insert_loc (e, &gsi, &new_bb)) + ins_after = gimple_find_edge_insert_loc (e, &gsi, &new_bb); + + node.stmt = stmt; + node.prev = node.next = NULL; + update_call_edge_frequencies (&node, gsi.bb); + + if (ins_after) gsi_insert_after (&gsi, stmt, GSI_NEW_STMT); else gsi_insert_before (&gsi, stmt, GSI_NEW_STMT); @@ -716,10 +753,14 @@ gsi_insert_seq_on_edge_immediate (edge e, gimple_seq stmts) { gimple_stmt_iterator gsi; basic_block new_bb = NULL; + bool ins_after; gcc_assert (!PENDING_STMT (e)); - if (gimple_find_edge_insert_loc (e, &gsi, &new_bb)) + ins_after = gimple_find_edge_insert_loc (e, &gsi, &new_bb); + update_call_edge_frequencies (gimple_seq_first (stmts), gsi.bb); + + if (ins_after) gsi_insert_seq_after (&gsi, stmts, GSI_NEW_STMT); else gsi_insert_seq_before (&gsi, stmts, GSI_NEW_STMT); @@ -758,10 +799,14 @@ gsi_commit_one_edge_insert (edge e, basic_block *new_bb) { gimple_stmt_iterator gsi; gimple_seq seq = PENDING_STMT (e); + bool ins_after; PENDING_STMT (e) = NULL; - if (gimple_find_edge_insert_loc (e, &gsi, new_bb)) + ins_after = gimple_find_edge_insert_loc (e, &gsi, new_bb); + update_call_edge_frequencies (gimple_seq_first (seq), gsi.bb); + + if (ins_after) gsi_insert_seq_after (&gsi, seq, GSI_NEW_STMT); else gsi_insert_seq_before (&gsi, seq, GSI_NEW_STMT); diff --git a/gcc/output.h b/gcc/output.h index d1e5f24..014ca1c 100644 --- a/gcc/output.h +++ b/gcc/output.h @@ -165,9 +165,6 @@ extern void merge_weak (tree, tree); /* Emit any pending weak declarations. */ extern void weak_finish (void); -/* Emit any pending emutls declarations and initializations. */ -extern void emutls_finish (void); - /* Return the default TLS model for a given variable. */ extern enum tls_model decl_default_tls_model (const_tree); @@ -479,10 +476,7 @@ enum section_category SECCAT_BSS, SECCAT_SBSS, - SECCAT_TBSS, - - SECCAT_EMUTLS_VAR, - SECCAT_EMUTLS_TMPL + SECCAT_TBSS }; /* Information that is provided by all instances of the section type. */ diff --git a/gcc/passes.c b/gcc/passes.c index 72e9b5a..5a4cdc8 100644 --- a/gcc/passes.c +++ b/gcc/passes.c @@ -804,6 +804,7 @@ init_optimization_passes (void) } NEXT_PASS (pass_ipa_increase_alignment); NEXT_PASS (pass_ipa_matrix_reorg); + NEXT_PASS (pass_ipa_lower_emutls); *p = NULL; p = &all_regular_ipa_passes; diff --git a/gcc/testsuite/g++.dg/gomp/clause-3.C b/gcc/testsuite/g++.dg/gomp/clause-3.C index 055c189..6b3d410 100644 --- a/gcc/testsuite/g++.dg/gomp/clause-3.C +++ b/gcc/testsuite/g++.dg/gomp/clause-3.C @@ -1,5 +1,5 @@ // { dg-do compile } -// { dg-require-effective-target tls_native } +// { dg-require-effective-target tls } #define p parallel diff --git a/gcc/testsuite/g++.dg/gomp/copyin-1.C b/gcc/testsuite/g++.dg/gomp/copyin-1.C index f984d10..117f82f 100644 --- a/gcc/testsuite/g++.dg/gomp/copyin-1.C +++ b/gcc/testsuite/g++.dg/gomp/copyin-1.C @@ -1,5 +1,5 @@ // { dg-do compile } -// { dg-require-effective-target tls_native } +// { dg-require-effective-target tls } int i, j; diff --git a/gcc/testsuite/g++.dg/gomp/pr35244.C b/gcc/testsuite/g++.dg/gomp/pr35244.C index 189df1e..022f9d0 100644 --- a/gcc/testsuite/g++.dg/gomp/pr35244.C +++ b/gcc/testsuite/g++.dg/gomp/pr35244.C @@ -1,6 +1,6 @@ // PR c++/35244 // { dg-do compile } -// { dg-require-effective-target tls_native } +// { dg-require-effective-target tls } // { dg-options "-fopenmp" } int v1; diff --git a/gcc/testsuite/g++.dg/gomp/sharing-1.C b/gcc/testsuite/g++.dg/gomp/sharing-1.C index 25626ff..83b8180 100644 --- a/gcc/testsuite/g++.dg/gomp/sharing-1.C +++ b/gcc/testsuite/g++.dg/gomp/sharing-1.C @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-require-effective-target tls_native } */ +/* { dg-require-effective-target tls } */ int thrglobalvar; #pragma omp threadprivate (thrglobalvar) diff --git a/gcc/testsuite/g++.dg/gomp/tls-1.C b/gcc/testsuite/g++.dg/gomp/tls-1.C index 13d2c0d..bfe62cb 100644 --- a/gcc/testsuite/g++.dg/gomp/tls-1.C +++ b/gcc/testsuite/g++.dg/gomp/tls-1.C @@ -1,5 +1,5 @@ // { dg-do compile } -// { dg-require-effective-target tls_native } +// { dg-require-effective-target tls } int tp1; static int tp2; diff --git a/gcc/testsuite/g++.dg/gomp/tls-2.C b/gcc/testsuite/g++.dg/gomp/tls-2.C index 26dbc53..80275f9 100644 --- a/gcc/testsuite/g++.dg/gomp/tls-2.C +++ b/gcc/testsuite/g++.dg/gomp/tls-2.C @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-require-effective-target tls_native } */ +/* { dg-require-effective-target tls } */ extern char buf[]; #pragma omp threadprivate (buf) /* { dg-error "has incomplete type" } */ diff --git a/gcc/testsuite/g++.dg/gomp/tls-3.C b/gcc/testsuite/g++.dg/gomp/tls-3.C index 04f6bbe..c710b6d 100644 --- a/gcc/testsuite/g++.dg/gomp/tls-3.C +++ b/gcc/testsuite/g++.dg/gomp/tls-3.C @@ -1,5 +1,5 @@ // { dg-do compile } -// { dg-require-effective-target tls_native } +// { dg-require-effective-target tls } #define thr threadprivate diff --git a/gcc/testsuite/g++.dg/gomp/tls-4.C b/gcc/testsuite/g++.dg/gomp/tls-4.C index e4377c5..f6c039e 100644 --- a/gcc/testsuite/g++.dg/gomp/tls-4.C +++ b/gcc/testsuite/g++.dg/gomp/tls-4.C @@ -1,5 +1,5 @@ // { dg-do compile } -// { dg-require-effective-target tls_native } +// { dg-require-effective-target tls } #define thr threadprivate diff --git a/gcc/testsuite/g++.dg/tls/diag-1.C b/gcc/testsuite/g++.dg/tls/diag-1.C index beeeccb..af53871 100644 --- a/gcc/testsuite/g++.dg/tls/diag-1.C +++ b/gcc/testsuite/g++.dg/tls/diag-1.C @@ -1,5 +1,5 @@ // Valid __thread specifiers. -// { dg-require-effective-target tls_native } +// { dg-require-effective-target tls } __thread int g1; extern __thread int g2; diff --git a/gcc/testsuite/g++.dg/tls/diag-2.C b/gcc/testsuite/g++.dg/tls/diag-2.C index b48b7d7..484b188 100644 --- a/gcc/testsuite/g++.dg/tls/diag-2.C +++ b/gcc/testsuite/g++.dg/tls/diag-2.C @@ -1,5 +1,5 @@ /* Invalid __thread specifiers. */ -/* { dg-require-effective-target tls_native } */ +/* { dg-require-effective-target tls } */ __thread extern int g1; /* { dg-error "'__thread' before 'extern'" } */ __thread static int g2; /* { dg-error "'__thread' before 'static'" } */ diff --git a/gcc/testsuite/g++.dg/tls/diag-3.C b/gcc/testsuite/g++.dg/tls/diag-3.C index 0a05cff..ea5158b 100644 --- a/gcc/testsuite/g++.dg/tls/diag-3.C +++ b/gcc/testsuite/g++.dg/tls/diag-3.C @@ -1,5 +1,5 @@ // Report invalid extern and __thread combinations. -// { dg-require-effective-target tls_native } +// { dg-require-effective-target tls } extern int j; // { dg-error "previously declared here" } __thread int j; // { dg-error "follows non-thread-local" } diff --git a/gcc/testsuite/g++.dg/tls/diag-4.C b/gcc/testsuite/g++.dg/tls/diag-4.C index 6fb9215..55e985e 100644 --- a/gcc/testsuite/g++.dg/tls/diag-4.C +++ b/gcc/testsuite/g++.dg/tls/diag-4.C @@ -1,5 +1,5 @@ /* Invalid __thread specifiers. */ -/* { dg-require-effective-target tls_native } */ +/* { dg-require-effective-target tls } */ __thread typedef int g4; /* { dg-error "multiple storage classes" } */ diff --git a/gcc/testsuite/g++.dg/tls/diag-5.C b/gcc/testsuite/g++.dg/tls/diag-5.C index 5859a3d..ca92b30 100644 --- a/gcc/testsuite/g++.dg/tls/diag-5.C +++ b/gcc/testsuite/g++.dg/tls/diag-5.C @@ -1,5 +1,5 @@ // PR c++/30536 // Invalid __thread specifiers. -// { dg-require-effective-target tls_native } +// { dg-require-effective-target tls } struct A { __thread register int i; }; // { dg-error "multiple storage classes|storage class specified" } diff --git a/gcc/testsuite/g++.dg/tls/init-1.C b/gcc/testsuite/g++.dg/tls/init-1.C index 91a3afe..9786712 100644 --- a/gcc/testsuite/g++.dg/tls/init-1.C +++ b/gcc/testsuite/g++.dg/tls/init-1.C @@ -1,5 +1,5 @@ /* Valid initializations. */ -/* { dg-require-effective-target tls_native } */ +/* { dg-require-effective-target tls } */ __thread int i = 42; diff --git a/gcc/testsuite/g++.dg/tls/init-2.C b/gcc/testsuite/g++.dg/tls/init-2.C index b4407d3..c9f646d 100644 --- a/gcc/testsuite/g++.dg/tls/init-2.C +++ b/gcc/testsuite/g++.dg/tls/init-2.C @@ -1,5 +1,5 @@ /* Invalid initializations. */ -/* { dg-require-effective-target tls_native } */ +/* { dg-require-effective-target tls } */ extern __thread int i; __thread int *p = &i; /* { dg-error "dynamically initialized" } */ diff --git a/gcc/testsuite/g++.dg/tls/trivial.C b/gcc/testsuite/g++.dg/tls/trivial.C index 6c30da7..e2b8f45 100644 --- a/gcc/testsuite/g++.dg/tls/trivial.C +++ b/gcc/testsuite/g++.dg/tls/trivial.C @@ -1,3 +1,3 @@ -// { dg-require-effective-target tls_native } +// { dg-require-effective-target tls } __thread int i; diff --git a/gcc/testsuite/gcc.dg/gomp/appendix-a/a.22.1.c b/gcc/testsuite/gcc.dg/gomp/appendix-a/a.22.1.c index 2cc1488..e358683 100644 --- a/gcc/testsuite/gcc.dg/gomp/appendix-a/a.22.1.c +++ b/gcc/testsuite/gcc.dg/gomp/appendix-a/a.22.1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-require-effective-target tls_native } */ +/* { dg-require-effective-target tls } */ int counter = 0; #pragma omp threadprivate(counter) diff --git a/gcc/testsuite/gcc.dg/gomp/appendix-a/a.22.2.c b/gcc/testsuite/gcc.dg/gomp/appendix-a/a.22.2.c index 171bc20..7a6e901 100644 --- a/gcc/testsuite/gcc.dg/gomp/appendix-a/a.22.2.c +++ b/gcc/testsuite/gcc.dg/gomp/appendix-a/a.22.2.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-require-effective-target tls_native } */ +/* { dg-require-effective-target tls } */ int increment_counter_2 () diff --git a/gcc/testsuite/gcc.dg/gomp/appendix-a/a.24.1.c b/gcc/testsuite/gcc.dg/gomp/appendix-a/a.24.1.c index 5662e70..9d8baa3 100644 --- a/gcc/testsuite/gcc.dg/gomp/appendix-a/a.24.1.c +++ b/gcc/testsuite/gcc.dg/gomp/appendix-a/a.24.1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-require-effective-target tls_native } */ +/* { dg-require-effective-target tls } */ extern int omp_get_num_threads (void); int x, y, t, z[1000]; diff --git a/gcc/testsuite/gcc.dg/gomp/appendix-a/a.32.1.c b/gcc/testsuite/gcc.dg/gomp/appendix-a/a.32.1.c index 89d841c..d2cb316 100644 --- a/gcc/testsuite/gcc.dg/gomp/appendix-a/a.32.1.c +++ b/gcc/testsuite/gcc.dg/gomp/appendix-a/a.32.1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-require-effective-target tls_native } */ +/* { dg-require-effective-target tls } */ #include float *work; diff --git a/gcc/testsuite/gcc.dg/gomp/appendix-a/a.33.1.c b/gcc/testsuite/gcc.dg/gomp/appendix-a/a.33.1.c index 364a71e..99c06da 100644 --- a/gcc/testsuite/gcc.dg/gomp/appendix-a/a.33.1.c +++ b/gcc/testsuite/gcc.dg/gomp/appendix-a/a.33.1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-require-effective-target tls_native } */ +/* { dg-require-effective-target tls } */ #include float x, y; diff --git a/gcc/testsuite/gcc.dg/gomp/clause-1.c b/gcc/testsuite/gcc.dg/gomp/clause-1.c index cfab168..ace9738 100644 --- a/gcc/testsuite/gcc.dg/gomp/clause-1.c +++ b/gcc/testsuite/gcc.dg/gomp/clause-1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-require-effective-target tls_native } */ +/* { dg-require-effective-target tls } */ #define p parallel diff --git a/gcc/testsuite/gcc.dg/gomp/copyin-1.c b/gcc/testsuite/gcc.dg/gomp/copyin-1.c index f984d10..117f82f 100644 --- a/gcc/testsuite/gcc.dg/gomp/copyin-1.c +++ b/gcc/testsuite/gcc.dg/gomp/copyin-1.c @@ -1,5 +1,5 @@ // { dg-do compile } -// { dg-require-effective-target tls_native } +// { dg-require-effective-target tls } int i, j; diff --git a/gcc/testsuite/gcc.dg/gomp/pr35244.c b/gcc/testsuite/gcc.dg/gomp/pr35244.c index aa19a18..92d6a1c 100644 --- a/gcc/testsuite/gcc.dg/gomp/pr35244.c +++ b/gcc/testsuite/gcc.dg/gomp/pr35244.c @@ -1,6 +1,6 @@ /* PR c++/35244 */ /* { dg-do compile } */ -/* { dg-require-effective-target tls_native } */ +/* { dg-require-effective-target tls } */ /* { dg-options "-fopenmp" } */ int v1; diff --git a/gcc/testsuite/gcc.dg/gomp/sharing-1.c b/gcc/testsuite/gcc.dg/gomp/sharing-1.c index 6b53efe..90d389b 100644 --- a/gcc/testsuite/gcc.dg/gomp/sharing-1.c +++ b/gcc/testsuite/gcc.dg/gomp/sharing-1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-require-effective-target tls_native } */ +/* { dg-require-effective-target tls } */ #include diff --git a/gcc/testsuite/gcc.dg/gomp/tls-1.c b/gcc/testsuite/gcc.dg/gomp/tls-1.c index 7a36c2d..9dc102e 100644 --- a/gcc/testsuite/gcc.dg/gomp/tls-1.c +++ b/gcc/testsuite/gcc.dg/gomp/tls-1.c @@ -1,5 +1,5 @@ // { dg-do compile } -// { dg-require-effective-target tls_native } +// { dg-require-effective-target tls } int tp1; static int tp2; diff --git a/gcc/testsuite/gcc.dg/gomp/tls-2.c b/gcc/testsuite/gcc.dg/gomp/tls-2.c index 26dbc53..80275f9 100644 --- a/gcc/testsuite/gcc.dg/gomp/tls-2.c +++ b/gcc/testsuite/gcc.dg/gomp/tls-2.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-require-effective-target tls_native } */ +/* { dg-require-effective-target tls } */ extern char buf[]; #pragma omp threadprivate (buf) /* { dg-error "has incomplete type" } */ diff --git a/gcc/testsuite/gcc.dg/tls/emutls-2.c b/gcc/testsuite/gcc.dg/tls/emutls-2.c new file mode 100644 index 0000000..1e26d5f --- /dev/null +++ b/gcc/testsuite/gcc.dg/tls/emutls-2.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target tls } */ +/* { dg-options "-O2" } */ + +/* With emulated TLS, the constructor generated during IPA + was not properly lowered to SSA form. */ + +__thread int i __attribute__((common)); diff --git a/gcc/testsuite/gcc.dg/tls/opt-1.c b/gcc/testsuite/gcc.dg/tls/opt-1.c index f96bb67..f9399e0 100644 --- a/gcc/testsuite/gcc.dg/tls/opt-1.c +++ b/gcc/testsuite/gcc.dg/tls/opt-1.c @@ -1,7 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-O2 -fPIC" } */ /* { dg-options "-O2 -fPIC -mtune=i686" { target { { i?86-*-* x86_64-*-* } && ilp32 } } } */ -/* { dg-require-effective-target tls_native } */ +/* { dg-require-effective-target tls } */ /* { dg-require-effective-target fpic } */ extern __thread int thr; diff --git a/gcc/testsuite/gcc.dg/tls/opt-13.c b/gcc/testsuite/gcc.dg/tls/opt-13.c index aadfb28..8eea76b 100644 --- a/gcc/testsuite/gcc.dg/tls/opt-13.c +++ b/gcc/testsuite/gcc.dg/tls/opt-13.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-options "-O2" } */ -/* { dg-require-effective-target tls_native } */ +/* { dg-require-effective-target tls } */ __thread struct { diff --git a/gcc/testsuite/gcc.dg/tls/opt-14.c b/gcc/testsuite/gcc.dg/tls/opt-14.c index 2549c89..5abeace 100644 --- a/gcc/testsuite/gcc.dg/tls/opt-14.c +++ b/gcc/testsuite/gcc.dg/tls/opt-14.c @@ -3,7 +3,7 @@ used. */ /* { dg-do assemble } */ /* { dg-options "-O2" } */ -/* { dg-require-effective-target tls_native } */ +/* { dg-require-effective-target tls } */ struct __res_state { diff --git a/gcc/testsuite/gcc.dg/tls/opt-15.c b/gcc/testsuite/gcc.dg/tls/opt-15.c index bebee8a..a6cc721 100644 --- a/gcc/testsuite/gcc.dg/tls/opt-15.c +++ b/gcc/testsuite/gcc.dg/tls/opt-15.c @@ -3,7 +3,7 @@ /* { dg-do compile } */ /* { dg-options "-O -fPIC" } */ -/* { dg-require-effective-target tls_native } */ +/* { dg-require-effective-target tls } */ /* { dg-require-effective-target fpic } */ extern void *memset(void *s, int c, __SIZE_TYPE__ n); diff --git a/gcc/testsuite/gcc.dg/tls/opt-2.c b/gcc/testsuite/gcc.dg/tls/opt-2.c index 0980fab..3ede352 100644 --- a/gcc/testsuite/gcc.dg/tls/opt-2.c +++ b/gcc/testsuite/gcc.dg/tls/opt-2.c @@ -5,7 +5,7 @@ /* { dg-do link } */ /* { dg-options "-O2 -ftls-model=initial-exec" } */ /* { dg-options "-O2 -ftls-model=initial-exec -march=i686" { target { { i?86-*-* x86_64-*-* } && ilp32 } } } */ -/* { dg-require-effective-target tls_native } */ +/* { dg-require-effective-target tls } */ /* { dg-require-effective-target tls_runtime } */ __thread int thr; diff --git a/gcc/testsuite/gcc.dg/tls/opt-3.c b/gcc/testsuite/gcc.dg/tls/opt-3.c index 61f5bdb..dd37dbc 100644 --- a/gcc/testsuite/gcc.dg/tls/opt-3.c +++ b/gcc/testsuite/gcc.dg/tls/opt-3.c @@ -1,7 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-O2 -fpic" } */ /* { dg-options "-O2 -fpic -mregparm=3" { target { { i?86-*-* x86_64-*-* } && ilp32 } } } */ -/* { dg-require-effective-target tls_native } */ +/* { dg-require-effective-target tls } */ /* { dg-require-effective-target fpic } */ extern __thread int i, j, k; diff --git a/gcc/testsuite/gcc.dg/tls/opt-7.c b/gcc/testsuite/gcc.dg/tls/opt-7.c index d3e81f4..44b900f 100644 --- a/gcc/testsuite/gcc.dg/tls/opt-7.c +++ b/gcc/testsuite/gcc.dg/tls/opt-7.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-options "-O2 -fPIC" } */ -/* { dg-require-effective-target tls_native } */ +/* { dg-require-effective-target tls } */ /* { dg-require-effective-target fpic } */ static __thread void *baz [4] __attribute__((tls_model ("initial-exec"))); diff --git a/gcc/testsuite/gcc.dg/tls/section-1.c b/gcc/testsuite/gcc.dg/tls/section-1.c index 1ca2ffb..4fc5066 100644 --- a/gcc/testsuite/gcc.dg/tls/section-1.c +++ b/gcc/testsuite/gcc.dg/tls/section-1.c @@ -1,6 +1,6 @@ /* Verify that we get errors for trying to put TLS data in sections which can't work. */ -/* { dg-require-effective-target tls_native } */ +/* { dg-require-effective-target tls } */ #define A(X) __attribute__((section(X))) diff --git a/gcc/testsuite/gcc.dg/tls/thr-init-1.c b/gcc/testsuite/gcc.dg/tls/thr-init-1.c new file mode 100644 index 0000000..de273d9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tls/thr-init-1.c @@ -0,0 +1,8 @@ +/* { dg-require-effective-target tls } */ +/* { dg-do compile } */ + +static __thread int fstat ; +static __thread int fstat = 1 ; +static __thread int fstat ; +static __thread int fstat = 2; /* { dg-error "redefinition of 'fstat'" } */ + /* { dg-message "note: previous definition of 'fstat' was here" "" { target *-*-* } 5 } */ diff --git a/gcc/testsuite/gcc.dg/tls/thr-init-2.c b/gcc/testsuite/gcc.dg/tls/thr-init-2.c new file mode 100644 index 0000000..6d00d8c --- /dev/null +++ b/gcc/testsuite/gcc.dg/tls/thr-init-2.c @@ -0,0 +1,23 @@ +/* { dg-require-effective-target tls } */ +/* { dg-do run } */ + +extern void abort() ; + +static __thread int fstat ; +static __thread int fstat = 1; + +int test_code(int b) +{ + fstat += b ; + return fstat; +} + +int main (int ac, char *av[]) +{ + int a = test_code(1); + + if ((a != 2) || (fstat != 2)) + abort () ; + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/torture/tls/thr-init-1.c b/gcc/testsuite/gcc.dg/torture/tls/thr-init-1.c new file mode 100644 index 0000000..89725c3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/tls/thr-init-1.c @@ -0,0 +1,25 @@ +/* { dg-do run } */ +/* { dg-require-effective-target tls } */ + +extern int printf (char *,...); +extern void abort() ; + +int test_code(int b) +{ +static __thread int fstat = 1; + fstat += b ; + return fstat; +} + +int main (int ac, char *av[]) +{ + int a = test_code(1); + + if ( a != 2 ) + { + printf ("a=%d\n", a) ; + abort (); + } + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/torture/tls/thr-init-2.c b/gcc/testsuite/gcc.dg/torture/tls/thr-init-2.c new file mode 100644 index 0000000..9d09319 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/tls/thr-init-2.c @@ -0,0 +1,28 @@ +/* { dg-do run } */ +/* { dg-require-effective-target tls } */ + +extern int printf (char *,...); +extern void abort() ; + +static __thread int fstat ; +static __thread int fstat = 1; +static __thread int fstat ; + +int test_code(int b) +{ + fstat += b ; + return fstat; +} + +int main (int ac, char *av[]) +{ + int a = test_code(1); + + if ( a != 2 || fstat != 2 ) + { + printf ("a=%d fstat=%d\n", a, fstat) ; + abort (); + } + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/torture/tls/tls-test.c b/gcc/testsuite/gcc.dg/torture/tls/tls-test.c new file mode 100644 index 0000000..8a23e77 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/tls/tls-test.c @@ -0,0 +1,52 @@ +/* { dg-do run } */ +/* { dg-require-effective-target tls } */ +/* { dg-require-effective-target pthread } */ +/* { dg-options "-pthread" } */ + +#include +extern int printf (char *,...); +__thread int a = 5; +int *volatile a_in_other_thread = (int *) 12345; + +static void * +thread_func (void *arg) +{ + a_in_other_thread = &a; + a+=5; + *((int *) arg) = a; + return (void *)0; +} + +int +main () +{ + pthread_t thread; + void *thread_retval; + int *volatile a_in_main_thread; + int *volatile again ; + int thr_a; + + a_in_main_thread = &a; + + if (pthread_create (&thread, (pthread_attr_t *)0, thread_func, &thr_a)) + return 0; + + if (pthread_join (thread, &thread_retval)) + return 0; + + again = &a; + if (again != a_in_main_thread) + { + printf ("FAIL: main thread addy changed from 0x%0x to 0x%0x\n", + a_in_other_thread, again); + return 1; + } + + if (a != 5 || thr_a != 10 || (a_in_other_thread == a_in_main_thread)) + { + printf ("FAIL: a= %d, thr_a = %d Addr = 0x%0x\n", + a, thr_a, a_in_other_thread); + return 1; + } + return 0; +} diff --git a/gcc/testsuite/gcc.dg/torture/tls/tls.exp b/gcc/testsuite/gcc.dg/torture/tls/tls.exp new file mode 100644 index 0000000..91c8843 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/tls/tls.exp @@ -0,0 +1,36 @@ +# Copyright (C) 2010 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . + +# GCC testsuite that uses the `dg.exp' driver. + +# Load support procs. +load_lib gcc-dg.exp + +# If a testcase doesn't have special options, use these. +global DEFAULT_CFLAGS +if ![info exists DEFAULT_CFLAGS] then { + set DEFAULT_CFLAGS " -ansi -pedantic-errors" +} + +# Initialize `dg'. +dg-init + +# Main loop. +gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] \ + $DEFAULT_CFLAGS + +# All done. +dg-finish diff --git a/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.1.f90 b/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.1.f90 index 96b6abc..cc94b14 100644 --- a/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.1.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.1.f90 @@ -1,5 +1,5 @@ ! { dg-do compile } -! { dg-require-effective-target tls_native } +! { dg-require-effective-target tls } INTEGER FUNCTION INCREMENT_COUNTER() COMMON/A22_COMMON/COUNTER diff --git a/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.4.f90 b/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.4.f90 index a272af5..2a63758 100644 --- a/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.4.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.4.f90 @@ -1,5 +1,5 @@ ! { dg-do compile } -! { dg-require-effective-target tls_native } +! { dg-require-effective-target tls } MODULE A22_MODULE COMMON /T/ A diff --git a/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.5.f90 b/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.5.f90 index abd911f..6531d82 100644 --- a/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.5.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.5.f90 @@ -1,5 +1,5 @@ ! { dg-do compile } -! { dg-require-effective-target tls_native } +! { dg-require-effective-target tls } SUBROUTINE A22_5_WRONG() COMMON /T/ A diff --git a/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.6.f90 b/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.6.f90 index 1d74593..0a2e6a6 100644 --- a/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.6.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.22.6.f90 @@ -1,5 +1,5 @@ ! { dg-do compile } -! { dg-require-effective-target tls_native } +! { dg-require-effective-target tls } SUBROUTINE A22_6_GOOD() COMMON /T/ A diff --git a/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.24.1.f90 b/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.24.1.f90 index 87388e3..e5b9545 100644 --- a/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.24.1.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.24.1.f90 @@ -1,5 +1,5 @@ ! { dg-do compile } -! { dg-require-effective-target tls_native } +! { dg-require-effective-target tls } SUBROUTINE A24(A) INTEGER A diff --git a/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.32.1.f90 b/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.32.1.f90 index 8bf2010..498a6d3 100644 --- a/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.32.1.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.32.1.f90 @@ -1,5 +1,5 @@ ! { dg-do compile } -! { dg-require-effective-target tls_native } +! { dg-require-effective-target tls } MODULE M REAL, POINTER, SAVE :: WORK(:) diff --git a/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.33.1.f90 b/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.33.1.f90 index a161d54..05145b1 100644 --- a/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.33.1.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/appendix-a/a.33.1.f90 @@ -1,5 +1,5 @@ ! { dg-do compile } -! { dg-require-effective-target tls_native } +! { dg-require-effective-target tls } SUBROUTINE INIT(A,B) REAL A, B diff --git a/gcc/testsuite/gfortran.dg/gomp/crayptr2.f90 b/gcc/testsuite/gfortran.dg/gomp/crayptr2.f90 index 0032080..476d7b9 100644 --- a/gcc/testsuite/gfortran.dg/gomp/crayptr2.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/crayptr2.f90 @@ -1,6 +1,6 @@ ! { dg-do compile } ! { dg-options "-fopenmp -fcray-pointer" } -! { dg-require-effective-target tls_native } +! { dg-require-effective-target tls } module crayptr2 integer :: e ! { dg-error "CRAY POINTEE attribute conflicts with THREADPRIVATE" } diff --git a/gcc/testsuite/gfortran.dg/gomp/fixed-1.f b/gcc/testsuite/gfortran.dg/gomp/fixed-1.f index 8323356..d61f2ba 100644 --- a/gcc/testsuite/gfortran.dg/gomp/fixed-1.f +++ b/gcc/testsuite/gfortran.dg/gomp/fixed-1.f @@ -1,6 +1,6 @@ C PR fortran/24493 C { dg-do compile } -C { dg-require-effective-target tls_native } +C { dg-require-effective-target tls } INTEGER I, J, K, L, M C$OMP THREADPRIVATE(I) C SOME COMMENT diff --git a/gcc/testsuite/gfortran.dg/gomp/free-1.f90 b/gcc/testsuite/gfortran.dg/gomp/free-1.f90 index 3503389..f6f9de4 100644 --- a/gcc/testsuite/gfortran.dg/gomp/free-1.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/free-1.f90 @@ -1,4 +1,4 @@ -! { dg-require-effective-target tls_native } +! { dg-require-effective-target tls } subroutine foo integer, save :: i ! Some comment diff --git a/gcc/testsuite/gfortran.dg/gomp/omp_threadprivate1.f90 b/gcc/testsuite/gfortran.dg/gomp/omp_threadprivate1.f90 index 2380e3b..2ccf93c 100644 --- a/gcc/testsuite/gfortran.dg/gomp/omp_threadprivate1.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/omp_threadprivate1.f90 @@ -1,4 +1,4 @@ -! { dg-require-effective-target tls_native } +! { dg-require-effective-target tls } module omp_threadprivate1 common /T/ a end module omp_threadprivate1 diff --git a/gcc/testsuite/gfortran.dg/gomp/omp_threadprivate2.f90 b/gcc/testsuite/gfortran.dg/gomp/omp_threadprivate2.f90 index 3112afd..cd1ab5c 100644 --- a/gcc/testsuite/gfortran.dg/gomp/omp_threadprivate2.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/omp_threadprivate2.f90 @@ -1,5 +1,5 @@ ! { dg-do compile } -! { dg-require-effective-target tls_native } +! { dg-require-effective-target tls } subroutine bad1 double precision :: d ! { dg-error "isn't SAVEd" } !$omp threadprivate (d) diff --git a/gcc/testsuite/gfortran.dg/gomp/reduction1.f90 b/gcc/testsuite/gfortran.dg/gomp/reduction1.f90 index 9c55d17..4912f71 100644 --- a/gcc/testsuite/gfortran.dg/gomp/reduction1.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/reduction1.f90 @@ -1,6 +1,6 @@ ! { dg-do compile } ! { dg-options "-fopenmp -fmax-errors=100" } -! { dg-require-effective-target tls_native } +! { dg-require-effective-target tls } subroutine foo (ia1) integer :: i1, i2, i3 diff --git a/gcc/testsuite/gfortran.dg/gomp/sharing-1.f90 b/gcc/testsuite/gfortran.dg/gomp/sharing-1.f90 index 89bc6a8..7a107ff 100644 --- a/gcc/testsuite/gfortran.dg/gomp/sharing-1.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/sharing-1.f90 @@ -1,5 +1,5 @@ ! { dg-do compile } -! { dg-require-effective-target tls_native } +! { dg-require-effective-target tls } integer :: thrpriv, thr, i, j, s, g1, g2, m integer, dimension (6) :: p diff --git a/gcc/toplev.c b/gcc/toplev.c index 964669f..60ca5dc 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -992,11 +992,6 @@ compile_file (void) if (seen_error ()) return; - /* Ensure that emulated TLS control vars are finalized and build - a static constructor for them, when it is required. */ - if (!targetm.have_tls) - emutls_finish (); - varpool_assemble_pending_decls (); finish_aliases_2 (); diff --git a/gcc/tree-emutls.c b/gcc/tree-emutls.c new file mode 100644 index 0000000..17f97be --- /dev/null +++ b/gcc/tree-emutls.c @@ -0,0 +1,802 @@ +/* Lower TLS operations to emulation functions. + Copyright (C) 2006, 2007, 2008, 2009, 2010 + Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3, or (at your option) any +later version. + +GCC is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree.h" +#include "gimple.h" +#include "tree-pass.h" +#include "tree-flow.h" +#include "cgraph.h" +#include "langhooks.h" +#include "target.h" +#include "targhooks.h" +#include "tree-iterator.h" + + +/* Whenever a target does not support thread-local storage (TLS) natively, + we can emulate it with some run-time support in libgcc. This will in + turn rely on "keyed storage" a-la pthread_key_create; essentially all + thread libraries provide such functionality. + + In order to coordinate with the libgcc runtime, each TLS variable is + described by a "control variable". This control variable records the + required size, alignment, and initial value of the TLS variable for + instantiation at runtime. It also stores an integer token to be used + by the runtime to find the address of the variable within each thread. + + On the compiler side, this means that we need to replace all instances + of "tls_var" in the code with "*__emutls_get_addr(&control_var)". We + also need to eliminate "tls_var" from the symbol table and introduce + "control_var". + + We used to perform all of the transformations during conversion to rtl, + and the variable substitutions magically within assemble_variable. + However, this late fiddling of the symbol table conflicts with LTO and + whole-program compilation. Therefore we must now make all the changes + to the symbol table early in the GIMPLE optimization path, before we + write things out to LTO intermediate files. */ + +/* These two vectors, once fully populated, are kept in lock-step so that + the index of a TLS variable equals the index of its control variable in + the other vector. */ +static varpool_node_set tls_vars; +static VEC(varpool_node_ptr, heap) *control_vars; + +/* For the current basic block, an SSA_NAME that has computed the address + of the TLS variable at the corresponding index. */ +static VEC(tree, heap) *access_vars; + +/* The type of the control structure, shared with the emutls.c runtime. */ +static tree emutls_object_type; + +#if !defined (NO_DOT_IN_LABEL) +# define EMUTLS_SEPARATOR "." +#elif !defined (NO_DOLLAR_IN_LABEL) +# define EMUTLS_SEPARATOR "$" +#else +# define EMUTLS_SEPARATOR "_" +#endif + +/* Create an IDENTIFIER_NODE by prefixing PREFIX to the + IDENTIFIER_NODE NAME's name. */ + +static tree +prefix_name (const char *prefix, tree name) +{ + unsigned plen = strlen (prefix); + unsigned nlen = strlen (IDENTIFIER_POINTER (name)); + char *toname = (char *) alloca (plen + nlen + 1); + + memcpy (toname, prefix, plen); + memcpy (toname + plen, IDENTIFIER_POINTER (name), nlen + 1); + + return get_identifier (toname); +} + +/* Create an identifier for the struct __emutls_object, given an identifier + of the DECL_ASSEMBLY_NAME of the original object. */ + +static tree +get_emutls_object_name (tree name) +{ + const char *prefix = (targetm.emutls.var_prefix + ? targetm.emutls.var_prefix + : "__emutls_v" EMUTLS_SEPARATOR); + return prefix_name (prefix, name); +} + +/* Create the fields of the type for the control variables. Ordinarily + this must match struct __emutls_object defined in emutls.c. However + this is a target hook so that VxWorks can define its own layout. */ + +tree +default_emutls_var_fields (tree type, tree *name ATTRIBUTE_UNUSED) +{ + tree word_type_node, field, next_field; + + field = build_decl (UNKNOWN_LOCATION, + FIELD_DECL, get_identifier ("__templ"), ptr_type_node); + DECL_CONTEXT (field) = type; + next_field = field; + + field = build_decl (UNKNOWN_LOCATION, + FIELD_DECL, get_identifier ("__offset"), + ptr_type_node); + DECL_CONTEXT (field) = type; + DECL_CHAIN (field) = next_field; + next_field = field; + + word_type_node = lang_hooks.types.type_for_mode (word_mode, 1); + field = build_decl (UNKNOWN_LOCATION, + FIELD_DECL, get_identifier ("__align"), + word_type_node); + DECL_CONTEXT (field) = type; + DECL_CHAIN (field) = next_field; + next_field = field; + + field = build_decl (UNKNOWN_LOCATION, + FIELD_DECL, get_identifier ("__size"), word_type_node); + DECL_CONTEXT (field) = type; + DECL_CHAIN (field) = next_field; + + return field; +} + +/* Initialize emulated tls object TO, which refers to TLS variable DECL and + is initialized by PROXY. As above, this is the default implementation of + a target hook overridden by VxWorks. */ + +tree +default_emutls_var_init (tree to, tree decl, tree proxy) +{ + VEC(constructor_elt,gc) *v = VEC_alloc (constructor_elt, gc, 4); + constructor_elt *elt; + tree type = TREE_TYPE (to); + tree field = TYPE_FIELDS (type); + + elt = VEC_quick_push (constructor_elt, v, NULL); + elt->index = field; + elt->value = fold_convert (TREE_TYPE (field), DECL_SIZE_UNIT (decl)); + + elt = VEC_quick_push (constructor_elt, v, NULL); + field = DECL_CHAIN (field); + elt->index = field; + elt->value = build_int_cst (TREE_TYPE (field), + DECL_ALIGN_UNIT (decl)); + + elt = VEC_quick_push (constructor_elt, v, NULL); + field = DECL_CHAIN (field); + elt->index = field; + elt->value = null_pointer_node; + + elt = VEC_quick_push (constructor_elt, v, NULL); + field = DECL_CHAIN (field); + elt->index = field; + elt->value = proxy; + + return build_constructor (type, v); +} + +/* Create the structure for struct __emutls_object. This should match the + structure at the top of emutls.c, modulo the union there. */ + +static tree +get_emutls_object_type (void) +{ + tree type, type_name, field; + + type = emutls_object_type; + if (type) + return type; + + emutls_object_type = type = lang_hooks.types.make_type (RECORD_TYPE); + type_name = NULL; + field = targetm.emutls.var_fields (type, &type_name); + if (!type_name) + type_name = get_identifier ("__emutls_object"); + type_name = build_decl (UNKNOWN_LOCATION, + TYPE_DECL, type_name, type); + TYPE_NAME (type) = type_name; + TYPE_FIELDS (type) = field; + layout_type (type); + + return type; +} + +/* Create a read-only variable like DECL, with the same DECL_INITIAL. + This will be used for initializing the emulated tls data area. */ + +static tree +get_emutls_init_templ_addr (tree decl) +{ + tree name, to; + + if (targetm.emutls.register_common && !DECL_INITIAL (decl) + && !DECL_SECTION_NAME (decl)) + return null_pointer_node; + + name = DECL_ASSEMBLER_NAME (decl); + if (!targetm.emutls.tmpl_prefix || targetm.emutls.tmpl_prefix[0]) + { + const char *prefix = (targetm.emutls.tmpl_prefix + ? targetm.emutls.tmpl_prefix + : "__emutls_t" EMUTLS_SEPARATOR); + name = prefix_name (prefix, name); + } + + to = build_decl (DECL_SOURCE_LOCATION (decl), + VAR_DECL, name, TREE_TYPE (decl)); + SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to)); + + DECL_ARTIFICIAL (to) = 1; + TREE_USED (to) = TREE_USED (decl); + TREE_READONLY (to) = 1; + DECL_IGNORED_P (to) = 1; + DECL_CONTEXT (to) = DECL_CONTEXT (decl); + DECL_SECTION_NAME (to) = DECL_SECTION_NAME (decl); + DECL_PRESERVE_P (to) = DECL_PRESERVE_P (decl); + + DECL_WEAK (to) = DECL_WEAK (decl); + if (DECL_ONE_ONLY (decl)) + { + make_decl_one_only (to, DECL_ASSEMBLER_NAME (to)); + TREE_STATIC (to) = TREE_STATIC (decl); + TREE_PUBLIC (to) = TREE_PUBLIC (decl); + DECL_VISIBILITY (to) = DECL_VISIBILITY (decl); + } + else + TREE_STATIC (to) = 1; + + DECL_VISIBILITY_SPECIFIED (to) = DECL_VISIBILITY_SPECIFIED (decl); + DECL_INITIAL (to) = DECL_INITIAL (decl); + DECL_INITIAL (decl) = NULL; + + if (targetm.emutls.tmpl_section) + { + DECL_SECTION_NAME (to) + = build_string (strlen (targetm.emutls.tmpl_section), + targetm.emutls.tmpl_section); + } + + varpool_finalize_decl (to); + return build_fold_addr_expr (to); +} + +/* Create and return the control variable for the TLS variable DECL. */ + +static tree +new_emutls_decl (tree decl) +{ + tree name, to; + + name = DECL_ASSEMBLER_NAME (decl); + to = build_decl (DECL_SOURCE_LOCATION (decl), VAR_DECL, + get_emutls_object_name (name), + get_emutls_object_type ()); + + SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to)); + + DECL_TLS_MODEL (to) = TLS_MODEL_EMULATED; + DECL_ARTIFICIAL (to) = 1; + DECL_IGNORED_P (to) = 1; + TREE_READONLY (to) = 0; + TREE_STATIC (to) = 1; + + DECL_PRESERVE_P (to) = DECL_PRESERVE_P (decl); + DECL_CONTEXT (to) = DECL_CONTEXT (decl); + TREE_USED (to) = TREE_USED (decl); + TREE_PUBLIC (to) = TREE_PUBLIC (decl); + DECL_EXTERNAL (to) = DECL_EXTERNAL (decl); + DECL_COMMON (to) = DECL_COMMON (decl); + DECL_WEAK (to) = DECL_WEAK (decl); + DECL_VISIBILITY (to) = DECL_VISIBILITY (decl); + DECL_VISIBILITY_SPECIFIED (to) = DECL_VISIBILITY_SPECIFIED (decl); + DECL_RESTRICTED_P (to) = DECL_RESTRICTED_P (decl); + DECL_DLLIMPORT_P (to) = DECL_DLLIMPORT_P (decl); + + DECL_ATTRIBUTES (to) = targetm.merge_decl_attributes (decl, to); + + if (DECL_ONE_ONLY (decl)) + make_decl_one_only (to, DECL_ASSEMBLER_NAME (to)); + + /* If we're not allowed to change the proxy object's alignment, + pretend it has been set by the user. */ + if (targetm.emutls.var_align_fixed) + DECL_USER_ALIGN (to) = 1; + + /* If the target wants the control variables grouped, do so. */ + if (!DECL_COMMON (to) && targetm.emutls.var_section) + { + DECL_SECTION_NAME (to) + = build_string (strlen (targetm.emutls.tmpl_section), + targetm.emutls.tmpl_section); + } + + /* If this variable is defined locally, then we need to initialize the + control structure with size and alignment information. Initialization + of COMMON block variables happens elsewhere via a constructor. */ + if (!DECL_EXTERNAL (to) + && (!DECL_COMMON (to) + || (DECL_INITIAL (decl) + && DECL_INITIAL (decl) != error_mark_node))) + { + tree tmpl = get_emutls_init_templ_addr (decl); + DECL_INITIAL (to) = targetm.emutls.var_init (to, decl, tmpl); + record_references_in_initializer (to, false); + } + + varpool_finalize_decl (to); + return to; +} + +/* Look up the index of the TLS variable DECL. This index can then be + used in both the control_vars and access_vars arrays. */ + +static unsigned int +emutls_index (tree decl) +{ + varpool_node_set_iterator i; + + i = varpool_node_set_find (tls_vars, varpool_get_node (decl)); + gcc_assert (i.index != ~0u); + + return i.index; +} + +/* Look up the control variable for the TLS variable DECL. */ + +static tree +emutls_decl (tree decl) +{ + struct varpool_node *var; + unsigned int i; + + i = emutls_index (decl); + var = VEC_index (varpool_node_ptr, control_vars, i); + return var->decl; +} + +/* Generate a call statement to initialize CONTROL_DECL for TLS_DECL. + This only needs to happen for TLS COMMON variables; non-COMMON + variables can be initialized statically. Insert the generated + call statement at the end of PSTMTS. */ + +static void +emutls_common_1 (tree tls_decl, tree control_decl, tree *pstmts) +{ + tree x; + tree word_type_node; + + if (! DECL_COMMON (tls_decl) + || (DECL_INITIAL (tls_decl) + && DECL_INITIAL (tls_decl) != error_mark_node)) + return; + + word_type_node = lang_hooks.types.type_for_mode (word_mode, 1); + + x = build_call_expr (built_in_decls[BUILT_IN_EMUTLS_REGISTER_COMMON], 4, + build_fold_addr_expr (control_decl), + fold_convert (word_type_node, + DECL_SIZE_UNIT (tls_decl)), + build_int_cst (word_type_node, + DECL_ALIGN_UNIT (tls_decl)), + get_emutls_init_templ_addr (tls_decl)); + + append_to_statement_list (x, pstmts); +} + +struct lower_emutls_data +{ + struct cgraph_node *cfun_node; + struct cgraph_node *builtin_node; + tree builtin_decl; + basic_block bb; + int bb_freq; + location_t loc; + gimple_seq seq; +}; + +/* Given a TLS variable DECL, return an SSA_NAME holding its address. + Append any new computation statements required to D->SEQ. */ + +static tree +gen_emutls_addr (tree decl, struct lower_emutls_data *d) +{ + unsigned int index; + tree addr; + + /* Compute the address of the TLS variable with help from runtime. */ + index = emutls_index (decl); + addr = VEC_index (tree, access_vars, index); + if (addr == NULL) + { + struct varpool_node *cvar; + tree cdecl; + gimple x; + + cvar = VEC_index (varpool_node_ptr, control_vars, index); + cdecl = cvar->decl; + TREE_ADDRESSABLE (cdecl) = 1; + + addr = create_tmp_var (build_pointer_type (TREE_TYPE (decl)), NULL); + x = gimple_build_call (d->builtin_decl, 1, build_fold_addr_expr (cdecl)); + gimple_set_location (x, d->loc); + + addr = make_ssa_name (addr, x); + gimple_call_set_lhs (x, addr); + + gimple_seq_add_stmt (&d->seq, x); + + cgraph_create_edge (d->cfun_node, d->builtin_node, x, + d->bb->count, d->bb_freq, d->bb->loop_depth); + + /* We may be adding a new reference to a new variable to the function. + This means we have to play with the ipa-reference web. */ + ipa_record_reference (d->cfun_node, NULL, NULL, cvar, IPA_REF_ADDR, x); + + /* Record this ssa_name for possible use later in the basic block. */ + VEC_replace (tree, access_vars, index, addr); + } + + return addr; +} + +/* Callback for walk_gimple_op. D = WI->INFO is a struct lower_emutls_data. + Given an operand *PTR within D->STMT, if the operand references a TLS + variable, then lower the reference to a call to the runtime. Insert + any new statements required into D->SEQ; the caller is responsible for + placing those appropriately. */ + +static tree +lower_emutls_1 (tree *ptr, int *walk_subtrees, void *cb_data) +{ + struct walk_stmt_info *wi = (struct walk_stmt_info *) cb_data; + struct lower_emutls_data *d = (struct lower_emutls_data *) wi->info; + tree t = *ptr; + bool is_addr = false; + tree addr; + + *walk_subtrees = 0; + + switch (TREE_CODE (t)) + { + case ADDR_EXPR: + /* If this is not a straight-forward "&var", but rather something + like "&var.a", then we may need special handling. */ + if (TREE_CODE (TREE_OPERAND (t, 0)) != VAR_DECL) + { + bool save_changed; + + /* If we're allowed more than just is_gimple_val, continue. */ + if (!wi->val_only) + { + *walk_subtrees = 1; + return NULL_TREE; + } + + /* See if any substitution would be made. */ + save_changed = wi->changed; + wi->changed = false; + wi->val_only = false; + walk_tree (&TREE_OPERAND (t, 0), lower_emutls_1, wi, NULL); + wi->val_only = true; + + /* If so, then extract this entire sub-expression "&p->a" into a + new assignment statement, and substitute yet another SSA_NAME. */ + if (wi->changed) + { + gimple x; + + addr = create_tmp_var (TREE_TYPE (t), NULL); + x = gimple_build_assign (addr, t); + gimple_set_location (x, d->loc); + + addr = make_ssa_name (addr, x); + gimple_assign_set_lhs (x, addr); + + gimple_seq_add_stmt (&d->seq, x); + + *ptr = addr; + } + else + wi->changed = save_changed; + + return NULL_TREE; + } + + t = TREE_OPERAND (t, 0); + is_addr = true; + /* FALLTHRU */ + + case VAR_DECL: + if (!DECL_THREAD_LOCAL_P (t)) + return NULL_TREE; + break; + + default: + /* We're not interested in other decls or types, only subexpressions. */ + if (EXPR_P (t)) + *walk_subtrees = 1; + /* FALLTHRU */ + + case SSA_NAME: + /* Special-case the return of SSA_NAME, since it's so common. */ + return NULL_TREE; + } + + addr = gen_emutls_addr (t, d); + if (is_addr) + { + /* Replace "&var" with "addr" in the statement. */ + *ptr = addr; + } + else + { + /* Replace "var" with "*addr" in the statement. */ + t = build2 (MEM_REF, TREE_TYPE (t), addr, + build_int_cst (TREE_TYPE (addr), 0)); + *ptr = t; + } + + wi->changed = true; + return NULL_TREE; +} + +/* Lower all of the operands of STMT. */ + +static void +lower_emutls_stmt (gimple stmt, struct lower_emutls_data *d) +{ + struct walk_stmt_info wi; + + d->loc = gimple_location (stmt); + + memset (&wi, 0, sizeof (wi)); + wi.info = d; + wi.val_only = true; + walk_gimple_op (stmt, lower_emutls_1, &wi); + + if (wi.changed) + update_stmt (stmt); +} + +/* Lower the I'th operand of PHI. */ + +static void +lower_emutls_phi_arg (gimple phi, unsigned int i, struct lower_emutls_data *d) +{ + struct walk_stmt_info wi; + struct phi_arg_d *pd = gimple_phi_arg (phi, i); + + /* Early out for a very common case we don't care about. */ + if (TREE_CODE (pd->def) == SSA_NAME) + return; + + d->loc = pd->locus; + + memset (&wi, 0, sizeof (wi)); + wi.info = d; + wi.val_only = true; + walk_tree (&pd->def, lower_emutls_1, &wi, NULL); + + /* For normal statements, we let update_stmt do its job. But for phi + nodes, we have to manipulate the immediate use list by hand. */ + if (wi.changed) + { + gcc_assert (TREE_CODE (pd->def) == SSA_NAME); + link_imm_use_stmt (&pd->imm_use, pd->def, phi); + } +} + +/* Clear the ACCESS_VARS array, in order to begin a new block. */ + +static inline void +clear_access_vars (void) +{ + memset (VEC_address (tree, access_vars), 0, + VEC_length (tree, access_vars) * sizeof(tree)); +} + +/* Lower the entire function NODE. */ + +static void +lower_emutls_function_body (struct cgraph_node *node) +{ + struct lower_emutls_data d; + bool any_edge_inserts = false; + + current_function_decl = node->decl; + push_cfun (DECL_STRUCT_FUNCTION (node->decl)); + + d.cfun_node = node; + d.builtin_decl = built_in_decls[BUILT_IN_EMUTLS_GET_ADDRESS]; + d.builtin_node = cgraph_node (d.builtin_decl); + + FOR_EACH_BB (d.bb) + { + gimple_stmt_iterator gsi; + unsigned int i, nedge; + + /* Lower each of the PHI nodes of the block, as we may have + propagated &tlsvar into a PHI argument. These loops are + arranged so that we process each edge at once, and each + PHI argument for that edge. */ + if (!gimple_seq_empty_p (phi_nodes (d.bb))) + { + /* The calls will be inserted on the edges, and the frequencies + will be computed during the commit process. */ + d.bb_freq = 0; + + nedge = EDGE_COUNT (d.bb->preds); + for (i = 0; i < nedge; ++i) + { + edge e = EDGE_PRED (d.bb, i); + + /* We can re-use any SSA_NAME created on this edge. */ + clear_access_vars (); + d.seq = NULL; + + for (gsi = gsi_start_phis (d.bb); + !gsi_end_p (gsi); + gsi_next (&gsi)) + lower_emutls_phi_arg (gsi_stmt (gsi), i, &d); + + /* Insert all statements generated by all phi nodes for this + particular edge all at once. */ + if (d.seq) + { + gsi_insert_seq_on_edge (e, d.seq); + any_edge_inserts = true; + } + } + } + + d.bb_freq = compute_call_stmt_bb_frequency (current_function_decl, d.bb); + + /* We can re-use any SSA_NAME created during this basic block. */ + clear_access_vars (); + + /* Lower each of the statements of the block. */ + for (gsi = gsi_start_bb (d.bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + d.seq = NULL; + lower_emutls_stmt (gsi_stmt (gsi), &d); + + /* If any new statements were created, insert them immediately + before the first use. This prevents variable lifetimes from + becoming unnecessarily long. */ + if (d.seq) + gsi_insert_seq_before (&gsi, d.seq, GSI_SAME_STMT); + } + } + + if (any_edge_inserts) + gsi_commit_edge_inserts (); + + pop_cfun (); + current_function_decl = NULL; +} + +/* Main entry point to the tls lowering pass. */ + +static unsigned int +ipa_lower_emutls (void) +{ + struct varpool_node *var; + struct cgraph_node *func; + bool any_aliases = false; + tree ctor_body = NULL; + unsigned int i, n_tls; + + tls_vars = varpool_node_set_new (); + + /* Examine all global variables for TLS variables. */ + for (var = varpool_nodes; var ; var = var->next) + if (DECL_THREAD_LOCAL_P (var->decl)) + { + gcc_checking_assert (TREE_STATIC (var->decl) + || DECL_EXTERNAL (var->decl)); + varpool_node_set_add (tls_vars, var); + } + + /* If we found no TLS variables, then there is no further work to do. */ + if (tls_vars->nodes == NULL) + { + tls_vars = NULL; + if (dump_file) + fprintf (dump_file, "No TLS variables found.\n"); + return 0; + } + + /* Allocate the on-the-side arrays that share indicies with the TLS vars. */ + n_tls = VEC_length (varpool_node_ptr, tls_vars->nodes); + control_vars = VEC_alloc (varpool_node_ptr, heap, n_tls); + access_vars = VEC_alloc (tree, heap, n_tls); + VEC_safe_grow (tree, heap, access_vars, n_tls); + + /* Create the control variables for each TLS variable. */ + for (i = 0; VEC_iterate (varpool_node_ptr, tls_vars->nodes, i, var); ++i) + { + tree cdecl; + struct varpool_node *cvar; + + var = VEC_index (varpool_node_ptr, tls_vars->nodes, i); + cdecl = new_emutls_decl (var->decl); + + cvar = varpool_get_node (cdecl); + VEC_quick_push (varpool_node_ptr, control_vars, cvar); + + if (var->alias) + { + any_aliases = true; + cvar->alias = true; + } + else + { + /* Make sure the COMMON block control variable gets initialized. + Note that there's no point in doing this for aliases; we only + need to do this once for the main variable. */ + emutls_common_1 (var->decl, cdecl, &ctor_body); + } + + /* Indicate that the value of the TLS variable may be found elsewhere, + preventing the variable from re-appearing in the GIMPLE. We cheat + and use the control variable here (rather than a full call_expr), + which is special-cased inside the DWARF2 output routines. */ + SET_DECL_VALUE_EXPR (var->decl, cdecl); + DECL_HAS_VALUE_EXPR_P (var->decl) = 1; + } + + /* If there were any aliases, then frob the alias_pairs vector. */ + if (any_aliases) + { + alias_pair *p; + for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); ++i) + if (DECL_THREAD_LOCAL_P (p->decl)) + { + p->decl = emutls_decl (p->decl); + p->target = get_emutls_object_name (p->target); + } + } + + /* Adjust all uses of TLS variables within the function bodies. */ + for (func = cgraph_nodes; func; func = func->next) + if (func->reachable && func->lowered) + lower_emutls_function_body (func); + + /* Generate the constructor for any COMMON control variables created. */ + if (ctor_body) + cgraph_build_static_cdtor ('I', ctor_body, DEFAULT_INIT_PRIORITY); + + VEC_free (varpool_node_ptr, heap, control_vars); + VEC_free (tree, heap, access_vars); + tls_vars = NULL; + + return TODO_dump_func | TODO_ggc_collect | TODO_verify_all; +} + +/* If the target supports TLS natively, we need do nothing here. */ + +static bool +gate_emutls (void) +{ + return !targetm.have_tls; +} + +struct simple_ipa_opt_pass pass_ipa_lower_emutls = +{ + { + SIMPLE_IPA_PASS, + "emutls", /* name */ + gate_emutls, /* gate */ + ipa_lower_emutls, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_NONE, /* tv_id */ + PROP_cfg | PROP_ssa, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ + } +}; diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index c72d7cf..33c898e 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -446,6 +446,7 @@ extern struct gimple_opt_pass pass_warn_unused_result; extern struct gimple_opt_pass pass_split_functions; /* IPA Passes */ +extern struct simple_ipa_opt_pass pass_ipa_lower_emutls; extern struct simple_ipa_opt_pass pass_ipa_function_and_variable_visibility; extern struct simple_ipa_opt_pass pass_ipa_early_inline; diff --git a/gcc/tree.h b/gcc/tree.h index 3c0806e..5aa5a89 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -5249,7 +5249,6 @@ extern void set_user_assembler_name (tree, const char *); extern void process_pending_assemble_externals (void); extern void finish_aliases_1 (void); extern void finish_aliases_2 (void); -extern tree emutls_decl (tree); extern void remove_unreachable_alias_pairs (void); /* In stmt.c */ diff --git a/gcc/varasm.c b/gcc/varasm.c index 9a4c193..58c9a1b 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -186,317 +186,6 @@ static GTY(()) int anchor_labelno; /* A pool of constants that can be shared between functions. */ static GTY(()) struct rtx_constant_pool *shared_constant_pool; -/* TLS emulation. */ - -static GTY ((if_marked ("tree_map_marked_p"), param_is (struct tree_map))) - htab_t emutls_htab; -static GTY (()) tree emutls_object_type; -/* Emulated TLS objects have the TLS model TLS_MODEL_EMULATED. This - macro can be used on them to distinguish the control variable from - the initialization template. */ -#define DECL_EMUTLS_VAR_P(D) (TREE_TYPE (D) == emutls_object_type) - -#if !defined (NO_DOT_IN_LABEL) -# define EMUTLS_SEPARATOR "." -#elif !defined (NO_DOLLAR_IN_LABEL) -# define EMUTLS_SEPARATOR "$" -#else -# define EMUTLS_SEPARATOR "_" -#endif - -/* Create an IDENTIFIER_NODE by prefixing PREFIX to the - IDENTIFIER_NODE NAME's name. */ - -static tree -prefix_name (const char *prefix, tree name) -{ - unsigned plen = strlen (prefix); - unsigned nlen = strlen (IDENTIFIER_POINTER (name)); - char *toname = (char *) alloca (plen + nlen + 1); - - memcpy (toname, prefix, plen); - memcpy (toname + plen, IDENTIFIER_POINTER (name), nlen + 1); - - return get_identifier (toname); -} - -/* Create an identifier for the struct __emutls_object, given an identifier - of the DECL_ASSEMBLY_NAME of the original object. */ - -static tree -get_emutls_object_name (tree name) -{ - const char *prefix = (targetm.emutls.var_prefix - ? targetm.emutls.var_prefix - : "__emutls_v" EMUTLS_SEPARATOR); - return prefix_name (prefix, name); -} - -tree -default_emutls_var_fields (tree type, tree *name ATTRIBUTE_UNUSED) -{ - tree word_type_node, field, next_field; - - field = build_decl (UNKNOWN_LOCATION, - FIELD_DECL, get_identifier ("__templ"), ptr_type_node); - DECL_CONTEXT (field) = type; - next_field = field; - - field = build_decl (UNKNOWN_LOCATION, - FIELD_DECL, get_identifier ("__offset"), - ptr_type_node); - DECL_CONTEXT (field) = type; - DECL_CHAIN (field) = next_field; - next_field = field; - - word_type_node = lang_hooks.types.type_for_mode (word_mode, 1); - field = build_decl (UNKNOWN_LOCATION, - FIELD_DECL, get_identifier ("__align"), - word_type_node); - DECL_CONTEXT (field) = type; - DECL_CHAIN (field) = next_field; - next_field = field; - - field = build_decl (UNKNOWN_LOCATION, - FIELD_DECL, get_identifier ("__size"), word_type_node); - DECL_CONTEXT (field) = type; - DECL_CHAIN (field) = next_field; - - return field; -} - -/* Create the structure for struct __emutls_object. This should match the - structure at the top of emutls.c, modulo the union there. */ - -static tree -get_emutls_object_type (void) -{ - tree type, type_name, field; - - type = emutls_object_type; - if (type) - return type; - - emutls_object_type = type = lang_hooks.types.make_type (RECORD_TYPE); - type_name = NULL; - field = targetm.emutls.var_fields (type, &type_name); - if (!type_name) - type_name = get_identifier ("__emutls_object"); - type_name = build_decl (UNKNOWN_LOCATION, - TYPE_DECL, type_name, type); - TYPE_NAME (type) = type_name; - TYPE_FIELDS (type) = field; - layout_type (type); - - return type; -} - -/* Create a read-only variable like DECL, with the same DECL_INITIAL. - This will be used for initializing the emulated tls data area. */ - -static tree -get_emutls_init_templ_addr (tree decl) -{ - tree name, to; - - if (targetm.emutls.register_common && !DECL_INITIAL (decl) - && !DECL_SECTION_NAME (decl)) - return null_pointer_node; - - name = DECL_ASSEMBLER_NAME (decl); - if (!targetm.emutls.tmpl_prefix || targetm.emutls.tmpl_prefix[0]) - { - const char *prefix = (targetm.emutls.tmpl_prefix - ? targetm.emutls.tmpl_prefix - : "__emutls_t" EMUTLS_SEPARATOR); - name = prefix_name (prefix, name); - } - - to = build_decl (DECL_SOURCE_LOCATION (decl), - VAR_DECL, name, TREE_TYPE (decl)); - SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to)); - - DECL_ARTIFICIAL (to) = 1; - TREE_USED (to) = TREE_USED (decl); - TREE_READONLY (to) = 1; - DECL_IGNORED_P (to) = 1; - DECL_CONTEXT (to) = DECL_CONTEXT (decl); - DECL_SECTION_NAME (to) = DECL_SECTION_NAME (decl); - DECL_PRESERVE_P (to) = DECL_PRESERVE_P (decl); - - DECL_WEAK (to) = DECL_WEAK (decl); - if (DECL_ONE_ONLY (decl)) - { - make_decl_one_only (to, DECL_ASSEMBLER_NAME (to)); - TREE_STATIC (to) = TREE_STATIC (decl); - TREE_PUBLIC (to) = TREE_PUBLIC (decl); - DECL_VISIBILITY (to) = DECL_VISIBILITY (decl); - } - else - TREE_STATIC (to) = 1; - - DECL_VISIBILITY_SPECIFIED (to) = DECL_VISIBILITY_SPECIFIED (decl); - DECL_INITIAL (to) = DECL_INITIAL (decl); - DECL_INITIAL (decl) = NULL; - - varpool_finalize_decl (to); - return build_fold_addr_expr (to); -} - -/* When emulating tls, we use a control structure for use by the runtime. - Create and return this structure. */ - -tree -emutls_decl (tree decl) -{ - tree name, to; - struct tree_map *h, in; - void **loc; - - if (targetm.have_tls || decl == NULL || decl == error_mark_node - || TREE_CODE (decl) != VAR_DECL || ! DECL_THREAD_LOCAL_P (decl)) - return decl; - - /* Look up the object in the hash; return the control structure if - it has already been created. */ - if (! emutls_htab) - emutls_htab = htab_create_ggc (512, tree_map_hash, tree_map_eq, 0); - - name = DECL_ASSEMBLER_NAME (decl); - - /* Note that we use the hash of the decl's name, rather than a hash - of the decl's pointer. In emutls_finish we iterate through the - hash table, and we want this traversal to be predictable. */ - in.hash = IDENTIFIER_HASH_VALUE (name); - in.base.from = decl; - loc = htab_find_slot_with_hash (emutls_htab, &in, in.hash, INSERT); - h = (struct tree_map *) *loc; - if (h != NULL) - to = h->to; - else - { - to = build_decl (DECL_SOURCE_LOCATION (decl), - VAR_DECL, get_emutls_object_name (name), - get_emutls_object_type ()); - - h = ggc_alloc_tree_map (); - h->hash = in.hash; - h->base.from = decl; - h->to = to; - *(struct tree_map **) loc = h; - - DECL_TLS_MODEL (to) = TLS_MODEL_EMULATED; - DECL_ARTIFICIAL (to) = 1; - DECL_IGNORED_P (to) = 1; - /* FIXME: work around PR44132. */ - DECL_PRESERVE_P (to) = 1; - TREE_READONLY (to) = 0; - SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to)); - if (DECL_ONE_ONLY (decl)) - make_decl_one_only (to, DECL_ASSEMBLER_NAME (to)); - DECL_CONTEXT (to) = DECL_CONTEXT (decl); - if (targetm.emutls.var_align_fixed) - /* If we're not allowed to change the proxy object's - alignment, pretend it's been set by the user. */ - DECL_USER_ALIGN (to) = 1; - } - - /* Note that these fields may need to be updated from time to time from - the original decl. Consider: - extern __thread int i; - int foo() { return i; } - __thread int i = 1; - in which I goes from external to locally defined and initialized. */ - DECL_DLLIMPORT_P (to) = DECL_DLLIMPORT_P (decl); - DECL_ATTRIBUTES (to) = targetm.merge_decl_attributes (decl, to); - - TREE_STATIC (to) = TREE_STATIC (decl); - TREE_USED (to) = TREE_USED (decl); - TREE_PUBLIC (to) = TREE_PUBLIC (decl); - DECL_EXTERNAL (to) = DECL_EXTERNAL (decl); - DECL_COMMON (to) = DECL_COMMON (decl); - DECL_WEAK (to) = DECL_WEAK (decl); - DECL_VISIBILITY (to) = DECL_VISIBILITY (decl); - DECL_VISIBILITY_SPECIFIED (to) = DECL_VISIBILITY_SPECIFIED (decl); - - /* Fortran might pass this to us. */ - DECL_RESTRICTED_P (to) = DECL_RESTRICTED_P (decl); - - return to; -} - -static int -emutls_common_1 (void **loc, void *xstmts) -{ - struct tree_map *h = *(struct tree_map **) loc; - tree x, *pstmts = (tree *) xstmts; - tree word_type_node; - - if (! DECL_COMMON (h->base.from) - || (DECL_INITIAL (h->base.from) - && DECL_INITIAL (h->base.from) != error_mark_node)) - return 1; - - word_type_node = lang_hooks.types.type_for_mode (word_mode, 1); - - /* The idea was to call get_emutls_init_templ_addr here, but if we - do this and there is an initializer, -fanchor_section loses, - because it would be too late to ensure the template is - output. */ - x = built_in_decls[BUILT_IN_EMUTLS_REGISTER_COMMON]; - x = build_call_expr (x, 4, - build_fold_addr_expr (h->to), - fold_convert (word_type_node, - DECL_SIZE_UNIT (h->base.from)), - build_int_cst (word_type_node, - DECL_ALIGN_UNIT (h->base.from)), - null_pointer_node); - - append_to_statement_list (x, pstmts); - return 1; -} - -/* Callback to finalize one emutls control variable. */ - -static int -emutls_finalize_control_var (void **loc, - void *unused ATTRIBUTE_UNUSED) -{ - struct tree_map *h = *(struct tree_map **) loc; - if (h != NULL) - { - struct varpool_node *node = varpool_node (h->to); - /* Because varpool_finalize_decl () has side-effects, - only apply to un-finalized vars. */ - if (node && !node->finalized) - varpool_finalize_decl (h->to); - } - return 1; -} - -/* Finalize emutls control vars and add a static constructor if - required. */ - -void -emutls_finish (void) -{ - if (emutls_htab == NULL) - return; - htab_traverse_noresize (emutls_htab, - emutls_finalize_control_var, NULL); - - if (targetm.emutls.register_common) - { - tree body = NULL_TREE; - - htab_traverse_noresize (emutls_htab, emutls_common_1, &body); - if (body == NULL_TREE) - return; - - cgraph_build_static_cdtor ('I', body, DEFAULT_INIT_PRIORITY); - } -} - /* Helper routines for maintaining section_htab. */ static int @@ -1210,11 +899,6 @@ get_variable_section (tree decl, bool prefer_noswitch_p) && ADDR_SPACE_GENERIC_P (as)); if (DECL_THREAD_LOCAL_P (decl)) return tls_comm_section; - /* This cannot be common bss for an emulated TLS object without - a register_common hook. */ - else if (DECL_TLS_MODEL (decl) == TLS_MODEL_EMULATED - && !targetm.emutls.register_common) - ; else if (TREE_PUBLIC (decl) && bss_initializer_p (decl)) return comm_section; } @@ -2098,40 +1782,6 @@ assemble_variable_contents (tree decl, const char *name, } } -/* Initialize emulated tls object TO, which refers to TLS variable - DECL and is initialized by PROXY. */ - -tree -default_emutls_var_init (tree to, tree decl, tree proxy) -{ - VEC(constructor_elt,gc) *v = VEC_alloc (constructor_elt, gc, 4); - constructor_elt *elt; - tree type = TREE_TYPE (to); - tree field = TYPE_FIELDS (type); - - elt = VEC_quick_push (constructor_elt, v, NULL); - elt->index = field; - elt->value = fold_convert (TREE_TYPE (field), DECL_SIZE_UNIT (decl)); - - elt = VEC_quick_push (constructor_elt, v, NULL); - field = DECL_CHAIN (field); - elt->index = field; - elt->value = build_int_cst (TREE_TYPE (field), - DECL_ALIGN_UNIT (decl)); - - elt = VEC_quick_push (constructor_elt, v, NULL); - field = DECL_CHAIN (field); - elt->index = field; - elt->value = null_pointer_node; - - elt = VEC_quick_push (constructor_elt, v, NULL); - field = DECL_CHAIN (field); - elt->index = field; - elt->value = proxy; - - return build_constructor (type, v); -} - /* Assemble everything that is needed for a variable or function declaration. Not used for automatic variables, and not used for function definitions. Should not be called for variables of incomplete structure type. @@ -2153,35 +1803,9 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED, /* This function is supposed to handle VARIABLES. Ensure we have one. */ gcc_assert (TREE_CODE (decl) == VAR_DECL); - if (! targetm.have_tls - && TREE_CODE (decl) == VAR_DECL - && DECL_THREAD_LOCAL_P (decl)) - { - tree to = emutls_decl (decl); - - /* If this variable is defined locally, then we need to initialize the - control structure with size and alignment information. We do this - at the last moment because tentative definitions can take a locally - defined but uninitialized variable and initialize it later, which - would result in incorrect contents. */ - if (! DECL_EXTERNAL (to) - && (! DECL_COMMON (to) - || (DECL_INITIAL (decl) - && DECL_INITIAL (decl) != error_mark_node))) - { - DECL_INITIAL (to) = targetm.emutls.var_init - (to, decl, get_emutls_init_templ_addr (decl)); - - /* Make sure the template is marked as needed early enough. - Without this, if the variable is placed in a - section-anchored block, the template will only be marked - when it's too late. */ - record_references_in_initializer (to, false); - } - - decl = to; - } - + /* Emulated TLS had better not get this far. */ + gcc_checking_assert (targetm.have_tls || !DECL_THREAD_LOCAL_P (decl)); + last_assemble_variable_decl = 0; /* Normally no need to say anything here for external references, @@ -5685,6 +5309,11 @@ find_decl_and_mark_needed (tree decl, tree target) static void do_assemble_alias (tree decl, tree target) { + /* Emulated TLS had better not get this var. */ + gcc_assert(!(!targetm.have_tls + && TREE_CODE (decl) == VAR_DECL + && DECL_THREAD_LOCAL_P (decl))); + if (TREE_ASM_WRITTEN (decl)) return; @@ -5699,14 +5328,6 @@ do_assemble_alias (tree decl, tree target) { ultimate_transparent_alias_target (&target); - if (!targetm.have_tls - && TREE_CODE (decl) == VAR_DECL - && DECL_THREAD_LOCAL_P (decl)) - { - decl = emutls_decl (decl); - target = get_emutls_object_name (target); - } - if (!TREE_SYMBOL_REFERENCED (target)) weakref_targets = tree_cons (decl, target, weakref_targets); @@ -5725,14 +5346,6 @@ do_assemble_alias (tree decl, tree target) return; } - if (!targetm.have_tls - && TREE_CODE (decl) == VAR_DECL - && DECL_THREAD_LOCAL_P (decl)) - { - decl = emutls_decl (decl); - target = get_emutls_object_name (target); - } - #ifdef ASM_OUTPUT_DEF /* Make name accessible from other files, if appropriate. */ @@ -6400,24 +6013,11 @@ categorize_decl_for_section (const_tree decl, int reloc) ret = SECCAT_RODATA; /* There are no read-only thread-local sections. */ - if (TREE_CODE (decl) == VAR_DECL && DECL_TLS_MODEL (decl)) + if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl)) { - if (DECL_TLS_MODEL (decl) == TLS_MODEL_EMULATED) - { - if (DECL_EMUTLS_VAR_P (decl)) - { - if (targetm.emutls.var_section) - ret = SECCAT_EMUTLS_VAR; - } - else - { - if (targetm.emutls.tmpl_prefix) - ret = SECCAT_EMUTLS_TMPL; - } - } /* Note that this would be *just* SECCAT_BSS, except that there's no concept of a read-only thread-local-data section. */ - else if (ret == SECCAT_BSS + if (ret == SECCAT_BSS || (flag_zero_initialized_in_bss && initializer_zerop (DECL_INITIAL (decl)))) ret = SECCAT_TBSS; @@ -6511,12 +6111,6 @@ default_elf_select_section (tree decl, int reloc, case SECCAT_TBSS: sname = ".tbss"; break; - case SECCAT_EMUTLS_VAR: - sname = targetm.emutls.var_section; - break; - case SECCAT_EMUTLS_TMPL: - sname = targetm.emutls.tmpl_section; - break; default: gcc_unreachable (); } @@ -6581,12 +6175,6 @@ default_unique_section (tree decl, int reloc) case SECCAT_TBSS: prefix = one_only ? ".tb" : ".tbss"; break; - case SECCAT_EMUTLS_VAR: - prefix = targetm.emutls.var_section; - break; - case SECCAT_EMUTLS_TMPL: - prefix = targetm.emutls.tmpl_section; - break; default: gcc_unreachable (); } @@ -6697,8 +6285,7 @@ default_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED) flags |= SYMBOL_FLAG_FUNCTION; if (targetm.binds_local_p (decl)) flags |= SYMBOL_FLAG_LOCAL; - if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl) - && DECL_TLS_MODEL (decl) != TLS_MODEL_EMULATED) + if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl)) flags |= DECL_TLS_MODEL (decl) << SYMBOL_FLAG_TLS_SHIFT; else if (targetm.in_small_data_p (decl)) flags |= SYMBOL_FLAG_SMALL; diff --git a/gcc/varpool.c b/gcc/varpool.c index 94c949e..dcf3518 100644 --- a/gcc/varpool.c +++ b/gcc/varpool.c @@ -346,17 +346,6 @@ decide_is_variable_needed (struct varpool_node *node, tree decl) && !DECL_EXTERNAL (decl)) return true; - /* When emulating tls, we actually see references to the control - variable, rather than the user-level variable. */ - if (!targetm.have_tls - && TREE_CODE (decl) == VAR_DECL - && DECL_THREAD_LOCAL_P (decl)) - { - tree control = emutls_decl (decl); - if (decide_is_variable_needed (varpool_node (control), control)) - return true; - } - /* When not reordering top level variables, we have to assume that we are going to keep everything. */ if (flag_toplevel_reorder) diff --git a/gcc/fortran/f95-lang.c b/gcc/fortran/f95-lang.c index 5b67621..9d0bf44 100644 --- a/gcc/fortran/f95-lang.c +++ b/gcc/fortran/f95-lang.c @@ -88,6 +88,7 @@ static void gfc_init_builtin_functions (void); /* Each front end provides its own. */ static bool gfc_init (void); static void gfc_finish (void); +static void gfc_write_global_declarations (void); static void gfc_print_identifier (FILE *, tree, int); void do_function_end (void); int global_bindings_p (void); @@ -99,6 +100,7 @@ static void gfc_init_ts (void); #undef LANG_HOOKS_NAME #undef LANG_HOOKS_INIT #undef LANG_HOOKS_FINISH +#undef LANG_HOOKS_WRITE_GLOBALS #undef LANG_HOOKS_INIT_OPTIONS #undef LANG_HOOKS_HANDLE_OPTION #undef LANG_HOOKS_POST_OPTIONS @@ -127,6 +129,7 @@ static void gfc_init_ts (void); #define LANG_HOOKS_NAME "GNU Fortran" #define LANG_HOOKS_INIT gfc_init #define LANG_HOOKS_FINISH gfc_finish +#define LANG_HOOKS_WRITE_GLOBALS gfc_write_global_declarations #define LANG_HOOKS_INIT_OPTIONS gfc_init_options #define LANG_HOOKS_HANDLE_OPTION gfc_handle_option #define LANG_HOOKS_POST_OPTIONS gfc_post_options @@ -282,6 +285,33 @@ gfc_finish (void) return; } +/* ??? This is something of a hack. + + Emulated tls lowering needs to see all TLS variables before we call + cgraph_finalize_compilation_unit. The C/C++ front ends manage this + by calling decl_rest_of_compilation on each global and static variable + as they are seen. The Fortran front end waits until this hook. + + A Correct solution is for cgraph_finalize_compilation_unit not to be + called during the WRITE_GLOBALS langhook, and have that hook only do what + its name suggests and write out globals. But the C++ and Java front ends + have (unspecified) problems with aliases that gets in the way. It has + been suggested that these problems would be solved by completing the + conversion to cgraph-based aliases. */ + +static void +gfc_write_global_declarations (void) +{ + tree decl; + + /* Finalize all of the globals. */ + for (decl = getdecls(); decl ; decl = DECL_CHAIN (decl)) + rest_of_decl_compilation (decl, true, true); + + write_global_declarations (); +} + + static void gfc_print_identifier (FILE * file ATTRIBUTE_UNUSED, tree node ATTRIBUTE_UNUSED,