re PR target/44132 (emutls is broken under a range of circumstances.)

PR target/44132
Emulated TLS rewrite.

From-SVN: r162549
This commit is contained in:
Richard Henderson 2010-07-26 15:53:50 -07:00
parent b57c6b13e0
commit 8b84c5966f
72 changed files with 1214 additions and 544 deletions

View File

@ -1,3 +1,40 @@
2010-07-26 Richard Henderson <rth@redhat.com>
PR target/44132
* tree-emutls.c: New file.
* Makefile.in (OBJS-common): Add it.
* tree-pass.h (pass_ipa_lower_emutls): Declare.
* passes.c (init_optimization_passes): Add it.
* dwarf2out.c (loc_list_from_tree): If emutls.debug_form_tls_address,
pull the control variable from DECL_VALUE_EXPR, not emutls_decl.
* expr.c (emutls_var_address): Delete.
(expand_expr_addr_expr_1, expand_expr_real_1): Don't use it.
* output.h (SECCAT_EMUTLS_VAR, SECCAT_EMUTLS_TMPL): Delete.
(emutls_finish): Delete.
* toplev.c (compile_file): Don't call it.
* tree.h (emutls_decl): Delete.
* varasm.c (emutls_htab, DECL_EMUTLS_VAR_P): Delete.
(emutls_finish, emutls_finalize_control_var): Delete.
(emutls_object_type): Move to tree-emutls.c.
(EMUTLS_SEPARATOR, prefix_name, get_emutls_object_name,
default_emutls_var_fields, get_emutls_object_type,
get_emutls_init_templ_addr, emutls_decl, emutls_common_1
default_emutls_var_init): Likewise.
(get_variable_section): Don't special case emutls.
(assemble_variable, do_assemble_alias, categorize_decl_for_section,
default_elf_select_section, default_unique_section,
default_encode_section_info): Likewise.
* varpool.c (decide_is_variable_needed): Likewise.
* gimple-iterator.c (update_call_edge_frequencies): New
(gsi_insert_on_edge_immediate): Use it.
(gsi_insert_seq_on_edge_immediate): Likewise.
(gsi_commit_one_edge_insert): Likewise.
* config/i386/i386.c (x86_64_elf_select_section): Don't handle
SECCAT_EMUTLS_VAR, SECCAT_EMUTLS_TMPL.
(x86_64_elf_unique_section): Likewise.
2010-07-26 Jan Hubicka <jh@suse.cz>
* lto-streamer.h (struct lto_file_decl_data): Mark resolutions with

View File

@ -1357,6 +1357,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 \
@ -3145,6 +3146,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) \

View File

@ -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)
{

View File

@ -15111,7 +15111,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;
}

View File

@ -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:

View File

@ -1,3 +1,9 @@
2010-07-26 Richard Henderson <rth@redhat.com>
PR target/44132
* f95-lang.c (LANG_HOOKS_WRITE_GLOBALS): New.
(gfc_write_global_declarations): New.
2010-07-26 Tobias Burnus <burnus@net-b.de>
PR fortran/45066

View File

@ -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,

View File

@ -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);

View File

@ -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. */

View File

@ -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;

View File

@ -1,3 +1,43 @@
2010-07-19 Iain Sandoe <iains@gcc.gnu.org>
Jack Howarth <howarth@bromo.med.uc.edu>
Richard Henderson <rth@redhat.com>
PR target/44132
* gcc.dg/tls/thr-init-1.c: New.
* gcc.dg/tls/thr-init-2.c: New.
* gcc.dg/torture/tls New.
* gcc.dg/torture/tls/tls-test.c: New.
* gcc.dg/torture/tls/thr-init-1.c: New.
* gcc.dg/torture/tls/tls.exp: New.
* gcc.dg/torture/tls/thr-init-2.c: New.
* gcc.dg/tls/emutls-2.c: New test
* g++.dg/gomp/clause-3.C: Require tls, not tls_native.
* g++.dg/gomp/copyin-1.C, g++.dg/gomp/pr35244.C,
g++.dg/gomp/sharing-1.C, g++.dg/gomp/tls-1.C, g++.dg/gomp/tls-2.C,
g++.dg/gomp/tls-3.C, g++.dg/gomp/tls-4.C, g++.dg/tls/diag-1.C,
g++.dg/tls/diag-2.C, g++.dg/tls/diag-3.C, g++.dg/tls/diag-4.C,
g++.dg/tls/diag-5.C, g++.dg/tls/init-1.C, g++.dg/tls/init-2.C,
g++.dg/tls/trivial.C, gcc.dg/gomp/appendix-a/a.22.1.c,
gcc.dg/gomp/appendix-a/a.22.2.c, gcc.dg/gomp/appendix-a/a.24.1.c,
gcc.dg/gomp/appendix-a/a.32.1.c, gcc.dg/gomp/appendix-a/a.33.1.c,
gcc.dg/gomp/clause-1.c, gcc.dg/gomp/copyin-1.c, gcc.dg/gomp/pr35244.c,
gcc.dg/gomp/sharing-1.c, gcc.dg/gomp/tls-1.c, gcc.dg/gomp/tls-2.c,
gcc.dg/tls/opt-1.c, gcc.dg/tls/opt-13.c, gcc.dg/tls/opt-14.c,
gcc.dg/tls/opt-15.c, gcc.dg/tls/opt-2.c, gcc.dg/tls/opt-3.c,
gcc.dg/tls/opt-7.c, gfortran.dg/gomp/appendix-a/a.22.1.f90,
gfortran.dg/gomp/appendix-a/a.22.4.f90,
gfortran.dg/gomp/appendix-a/a.22.5.f90,
gfortran.dg/gomp/appendix-a/a.22.6.f90,
gfortran.dg/gomp/appendix-a/a.24.1.f90,
gfortran.dg/gomp/appendix-a/a.32.1.f90,
gfortran.dg/gomp/appendix-a/a.33.1.f90, gfortran.dg/gomp/crayptr2.f90,
gfortran.dg/gomp/fixed-1.f, gfortran.dg/gomp/free-1.f90,
gfortran.dg/gomp/omp_threadprivate1.f90,
gfortran.dg/gomp/omp_threadprivate2.f90,
gfortran.dg/gomp/reduction1.f90,
gfortran.dg/gomp/sharing-1.f90: Likewise.
2010-07-26 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
* g++.dg/torture/pr44900.C: Use dg-require-effective-target

