LCOV - code coverage report
Current view: top level - gcc - tree-emutls.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 1.7 % 363 6
Test Date: 2026-02-28 14:20:25 Functions: 10.0 % 20 2
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Lower TLS operations to emulation functions.
       2              :    Copyright (C) 2006-2026 Free Software Foundation, Inc.
       3              : 
       4              : This file is part of GCC.
       5              : 
       6              : GCC is free software; you can redistribute it and/or modify it
       7              : under the terms of the GNU General Public License as published by the
       8              : Free Software Foundation; either version 3, or (at your option) any
       9              : later version.
      10              : 
      11              : GCC is distributed in the hope that it will be useful, but WITHOUT
      12              : ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      13              : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      14              : for more details.
      15              : 
      16              : You should have received a copy of the GNU General Public License
      17              : along with GCC; see the file COPYING3.  If not see
      18              : <http://www.gnu.org/licenses/>.  */
      19              : 
      20              : #include "config.h"
      21              : #include "system.h"
      22              : #include "coretypes.h"
      23              : #include "backend.h"
      24              : #include "target.h"
      25              : #include "tree.h"
      26              : #include "gimple.h"
      27              : #include "tree-pass.h"
      28              : #include "ssa.h"
      29              : #include "cgraph.h"
      30              : #include "fold-const.h"
      31              : #include "stor-layout.h"
      32              : #include "varasm.h"
      33              : #include "gimple-iterator.h"
      34              : #include "gimple-walk.h"
      35              : #include "langhooks.h"
      36              : #include "tree-iterator.h"
      37              : #include "gimplify.h"
      38              : #include "diagnostic-core.h" /* for seen_error */
      39              : 
      40              : /* Whenever a target does not support thread-local storage (TLS) natively,
      41              :    we can emulate it with some run-time support in libgcc.  This will in
      42              :    turn rely on "keyed storage" a-la pthread_key_create; essentially all
      43              :    thread libraries provide such functionality.
      44              : 
      45              :    In order to coordinate with the libgcc runtime, each TLS variable is
      46              :    described by a "control variable".  This control variable records the
      47              :    required size, alignment, and initial value of the TLS variable for
      48              :    instantiation at runtime.  It also stores an integer token to be used
      49              :    by the runtime to find the address of the variable within each thread.
      50              : 
      51              :    On the compiler side, this means that we need to replace all instances
      52              :    of "tls_var" in the code with "*__emutls_get_addr(&control_var)".  We
      53              :    also need to eliminate "tls_var" from the symbol table and introduce
      54              :    "control_var".
      55              : 
      56              :    We used to perform all of the transformations during conversion to rtl,
      57              :    and the variable substitutions magically within assemble_variable.
      58              :    However, this late fiddling of the symbol table conflicts with LTO and
      59              :    whole-program compilation.  Therefore we must now make all the changes
      60              :    to the symbol table early in the GIMPLE optimization path, before we
      61              :    write things out to LTO intermediate files.  */
      62              : 
      63              : /* Value for TLS varpool node where a pointer to control variable and
      64              :    access variable are stored.  */
      65              : struct tls_var_data
      66              : {
      67              :   varpool_node *control_var;
      68              :   tree access;
      69              : };
      70              : 
      71              : /* TLS map accesses mapping between a TLS varpool node and a pair
      72              :    made by control variable and access variable.  */
      73              : static hash_map<varpool_node *, tls_var_data> *tls_map = NULL;
      74              : 
      75              : /* The type of the control structure, shared with the emutls.c runtime.  */
      76              : static tree emutls_object_type;
      77              : 
      78              : #if !defined (NO_DOT_IN_LABEL)
      79              : # define EMUTLS_SEPARATOR       "."
      80              : #elif !defined (NO_DOLLAR_IN_LABEL)
      81              : # define EMUTLS_SEPARATOR       "$"
      82              : #else
      83              : # define EMUTLS_SEPARATOR       "_"
      84              : #endif
      85              : 
      86              : /* Create an IDENTIFIER_NODE by prefixing PREFIX to the
      87              :    IDENTIFIER_NODE NAME's name.  */
      88              : 
      89              : static tree
      90            0 : prefix_name (const char *prefix, tree name)
      91              : {
      92            0 :   unsigned plen = strlen (prefix);
      93            0 :   unsigned nlen = strlen (IDENTIFIER_POINTER (name));
      94            0 :   char *toname = (char *) alloca (plen + nlen + 1);
      95              : 
      96            0 :   memcpy (toname, prefix, plen);
      97            0 :   memcpy (toname + plen, IDENTIFIER_POINTER (name), nlen + 1);
      98              : 
      99            0 :   return get_identifier (toname);
     100              : }
     101              : 
     102              : /* Create an identifier for the struct __emutls_object, given an identifier
     103              :    of the DECL_ASSEMBLY_NAME of the original object.  */
     104              : 
     105              : static tree
     106            0 : get_emutls_object_name (tree name)
     107              : {
     108            0 :   const char *prefix = (targetm.emutls.var_prefix
     109            0 :                         ? targetm.emutls.var_prefix
     110              :                         : "__emutls_v" EMUTLS_SEPARATOR);
     111            0 :   return prefix_name (prefix, name);
     112              : }
     113              : 
     114              : /* Create the fields of the type for the control variables.  Ordinarily
     115              :    this must match struct __emutls_object defined in emutls.c.  However
     116              :    this is a target hook so that VxWorks can define its own layout.  */
     117              : 
     118              : tree
     119            0 : default_emutls_var_fields (tree type, tree *name ATTRIBUTE_UNUSED)
     120              : {
     121            0 :   tree word_type_node, field, next_field;
     122              : 
     123            0 :   field = build_decl (UNKNOWN_LOCATION,
     124              :                       FIELD_DECL, get_identifier ("__templ"), ptr_type_node);
     125            0 :   DECL_CONTEXT (field) = type;
     126            0 :   next_field = field;
     127              : 
     128            0 :   field = build_decl (UNKNOWN_LOCATION,
     129              :                       FIELD_DECL, get_identifier ("__offset"),
     130              :                       ptr_type_node);
     131            0 :   DECL_CONTEXT (field) = type;
     132            0 :   DECL_CHAIN (field) = next_field;
     133            0 :   next_field = field;
     134              : 
     135            0 :   word_type_node = lang_hooks.types.type_for_mode (word_mode, 1);
     136            0 :   field = build_decl (UNKNOWN_LOCATION,
     137              :                       FIELD_DECL, get_identifier ("__align"),
     138              :                       word_type_node);
     139            0 :   DECL_CONTEXT (field) = type;
     140            0 :   DECL_CHAIN (field) = next_field;
     141            0 :   next_field = field;
     142              : 
     143            0 :   field = build_decl (UNKNOWN_LOCATION,
     144              :                       FIELD_DECL, get_identifier ("__size"), word_type_node);
     145            0 :   DECL_CONTEXT (field) = type;
     146            0 :   DECL_CHAIN (field) = next_field;
     147              : 
     148            0 :   return field;
     149              : }
     150              : 
     151              : /* Initialize emulated tls object TO, which refers to TLS variable DECL and
     152              :    is initialized by PROXY.  As above, this is the default implementation of
     153              :    a target hook overridden by VxWorks.  */
     154              : 
     155              : tree
     156            0 : default_emutls_var_init (tree to, tree decl, tree proxy)
     157              : {
     158            0 :   vec<constructor_elt, va_gc> *v;
     159            0 :   vec_alloc (v, 4);
     160            0 :   constructor_elt elt;
     161            0 :   tree type = TREE_TYPE (to);
     162            0 :   tree field = TYPE_FIELDS (type);
     163              : 
     164            0 :   elt.index = field;
     165            0 :   elt.value = fold_convert (TREE_TYPE (field), DECL_SIZE_UNIT (decl));
     166            0 :   v->quick_push (elt);
     167              : 
     168            0 :   field = DECL_CHAIN (field);
     169            0 :   elt.index = field;
     170            0 :   elt.value = build_int_cst (TREE_TYPE (field),
     171            0 :                              DECL_ALIGN_UNIT (decl));
     172            0 :   v->quick_push (elt);
     173              : 
     174            0 :   field = DECL_CHAIN (field);
     175            0 :   elt.index = field;
     176            0 :   elt.value = null_pointer_node;
     177            0 :   v->quick_push (elt);
     178              : 
     179            0 :   field = DECL_CHAIN (field);
     180            0 :   elt.index = field;
     181            0 :   elt.value = proxy;
     182            0 :   v->quick_push (elt);
     183              : 
     184            0 :   return build_constructor (type, v);
     185              : }
     186              : 
     187              : /* Create the structure for struct __emutls_object.  This should match the
     188              :    structure at the top of emutls.c, modulo the union there.  */
     189              : 
     190              : static tree
     191            0 : get_emutls_object_type (void)
     192              : {
     193            0 :   tree type, type_name, field;
     194              : 
     195            0 :   type = emutls_object_type;
     196            0 :   if (type)
     197              :     return type;
     198              : 
     199            0 :   emutls_object_type = type = lang_hooks.types.make_type (RECORD_TYPE);
     200            0 :   type_name = NULL;
     201            0 :   field = targetm.emutls.var_fields (type, &type_name);
     202            0 :   if (!type_name)
     203            0 :     type_name = get_identifier ("__emutls_object");
     204            0 :   type_name = build_decl (UNKNOWN_LOCATION,
     205              :                           TYPE_DECL, type_name, type);
     206            0 :   TYPE_NAME (type) = type_name;
     207            0 :   TYPE_FIELDS (type) = field;
     208            0 :   layout_type (type);
     209              : 
     210            0 :   return type;
     211              : }
     212              : 
     213              : /* Create a read-only variable like DECL, with the same DECL_INITIAL.
     214              :    This will be used for initializing the emulated tls data area.  */
     215              : 
     216              : static tree
     217            0 : get_emutls_init_templ_addr (tree decl)
     218              : {
     219            0 :   tree name, to;
     220              : 
     221            0 :   if (targetm.emutls.register_common && !DECL_INITIAL (decl)
     222            0 :       && !DECL_SECTION_NAME (decl))
     223            0 :     return null_pointer_node;
     224              : 
     225            0 :   name = DECL_ASSEMBLER_NAME (decl);
     226            0 :   if (!targetm.emutls.tmpl_prefix || targetm.emutls.tmpl_prefix[0])
     227              :     {
     228            0 :       const char *prefix = (targetm.emutls.tmpl_prefix
     229            0 :                             ? targetm.emutls.tmpl_prefix
     230              :                             : "__emutls_t" EMUTLS_SEPARATOR);
     231            0 :       name = prefix_name (prefix, name);
     232              :     }
     233              : 
     234            0 :   to = build_decl (DECL_SOURCE_LOCATION (decl),
     235            0 :                    VAR_DECL, name, TREE_TYPE (decl));
     236            0 :   SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to));
     237              : 
     238            0 :   DECL_ARTIFICIAL (to) = 1;
     239            0 :   TREE_USED (to) = TREE_USED (decl);
     240            0 :   TREE_READONLY (to) = 1;
     241            0 :   DECL_IGNORED_P (to) = 1;
     242            0 :   DECL_CONTEXT (to) = DECL_CONTEXT (decl);
     243            0 :   DECL_PRESERVE_P (to) = DECL_PRESERVE_P (decl);
     244              : 
     245            0 :   DECL_WEAK (to) = DECL_WEAK (decl);
     246            0 :   if (DECL_ONE_ONLY (decl) || DECL_WEAK (decl))
     247              :     {
     248            0 :       TREE_STATIC (to) = TREE_STATIC (decl);
     249            0 :       TREE_PUBLIC (to) = TREE_PUBLIC (decl);
     250            0 :       DECL_VISIBILITY (to) = DECL_VISIBILITY (decl);
     251              :     }
     252              :   else
     253            0 :     TREE_STATIC (to) = 1;
     254              : 
     255            0 :   if (DECL_ONE_ONLY (decl))
     256            0 :     make_decl_one_only (to, DECL_ASSEMBLER_NAME (to));
     257              : 
     258            0 :   DECL_VISIBILITY_SPECIFIED (to) = DECL_VISIBILITY_SPECIFIED (decl);
     259            0 :   DECL_INITIAL (to) = DECL_INITIAL (decl);
     260            0 :   DECL_INITIAL (decl) = NULL;
     261              : 
     262            0 :   if (targetm.emutls.tmpl_section)
     263            0 :     set_decl_section_name (to, targetm.emutls.tmpl_section);
     264              :   else
     265            0 :     set_decl_section_name (to, decl);
     266              : 
     267              :   /* Create varpool node for the new variable and finalize it if it is
     268              :      not external one.  */
     269            0 :   if (DECL_EXTERNAL (to))
     270            0 :     varpool_node::get_create (to);
     271              :   else
     272            0 :     varpool_node::add (to);
     273            0 :   return build_fold_addr_expr (to);
     274              : }
     275              : 
     276              : /* Create and return the control variable for the TLS variable DECL.  */
     277              : 
     278              : static tree
     279            0 : new_emutls_decl (tree decl, tree alias_of)
     280              : {
     281            0 :   tree name, to;
     282              : 
     283            0 :   name = DECL_ASSEMBLER_NAME (decl);
     284            0 :   to = build_decl (DECL_SOURCE_LOCATION (decl), VAR_DECL,
     285              :                    get_emutls_object_name (name),
     286              :                    get_emutls_object_type ());
     287              : 
     288            0 :   SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to));
     289              : 
     290            0 :   DECL_ARTIFICIAL (to) = 1;
     291            0 :   DECL_IGNORED_P (to) = 1;
     292            0 :   TREE_READONLY (to) = 0;
     293            0 :   TREE_STATIC (to) = 1;
     294              : 
     295            0 :   DECL_PRESERVE_P (to) = DECL_PRESERVE_P (decl);
     296            0 :   DECL_CONTEXT (to) = DECL_CONTEXT (decl);
     297            0 :   TREE_USED (to) = TREE_USED (decl);
     298            0 :   TREE_PUBLIC (to) = TREE_PUBLIC (decl);
     299            0 :   DECL_EXTERNAL (to) = DECL_EXTERNAL (decl);
     300            0 :   DECL_COMMON (to) = DECL_COMMON (decl);
     301            0 :   DECL_WEAK (to) = DECL_WEAK (decl);
     302            0 :   DECL_VISIBILITY (to) = DECL_VISIBILITY (decl);
     303            0 :   DECL_VISIBILITY_SPECIFIED (to) = DECL_VISIBILITY_SPECIFIED (decl);
     304            0 :   DECL_DLLIMPORT_P (to) = DECL_DLLIMPORT_P (decl);
     305              : 
     306            0 :   DECL_ATTRIBUTES (to) = targetm.merge_decl_attributes (decl, to);
     307              : 
     308            0 :   if (DECL_ONE_ONLY (decl))
     309            0 :     make_decl_one_only (to, DECL_ASSEMBLER_NAME (to));
     310              : 
     311            0 :   set_decl_tls_model (to, TLS_MODEL_EMULATED);
     312              : 
     313              :   /* If we're not allowed to change the proxy object's alignment,
     314              :      pretend it has been set by the user.  */
     315            0 :   if (targetm.emutls.var_align_fixed)
     316            0 :     DECL_USER_ALIGN (to) = 1;
     317              : 
     318              :   /* If the target wants the control variables grouped, do so.  */
     319            0 :   if (!DECL_COMMON (to) && targetm.emutls.var_section)
     320              :     {
     321            0 :       set_decl_section_name (to, targetm.emutls.var_section);
     322              :     }
     323              : 
     324              :   /* If this variable is defined locally, then we need to initialize the
     325              :      control structure with size and alignment information.  Initialization
     326              :      of COMMON block variables happens elsewhere via a constructor.  */
     327            0 :   if (!DECL_EXTERNAL (to)
     328            0 :       && (!DECL_COMMON (to) || !targetm.emutls.register_common
     329            0 :           || (DECL_INITIAL (decl)
     330            0 :               && DECL_INITIAL (decl) != error_mark_node)))
     331              :     {
     332            0 :       tree tmpl = get_emutls_init_templ_addr (decl);
     333            0 :       DECL_INITIAL (to) = targetm.emutls.var_init (to, decl, tmpl);
     334            0 :       record_references_in_initializer (to, false);
     335              :     }
     336              : 
     337              :   /* Create varpool node for the new variable and finalize it if it is
     338              :      not external one.  */
     339            0 :   if (DECL_EXTERNAL (to))
     340            0 :     varpool_node::get_create (to);
     341            0 :   else if (!alias_of)
     342            0 :     varpool_node::add (to);
     343              :   else
     344              :     {
     345            0 :       varpool_node *n;
     346            0 :       varpool_node *t = varpool_node::get_for_asmname
     347            0 :          (DECL_ASSEMBLER_NAME (DECL_VALUE_EXPR (alias_of)));
     348              : 
     349            0 :       n = varpool_node::create_alias (to, t->decl);
     350            0 :       n->resolve_alias (t);
     351              :     }
     352            0 :   return to;
     353              : }
     354              : 
     355              : /* Generate a call statement to initialize CONTROL_DECL for TLS_DECL.
     356              :    This only needs to happen for TLS COMMON variables; non-COMMON
     357              :    variables can be initialized statically.  Insert the generated
     358              :    call statement at the end of PSTMTS.  */
     359              : 
     360              : static void
     361            0 : emutls_common_1 (tree tls_decl, tree control_decl, tree *pstmts)
     362              : {
     363            0 :   tree x;
     364            0 :   tree word_type_node;
     365              : 
     366            0 :   if (!DECL_COMMON (tls_decl) || !targetm.emutls.register_common
     367            0 :       || (DECL_INITIAL (tls_decl)
     368            0 :           && DECL_INITIAL (tls_decl) != error_mark_node))
     369              :     return;
     370              : 
     371            0 :   word_type_node = lang_hooks.types.type_for_mode (word_mode, 1);
     372              : 
     373            0 :   x = build_call_expr (builtin_decl_explicit (BUILT_IN_EMUTLS_REGISTER_COMMON),
     374              :                        4, build_fold_addr_expr (control_decl),
     375            0 :                        fold_convert (word_type_node,
     376              :                                      DECL_SIZE_UNIT (tls_decl)),
     377              :                        build_int_cst (word_type_node,
     378            0 :                                       DECL_ALIGN_UNIT (tls_decl)),
     379              :                        get_emutls_init_templ_addr (tls_decl));
     380              : 
     381            0 :   append_to_statement_list (x, pstmts);
     382              : }
     383              : 
     384              : struct lower_emutls_data
     385              : {
     386              :   struct cgraph_node *cfun_node;
     387              :   struct cgraph_node *builtin_node;
     388              :   tree builtin_decl;
     389              :   basic_block bb;
     390              :   location_t loc;
     391              :   gimple_seq seq;
     392              : };
     393              : 
     394              : /* Given a TLS variable DECL, return an SSA_NAME holding its address.
     395              :    Append any new computation statements required to D->SEQ.  */
     396              : 
     397              : static tree
     398            0 : gen_emutls_addr (tree decl, struct lower_emutls_data *d, bool for_debug)
     399              : {
     400              :   /* Compute the address of the TLS variable with help from runtime.  */
     401            0 :   tls_var_data *data = tls_map->get (varpool_node::get (decl));
     402            0 :   tree addr = data->access;
     403              : 
     404            0 :   if (addr == NULL && !for_debug)
     405              :     {
     406            0 :       varpool_node *cvar;
     407            0 :       tree cdecl;
     408            0 :       gcall *x;
     409              : 
     410            0 :       cvar = data->control_var;
     411            0 :       cdecl = cvar->decl;
     412            0 :       TREE_ADDRESSABLE (cdecl) = 1;
     413              : 
     414            0 :       addr = create_tmp_var (build_pointer_type (TREE_TYPE (decl)));
     415            0 :       x = gimple_build_call (d->builtin_decl, 1, build_fold_addr_expr (cdecl));
     416            0 :       gimple_set_location (x, d->loc);
     417              : 
     418            0 :       addr = make_ssa_name (addr, x);
     419            0 :       gimple_call_set_lhs (x, addr);
     420              : 
     421            0 :       gimple_seq_add_stmt (&d->seq, x);
     422              : 
     423            0 :       d->cfun_node->create_edge (d->builtin_node, x, d->bb->count);
     424              : 
     425              :       /* We may be adding a new reference to a new variable to the function.
     426              :          This means we have to play with the ipa-reference web.  */
     427            0 :       d->cfun_node->create_reference (cvar, IPA_REF_ADDR, x);
     428              : 
     429              :       /* Record this ssa_name for possible use later in the basic block.  */
     430            0 :       data->access = addr;
     431              :     }
     432              : 
     433            0 :   return addr;
     434              : }
     435              : 
     436              : /* Callback for lower_emutls_1, return non-NULL if there is any TLS
     437              :    VAR_DECL in the subexpressions.  */
     438              : 
     439              : static tree
     440            0 : lower_emutls_2 (tree *ptr, int *walk_subtrees, void *)
     441              : {
     442            0 :   tree t = *ptr;
     443            0 :   if (VAR_P (t))
     444            0 :     return DECL_THREAD_LOCAL_P (t) ? t : NULL_TREE;
     445            0 :   else if (!EXPR_P (t))
     446            0 :     *walk_subtrees = 0;
     447              :   return NULL_TREE;
     448              : }
     449              : 
     450              : /* Callback for walk_gimple_op.  D = WI->INFO is a struct lower_emutls_data.
     451              :    Given an operand *PTR within D->STMT, if the operand references a TLS
     452              :    variable, then lower the reference to a call to the runtime.  Insert
     453              :    any new statements required into D->SEQ; the caller is responsible for
     454              :    placing those appropriately.  */
     455              : 
     456              : static tree
     457            0 : lower_emutls_1 (tree *ptr, int *walk_subtrees, void *cb_data)
     458              : {
     459            0 :   struct walk_stmt_info *wi = (struct walk_stmt_info *) cb_data;
     460            0 :   struct lower_emutls_data *d = (struct lower_emutls_data *) wi->info;
     461            0 :   tree t = *ptr;
     462            0 :   bool is_addr = false;
     463            0 :   tree addr;
     464              : 
     465            0 :   *walk_subtrees = 0;
     466              : 
     467            0 :   switch (TREE_CODE (t))
     468              :     {
     469            0 :     case ADDR_EXPR:
     470              :       /* If this is not a straight-forward "&var", but rather something
     471              :          like "&var.a", then we may need special handling.  */
     472            0 :       if (TREE_CODE (TREE_OPERAND (t, 0)) != VAR_DECL)
     473              :         {
     474            0 :           bool save_changed;
     475              : 
     476              :           /* Gimple invariants are shareable trees, so before changing
     477              :              anything in them if we will need to change anything, unshare
     478              :              them.  */
     479            0 :           if (is_gimple_min_invariant (t)
     480            0 :               && walk_tree (&TREE_OPERAND (t, 0), lower_emutls_2, NULL, NULL))
     481            0 :             *ptr = t = unshare_expr (t);
     482              : 
     483              :           /* If we're allowed more than just is_gimple_val, continue.  */
     484            0 :           if (!wi->val_only || is_gimple_debug (wi->stmt))
     485              :             {
     486            0 :               *walk_subtrees = 1;
     487            0 :               return NULL_TREE;
     488              :             }
     489              : 
     490              :           /* See if any substitution would be made.  */
     491            0 :           save_changed = wi->changed;
     492            0 :           wi->changed = false;
     493            0 :           wi->val_only = false;
     494            0 :           walk_tree (&TREE_OPERAND (t, 0), lower_emutls_1, wi, NULL);
     495            0 :           wi->val_only = true;
     496              : 
     497              :           /* If so, then extract this entire sub-expression "&p->a" into a
     498              :              new assignment statement, and substitute yet another SSA_NAME.  */
     499            0 :           if (wi->changed)
     500              :             {
     501            0 :               gimple *x;
     502              : 
     503            0 :               addr = create_tmp_var (TREE_TYPE (t));
     504            0 :               x = gimple_build_assign (addr, t);
     505            0 :               gimple_set_location (x, d->loc);
     506              : 
     507            0 :               addr = make_ssa_name (addr, x);
     508            0 :               gimple_assign_set_lhs (x, addr);
     509              : 
     510            0 :               gimple_seq_add_stmt (&d->seq, x);
     511              : 
     512            0 :               *ptr = addr;
     513              :             }
     514              :           else
     515            0 :             wi->changed = save_changed;
     516              : 
     517            0 :           return NULL_TREE;
     518              :         }
     519              : 
     520            0 :       t = TREE_OPERAND (t, 0);
     521            0 :       is_addr = true;
     522              :       /* FALLTHRU */
     523              : 
     524            0 :     case VAR_DECL:
     525            0 :       if (!DECL_THREAD_LOCAL_P (t))
     526            0 :         return NULL_TREE;
     527            0 :       break;
     528              : 
     529            0 :     default:
     530              :       /* We're not interested in other decls or types, only subexpressions.  */
     531            0 :       if (EXPR_P (t))
     532            0 :         *walk_subtrees = 1;
     533              :       /* FALLTHRU */
     534              : 
     535              :     case SSA_NAME:
     536              :       /* Special-case the return of SSA_NAME, since it's so common.  */
     537              :       return NULL_TREE;
     538              :     }
     539              : 
     540            0 :   addr = gen_emutls_addr (t, d, is_gimple_debug (wi->stmt));
     541            0 :   if (!addr)
     542              :     {
     543            0 :       gimple_debug_bind_reset_value (wi->stmt);
     544            0 :       update_stmt (wi->stmt);
     545            0 :       wi->changed = false;
     546              :       /* Stop walking operands.  */
     547            0 :       return error_mark_node;
     548              :     }
     549            0 :   if (is_addr)
     550              :     {
     551              :       /* Replace "&var" with "addr" in the statement.  */
     552            0 :       *ptr = addr;
     553              :     }
     554              :   else
     555              :     {
     556              :       /* Replace "var" with "*addr" in the statement.  */
     557            0 :       t = build2 (MEM_REF, TREE_TYPE (t), addr,
     558            0 :                   build_int_cst (TREE_TYPE (addr), 0));
     559            0 :       *ptr = t;
     560              :     }
     561              : 
     562            0 :   wi->changed = true;
     563            0 :   return NULL_TREE;
     564              : }
     565              : 
     566              : /* Lower all of the operands of STMT.  */
     567              : 
     568              : static void
     569            0 : lower_emutls_stmt (gimple *stmt, struct lower_emutls_data *d)
     570              : {
     571            0 :   struct walk_stmt_info wi;
     572              : 
     573            0 :   d->loc = gimple_location (stmt);
     574              : 
     575            0 :   memset (&wi, 0, sizeof (wi));
     576            0 :   wi.info = d;
     577            0 :   wi.val_only = true;
     578            0 :   walk_gimple_op (stmt, lower_emutls_1, &wi);
     579              : 
     580            0 :   if (wi.changed)
     581            0 :     update_stmt (stmt);
     582            0 : }
     583              : 
     584              : /* Lower the I'th operand of PHI.  */
     585              : 
     586              : static void
     587            0 : lower_emutls_phi_arg (gphi *phi, unsigned int i,
     588              :                       struct lower_emutls_data *d)
     589              : {
     590            0 :   struct walk_stmt_info wi;
     591            0 :   struct phi_arg_d *pd = gimple_phi_arg (phi, i);
     592              : 
     593              :   /* Early out for a very common case we don't care about.  */
     594            0 :   if (TREE_CODE (pd->def) == SSA_NAME)
     595            0 :     return;
     596              : 
     597            0 :   d->loc = pd->locus;
     598              : 
     599            0 :   memset (&wi, 0, sizeof (wi));
     600            0 :   wi.info = d;
     601            0 :   wi.val_only = true;
     602            0 :   wi.stmt = phi;
     603            0 :   walk_tree (&pd->def, lower_emutls_1, &wi, NULL);
     604              : 
     605              :   /* For normal statements, we let update_stmt do its job.  But for phi
     606              :      nodes, we have to manipulate the immediate use list by hand.  */
     607            0 :   if (wi.changed)
     608              :     {
     609            0 :       gcc_assert (TREE_CODE (pd->def) == SSA_NAME);
     610            0 :       link_imm_use_stmt (&pd->imm_use, pd->def, phi);
     611              :     }
     612              : }
     613              : 
     614              : /* Reset access variable for a given TLS variable data DATA.  */
     615              : 
     616              : bool
     617            0 : reset_access (varpool_node * const &, tls_var_data *data, void *)
     618              : {
     619            0 :   data->access = NULL;
     620              : 
     621            0 :   return true;
     622              : }
     623              : 
     624              : /* Clear the access variables, in order to begin a new block.  */
     625              : 
     626              : static inline void
     627            0 : clear_access_vars (void)
     628              : {
     629            0 :   tls_map->traverse<void *, reset_access> (NULL);
     630              : }
     631              : 
     632              : /* Lower the entire function NODE.  */
     633              : 
     634              : static void
     635            0 : lower_emutls_function_body (struct cgraph_node *node)
     636              : {
     637            0 :   struct lower_emutls_data d;
     638            0 :   bool any_edge_inserts = false;
     639              : 
     640            0 :   push_cfun (DECL_STRUCT_FUNCTION (node->decl));
     641              : 
     642            0 :   d.cfun_node = node;
     643            0 :   d.builtin_decl = builtin_decl_explicit (BUILT_IN_EMUTLS_GET_ADDRESS);
     644              :   /* This is where we introduce the declaration to the IL and so we have to
     645              :      create a node for it.  */
     646            0 :   d.builtin_node = cgraph_node::get_create (d.builtin_decl);
     647              : 
     648            0 :   FOR_EACH_BB_FN (d.bb, cfun)
     649              :     {
     650            0 :       unsigned int i, nedge;
     651              : 
     652              :       /* Lower each of the PHI nodes of the block, as we may have
     653              :          propagated &tlsvar into a PHI argument.  These loops are
     654              :          arranged so that we process each edge at once, and each
     655              :          PHI argument for that edge.  */
     656            0 :       if (!gimple_seq_empty_p (phi_nodes (d.bb)))
     657              :         {
     658            0 :           nedge = EDGE_COUNT (d.bb->preds);
     659            0 :           for (i = 0; i < nedge; ++i)
     660              :             {
     661            0 :               edge e = EDGE_PRED (d.bb, i);
     662              : 
     663              :               /* We can re-use any SSA_NAME created on this edge.  */
     664            0 :               clear_access_vars ();
     665            0 :               d.seq = NULL;
     666              : 
     667            0 :               for (gphi_iterator gsi = gsi_start_phis (d.bb);
     668            0 :                    !gsi_end_p (gsi);
     669            0 :                    gsi_next (&gsi))
     670            0 :                 lower_emutls_phi_arg (gsi.phi (), i, &d);
     671              : 
     672              :               /* Insert all statements generated by all phi nodes for this
     673              :                  particular edge all at once.  */
     674            0 :               if (d.seq)
     675              :                 {
     676            0 :                   gsi_insert_seq_on_edge (e, d.seq);
     677            0 :                   any_edge_inserts = true;
     678              :                 }
     679              :             }
     680              :         }
     681              : 
     682              :       /* We can re-use any SSA_NAME created during this basic block.  */
     683            0 :       clear_access_vars ();
     684              : 
     685              :       /* Lower each of the statements of the block.  */
     686            0 :       for (gimple_stmt_iterator gsi = gsi_start_bb (d.bb); !gsi_end_p (gsi);
     687            0 :            gsi_next (&gsi))
     688              :         {
     689            0 :           d.seq = NULL;
     690            0 :           lower_emutls_stmt (gsi_stmt (gsi), &d);
     691              : 
     692              :           /* If any new statements were created, insert them immediately
     693              :              before the first use.  This prevents variable lifetimes from
     694              :              becoming unnecessarily long.  */
     695            0 :           if (d.seq)
     696            0 :             gsi_insert_seq_before (&gsi, d.seq, GSI_SAME_STMT);
     697              :         }
     698              :     }
     699              : 
     700            0 :   if (any_edge_inserts)
     701            0 :     gsi_commit_edge_inserts ();
     702              : 
     703            0 :   pop_cfun ();
     704            0 : }
     705              : 
     706              : /* Create emutls variable for VAR, DATA is pointer to static
     707              :    ctor body we can add constructors to.
     708              :    Callback for varpool_for_variable_and_aliases.  */
     709              : 
     710              : static bool
     711            0 : create_emultls_var (varpool_node *var, void *data)
     712              : {
     713            0 :   tree cdecl;
     714            0 :   tls_var_data value;
     715              : 
     716            0 :   cdecl = new_emutls_decl (var->decl,
     717            0 :                            var->alias && var->analyzed
     718            0 :                            ? var->get_alias_target ()->decl : NULL);
     719              : 
     720            0 :   varpool_node *cvar = varpool_node::get (cdecl);
     721              : 
     722            0 :   if (!var->alias)
     723              :     {
     724              :       /* Make sure the COMMON block control variable gets initialized.
     725              :          Note that there's no point in doing this for aliases; we only
     726              :          need to do this once for the main variable.  */
     727            0 :       emutls_common_1 (var->decl, cdecl, (tree *)data);
     728              :     }
     729            0 :   if (var->alias && !var->analyzed)
     730            0 :     cvar->alias = true;
     731              : 
     732              :   /* Indicate that the value of the TLS variable may be found elsewhere,
     733              :      preventing the variable from re-appearing in the GIMPLE.  We cheat
     734              :      and use the control variable here (rather than a full call_expr),
     735              :      which is special-cased inside the DWARF2 output routines.  */
     736            0 :   SET_DECL_VALUE_EXPR (var->decl, cdecl);
     737            0 :   DECL_HAS_VALUE_EXPR_P (var->decl) = 1;
     738              : 
     739            0 :   value.control_var = cvar;
     740            0 :   tls_map->put (var, value);
     741              : 
     742            0 :   return false;
     743              : }
     744              : 
     745              : /* Main entry point to the tls lowering pass.  */
     746              : 
     747              : static unsigned int
     748            0 : ipa_lower_emutls (void)
     749              : {
     750            0 :   varpool_node *var;
     751            0 :   cgraph_node *func;
     752            0 :   bool any_aliases = false;
     753            0 :   tree ctor_body = NULL;
     754            0 :   hash_set <varpool_node *> visited;
     755            0 :   auto_vec <varpool_node *> tls_vars;
     756              : 
     757              :   /* Examine all global variables for TLS variables.  */
     758            0 :   FOR_EACH_VARIABLE (var)
     759            0 :     if (DECL_THREAD_LOCAL_P (var->decl)
     760            0 :         && !visited.add (var))
     761              :       {
     762            0 :         gcc_checking_assert (TREE_STATIC (var->decl)
     763              :                              || DECL_EXTERNAL (var->decl));
     764            0 :         tls_vars.safe_push (var);
     765            0 :         if (var->alias && var->definition
     766            0 :             && !visited.add (var->ultimate_alias_target ()))
     767            0 :           tls_vars.safe_push (var->ultimate_alias_target ());
     768              :       }
     769              : 
     770              :   /* If we found no TLS variables, then there is no further work to do.  */
     771            0 :   if (tls_vars.is_empty ())
     772              :     {
     773            0 :       if (dump_file)
     774            0 :         fprintf (dump_file, "No TLS variables found.\n");
     775            0 :       return 0;
     776              :     }
     777              : 
     778            0 :   tls_map = new hash_map <varpool_node *, tls_var_data> ();
     779              : 
     780              :   /* Create the control variables for each TLS variable.  */
     781            0 :   for (unsigned i = 0; i < tls_vars.length (); i++)
     782              :     {
     783            0 :       var = tls_vars[i];
     784              : 
     785            0 :       if (var->alias && !var->analyzed)
     786              :         any_aliases = true;
     787            0 :       else if (!var->alias)
     788            0 :         var->call_for_symbol_and_aliases (create_emultls_var, &ctor_body, true);
     789              :     }
     790              : 
     791              :   /* If there were any aliases, then frob the alias_pairs vector.  */
     792            0 :   if (any_aliases)
     793              :     {
     794              :       alias_pair *p;
     795              :       unsigned int i;
     796            0 :       FOR_EACH_VEC_SAFE_ELT (alias_pairs, i, p)
     797            0 :         if (DECL_THREAD_LOCAL_P (p->decl))
     798              :           {
     799            0 :             p->decl = tls_map->get
     800            0 :               (varpool_node::get (p->decl))->control_var->decl;
     801            0 :             p->target = get_emutls_object_name (p->target);
     802              :           }
     803              :     }
     804              : 
     805              :   /* Adjust all uses of TLS variables within the function bodies.  */
     806            0 :   FOR_EACH_DEFINED_FUNCTION (func)
     807            0 :     if (func->lowered)
     808            0 :       lower_emutls_function_body (func);
     809              : 
     810              :   /* Generate the constructor for any COMMON control variables created.  */
     811            0 :   if (ctor_body)
     812            0 :     cgraph_build_static_cdtor ('I', ctor_body, DEFAULT_INIT_PRIORITY);
     813              : 
     814            0 :   delete tls_map;
     815              : 
     816              :   return 0;
     817            0 : }
     818              : 
     819              : namespace {
     820              : 
     821              : const pass_data pass_data_ipa_lower_emutls =
     822              : {
     823              :   SIMPLE_IPA_PASS, /* type */
     824              :   "emutls", /* name */
     825              :   OPTGROUP_NONE, /* optinfo_flags */
     826              :   TV_IPA_OPT, /* tv_id */
     827              :   ( PROP_cfg | PROP_ssa ), /* properties_required */
     828              :   0, /* properties_provided */
     829              :   0, /* properties_destroyed */
     830              :   0, /* todo_flags_start */
     831              :   0, /* todo_flags_finish */
     832              : };
     833              : 
     834              : class pass_ipa_lower_emutls : public simple_ipa_opt_pass
     835              : {
     836              : public:
     837       285722 :   pass_ipa_lower_emutls (gcc::context *ctxt)
     838       571444 :     : simple_ipa_opt_pass (pass_data_ipa_lower_emutls, ctxt)
     839              :   {}
     840              : 
     841              :   /* opt_pass methods: */
     842       229960 :   bool gate (function *) final override
     843              :     {
     844              :       /* If the target supports TLS natively, we need do nothing here.  */
     845       229960 :       return !targetm.have_tls && !seen_error ();
     846              :     }
     847              : 
     848            0 :   unsigned int execute (function *) final override
     849              :   {
     850            0 :     return ipa_lower_emutls ();
     851              :   }
     852              : 
     853              : }; // class pass_ipa_lower_emutls
     854              : 
     855              : } // anon namespace
     856              : 
     857              : simple_ipa_opt_pass *
     858       285722 : make_pass_ipa_lower_emutls (gcc::context *ctxt)
     859              : {
     860       285722 :   return new pass_ipa_lower_emutls (ctxt);
     861              : }
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.