===================================================================
@@ -6862,21 +6862,7 @@ highest_pow2_factor_for_target (const_tree target,
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 arglist = build_tree_list (NULL_TREE, arg);
- tree call = build_function_call_expr (UNKNOWN_LOCATION, fn, arglist);
- 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
@@ -6980,17 +6966,6 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enu
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
@@ -8428,16 +8403,6 @@ expand_expr_real_1 (tree exp, rtx target, enum mac
&& (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:
===================================================================
@@ -1341,7 +1341,19 @@ gimplify_vla_decl (tree decl, gimple_seq *seq_p)
gimplify_ctxp->save_stack = true;
}
+/* 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 arglist = build_tree_list (NULL_TREE, arg);
+ tree call = build_function_call_expr (UNKNOWN_LOCATION, fn, arglist);
+ return fold_convert (build_pointer_type (TREE_TYPE (var)), call);
+}
+
/* Gimplifies a DECL_EXPR node *STMT_P by making any necessary allocation
and initialization explicit. */
@@ -1356,6 +1368,18 @@ gimplify_decl_expr (tree *stmt_p, gimple_seq *seq_
if (TREE_TYPE (decl) == error_mark_node)
return GS_ERROR;
+ /* TLS emulation hook - replace __thread VAR's &VAR with
+ __emutls_get_address (&_emutls.VAR). We then ignore the original
+ var. */
+ if (! targetm.have_tls
+ && TREE_CODE (decl) == VAR_DECL
+ && DECL_THREAD_LOCAL_P (decl))
+ {
+ stmt = build_fold_indirect_ref (emutls_var_address (decl));
+ gimplify_and_add (stmt, seq_p);
+ return GS_ALL_DONE;
+ }
+
if ((TREE_CODE (decl) == TYPE_DECL
|| TREE_CODE (decl) == VAR_DECL)
&& !TYPE_SIZES_GIMPLIFIED (TREE_TYPE (decl)))
@@ -1875,6 +1899,17 @@ gimplify_var_or_parm_decl (tree *expr_p)
return GS_ERROR;
}
+ /* TLS emulation hook - replace __thread VAR's &VAR with
+ __emutls_get_address (&_emutls.VAR). */
+ if (! targetm.have_tls
+ && TREE_CODE (decl) == VAR_DECL
+ && DECL_THREAD_LOCAL_P (decl))
+ {
+ gcc_assert (!DECL_HAS_VALUE_EXPR_P (decl)) ;
+ *expr_p = build_fold_indirect_ref (emutls_var_address (decl));
+ return GS_OK ;
+ }
+
/* When within an OpenMP context, notice uses of variables. */
if (gimplify_omp_ctxp && omp_notice_variable (gimplify_omp_ctxp, decl, true))
return GS_ALL_DONE;
@@ -5555,14 +5590,15 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx,
/* Threadprivate variables are predetermined. */
if (is_global_var (decl))
{
- if (DECL_THREAD_LOCAL_P (decl))
+ if ((DECL_TLS_MODEL (decl) >= TLS_MODEL_EMULATED))
return omp_notice_threadprivate_variable (ctx, decl, NULL_TREE);
if (DECL_HAS_VALUE_EXPR_P (decl))
{
tree value = get_base_address (DECL_VALUE_EXPR (decl));
- if (value && DECL_P (value) && DECL_THREAD_LOCAL_P (value))
+ if (value && DECL_P (value) &&
+ (DECL_TLS_MODEL (value) >= TLS_MODEL_EMULATED))
return omp_notice_threadprivate_variable (ctx, decl, value);
}
}
===================================================================
@@ -319,9 +319,11 @@ get_emutls_init_templ_addr (tree decl)
TREE_USED (to) = TREE_USED (decl);
TREE_READONLY (to) = 1;
DECL_IGNORED_P (to) = 1;
+
+ DECL_PRESERVE_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))
@@ -336,7 +338,6 @@ get_emutls_init_templ_addr (tree decl)
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);
@@ -361,6 +362,8 @@ emutls_decl (tree decl)
if (! emutls_htab)
emutls_htab = htab_create_ggc (512, tree_map_hash, tree_map_eq, 0);
+ gcc_assert (DECL_NAME (decl)) ;
+
name = DECL_ASSEMBLER_NAME (decl);
/* Note that we use the hash of the decl's name, rather than a hash
@@ -387,8 +390,7 @@ emutls_decl (tree decl)
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))
@@ -412,18 +414,42 @@ emutls_decl (tree decl)
TREE_STATIC (to) = TREE_STATIC (decl);
TREE_USED (to) = TREE_USED (decl);
TREE_PUBLIC (to) = TREE_PUBLIC (decl);
+ TREE_ADDRESSABLE (to) = TREE_ADDRESSABLE (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_PRESERVE_P (to) = DECL_PRESERVE_P (decl);
/* Fortran might pass this to us. */
DECL_RESTRICTED_P (to) = DECL_RESTRICTED_P (decl);
+
+ /* As soon as we see an initializer (and providing one is not already
+ present) we can setup the init. template. */
+ if (!DECL_INITIAL (to) &&
+ DECL_INITIAL (decl) && (DECL_INITIAL (decl) != error_mark_node))
+ if (! DECL_EXTERNAL (to) && ! DECL_COMMON (to))
+ {
+ 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);
+ /* We leave this marked, so that any attempt at duplicate
+ or re-initialization will give the appropriate error. */
+ DECL_INITIAL (decl) = error_mark_node ;
+ }
+ /* Say we are not interested in emitting this Var. */
+ TREE_ASM_WRITTEN (decl) = 1;
return to;
}
+/* Add static constructors for emutls vars, where required. */
+
static int
emutls_common_1 (void **loc, void *xstmts)
{
@@ -431,17 +457,21 @@ emutls_common_1 (void **loc, void *xstmts)
tree args, 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))
+ /* ??? It is not enough to check DECL_COMMON because variables might be
+ allocated in other uninitialized sections. However, this might still
+ not be an adequate test. */
+ if (DECL_INITIAL (h->to))
return 1;
+
+ /* Refuse to build a zero-sized item, first make sure there's
+ a valid layout. */
+ if (DECL_SIZE (h->base.from) == 0)
+ layout_decl (h->base.from, 0);
+
+ gcc_assert (DECL_SIZE (h->base.from) != 0);
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 = null_pointer_node;
args = tree_cons (NULL, x, NULL);
x = build_int_cst (word_type_node, DECL_ALIGN_UNIT (h->base.from));
@@ -468,6 +498,9 @@ emutls_finalize_control_var (void **loc,
if (h != NULL)
{
struct varpool_node *node = varpool_node (h->to);
+ gcc_assert (! DECL_THREAD_LOCAL_P (h->to));
+ if (TREE_USED (h->base.from))
+ TREE_USED (h->to) = 1;
/* Because varpool_finalize_decl () has side-effects,
only apply to un-finalized vars. */
if (node && !node->finalized)
@@ -791,6 +824,10 @@ asm_output_bss (FILE *file, tree decl ATTRIBUTE_UN
gcc_assert (strcmp (XSTR (XEXP (DECL_RTL (decl), 0), 0), name) == 0);
targetm.asm_out.globalize_decl_name (file, decl);
switch_to_section (bss_section);
+ /* We don't emit the userland vars for emulated TLS, just the control. */
+ gcc_assert (targetm.have_tls
+ || (TREE_CODE (decl) != VAR_DECL)
+ || !DECL_THREAD_LOCAL_P (decl));
#ifdef ASM_DECLARE_OBJECT_NAME
last_assemble_variable_decl = decl;
ASM_DECLARE_OBJECT_NAME (file, name, decl);
@@ -817,6 +854,10 @@ asm_output_aligned_bss (FILE *file, tree decl ATTR
{
switch_to_section (bss_section);
ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
+ /* We don't emit the userland vars for emulated TLS, just the control. */
+ gcc_assert (targetm.have_tls
+ || (TREE_CODE (decl) != VAR_DECL)
+ || !DECL_THREAD_LOCAL_P (decl));
#ifdef ASM_DECLARE_OBJECT_NAME
last_assemble_variable_decl = decl;
ASM_DECLARE_OBJECT_NAME (file, name, decl);
@@ -1232,7 +1273,12 @@ get_variable_section (tree decl, bool prefer_noswi
if (IN_NAMED_SECTION (decl))
return get_named_section (decl, NULL, reloc);
- if (ADDR_SPACE_GENERIC_P (as)
+ /* This cannot be lcomm for an emulated TLS object, without
+ a register_common hook. */
+ if (DECL_TLS_MODEL (decl) == TLS_MODEL_EMULATED
+ && !targetm.emutls.register_common)
+ ;
+ else if (ADDR_SPACE_GENERIC_P (as)
&& !DECL_THREAD_LOCAL_P (decl)
&& !(prefer_noswitch_p && targetm.have_switchable_bss_sections)
&& bss_initializer_p (decl))
@@ -2152,35 +2198,6 @@ assemble_variable (tree decl, int top_level ATTRIB
rtx decl_rtl, symbol;
section *sect;
- 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;
- }
-
last_assemble_variable_decl = 0;
/* Normally no need to say anything here for external references,
@@ -2196,6 +2213,14 @@ assemble_variable (tree decl, int top_level ATTRIB
if (TREE_CODE (decl) == FUNCTION_DECL)
return;
+ /* The first declaration of a variable that comes through this function
+ decides whether it is global (in C, has external linkage)
+ or local (in C, has internal linkage). So do nothing more
+ if this function has already run. */
+
+ if (TREE_ASM_WRITTEN (decl))
+ return;
+
/* Do nothing for global register variables. */
if (DECL_RTL_SET_P (decl) && REG_P (DECL_RTL (decl)))
{
@@ -2219,14 +2244,6 @@ assemble_variable (tree decl, int top_level ATTRIB
return;
}
- /* The first declaration of a variable that comes through this function
- decides whether it is global (in C, has external linkage)
- or local (in C, has internal linkage). So do nothing more
- if this function has already run. */
-
- if (TREE_ASM_WRITTEN (decl))
- return;
-
/* Make sure targetm.encode_section_info is invoked before we set
ASM_WRITTEN. */
decl_rtl = DECL_RTL (decl);
@@ -2237,6 +2254,12 @@ assemble_variable (tree decl, int top_level ATTRIB
if (flag_syntax_only)
return;
+ /* We don't emit the userland vars for emulated TLS - they should never
+ get to here, only the control vars should be emitted. */
+ gcc_assert (targetm.have_tls
+ || (TREE_CODE (decl) != VAR_DECL)
+ || !DECL_THREAD_LOCAL_P (decl));
+
if (! dont_output_data
&& ! host_integerp (DECL_SIZE_UNIT (decl), 1))
{
@@ -5700,18 +5723,14 @@ do_assemble_alias (tree decl, tree target)
TREE_ASM_WRITTEN (decl) = 1;
TREE_ASM_WRITTEN (DECL_ASSEMBLER_NAME (decl)) = 1;
+ gcc_assert (targetm.have_tls
+ || (TREE_CODE (decl) != VAR_DECL)
+ || !DECL_THREAD_LOCAL_P (decl));
+
if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))
{
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);
@@ -5730,14 +5749,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. */
@@ -5819,6 +5830,15 @@ remove_unreachable_alias_pairs (void)
}
}
+/* Lookup the decl for a symbol in the varpool. */
+static tree
+var_decl_for_asm (tree symbol)
+{
+ struct varpool_node *vnode = varpool_node_for_asm (symbol);
+ if (vnode)
+ return vnode->decl;
+ return NULL;
+}
/* First pass of completing pending aliases. Make sure that cgraph knows
which symbols will be required. */
@@ -5831,8 +5851,55 @@ finish_aliases_1 (void)
for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); i++)
{
- tree target_decl;
+ tree target_decl=NULL;
+ /* When emulated TLS is in effect, redirect aliases so that they
+ are registered between the control vars. */
+ if (!targetm.have_tls
+ && TREE_CODE (p->decl) == VAR_DECL
+ && (DECL_TLS_MODEL (p->decl) >= TLS_MODEL_EMULATED))
+ {
+ tree tsym = p->target ;
+ target_decl = var_decl_for_asm (tsym) ;
+ if (!target_decl)
+ {
+ /* If we didn't find the user's symbol, it could
+ be because the alias really refers to a control
+ var. */
+ tsym = get_emutls_object_name (p->target);
+ target_decl = var_decl_for_asm (tsym);
+ }
+ if (target_decl)
+ {
+ struct varpool_node *vnode;
+ /* If it hasn't been done already, substitute the control
+ var for the original. */
+ if (DECL_THREAD_LOCAL_P (p->decl))
+ p->decl = emutls_decl (p->decl);
+ /* If not TLS target, we've made a mistake. */
+ if (DECL_TLS_MODEL (target_decl) < TLS_MODEL_EMULATED)
+ error ("TLS symbol %q+D aliased to non-TLS symbol %qE",
+ p->decl, p->target);
+ /* If it's the original we need to substitute the contol. */
+ else if (DECL_THREAD_LOCAL_P (target_decl))
+ {
+ target_decl = emutls_decl (target_decl);
+ tsym = get_emutls_object_name (p->target);
+ }
+ /* else it's already the emulation control. */
+ /* Mark the var needed. */
+ vnode = varpool_node (target_decl);
+ if (vnode)
+ {
+ varpool_mark_needed_node (vnode);
+ vnode->force_output = 1;
+ }
+ p->target = tsym;
+ }
+ /* Else we didn't find a decl for the symbol, which is an error
+ unless there's a weak ref. */
+ }
+ else
target_decl = find_decl_and_mark_needed (p->decl, p->target);
if (target_decl == NULL)
{
===================================================================
@@ -152,6 +152,16 @@ rest_of_decl_compilation (tree decl,
int top_level,
int at_end)
{
+ if (! targetm.have_tls
+ && !in_lto_p
+ && TREE_CODE (decl) == VAR_DECL
+ && DECL_THREAD_LOCAL_P (decl))
+ {
+ /* Substitute the control var. for the user one. */
+ rest_of_decl_compilation (emutls_decl (decl), top_level, at_end);
+ return;
+ }
+
/* We deferred calling assemble_alias so that we could collect
other attributes such as visibility. Emit the alias now. */
{
===================================================================
@@ -312,6 +312,14 @@ varpool_mark_needed_node (struct varpool_node *nod
&& !TREE_ASM_WRITTEN (node->decl))
varpool_enqueue_needed_node (node);
node->needed = 1;
+ /* If we need the var, and it's an emulated TLS entity, that
+ means we need the control var. */
+ if (!targetm.have_tls && DECL_THREAD_LOCAL_P (node->decl))
+ {
+ struct varpool_node *cv_node;
+ cv_node = varpool_node (emutls_decl (node->decl)) ;
+ varpool_mark_needed_node (cv_node);
+ }
}
/* Reset the queue of needed nodes. */
@@ -346,17 +354,6 @@ decide_is_variable_needed (struct varpool_node *no
&& !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)
@@ -381,14 +378,19 @@ varpool_finalize_decl (tree decl)
or local (in C, has internal linkage). So do nothing more
if this function has already run. */
if (node->finalized)
+ return;
+
+ /* For emulated TLS vars, if we are in a position to finalize the userland
+ var, then we should be able to finalize the control var too. */
+ if (!targetm.have_tls && decl
+ && TREE_CODE (decl) == VAR_DECL
+ && DECL_THREAD_LOCAL_P (decl))
{
- if (cgraph_global_info_ready)
- varpool_assemble_pending_decls ();
+ varpool_finalize_decl (emutls_decl (decl)) ;
+ node->finalized = true;
return;
}
- if (node->needed)
- varpool_enqueue_needed_node (node);
- node->finalized = true;
+
if (TREE_THIS_VOLATILE (decl) || DECL_PRESERVE_P (decl))
node->force_output = true;
@@ -399,8 +401,11 @@ varpool_finalize_decl (tree decl)
there. */
else if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))
varpool_mark_needed_node (node);
- if (cgraph_global_info_ready)
- varpool_assemble_pending_decls ();
+
+ if (node->needed)
+ varpool_enqueue_needed_node (node);
+
+ node->finalized = true;
}
/* Return variable availability. See cgraph.h for description of individual
@@ -449,7 +454,7 @@ varpool_analyze_pending_decls (void)
already informed about increased alignment. */
align_variable (decl, 0);
}
- if (DECL_INITIAL (decl))
+ if (DECL_INITIAL (decl) && (DECL_INITIAL (decl) != error_mark_node))
record_references_in_initializer (decl, analyzed);
if (node->same_comdat_group)
{