11debfc3dSmrg /* Lower TLS operations to emulation functions.
2*8feb0f0bSmrg Copyright (C) 2006-2020 Free Software Foundation, Inc.
31debfc3dSmrg
41debfc3dSmrg This file is part of GCC.
51debfc3dSmrg
61debfc3dSmrg GCC is free software; you can redistribute it and/or modify it
71debfc3dSmrg under the terms of the GNU General Public License as published by the
81debfc3dSmrg Free Software Foundation; either version 3, or (at your option) any
91debfc3dSmrg later version.
101debfc3dSmrg
111debfc3dSmrg GCC is distributed in the hope that it will be useful, but WITHOUT
121debfc3dSmrg ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
131debfc3dSmrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
141debfc3dSmrg for more details.
151debfc3dSmrg
161debfc3dSmrg You should have received a copy of the GNU General Public License
171debfc3dSmrg along with GCC; see the file COPYING3. If not see
181debfc3dSmrg <http://www.gnu.org/licenses/>. */
191debfc3dSmrg
201debfc3dSmrg #include "config.h"
211debfc3dSmrg #include "system.h"
221debfc3dSmrg #include "coretypes.h"
231debfc3dSmrg #include "backend.h"
241debfc3dSmrg #include "target.h"
251debfc3dSmrg #include "tree.h"
261debfc3dSmrg #include "gimple.h"
271debfc3dSmrg #include "tree-pass.h"
281debfc3dSmrg #include "ssa.h"
291debfc3dSmrg #include "cgraph.h"
301debfc3dSmrg #include "fold-const.h"
311debfc3dSmrg #include "stor-layout.h"
321debfc3dSmrg #include "varasm.h"
331debfc3dSmrg #include "gimple-iterator.h"
341debfc3dSmrg #include "gimple-walk.h"
351debfc3dSmrg #include "langhooks.h"
361debfc3dSmrg #include "tree-iterator.h"
371debfc3dSmrg #include "gimplify.h"
381debfc3dSmrg
391debfc3dSmrg /* Whenever a target does not support thread-local storage (TLS) natively,
401debfc3dSmrg we can emulate it with some run-time support in libgcc. This will in
411debfc3dSmrg turn rely on "keyed storage" a-la pthread_key_create; essentially all
421debfc3dSmrg thread libraries provide such functionality.
431debfc3dSmrg
441debfc3dSmrg In order to coordinate with the libgcc runtime, each TLS variable is
451debfc3dSmrg described by a "control variable". This control variable records the
461debfc3dSmrg required size, alignment, and initial value of the TLS variable for
471debfc3dSmrg instantiation at runtime. It also stores an integer token to be used
481debfc3dSmrg by the runtime to find the address of the variable within each thread.
491debfc3dSmrg
501debfc3dSmrg On the compiler side, this means that we need to replace all instances
511debfc3dSmrg of "tls_var" in the code with "*__emutls_get_addr(&control_var)". We
521debfc3dSmrg also need to eliminate "tls_var" from the symbol table and introduce
531debfc3dSmrg "control_var".
541debfc3dSmrg
551debfc3dSmrg We used to perform all of the transformations during conversion to rtl,
561debfc3dSmrg and the variable substitutions magically within assemble_variable.
571debfc3dSmrg However, this late fiddling of the symbol table conflicts with LTO and
581debfc3dSmrg whole-program compilation. Therefore we must now make all the changes
591debfc3dSmrg to the symbol table early in the GIMPLE optimization path, before we
601debfc3dSmrg write things out to LTO intermediate files. */
611debfc3dSmrg
621debfc3dSmrg /* Value for TLS varpool node where a pointer to control variable and
631debfc3dSmrg access variable are stored. */
641debfc3dSmrg struct tls_var_data
651debfc3dSmrg {
661debfc3dSmrg varpool_node *control_var;
671debfc3dSmrg tree access;
681debfc3dSmrg };
691debfc3dSmrg
701debfc3dSmrg /* TLS map accesses mapping between a TLS varpool node and a pair
711debfc3dSmrg made by control variable and access variable. */
721debfc3dSmrg static hash_map<varpool_node *, tls_var_data> *tls_map = NULL;
731debfc3dSmrg
741debfc3dSmrg /* The type of the control structure, shared with the emutls.c runtime. */
751debfc3dSmrg static tree emutls_object_type;
761debfc3dSmrg
771debfc3dSmrg #if !defined (NO_DOT_IN_LABEL)
781debfc3dSmrg # define EMUTLS_SEPARATOR "."
791debfc3dSmrg #elif !defined (NO_DOLLAR_IN_LABEL)
801debfc3dSmrg # define EMUTLS_SEPARATOR "$"
811debfc3dSmrg #else
821debfc3dSmrg # define EMUTLS_SEPARATOR "_"
831debfc3dSmrg #endif
841debfc3dSmrg
851debfc3dSmrg /* Create an IDENTIFIER_NODE by prefixing PREFIX to the
861debfc3dSmrg IDENTIFIER_NODE NAME's name. */
871debfc3dSmrg
881debfc3dSmrg static tree
prefix_name(const char * prefix,tree name)891debfc3dSmrg prefix_name (const char *prefix, tree name)
901debfc3dSmrg {
911debfc3dSmrg unsigned plen = strlen (prefix);
921debfc3dSmrg unsigned nlen = strlen (IDENTIFIER_POINTER (name));
931debfc3dSmrg char *toname = (char *) alloca (plen + nlen + 1);
941debfc3dSmrg
951debfc3dSmrg memcpy (toname, prefix, plen);
961debfc3dSmrg memcpy (toname + plen, IDENTIFIER_POINTER (name), nlen + 1);
971debfc3dSmrg
981debfc3dSmrg return get_identifier (toname);
991debfc3dSmrg }
1001debfc3dSmrg
1011debfc3dSmrg /* Create an identifier for the struct __emutls_object, given an identifier
1021debfc3dSmrg of the DECL_ASSEMBLY_NAME of the original object. */
1031debfc3dSmrg
1041debfc3dSmrg static tree
get_emutls_object_name(tree name)1051debfc3dSmrg get_emutls_object_name (tree name)
1061debfc3dSmrg {
1071debfc3dSmrg const char *prefix = (targetm.emutls.var_prefix
1081debfc3dSmrg ? targetm.emutls.var_prefix
1091debfc3dSmrg : "__emutls_v" EMUTLS_SEPARATOR);
1101debfc3dSmrg return prefix_name (prefix, name);
1111debfc3dSmrg }
1121debfc3dSmrg
1131debfc3dSmrg /* Create the fields of the type for the control variables. Ordinarily
1141debfc3dSmrg this must match struct __emutls_object defined in emutls.c. However
1151debfc3dSmrg this is a target hook so that VxWorks can define its own layout. */
1161debfc3dSmrg
1171debfc3dSmrg tree
default_emutls_var_fields(tree type,tree * name ATTRIBUTE_UNUSED)1181debfc3dSmrg default_emutls_var_fields (tree type, tree *name ATTRIBUTE_UNUSED)
1191debfc3dSmrg {
1201debfc3dSmrg tree word_type_node, field, next_field;
1211debfc3dSmrg
1221debfc3dSmrg field = build_decl (UNKNOWN_LOCATION,
1231debfc3dSmrg FIELD_DECL, get_identifier ("__templ"), ptr_type_node);
1241debfc3dSmrg DECL_CONTEXT (field) = type;
1251debfc3dSmrg next_field = field;
1261debfc3dSmrg
1271debfc3dSmrg field = build_decl (UNKNOWN_LOCATION,
1281debfc3dSmrg FIELD_DECL, get_identifier ("__offset"),
1291debfc3dSmrg ptr_type_node);
1301debfc3dSmrg DECL_CONTEXT (field) = type;
1311debfc3dSmrg DECL_CHAIN (field) = next_field;
1321debfc3dSmrg next_field = field;
1331debfc3dSmrg
1341debfc3dSmrg word_type_node = lang_hooks.types.type_for_mode (word_mode, 1);
1351debfc3dSmrg field = build_decl (UNKNOWN_LOCATION,
1361debfc3dSmrg FIELD_DECL, get_identifier ("__align"),
1371debfc3dSmrg word_type_node);
1381debfc3dSmrg DECL_CONTEXT (field) = type;
1391debfc3dSmrg DECL_CHAIN (field) = next_field;
1401debfc3dSmrg next_field = field;
1411debfc3dSmrg
1421debfc3dSmrg field = build_decl (UNKNOWN_LOCATION,
1431debfc3dSmrg FIELD_DECL, get_identifier ("__size"), word_type_node);
1441debfc3dSmrg DECL_CONTEXT (field) = type;
1451debfc3dSmrg DECL_CHAIN (field) = next_field;
1461debfc3dSmrg
1471debfc3dSmrg return field;
1481debfc3dSmrg }
1491debfc3dSmrg
1501debfc3dSmrg /* Initialize emulated tls object TO, which refers to TLS variable DECL and
1511debfc3dSmrg is initialized by PROXY. As above, this is the default implementation of
1521debfc3dSmrg a target hook overridden by VxWorks. */
1531debfc3dSmrg
1541debfc3dSmrg tree
default_emutls_var_init(tree to,tree decl,tree proxy)1551debfc3dSmrg default_emutls_var_init (tree to, tree decl, tree proxy)
1561debfc3dSmrg {
1571debfc3dSmrg vec<constructor_elt, va_gc> *v;
1581debfc3dSmrg vec_alloc (v, 4);
1591debfc3dSmrg constructor_elt elt;
1601debfc3dSmrg tree type = TREE_TYPE (to);
1611debfc3dSmrg tree field = TYPE_FIELDS (type);
1621debfc3dSmrg
1631debfc3dSmrg elt.index = field;
1641debfc3dSmrg elt.value = fold_convert (TREE_TYPE (field), DECL_SIZE_UNIT (decl));
1651debfc3dSmrg v->quick_push (elt);
1661debfc3dSmrg
1671debfc3dSmrg field = DECL_CHAIN (field);
1681debfc3dSmrg elt.index = field;
1691debfc3dSmrg elt.value = build_int_cst (TREE_TYPE (field),
1701debfc3dSmrg DECL_ALIGN_UNIT (decl));
1711debfc3dSmrg v->quick_push (elt);
1721debfc3dSmrg
1731debfc3dSmrg field = DECL_CHAIN (field);
1741debfc3dSmrg elt.index = field;
1751debfc3dSmrg elt.value = null_pointer_node;
1761debfc3dSmrg v->quick_push (elt);
1771debfc3dSmrg
1781debfc3dSmrg field = DECL_CHAIN (field);
1791debfc3dSmrg elt.index = field;
1801debfc3dSmrg elt.value = proxy;
1811debfc3dSmrg v->quick_push (elt);
1821debfc3dSmrg
1831debfc3dSmrg return build_constructor (type, v);
1841debfc3dSmrg }
1851debfc3dSmrg
1861debfc3dSmrg /* Create the structure for struct __emutls_object. This should match the
1871debfc3dSmrg structure at the top of emutls.c, modulo the union there. */
1881debfc3dSmrg
1891debfc3dSmrg static tree
get_emutls_object_type(void)1901debfc3dSmrg get_emutls_object_type (void)
1911debfc3dSmrg {
1921debfc3dSmrg tree type, type_name, field;
1931debfc3dSmrg
1941debfc3dSmrg type = emutls_object_type;
1951debfc3dSmrg if (type)
1961debfc3dSmrg return type;
1971debfc3dSmrg
1981debfc3dSmrg emutls_object_type = type = lang_hooks.types.make_type (RECORD_TYPE);
1991debfc3dSmrg type_name = NULL;
2001debfc3dSmrg field = targetm.emutls.var_fields (type, &type_name);
2011debfc3dSmrg if (!type_name)
2021debfc3dSmrg type_name = get_identifier ("__emutls_object");
2031debfc3dSmrg type_name = build_decl (UNKNOWN_LOCATION,
2041debfc3dSmrg TYPE_DECL, type_name, type);
2051debfc3dSmrg TYPE_NAME (type) = type_name;
2061debfc3dSmrg TYPE_FIELDS (type) = field;
2071debfc3dSmrg layout_type (type);
2081debfc3dSmrg
2091debfc3dSmrg return type;
2101debfc3dSmrg }
2111debfc3dSmrg
2121debfc3dSmrg /* Create a read-only variable like DECL, with the same DECL_INITIAL.
2131debfc3dSmrg This will be used for initializing the emulated tls data area. */
2141debfc3dSmrg
2151debfc3dSmrg static tree
get_emutls_init_templ_addr(tree decl)2161debfc3dSmrg get_emutls_init_templ_addr (tree decl)
2171debfc3dSmrg {
2181debfc3dSmrg tree name, to;
2191debfc3dSmrg
2201debfc3dSmrg if (targetm.emutls.register_common && !DECL_INITIAL (decl)
2211debfc3dSmrg && !DECL_SECTION_NAME (decl))
2221debfc3dSmrg return null_pointer_node;
2231debfc3dSmrg
2241debfc3dSmrg name = DECL_ASSEMBLER_NAME (decl);
2251debfc3dSmrg if (!targetm.emutls.tmpl_prefix || targetm.emutls.tmpl_prefix[0])
2261debfc3dSmrg {
2271debfc3dSmrg const char *prefix = (targetm.emutls.tmpl_prefix
2281debfc3dSmrg ? targetm.emutls.tmpl_prefix
2291debfc3dSmrg : "__emutls_t" EMUTLS_SEPARATOR);
2301debfc3dSmrg name = prefix_name (prefix, name);
2311debfc3dSmrg }
2321debfc3dSmrg
2331debfc3dSmrg to = build_decl (DECL_SOURCE_LOCATION (decl),
2341debfc3dSmrg VAR_DECL, name, TREE_TYPE (decl));
2351debfc3dSmrg SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to));
2361debfc3dSmrg
2371debfc3dSmrg DECL_ARTIFICIAL (to) = 1;
2381debfc3dSmrg TREE_USED (to) = TREE_USED (decl);
2391debfc3dSmrg TREE_READONLY (to) = 1;
2401debfc3dSmrg DECL_IGNORED_P (to) = 1;
2411debfc3dSmrg DECL_CONTEXT (to) = DECL_CONTEXT (decl);
2421debfc3dSmrg DECL_PRESERVE_P (to) = DECL_PRESERVE_P (decl);
2431debfc3dSmrg
2441debfc3dSmrg DECL_WEAK (to) = DECL_WEAK (decl);
245*8feb0f0bSmrg if (DECL_ONE_ONLY (decl) || DECL_WEAK (decl))
2461debfc3dSmrg {
2471debfc3dSmrg TREE_STATIC (to) = TREE_STATIC (decl);
2481debfc3dSmrg TREE_PUBLIC (to) = TREE_PUBLIC (decl);
2491debfc3dSmrg DECL_VISIBILITY (to) = DECL_VISIBILITY (decl);
2501debfc3dSmrg }
2511debfc3dSmrg else
2521debfc3dSmrg TREE_STATIC (to) = 1;
2531debfc3dSmrg
254*8feb0f0bSmrg if (DECL_ONE_ONLY (decl))
255*8feb0f0bSmrg make_decl_one_only (to, DECL_ASSEMBLER_NAME (to));
256*8feb0f0bSmrg
2571debfc3dSmrg DECL_VISIBILITY_SPECIFIED (to) = DECL_VISIBILITY_SPECIFIED (decl);
2581debfc3dSmrg DECL_INITIAL (to) = DECL_INITIAL (decl);
2591debfc3dSmrg DECL_INITIAL (decl) = NULL;
2601debfc3dSmrg
2611debfc3dSmrg if (targetm.emutls.tmpl_section)
2621debfc3dSmrg set_decl_section_name (to, targetm.emutls.tmpl_section);
2631debfc3dSmrg else
2641debfc3dSmrg set_decl_section_name (to, DECL_SECTION_NAME (decl));
2651debfc3dSmrg
2661debfc3dSmrg /* Create varpool node for the new variable and finalize it if it is
2671debfc3dSmrg not external one. */
2681debfc3dSmrg if (DECL_EXTERNAL (to))
2691debfc3dSmrg varpool_node::get_create (to);
2701debfc3dSmrg else
2711debfc3dSmrg varpool_node::add (to);
2721debfc3dSmrg return build_fold_addr_expr (to);
2731debfc3dSmrg }
2741debfc3dSmrg
2751debfc3dSmrg /* Create and return the control variable for the TLS variable DECL. */
2761debfc3dSmrg
2771debfc3dSmrg static tree
new_emutls_decl(tree decl,tree alias_of)2781debfc3dSmrg new_emutls_decl (tree decl, tree alias_of)
2791debfc3dSmrg {
2801debfc3dSmrg tree name, to;
2811debfc3dSmrg
2821debfc3dSmrg name = DECL_ASSEMBLER_NAME (decl);
2831debfc3dSmrg to = build_decl (DECL_SOURCE_LOCATION (decl), VAR_DECL,
2841debfc3dSmrg get_emutls_object_name (name),
2851debfc3dSmrg get_emutls_object_type ());
2861debfc3dSmrg
2871debfc3dSmrg SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to));
2881debfc3dSmrg
2891debfc3dSmrg DECL_ARTIFICIAL (to) = 1;
2901debfc3dSmrg DECL_IGNORED_P (to) = 1;
2911debfc3dSmrg TREE_READONLY (to) = 0;
2921debfc3dSmrg TREE_STATIC (to) = 1;
2931debfc3dSmrg
2941debfc3dSmrg DECL_PRESERVE_P (to) = DECL_PRESERVE_P (decl);
2951debfc3dSmrg DECL_CONTEXT (to) = DECL_CONTEXT (decl);
2961debfc3dSmrg TREE_USED (to) = TREE_USED (decl);
2971debfc3dSmrg TREE_PUBLIC (to) = TREE_PUBLIC (decl);
2981debfc3dSmrg DECL_EXTERNAL (to) = DECL_EXTERNAL (decl);
2991debfc3dSmrg DECL_COMMON (to) = DECL_COMMON (decl);
3001debfc3dSmrg DECL_WEAK (to) = DECL_WEAK (decl);
3011debfc3dSmrg DECL_VISIBILITY (to) = DECL_VISIBILITY (decl);
3021debfc3dSmrg DECL_VISIBILITY_SPECIFIED (to) = DECL_VISIBILITY_SPECIFIED (decl);
3031debfc3dSmrg DECL_DLLIMPORT_P (to) = DECL_DLLIMPORT_P (decl);
3041debfc3dSmrg
3051debfc3dSmrg DECL_ATTRIBUTES (to) = targetm.merge_decl_attributes (decl, to);
3061debfc3dSmrg
3071debfc3dSmrg if (DECL_ONE_ONLY (decl))
3081debfc3dSmrg make_decl_one_only (to, DECL_ASSEMBLER_NAME (to));
3091debfc3dSmrg
3101debfc3dSmrg set_decl_tls_model (to, TLS_MODEL_EMULATED);
3111debfc3dSmrg
3121debfc3dSmrg /* If we're not allowed to change the proxy object's alignment,
3131debfc3dSmrg pretend it has been set by the user. */
3141debfc3dSmrg if (targetm.emutls.var_align_fixed)
3151debfc3dSmrg DECL_USER_ALIGN (to) = 1;
3161debfc3dSmrg
3171debfc3dSmrg /* If the target wants the control variables grouped, do so. */
3181debfc3dSmrg if (!DECL_COMMON (to) && targetm.emutls.var_section)
3191debfc3dSmrg {
3201debfc3dSmrg set_decl_section_name (to, targetm.emutls.var_section);
3211debfc3dSmrg }
3221debfc3dSmrg
3231debfc3dSmrg /* If this variable is defined locally, then we need to initialize the
3241debfc3dSmrg control structure with size and alignment information. Initialization
3251debfc3dSmrg of COMMON block variables happens elsewhere via a constructor. */
3261debfc3dSmrg if (!DECL_EXTERNAL (to)
327*8feb0f0bSmrg && (!DECL_COMMON (to) || !targetm.emutls.register_common
3281debfc3dSmrg || (DECL_INITIAL (decl)
3291debfc3dSmrg && DECL_INITIAL (decl) != error_mark_node)))
3301debfc3dSmrg {
3311debfc3dSmrg tree tmpl = get_emutls_init_templ_addr (decl);
3321debfc3dSmrg DECL_INITIAL (to) = targetm.emutls.var_init (to, decl, tmpl);
3331debfc3dSmrg record_references_in_initializer (to, false);
3341debfc3dSmrg }
3351debfc3dSmrg
3361debfc3dSmrg /* Create varpool node for the new variable and finalize it if it is
3371debfc3dSmrg not external one. */
3381debfc3dSmrg if (DECL_EXTERNAL (to))
3391debfc3dSmrg varpool_node::get_create (to);
3401debfc3dSmrg else if (!alias_of)
3411debfc3dSmrg varpool_node::add (to);
3421debfc3dSmrg else
3431debfc3dSmrg {
3441debfc3dSmrg varpool_node *n;
3451debfc3dSmrg varpool_node *t = varpool_node::get_for_asmname
3461debfc3dSmrg (DECL_ASSEMBLER_NAME (DECL_VALUE_EXPR (alias_of)));
3471debfc3dSmrg
3481debfc3dSmrg n = varpool_node::create_alias (to, t->decl);
3491debfc3dSmrg n->resolve_alias (t);
3501debfc3dSmrg }
3511debfc3dSmrg return to;
3521debfc3dSmrg }
3531debfc3dSmrg
3541debfc3dSmrg /* Generate a call statement to initialize CONTROL_DECL for TLS_DECL.
3551debfc3dSmrg This only needs to happen for TLS COMMON variables; non-COMMON
3561debfc3dSmrg variables can be initialized statically. Insert the generated
3571debfc3dSmrg call statement at the end of PSTMTS. */
3581debfc3dSmrg
3591debfc3dSmrg static void
emutls_common_1(tree tls_decl,tree control_decl,tree * pstmts)3601debfc3dSmrg emutls_common_1 (tree tls_decl, tree control_decl, tree *pstmts)
3611debfc3dSmrg {
3621debfc3dSmrg tree x;
3631debfc3dSmrg tree word_type_node;
3641debfc3dSmrg
365*8feb0f0bSmrg if (!DECL_COMMON (tls_decl) || !targetm.emutls.register_common
3661debfc3dSmrg || (DECL_INITIAL (tls_decl)
3671debfc3dSmrg && DECL_INITIAL (tls_decl) != error_mark_node))
3681debfc3dSmrg return;
3691debfc3dSmrg
3701debfc3dSmrg word_type_node = lang_hooks.types.type_for_mode (word_mode, 1);
3711debfc3dSmrg
3721debfc3dSmrg x = build_call_expr (builtin_decl_explicit (BUILT_IN_EMUTLS_REGISTER_COMMON),
3731debfc3dSmrg 4, build_fold_addr_expr (control_decl),
3741debfc3dSmrg fold_convert (word_type_node,
3751debfc3dSmrg DECL_SIZE_UNIT (tls_decl)),
3761debfc3dSmrg build_int_cst (word_type_node,
3771debfc3dSmrg DECL_ALIGN_UNIT (tls_decl)),
3781debfc3dSmrg get_emutls_init_templ_addr (tls_decl));
3791debfc3dSmrg
3801debfc3dSmrg append_to_statement_list (x, pstmts);
3811debfc3dSmrg }
3821debfc3dSmrg
3831debfc3dSmrg struct lower_emutls_data
3841debfc3dSmrg {
3851debfc3dSmrg struct cgraph_node *cfun_node;
3861debfc3dSmrg struct cgraph_node *builtin_node;
3871debfc3dSmrg tree builtin_decl;
3881debfc3dSmrg basic_block bb;
3891debfc3dSmrg location_t loc;
3901debfc3dSmrg gimple_seq seq;
3911debfc3dSmrg };
3921debfc3dSmrg
3931debfc3dSmrg /* Given a TLS variable DECL, return an SSA_NAME holding its address.
3941debfc3dSmrg Append any new computation statements required to D->SEQ. */
3951debfc3dSmrg
3961debfc3dSmrg static tree
gen_emutls_addr(tree decl,struct lower_emutls_data * d)3971debfc3dSmrg gen_emutls_addr (tree decl, struct lower_emutls_data *d)
3981debfc3dSmrg {
3991debfc3dSmrg /* Compute the address of the TLS variable with help from runtime. */
4001debfc3dSmrg tls_var_data *data = tls_map->get (varpool_node::get (decl));
4011debfc3dSmrg tree addr = data->access;
4021debfc3dSmrg
4031debfc3dSmrg if (addr == NULL)
4041debfc3dSmrg {
4051debfc3dSmrg varpool_node *cvar;
4061debfc3dSmrg tree cdecl;
4071debfc3dSmrg gcall *x;
4081debfc3dSmrg
4091debfc3dSmrg cvar = data->control_var;
4101debfc3dSmrg cdecl = cvar->decl;
4111debfc3dSmrg TREE_ADDRESSABLE (cdecl) = 1;
4121debfc3dSmrg
4131debfc3dSmrg addr = create_tmp_var (build_pointer_type (TREE_TYPE (decl)));
4141debfc3dSmrg x = gimple_build_call (d->builtin_decl, 1, build_fold_addr_expr (cdecl));
4151debfc3dSmrg gimple_set_location (x, d->loc);
4161debfc3dSmrg
4171debfc3dSmrg addr = make_ssa_name (addr, x);
4181debfc3dSmrg gimple_call_set_lhs (x, addr);
4191debfc3dSmrg
4201debfc3dSmrg gimple_seq_add_stmt (&d->seq, x);
4211debfc3dSmrg
422a2dc1f3fSmrg d->cfun_node->create_edge (d->builtin_node, x, d->bb->count);
4231debfc3dSmrg
4241debfc3dSmrg /* We may be adding a new reference to a new variable to the function.
4251debfc3dSmrg This means we have to play with the ipa-reference web. */
4261debfc3dSmrg d->cfun_node->create_reference (cvar, IPA_REF_ADDR, x);
4271debfc3dSmrg
4281debfc3dSmrg /* Record this ssa_name for possible use later in the basic block. */
4291debfc3dSmrg data->access = addr;
4301debfc3dSmrg }
4311debfc3dSmrg
4321debfc3dSmrg return addr;
4331debfc3dSmrg }
4341debfc3dSmrg
4351debfc3dSmrg /* Callback for lower_emutls_1, return non-NULL if there is any TLS
4361debfc3dSmrg VAR_DECL in the subexpressions. */
4371debfc3dSmrg
4381debfc3dSmrg static tree
lower_emutls_2(tree * ptr,int * walk_subtrees,void *)4391debfc3dSmrg lower_emutls_2 (tree *ptr, int *walk_subtrees, void *)
4401debfc3dSmrg {
4411debfc3dSmrg tree t = *ptr;
4421debfc3dSmrg if (TREE_CODE (t) == VAR_DECL)
4431debfc3dSmrg return DECL_THREAD_LOCAL_P (t) ? t : NULL_TREE;
4441debfc3dSmrg else if (!EXPR_P (t))
4451debfc3dSmrg *walk_subtrees = 0;
4461debfc3dSmrg return NULL_TREE;
4471debfc3dSmrg }
4481debfc3dSmrg
4491debfc3dSmrg /* Callback for walk_gimple_op. D = WI->INFO is a struct lower_emutls_data.
4501debfc3dSmrg Given an operand *PTR within D->STMT, if the operand references a TLS
4511debfc3dSmrg variable, then lower the reference to a call to the runtime. Insert
4521debfc3dSmrg any new statements required into D->SEQ; the caller is responsible for
4531debfc3dSmrg placing those appropriately. */
4541debfc3dSmrg
4551debfc3dSmrg static tree
lower_emutls_1(tree * ptr,int * walk_subtrees,void * cb_data)4561debfc3dSmrg lower_emutls_1 (tree *ptr, int *walk_subtrees, void *cb_data)
4571debfc3dSmrg {
4581debfc3dSmrg struct walk_stmt_info *wi = (struct walk_stmt_info *) cb_data;
4591debfc3dSmrg struct lower_emutls_data *d = (struct lower_emutls_data *) wi->info;
4601debfc3dSmrg tree t = *ptr;
4611debfc3dSmrg bool is_addr = false;
4621debfc3dSmrg tree addr;
4631debfc3dSmrg
4641debfc3dSmrg *walk_subtrees = 0;
4651debfc3dSmrg
4661debfc3dSmrg switch (TREE_CODE (t))
4671debfc3dSmrg {
4681debfc3dSmrg case ADDR_EXPR:
4691debfc3dSmrg /* If this is not a straight-forward "&var", but rather something
4701debfc3dSmrg like "&var.a", then we may need special handling. */
4711debfc3dSmrg if (TREE_CODE (TREE_OPERAND (t, 0)) != VAR_DECL)
4721debfc3dSmrg {
4731debfc3dSmrg bool save_changed;
4741debfc3dSmrg
4751debfc3dSmrg /* Gimple invariants are shareable trees, so before changing
4761debfc3dSmrg anything in them if we will need to change anything, unshare
4771debfc3dSmrg them. */
4781debfc3dSmrg if (is_gimple_min_invariant (t)
4791debfc3dSmrg && walk_tree (&TREE_OPERAND (t, 0), lower_emutls_2, NULL, NULL))
4801debfc3dSmrg *ptr = t = unshare_expr (t);
4811debfc3dSmrg
4821debfc3dSmrg /* If we're allowed more than just is_gimple_val, continue. */
4831debfc3dSmrg if (!wi->val_only)
4841debfc3dSmrg {
4851debfc3dSmrg *walk_subtrees = 1;
4861debfc3dSmrg return NULL_TREE;
4871debfc3dSmrg }
4881debfc3dSmrg
4891debfc3dSmrg /* See if any substitution would be made. */
4901debfc3dSmrg save_changed = wi->changed;
4911debfc3dSmrg wi->changed = false;
4921debfc3dSmrg wi->val_only = false;
4931debfc3dSmrg walk_tree (&TREE_OPERAND (t, 0), lower_emutls_1, wi, NULL);
4941debfc3dSmrg wi->val_only = true;
4951debfc3dSmrg
4961debfc3dSmrg /* If so, then extract this entire sub-expression "&p->a" into a
4971debfc3dSmrg new assignment statement, and substitute yet another SSA_NAME. */
4981debfc3dSmrg if (wi->changed)
4991debfc3dSmrg {
5001debfc3dSmrg gimple *x;
5011debfc3dSmrg
5021debfc3dSmrg addr = create_tmp_var (TREE_TYPE (t));
5031debfc3dSmrg x = gimple_build_assign (addr, t);
5041debfc3dSmrg gimple_set_location (x, d->loc);
5051debfc3dSmrg
5061debfc3dSmrg addr = make_ssa_name (addr, x);
5071debfc3dSmrg gimple_assign_set_lhs (x, addr);
5081debfc3dSmrg
5091debfc3dSmrg gimple_seq_add_stmt (&d->seq, x);
5101debfc3dSmrg
5111debfc3dSmrg *ptr = addr;
5121debfc3dSmrg }
5131debfc3dSmrg else
5141debfc3dSmrg wi->changed = save_changed;
5151debfc3dSmrg
5161debfc3dSmrg return NULL_TREE;
5171debfc3dSmrg }
5181debfc3dSmrg
5191debfc3dSmrg t = TREE_OPERAND (t, 0);
5201debfc3dSmrg is_addr = true;
5211debfc3dSmrg /* FALLTHRU */
5221debfc3dSmrg
5231debfc3dSmrg case VAR_DECL:
5241debfc3dSmrg if (!DECL_THREAD_LOCAL_P (t))
5251debfc3dSmrg return NULL_TREE;
5261debfc3dSmrg break;
5271debfc3dSmrg
5281debfc3dSmrg default:
5291debfc3dSmrg /* We're not interested in other decls or types, only subexpressions. */
5301debfc3dSmrg if (EXPR_P (t))
5311debfc3dSmrg *walk_subtrees = 1;
5321debfc3dSmrg /* FALLTHRU */
5331debfc3dSmrg
5341debfc3dSmrg case SSA_NAME:
5351debfc3dSmrg /* Special-case the return of SSA_NAME, since it's so common. */
5361debfc3dSmrg return NULL_TREE;
5371debfc3dSmrg }
5381debfc3dSmrg
5391debfc3dSmrg addr = gen_emutls_addr (t, d);
5401debfc3dSmrg if (is_addr)
5411debfc3dSmrg {
5421debfc3dSmrg /* Replace "&var" with "addr" in the statement. */
5431debfc3dSmrg *ptr = addr;
5441debfc3dSmrg }
5451debfc3dSmrg else
5461debfc3dSmrg {
5471debfc3dSmrg /* Replace "var" with "*addr" in the statement. */
5481debfc3dSmrg t = build2 (MEM_REF, TREE_TYPE (t), addr,
5491debfc3dSmrg build_int_cst (TREE_TYPE (addr), 0));
5501debfc3dSmrg *ptr = t;
5511debfc3dSmrg }
5521debfc3dSmrg
5531debfc3dSmrg wi->changed = true;
5541debfc3dSmrg return NULL_TREE;
5551debfc3dSmrg }
5561debfc3dSmrg
5571debfc3dSmrg /* Lower all of the operands of STMT. */
5581debfc3dSmrg
5591debfc3dSmrg static void
lower_emutls_stmt(gimple * stmt,struct lower_emutls_data * d)5601debfc3dSmrg lower_emutls_stmt (gimple *stmt, struct lower_emutls_data *d)
5611debfc3dSmrg {
5621debfc3dSmrg struct walk_stmt_info wi;
5631debfc3dSmrg
5641debfc3dSmrg d->loc = gimple_location (stmt);
5651debfc3dSmrg
5661debfc3dSmrg memset (&wi, 0, sizeof (wi));
5671debfc3dSmrg wi.info = d;
5681debfc3dSmrg wi.val_only = true;
5691debfc3dSmrg walk_gimple_op (stmt, lower_emutls_1, &wi);
5701debfc3dSmrg
5711debfc3dSmrg if (wi.changed)
5721debfc3dSmrg update_stmt (stmt);
5731debfc3dSmrg }
5741debfc3dSmrg
5751debfc3dSmrg /* Lower the I'th operand of PHI. */
5761debfc3dSmrg
5771debfc3dSmrg static void
lower_emutls_phi_arg(gphi * phi,unsigned int i,struct lower_emutls_data * d)5781debfc3dSmrg lower_emutls_phi_arg (gphi *phi, unsigned int i,
5791debfc3dSmrg struct lower_emutls_data *d)
5801debfc3dSmrg {
5811debfc3dSmrg struct walk_stmt_info wi;
5821debfc3dSmrg struct phi_arg_d *pd = gimple_phi_arg (phi, i);
5831debfc3dSmrg
5841debfc3dSmrg /* Early out for a very common case we don't care about. */
5851debfc3dSmrg if (TREE_CODE (pd->def) == SSA_NAME)
5861debfc3dSmrg return;
5871debfc3dSmrg
5881debfc3dSmrg d->loc = pd->locus;
5891debfc3dSmrg
5901debfc3dSmrg memset (&wi, 0, sizeof (wi));
5911debfc3dSmrg wi.info = d;
5921debfc3dSmrg wi.val_only = true;
5931debfc3dSmrg walk_tree (&pd->def, lower_emutls_1, &wi, NULL);
5941debfc3dSmrg
5951debfc3dSmrg /* For normal statements, we let update_stmt do its job. But for phi
5961debfc3dSmrg nodes, we have to manipulate the immediate use list by hand. */
5971debfc3dSmrg if (wi.changed)
5981debfc3dSmrg {
5991debfc3dSmrg gcc_assert (TREE_CODE (pd->def) == SSA_NAME);
6001debfc3dSmrg link_imm_use_stmt (&pd->imm_use, pd->def, phi);
6011debfc3dSmrg }
6021debfc3dSmrg }
6031debfc3dSmrg
6041debfc3dSmrg /* Reset access variable for a given TLS variable data DATA. */
6051debfc3dSmrg
6061debfc3dSmrg bool
reset_access(varpool_node * const &,tls_var_data * data,void *)6071debfc3dSmrg reset_access (varpool_node * const &, tls_var_data *data, void *)
6081debfc3dSmrg {
6091debfc3dSmrg data->access = NULL;
6101debfc3dSmrg
6111debfc3dSmrg return true;
6121debfc3dSmrg }
6131debfc3dSmrg
6141debfc3dSmrg /* Clear the access variables, in order to begin a new block. */
6151debfc3dSmrg
6161debfc3dSmrg static inline void
clear_access_vars(void)6171debfc3dSmrg clear_access_vars (void)
6181debfc3dSmrg {
6191debfc3dSmrg tls_map->traverse<void *, reset_access> (NULL);
6201debfc3dSmrg }
6211debfc3dSmrg
6221debfc3dSmrg /* Lower the entire function NODE. */
6231debfc3dSmrg
6241debfc3dSmrg static void
lower_emutls_function_body(struct cgraph_node * node)6251debfc3dSmrg lower_emutls_function_body (struct cgraph_node *node)
6261debfc3dSmrg {
6271debfc3dSmrg struct lower_emutls_data d;
6281debfc3dSmrg bool any_edge_inserts = false;
6291debfc3dSmrg
6301debfc3dSmrg push_cfun (DECL_STRUCT_FUNCTION (node->decl));
6311debfc3dSmrg
6321debfc3dSmrg d.cfun_node = node;
6331debfc3dSmrg d.builtin_decl = builtin_decl_explicit (BUILT_IN_EMUTLS_GET_ADDRESS);
6341debfc3dSmrg /* This is where we introduce the declaration to the IL and so we have to
6351debfc3dSmrg create a node for it. */
6361debfc3dSmrg d.builtin_node = cgraph_node::get_create (d.builtin_decl);
6371debfc3dSmrg
6381debfc3dSmrg FOR_EACH_BB_FN (d.bb, cfun)
6391debfc3dSmrg {
6401debfc3dSmrg unsigned int i, nedge;
6411debfc3dSmrg
6421debfc3dSmrg /* Lower each of the PHI nodes of the block, as we may have
6431debfc3dSmrg propagated &tlsvar into a PHI argument. These loops are
6441debfc3dSmrg arranged so that we process each edge at once, and each
6451debfc3dSmrg PHI argument for that edge. */
6461debfc3dSmrg if (!gimple_seq_empty_p (phi_nodes (d.bb)))
6471debfc3dSmrg {
6481debfc3dSmrg nedge = EDGE_COUNT (d.bb->preds);
6491debfc3dSmrg for (i = 0; i < nedge; ++i)
6501debfc3dSmrg {
6511debfc3dSmrg edge e = EDGE_PRED (d.bb, i);
6521debfc3dSmrg
6531debfc3dSmrg /* We can re-use any SSA_NAME created on this edge. */
6541debfc3dSmrg clear_access_vars ();
6551debfc3dSmrg d.seq = NULL;
6561debfc3dSmrg
6571debfc3dSmrg for (gphi_iterator gsi = gsi_start_phis (d.bb);
6581debfc3dSmrg !gsi_end_p (gsi);
6591debfc3dSmrg gsi_next (&gsi))
6601debfc3dSmrg lower_emutls_phi_arg (gsi.phi (), i, &d);
6611debfc3dSmrg
6621debfc3dSmrg /* Insert all statements generated by all phi nodes for this
6631debfc3dSmrg particular edge all at once. */
6641debfc3dSmrg if (d.seq)
6651debfc3dSmrg {
6661debfc3dSmrg gsi_insert_seq_on_edge (e, d.seq);
6671debfc3dSmrg any_edge_inserts = true;
6681debfc3dSmrg }
6691debfc3dSmrg }
6701debfc3dSmrg }
6711debfc3dSmrg
6721debfc3dSmrg /* We can re-use any SSA_NAME created during this basic block. */
6731debfc3dSmrg clear_access_vars ();
6741debfc3dSmrg
6751debfc3dSmrg /* Lower each of the statements of the block. */
6761debfc3dSmrg for (gimple_stmt_iterator gsi = gsi_start_bb (d.bb); !gsi_end_p (gsi);
6771debfc3dSmrg gsi_next (&gsi))
6781debfc3dSmrg {
6791debfc3dSmrg d.seq = NULL;
6801debfc3dSmrg lower_emutls_stmt (gsi_stmt (gsi), &d);
6811debfc3dSmrg
6821debfc3dSmrg /* If any new statements were created, insert them immediately
6831debfc3dSmrg before the first use. This prevents variable lifetimes from
6841debfc3dSmrg becoming unnecessarily long. */
6851debfc3dSmrg if (d.seq)
6861debfc3dSmrg gsi_insert_seq_before (&gsi, d.seq, GSI_SAME_STMT);
6871debfc3dSmrg }
6881debfc3dSmrg }
6891debfc3dSmrg
6901debfc3dSmrg if (any_edge_inserts)
6911debfc3dSmrg gsi_commit_edge_inserts ();
6921debfc3dSmrg
6931debfc3dSmrg pop_cfun ();
6941debfc3dSmrg }
6951debfc3dSmrg
6961debfc3dSmrg /* Create emutls variable for VAR, DATA is pointer to static
6971debfc3dSmrg ctor body we can add constructors to.
6981debfc3dSmrg Callback for varpool_for_variable_and_aliases. */
6991debfc3dSmrg
7001debfc3dSmrg static bool
create_emultls_var(varpool_node * var,void * data)7011debfc3dSmrg create_emultls_var (varpool_node *var, void *data)
7021debfc3dSmrg {
7031debfc3dSmrg tree cdecl;
7041debfc3dSmrg tls_var_data value;
7051debfc3dSmrg
7061debfc3dSmrg cdecl = new_emutls_decl (var->decl,
7071debfc3dSmrg var->alias && var->analyzed
7081debfc3dSmrg ? var->get_alias_target ()->decl : NULL);
7091debfc3dSmrg
7101debfc3dSmrg varpool_node *cvar = varpool_node::get (cdecl);
7111debfc3dSmrg
7121debfc3dSmrg if (!var->alias)
7131debfc3dSmrg {
7141debfc3dSmrg /* Make sure the COMMON block control variable gets initialized.
7151debfc3dSmrg Note that there's no point in doing this for aliases; we only
7161debfc3dSmrg need to do this once for the main variable. */
7171debfc3dSmrg emutls_common_1 (var->decl, cdecl, (tree *)data);
7181debfc3dSmrg }
7191debfc3dSmrg if (var->alias && !var->analyzed)
7201debfc3dSmrg cvar->alias = true;
7211debfc3dSmrg
7221debfc3dSmrg /* Indicate that the value of the TLS variable may be found elsewhere,
7231debfc3dSmrg preventing the variable from re-appearing in the GIMPLE. We cheat
7241debfc3dSmrg and use the control variable here (rather than a full call_expr),
7251debfc3dSmrg which is special-cased inside the DWARF2 output routines. */
7261debfc3dSmrg SET_DECL_VALUE_EXPR (var->decl, cdecl);
7271debfc3dSmrg DECL_HAS_VALUE_EXPR_P (var->decl) = 1;
7281debfc3dSmrg
7291debfc3dSmrg value.control_var = cvar;
7301debfc3dSmrg tls_map->put (var, value);
7311debfc3dSmrg
7321debfc3dSmrg return false;
7331debfc3dSmrg }
7341debfc3dSmrg
7351debfc3dSmrg /* Main entry point to the tls lowering pass. */
7361debfc3dSmrg
7371debfc3dSmrg static unsigned int
ipa_lower_emutls(void)7381debfc3dSmrg ipa_lower_emutls (void)
7391debfc3dSmrg {
7401debfc3dSmrg varpool_node *var;
7411debfc3dSmrg cgraph_node *func;
7421debfc3dSmrg bool any_aliases = false;
7431debfc3dSmrg tree ctor_body = NULL;
7441debfc3dSmrg hash_set <varpool_node *> visited;
7451debfc3dSmrg auto_vec <varpool_node *> tls_vars;
7461debfc3dSmrg
7471debfc3dSmrg /* Examine all global variables for TLS variables. */
7481debfc3dSmrg FOR_EACH_VARIABLE (var)
7491debfc3dSmrg if (DECL_THREAD_LOCAL_P (var->decl)
7501debfc3dSmrg && !visited.add (var))
7511debfc3dSmrg {
7521debfc3dSmrg gcc_checking_assert (TREE_STATIC (var->decl)
7531debfc3dSmrg || DECL_EXTERNAL (var->decl));
7541debfc3dSmrg tls_vars.safe_push (var);
7551debfc3dSmrg if (var->alias && var->definition
7561debfc3dSmrg && !visited.add (var->ultimate_alias_target ()))
7571debfc3dSmrg tls_vars.safe_push (var->ultimate_alias_target ());
7581debfc3dSmrg }
7591debfc3dSmrg
7601debfc3dSmrg /* If we found no TLS variables, then there is no further work to do. */
7611debfc3dSmrg if (tls_vars.is_empty ())
7621debfc3dSmrg {
7631debfc3dSmrg if (dump_file)
7641debfc3dSmrg fprintf (dump_file, "No TLS variables found.\n");
7651debfc3dSmrg return 0;
7661debfc3dSmrg }
7671debfc3dSmrg
7681debfc3dSmrg tls_map = new hash_map <varpool_node *, tls_var_data> ();
7691debfc3dSmrg
7701debfc3dSmrg /* Create the control variables for each TLS variable. */
7711debfc3dSmrg for (unsigned i = 0; i < tls_vars.length (); i++)
7721debfc3dSmrg {
7731debfc3dSmrg var = tls_vars[i];
7741debfc3dSmrg
7751debfc3dSmrg if (var->alias && !var->analyzed)
7761debfc3dSmrg any_aliases = true;
7771debfc3dSmrg else if (!var->alias)
7781debfc3dSmrg var->call_for_symbol_and_aliases (create_emultls_var, &ctor_body, true);
7791debfc3dSmrg }
7801debfc3dSmrg
7811debfc3dSmrg /* If there were any aliases, then frob the alias_pairs vector. */
7821debfc3dSmrg if (any_aliases)
7831debfc3dSmrg {
7841debfc3dSmrg alias_pair *p;
7851debfc3dSmrg unsigned int i;
7861debfc3dSmrg FOR_EACH_VEC_SAFE_ELT (alias_pairs, i, p)
7871debfc3dSmrg if (DECL_THREAD_LOCAL_P (p->decl))
7881debfc3dSmrg {
7891debfc3dSmrg p->decl = tls_map->get
7901debfc3dSmrg (varpool_node::get (p->decl))->control_var->decl;
7911debfc3dSmrg p->target = get_emutls_object_name (p->target);
7921debfc3dSmrg }
7931debfc3dSmrg }
7941debfc3dSmrg
7951debfc3dSmrg /* Adjust all uses of TLS variables within the function bodies. */
7961debfc3dSmrg FOR_EACH_DEFINED_FUNCTION (func)
7971debfc3dSmrg if (func->lowered)
7981debfc3dSmrg lower_emutls_function_body (func);
7991debfc3dSmrg
8001debfc3dSmrg /* Generate the constructor for any COMMON control variables created. */
8011debfc3dSmrg if (ctor_body)
8021debfc3dSmrg cgraph_build_static_cdtor ('I', ctor_body, DEFAULT_INIT_PRIORITY);
8031debfc3dSmrg
8041debfc3dSmrg delete tls_map;
8051debfc3dSmrg
8061debfc3dSmrg return 0;
8071debfc3dSmrg }
8081debfc3dSmrg
8091debfc3dSmrg namespace {
8101debfc3dSmrg
8111debfc3dSmrg const pass_data pass_data_ipa_lower_emutls =
8121debfc3dSmrg {
8131debfc3dSmrg SIMPLE_IPA_PASS, /* type */
8141debfc3dSmrg "emutls", /* name */
8151debfc3dSmrg OPTGROUP_NONE, /* optinfo_flags */
8161debfc3dSmrg TV_IPA_OPT, /* tv_id */
8171debfc3dSmrg ( PROP_cfg | PROP_ssa ), /* properties_required */
8181debfc3dSmrg 0, /* properties_provided */
8191debfc3dSmrg 0, /* properties_destroyed */
8201debfc3dSmrg 0, /* todo_flags_start */
8211debfc3dSmrg 0, /* todo_flags_finish */
8221debfc3dSmrg };
8231debfc3dSmrg
8241debfc3dSmrg class pass_ipa_lower_emutls : public simple_ipa_opt_pass
8251debfc3dSmrg {
8261debfc3dSmrg public:
pass_ipa_lower_emutls(gcc::context * ctxt)8271debfc3dSmrg pass_ipa_lower_emutls (gcc::context *ctxt)
8281debfc3dSmrg : simple_ipa_opt_pass (pass_data_ipa_lower_emutls, ctxt)
8291debfc3dSmrg {}
8301debfc3dSmrg
8311debfc3dSmrg /* opt_pass methods: */
gate(function *)8321debfc3dSmrg virtual bool gate (function *)
8331debfc3dSmrg {
8341debfc3dSmrg /* If the target supports TLS natively, we need do nothing here. */
8351debfc3dSmrg return !targetm.have_tls;
8361debfc3dSmrg }
8371debfc3dSmrg
execute(function *)8381debfc3dSmrg virtual unsigned int execute (function *) { return ipa_lower_emutls (); }
8391debfc3dSmrg
8401debfc3dSmrg }; // class pass_ipa_lower_emutls
8411debfc3dSmrg
8421debfc3dSmrg } // anon namespace
8431debfc3dSmrg
8441debfc3dSmrg simple_ipa_opt_pass *
make_pass_ipa_lower_emutls(gcc::context * ctxt)8451debfc3dSmrg make_pass_ipa_lower_emutls (gcc::context *ctxt)
8461debfc3dSmrg {
8471debfc3dSmrg return new pass_ipa_lower_emutls (ctxt);
8481debfc3dSmrg }
849