View File

@ -1,5 +1,5 @@
// { dg-do compile }
// { dg-require-effective-target tls_native }
// { dg-require-effective-target tls }
#define p parallel

View File

@ -1,5 +1,5 @@
// { dg-do compile }
// { dg-require-effective-target tls_native }
// { dg-require-effective-target tls }
int i, j;

View File

@ -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;

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-require-effective-target tls_native } */
/* { dg-require-effective-target tls } */
int thrglobalvar;
#pragma omp threadprivate (thrglobalvar)

View File

@ -1,5 +1,5 @@
// { dg-do compile }
// { dg-require-effective-target tls_native }
// { dg-require-effective-target tls }
int tp1;
static int tp2;

View File

@ -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" } */

View File

@ -1,5 +1,5 @@
// { dg-do compile }
// { dg-require-effective-target tls_native }
// { dg-require-effective-target tls }
#define thr threadprivate

View File

@ -1,5 +1,5 @@
// { dg-do compile }
// { dg-require-effective-target tls_native }
// { dg-require-effective-target tls }
#define thr threadprivate

View File

@ -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;

View File

@ -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'" } */

View File

@ -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" }

View File

@ -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" } */

View File

@ -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" }

View File

@ -1,5 +1,5 @@
/* Valid initializations. */
/* { dg-require-effective-target tls_native } */
/* { dg-require-effective-target tls } */
__thread int i = 42;

View File

@ -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" } */

View File

@ -1,3 +1,3 @@
// { dg-require-effective-target tls_native }
// { dg-require-effective-target tls }
__thread int i;

View File

@ -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)

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-require-effective-target tls_native } */
/* { dg-require-effective-target tls } */
int
increment_counter_2 ()

View File

@ -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];

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-require-effective-target tls_native } */
/* { dg-require-effective-target tls } */
#include <stdlib.h>
float *work;

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-require-effective-target tls_native } */
/* { dg-require-effective-target tls } */
#include <stdio.h>
float x, y;

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-require-effective-target tls_native } */
/* { dg-require-effective-target tls } */
#define p parallel

View File

@ -1,5 +1,5 @@
// { dg-do compile }
// { dg-require-effective-target tls_native }
// { dg-require-effective-target tls }
int i, j;

View File

@ -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;

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-require-effective-target tls_native } */
/* { dg-require-effective-target tls } */
#include <stdlib.h>

View File

@ -1,5 +1,5 @@
// { dg-do compile }
// { dg-require-effective-target tls_native }
// { dg-require-effective-target tls }
int tp1;
static int tp2;

View File

@ -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" } */

View File

@ -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));

View File

@ -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;

View File

@ -1,6 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-O2" } */
/* { dg-require-effective-target tls_native } */
/* { dg-require-effective-target tls } */
__thread struct
{

View File

@ -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
{

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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")));

View File

@ -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 } */

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -0,0 +1,52 @@
/* { dg-do run } */
/* { dg-require-effective-target tls } */
/* { dg-require-effective-target pthread } */
/* { dg-options "-pthread" } */
#include <pthread.h>
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;
}

View File

@ -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
# <http://www.gnu.org/licenses/>.
# 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

View File

@ -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

View File

@ -1,5 +1,5 @@
! { dg-do compile }
! { dg-require-effective-target tls_native }
! { dg-require-effective-target tls }
MODULE A22_MODULE
COMMON /T/ A

View File

@ -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

View File

@ -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

View File

@ -1,5 +1,5 @@
! { dg-do compile }
! { dg-require-effective-target tls_native }
! { dg-require-effective-target tls }
SUBROUTINE A24(A)
INTEGER A

View File

@ -1,5 +1,5 @@
! { dg-do compile }
! { dg-require-effective-target tls_native }
! { dg-require-effective-target tls }
MODULE M
REAL, POINTER, SAVE :: WORK(:)

View File

@ -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

View File

@ -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" }

View File

@ -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

View File

@ -1,4 +1,4 @@
! { dg-require-effective-target tls_native }
! { dg-require-effective-target tls }
subroutine foo
integer, save :: i ! Some comment

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -959,11 +959,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 ();

802
gcc/tree-emutls.c Normal file
View File

@ -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
<http://www.gnu.org/licenses/>. */
#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 */
}
};

View File

@ -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;

View File

@ -5257,7 +5257,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 */

View File

@ -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;

View File

@ -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)