123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022 |
- /* Symbol table.
- Copyright (C) 2012-2015 Free Software Foundation, Inc.
- Contributed by Jan Hubicka
- This file is part of GCC.
- GCC is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free
- Software Foundation; either version 3, or (at your option) any later
- version.
- GCC is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
- You should have received a copy of the GNU General Public License
- along with GCC; see the file COPYING3. If not see
- <http://www.gnu.org/licenses/>. */
- #include "config.h"
- #include "system.h"
- #include "coretypes.h"
- #include "tm.h"
- #include "rtl.h"
- #include "hash-set.h"
- #include "machmode.h"
- #include "vec.h"
- #include "double-int.h"
- #include "input.h"
- #include "alias.h"
- #include "symtab.h"
- #include "wide-int.h"
- #include "inchash.h"
- #include "tree.h"
- #include "fold-const.h"
- #include "print-tree.h"
- #include "varasm.h"
- #include "hashtab.h"
- #include "hard-reg-set.h"
- #include "input.h"
- #include "function.h"
- #include "emit-rtl.h"
- #include "predict.h"
- #include "basic-block.h"
- #include "tree-ssa-alias.h"
- #include "internal-fn.h"
- #include "gimple-expr.h"
- #include "is-a.h"
- #include "gimple.h"
- #include "tree-inline.h"
- #include "langhooks.h"
- #include "hash-map.h"
- #include "plugin-api.h"
- #include "ipa-ref.h"
- #include "cgraph.h"
- #include "diagnostic.h"
- #include "timevar.h"
- #include "lto-streamer.h"
- #include "output.h"
- #include "ipa-utils.h"
- #include "calls.h"
- static const char *ipa_ref_use_name[] = {"read","write","addr","alias","chkp"};
- const char * const ld_plugin_symbol_resolution_names[]=
- {
- "",
- "undef",
- "prevailing_def",
- "prevailing_def_ironly",
- "preempted_reg",
- "preempted_ir",
- "resolved_ir",
- "resolved_exec",
- "resolved_dyn",
- "prevailing_def_ironly_exp"
- };
- /* Hash asmnames ignoring the user specified marks. */
- hashval_t
- symbol_table::decl_assembler_name_hash (const_tree asmname)
- {
- if (IDENTIFIER_POINTER (asmname)[0] == '*')
- {
- const char *decl_str = IDENTIFIER_POINTER (asmname) + 1;
- size_t ulp_len = strlen (user_label_prefix);
- if (ulp_len == 0)
- ;
- else if (strncmp (decl_str, user_label_prefix, ulp_len) == 0)
- decl_str += ulp_len;
- return htab_hash_string (decl_str);
- }
- return htab_hash_string (IDENTIFIER_POINTER (asmname));
- }
- /* Compare ASMNAME with the DECL_ASSEMBLER_NAME of DECL. */
- bool
- symbol_table::decl_assembler_name_equal (tree decl, const_tree asmname)
- {
- tree decl_asmname = DECL_ASSEMBLER_NAME (decl);
- const char *decl_str;
- const char *asmname_str;
- bool test = false;
- if (decl_asmname == asmname)
- return true;
- decl_str = IDENTIFIER_POINTER (decl_asmname);
- asmname_str = IDENTIFIER_POINTER (asmname);
- /* If the target assembler name was set by the user, things are trickier.
- We have a leading '*' to begin with. After that, it's arguable what
- is the correct thing to do with -fleading-underscore. Arguably, we've
- historically been doing the wrong thing in assemble_alias by always
- printing the leading underscore. Since we're not changing that, make
- sure user_label_prefix follows the '*' before matching. */
- if (decl_str[0] == '*')
- {
- size_t ulp_len = strlen (user_label_prefix);
- decl_str ++;
- if (ulp_len == 0)
- test = true;
- else if (strncmp (decl_str, user_label_prefix, ulp_len) == 0)
- decl_str += ulp_len, test=true;
- else
- decl_str --;
- }
- if (asmname_str[0] == '*')
- {
- size_t ulp_len = strlen (user_label_prefix);
- asmname_str ++;
- if (ulp_len == 0)
- test = true;
- else if (strncmp (asmname_str, user_label_prefix, ulp_len) == 0)
- asmname_str += ulp_len, test=true;
- else
- asmname_str --;
- }
- if (!test)
- return false;
- return strcmp (decl_str, asmname_str) == 0;
- }
- /* Returns nonzero if P1 and P2 are equal. */
- /* Insert NODE to assembler name hash. */
- void
- symbol_table::insert_to_assembler_name_hash (symtab_node *node,
- bool with_clones)
- {
- if (is_a <varpool_node *> (node) && DECL_HARD_REGISTER (node->decl))
- return;
- gcc_checking_assert (!node->previous_sharing_asm_name
- && !node->next_sharing_asm_name);
- if (assembler_name_hash)
- {
- symtab_node **aslot;
- cgraph_node *cnode;
- tree decl = node->decl;
- tree name = DECL_ASSEMBLER_NAME (node->decl);
- /* C++ FE can produce decls without associated assembler name and insert
- them to symtab to hold section or TLS information. */
- if (!name)
- return;
- hashval_t hash = decl_assembler_name_hash (name);
- aslot = assembler_name_hash->find_slot_with_hash (name, hash, INSERT);
- gcc_assert (*aslot != node);
- node->next_sharing_asm_name = (symtab_node *)*aslot;
- if (*aslot != NULL)
- (*aslot)->previous_sharing_asm_name = node;
- *aslot = node;
- /* Update also possible inline clones sharing a decl. */
- cnode = dyn_cast <cgraph_node *> (node);
- if (cnode && cnode->clones && with_clones)
- for (cnode = cnode->clones; cnode; cnode = cnode->next_sibling_clone)
- if (cnode->decl == decl)
- insert_to_assembler_name_hash (cnode, true);
- }
- }
- /* Remove NODE from assembler name hash. */
- void
- symbol_table::unlink_from_assembler_name_hash (symtab_node *node,
- bool with_clones)
- {
- if (assembler_name_hash)
- {
- cgraph_node *cnode;
- tree decl = node->decl;
- if (node->next_sharing_asm_name)
- node->next_sharing_asm_name->previous_sharing_asm_name
- = node->previous_sharing_asm_name;
- if (node->previous_sharing_asm_name)
- {
- node->previous_sharing_asm_name->next_sharing_asm_name
- = node->next_sharing_asm_name;
- }
- else
- {
- tree name = DECL_ASSEMBLER_NAME (node->decl);
- symtab_node **slot;
- if (!name)
- return;
- hashval_t hash = decl_assembler_name_hash (name);
- slot = assembler_name_hash->find_slot_with_hash (name, hash,
- NO_INSERT);
- gcc_assert (*slot == node);
- if (!node->next_sharing_asm_name)
- assembler_name_hash->clear_slot (slot);
- else
- *slot = node->next_sharing_asm_name;
- }
- node->next_sharing_asm_name = NULL;
- node->previous_sharing_asm_name = NULL;
- /* Update also possible inline clones sharing a decl. */
- cnode = dyn_cast <cgraph_node *> (node);
- if (cnode && cnode->clones && with_clones)
- for (cnode = cnode->clones; cnode; cnode = cnode->next_sibling_clone)
- if (cnode->decl == decl)
- unlink_from_assembler_name_hash (cnode, true);
- }
- }
- /* Arrange node to be first in its entry of assembler_name_hash. */
- void
- symbol_table::symtab_prevail_in_asm_name_hash (symtab_node *node)
- {
- unlink_from_assembler_name_hash (node, false);
- insert_to_assembler_name_hash (node, false);
- }
- /* Initalize asm name hash unless. */
- void
- symbol_table::symtab_initialize_asm_name_hash (void)
- {
- symtab_node *node;
- if (!assembler_name_hash)
- {
- assembler_name_hash = hash_table<asmname_hasher>::create_ggc (10);
- FOR_EACH_SYMBOL (node)
- insert_to_assembler_name_hash (node, false);
- }
- }
- /* Set the DECL_ASSEMBLER_NAME and update symtab hashtables. */
- void
- symbol_table::change_decl_assembler_name (tree decl, tree name)
- {
- symtab_node *node = NULL;
- /* We can have user ASM names on things, like global register variables, that
- are not in the symbol table. */
- if ((TREE_CODE (decl) == VAR_DECL
- && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
- || TREE_CODE (decl) == FUNCTION_DECL)
- node = symtab_node::get (decl);
- if (!DECL_ASSEMBLER_NAME_SET_P (decl))
- {
- SET_DECL_ASSEMBLER_NAME (decl, name);
- if (node)
- insert_to_assembler_name_hash (node, true);
- }
- else
- {
- if (name == DECL_ASSEMBLER_NAME (decl))
- return;
- tree alias = (IDENTIFIER_TRANSPARENT_ALIAS (DECL_ASSEMBLER_NAME (decl))
- ? TREE_CHAIN (DECL_ASSEMBLER_NAME (decl))
- : NULL);
- if (node)
- unlink_from_assembler_name_hash (node, true);
- if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))
- && DECL_RTL_SET_P (decl))
- warning (0, "%D renamed after being referenced in assembly", decl);
- SET_DECL_ASSEMBLER_NAME (decl, name);
- if (alias)
- {
- IDENTIFIER_TRANSPARENT_ALIAS (name) = 1;
- TREE_CHAIN (name) = alias;
- }
- if (node)
- insert_to_assembler_name_hash (node, true);
- }
- }
- /* Hash sections by their names. */
- hashval_t
- section_name_hasher::hash (section_hash_entry *n)
- {
- return htab_hash_string (n->name);
- }
- /* Return true if section P1 name equals to P2. */
- bool
- section_name_hasher::equal (section_hash_entry *n1, const char *name)
- {
- return n1->name == name || !strcmp (n1->name, name);
- }
- /* Add node into symbol table. This function is not used directly, but via
- cgraph/varpool node creation routines. */
- void
- symtab_node::register_symbol (void)
- {
- symtab->register_symbol (this);
- if (!decl->decl_with_vis.symtab_node)
- decl->decl_with_vis.symtab_node = this;
- ref_list.clear ();
- /* Be sure to do this last; C++ FE might create new nodes via
- DECL_ASSEMBLER_NAME langhook! */
- symtab->insert_to_assembler_name_hash (this, false);
- }
- /* Remove NODE from same comdat group. */
- void
- symtab_node::remove_from_same_comdat_group (void)
- {
- if (same_comdat_group)
- {
- symtab_node *prev;
- for (prev = same_comdat_group;
- prev->same_comdat_group != this;
- prev = prev->same_comdat_group)
- ;
- if (same_comdat_group == prev)
- prev->same_comdat_group = NULL;
- else
- prev->same_comdat_group = same_comdat_group;
- same_comdat_group = NULL;
- set_comdat_group (NULL);
- }
- }
- /* Remove node from symbol table. This function is not used directly, but via
- cgraph/varpool node removal routines. */
- void
- symtab_node::unregister (void)
- {
- remove_all_references ();
- remove_all_referring ();
- /* Remove reference to section. */
- set_section_for_node (NULL);
- remove_from_same_comdat_group ();
- symtab->unregister (this);
- /* During LTO symtab merging we temporarily corrupt decl to symtab node
- hash. */
- gcc_assert (decl->decl_with_vis.symtab_node || in_lto_p);
- if (decl->decl_with_vis.symtab_node == this)
- {
- symtab_node *replacement_node = NULL;
- if (cgraph_node *cnode = dyn_cast <cgraph_node *> (this))
- replacement_node = cnode->find_replacement ();
- decl->decl_with_vis.symtab_node = replacement_node;
- }
- if (!is_a <varpool_node *> (this) || !DECL_HARD_REGISTER (decl))
- symtab->unlink_from_assembler_name_hash (this, false);
- if (in_init_priority_hash)
- symtab->init_priority_hash->remove (this);
- }
- /* Remove symbol from symbol table. */
- void
- symtab_node::remove (void)
- {
- if (cgraph_node *cnode = dyn_cast <cgraph_node *> (this))
- cnode->remove ();
- else if (varpool_node *vnode = dyn_cast <varpool_node *> (this))
- vnode->remove ();
- }
- /* Add NEW_ to the same comdat group that OLD is in. */
- void
- symtab_node::add_to_same_comdat_group (symtab_node *old_node)
- {
- gcc_assert (old_node->get_comdat_group ());
- gcc_assert (!same_comdat_group);
- gcc_assert (this != old_node);
- set_comdat_group (old_node->get_comdat_group ());
- same_comdat_group = old_node;
- if (!old_node->same_comdat_group)
- old_node->same_comdat_group = this;
- else
- {
- symtab_node *n;
- for (n = old_node->same_comdat_group;
- n->same_comdat_group != old_node;
- n = n->same_comdat_group)
- ;
- n->same_comdat_group = this;
- }
- }
- /* Dissolve the same_comdat_group list in which NODE resides. */
- void
- symtab_node::dissolve_same_comdat_group_list (void)
- {
- symtab_node *n = this;
- symtab_node *next;
- if (!same_comdat_group)
- return;
- do
- {
- next = n->same_comdat_group;
- n->same_comdat_group = NULL;
- /* Clear comdat_group for comdat locals, since
- make_decl_local doesn't. */
- if (!TREE_PUBLIC (n->decl))
- n->set_comdat_group (NULL);
- n = next;
- }
- while (n != this);
- }
- /* Return printable assembler name of NODE.
- This function is used only for debugging. When assembler name
- is unknown go with identifier name. */
- const char *
- symtab_node::asm_name () const
- {
- if (!DECL_ASSEMBLER_NAME_SET_P (decl))
- return lang_hooks.decl_printable_name (decl, 2);
- return IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
- }
- /* Return printable identifier name. */
- const char *
- symtab_node::name () const
- {
- return lang_hooks.decl_printable_name (decl, 2);
- }
- /* Return ipa reference from this symtab_node to
- REFERED_NODE or REFERED_VARPOOL_NODE. USE_TYPE specify type
- of the use. */
- ipa_ref *
- symtab_node::create_reference (symtab_node *referred_node,
- enum ipa_ref_use use_type)
- {
- return create_reference (referred_node, use_type, NULL);
- }
- /* Return ipa reference from this symtab_node to
- REFERED_NODE or REFERED_VARPOOL_NODE. USE_TYPE specify type
- of the use and STMT the statement (if it exists). */
- ipa_ref *
- symtab_node::create_reference (symtab_node *referred_node,
- enum ipa_ref_use use_type, gimple stmt)
- {
- ipa_ref *ref = NULL, *ref2 = NULL;
- ipa_ref_list *list, *list2;
- ipa_ref_t *old_references;
- gcc_checking_assert (!stmt || is_a <cgraph_node *> (this));
- gcc_checking_assert (use_type != IPA_REF_ALIAS || !stmt);
- list = &ref_list;
- old_references = vec_safe_address (list->references);
- vec_safe_grow (list->references, vec_safe_length (list->references) + 1);
- ref = &list->references->last ();
- list2 = &referred_node->ref_list;
- /* IPA_REF_ALIAS is always inserted at the beginning of the list. */
- if(use_type == IPA_REF_ALIAS)
- {
- list2->referring.safe_insert (0, ref);
- ref->referred_index = 0;
- for (unsigned int i = 1; i < list2->referring.length (); i++)
- list2->referring[i]->referred_index = i;
- }
- else
- {
- list2->referring.safe_push (ref);
- ref->referred_index = list2->referring.length () - 1;
- }
- ref->referring = this;
- ref->referred = referred_node;
- ref->stmt = stmt;
- ref->lto_stmt_uid = 0;
- ref->use = use_type;
- ref->speculative = 0;
- /* If vector was moved in memory, update pointers. */
- if (old_references != list->references->address ())
- {
- int i;
- for (i = 0; iterate_reference(i, ref2); i++)
- ref2->referred_ref_list ()->referring[ref2->referred_index] = ref2;
- }
- return ref;
- }
- /* If VAL is a reference to a function or a variable, add a reference from
- this symtab_node to the corresponding symbol table node. USE_TYPE specify
- type of the use and STMT the statement (if it exists). Return the new
- reference or NULL if none was created. */
- ipa_ref *
- symtab_node::maybe_create_reference (tree val, enum ipa_ref_use use_type,
- gimple stmt)
- {
- STRIP_NOPS (val);
- if (TREE_CODE (val) != ADDR_EXPR)
- return NULL;
- val = get_base_var (val);
- if (val && (TREE_CODE (val) == FUNCTION_DECL
- || TREE_CODE (val) == VAR_DECL))
- {
- symtab_node *referred = symtab_node::get (val);
- gcc_checking_assert (referred);
- return create_reference (referred, use_type, stmt);
- }
- return NULL;
- }
- /* Clone all references from symtab NODE to this symtab_node. */
- void
- symtab_node::clone_references (symtab_node *node)
- {
- ipa_ref *ref = NULL, *ref2 = NULL;
- int i;
- for (i = 0; node->iterate_reference (i, ref); i++)
- {
- bool speculative = ref->speculative;
- unsigned int stmt_uid = ref->lto_stmt_uid;
- ref2 = create_reference (ref->referred, ref->use, ref->stmt);
- ref2->speculative = speculative;
- ref2->lto_stmt_uid = stmt_uid;
- }
- }
- /* Clone all referring from symtab NODE to this symtab_node. */
- void
- symtab_node::clone_referring (symtab_node *node)
- {
- ipa_ref *ref = NULL, *ref2 = NULL;
- int i;
- for (i = 0; node->iterate_referring(i, ref); i++)
- {
- bool speculative = ref->speculative;
- unsigned int stmt_uid = ref->lto_stmt_uid;
- ref2 = ref->referring->create_reference (this, ref->use, ref->stmt);
- ref2->speculative = speculative;
- ref2->lto_stmt_uid = stmt_uid;
- }
- }
- /* Clone reference REF to this symtab_node and set its stmt to STMT. */
- ipa_ref *
- symtab_node::clone_reference (ipa_ref *ref, gimple stmt)
- {
- bool speculative = ref->speculative;
- unsigned int stmt_uid = ref->lto_stmt_uid;
- ipa_ref *ref2;
- ref2 = create_reference (ref->referred, ref->use, stmt);
- ref2->speculative = speculative;
- ref2->lto_stmt_uid = stmt_uid;
- return ref2;
- }
- /* Find the structure describing a reference to REFERRED_NODE
- and associated with statement STMT. */
- ipa_ref *
- symtab_node::find_reference (symtab_node *referred_node,
- gimple stmt, unsigned int lto_stmt_uid)
- {
- ipa_ref *r = NULL;
- int i;
- for (i = 0; iterate_reference (i, r); i++)
- if (r->referred == referred_node
- && !r->speculative
- && ((stmt && r->stmt == stmt)
- || (lto_stmt_uid && r->lto_stmt_uid == lto_stmt_uid)
- || (!stmt && !lto_stmt_uid && !r->stmt && !r->lto_stmt_uid)))
- return r;
- return NULL;
- }
- /* Remove all references that are associated with statement STMT. */
- void
- symtab_node::remove_stmt_references (gimple stmt)
- {
- ipa_ref *r = NULL;
- int i = 0;
- while (iterate_reference (i, r))
- if (r->stmt == stmt)
- r->remove_reference ();
- else
- i++;
- }
- /* Remove all stmt references in non-speculative references.
- Those are not maintained during inlining & clonning.
- The exception are speculative references that are updated along
- with callgraph edges associated with them. */
- void
- symtab_node::clear_stmts_in_references (void)
- {
- ipa_ref *r = NULL;
- int i;
- for (i = 0; iterate_reference (i, r); i++)
- if (!r->speculative)
- {
- r->stmt = NULL;
- r->lto_stmt_uid = 0;
- }
- }
- /* Remove all references in ref list. */
- void
- symtab_node::remove_all_references (void)
- {
- while (vec_safe_length (ref_list.references))
- ref_list.references->last ().remove_reference ();
- vec_free (ref_list.references);
- }
- /* Remove all referring items in ref list. */
- void
- symtab_node::remove_all_referring (void)
- {
- while (ref_list.referring.length ())
- ref_list.referring.last ()->remove_reference ();
- ref_list.referring.release ();
- }
- /* Dump references in ref list to FILE. */
- void
- symtab_node::dump_references (FILE *file)
- {
- ipa_ref *ref = NULL;
- int i;
- for (i = 0; iterate_reference (i, ref); i++)
- {
- fprintf (file, "%s/%i (%s)",
- ref->referred->asm_name (),
- ref->referred->order,
- ipa_ref_use_name [ref->use]);
- if (ref->speculative)
- fprintf (file, " (speculative)");
- }
- fprintf (file, "\n");
- }
- /* Dump referring in list to FILE. */
- void
- symtab_node::dump_referring (FILE *file)
- {
- ipa_ref *ref = NULL;
- int i;
- for (i = 0; iterate_referring(i, ref); i++)
- {
- fprintf (file, "%s/%i (%s)",
- ref->referring->asm_name (),
- ref->referring->order,
- ipa_ref_use_name [ref->use]);
- if (ref->speculative)
- fprintf (file, " (speculative)");
- }
- fprintf (file, "\n");
- }
- static const char * const symtab_type_names[] = {"symbol", "function", "variable"};
- /* Dump base fields of symtab nodes to F. Not to be used directly. */
- void
- symtab_node::dump_base (FILE *f)
- {
- static const char * const visibility_types[] = {
- "default", "protected", "hidden", "internal"
- };
- fprintf (f, "%s/%i (%s)", asm_name (), order, name ());
- dump_addr (f, " @", (void *)this);
- fprintf (f, "\n Type: %s", symtab_type_names[type]);
- if (definition)
- fprintf (f, " definition");
- if (analyzed)
- fprintf (f, " analyzed");
- if (alias)
- fprintf (f, " alias");
- if (weakref)
- fprintf (f, " weakref");
- if (cpp_implicit_alias)
- fprintf (f, " cpp_implicit_alias");
- if (alias_target)
- fprintf (f, " target:%s",
- DECL_P (alias_target)
- ? IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME
- (alias_target))
- : IDENTIFIER_POINTER (alias_target));
- if (body_removed)
- fprintf (f, "\n Body removed by symtab_remove_unreachable_nodes");
- fprintf (f, "\n Visibility:");
- if (in_other_partition)
- fprintf (f, " in_other_partition");
- if (used_from_other_partition)
- fprintf (f, " used_from_other_partition");
- if (force_output)
- fprintf (f, " force_output");
- if (forced_by_abi)
- fprintf (f, " forced_by_abi");
- if (externally_visible)
- fprintf (f, " externally_visible");
- if (no_reorder)
- fprintf (f, " no_reorder");
- if (resolution != LDPR_UNKNOWN)
- fprintf (f, " %s",
- ld_plugin_symbol_resolution_names[(int)resolution]);
- if (TREE_ASM_WRITTEN (decl))
- fprintf (f, " asm_written");
- if (DECL_EXTERNAL (decl))
- fprintf (f, " external");
- if (TREE_PUBLIC (decl))
- fprintf (f, " public");
- if (DECL_COMMON (decl))
- fprintf (f, " common");
- if (DECL_WEAK (decl))
- fprintf (f, " weak");
- if (DECL_DLLIMPORT_P (decl))
- fprintf (f, " dll_import");
- if (DECL_COMDAT (decl))
- fprintf (f, " comdat");
- if (get_comdat_group ())
- fprintf (f, " comdat_group:%s",
- IDENTIFIER_POINTER (get_comdat_group_id ()));
- if (DECL_ONE_ONLY (decl))
- fprintf (f, " one_only");
- if (get_section ())
- fprintf (f, " section:%s",
- get_section ());
- if (implicit_section)
- fprintf (f," (implicit_section)");
- if (DECL_VISIBILITY_SPECIFIED (decl))
- fprintf (f, " visibility_specified");
- if (DECL_VISIBILITY (decl))
- fprintf (f, " visibility:%s",
- visibility_types [DECL_VISIBILITY (decl)]);
- if (DECL_VIRTUAL_P (decl))
- fprintf (f, " virtual");
- if (DECL_ARTIFICIAL (decl))
- fprintf (f, " artificial");
- if (TREE_CODE (decl) == FUNCTION_DECL)
- {
- if (DECL_STATIC_CONSTRUCTOR (decl))
- fprintf (f, " constructor");
- if (DECL_STATIC_DESTRUCTOR (decl))
- fprintf (f, " destructor");
- }
- fprintf (f, "\n");
-
- if (same_comdat_group)
- fprintf (f, " Same comdat group as: %s/%i\n",
- same_comdat_group->asm_name (),
- same_comdat_group->order);
- if (next_sharing_asm_name)
- fprintf (f, " next sharing asm name: %i\n",
- next_sharing_asm_name->order);
- if (previous_sharing_asm_name)
- fprintf (f, " previous sharing asm name: %i\n",
- previous_sharing_asm_name->order);
- if (address_taken)
- fprintf (f, " Address is taken.\n");
- if (aux)
- {
- fprintf (f, " Aux:");
- dump_addr (f, " @", (void *)aux);
- }
- fprintf (f, " References: ");
- dump_references (f);
- fprintf (f, " Referring: ");
- dump_referring (f);
- if (lto_file_data)
- fprintf (f, " Read from file: %s\n",
- lto_file_data->file_name);
- }
- /* Dump symtab node to F. */
- void
- symtab_node::dump (FILE *f)
- {
- if (cgraph_node *cnode = dyn_cast <cgraph_node *> (this))
- cnode->dump (f);
- else if (varpool_node *vnode = dyn_cast <varpool_node *> (this))
- vnode->dump (f);
- }
- /* Dump symbol table to F. */
- void
- symtab_node::dump_table (FILE *f)
- {
- symtab_node *node;
- fprintf (f, "Symbol table:\n\n");
- FOR_EACH_SYMBOL (node)
- node->dump (f);
- }
- /* Return the cgraph node that has ASMNAME for its DECL_ASSEMBLER_NAME.
- Return NULL if there's no such node. */
- symtab_node *
- symtab_node::get_for_asmname (const_tree asmname)
- {
- symtab_node *node;
- symtab->symtab_initialize_asm_name_hash ();
- hashval_t hash = symtab->decl_assembler_name_hash (asmname);
- symtab_node **slot
- = symtab->assembler_name_hash->find_slot_with_hash (asmname, hash,
- NO_INSERT);
- if (slot)
- {
- node = *slot;
- return node;
- }
- return NULL;
- }
- /* Dump symtab node NODE to stderr. */
- DEBUG_FUNCTION void
- symtab_node::debug (void)
- {
- dump (stderr);
- }
- /* Verify common part of symtab nodes. */
- DEBUG_FUNCTION bool
- symtab_node::verify_base (void)
- {
- bool error_found = false;
- symtab_node *hashed_node;
- if (is_a <cgraph_node *> (this))
- {
- if (TREE_CODE (decl) != FUNCTION_DECL)
- {
- error ("function symbol is not function");
- error_found = true;
- }
- }
- else if (is_a <varpool_node *> (this))
- {
- if (TREE_CODE (decl) != VAR_DECL)
- {
- error ("variable symbol is not variable");
- error_found = true;
- }
- }
- else
- {
- error ("node has unknown type");
- error_found = true;
- }
-
- if (symtab->state != LTO_STREAMING)
- {
- hashed_node = symtab_node::get (decl);
- if (!hashed_node)
- {
- error ("node not found node->decl->decl_with_vis.symtab_node");
- error_found = true;
- }
- if (hashed_node != this
- && (!is_a <cgraph_node *> (this)
- || !dyn_cast <cgraph_node *> (this)->clone_of
- || dyn_cast <cgraph_node *> (this)->clone_of->decl != decl))
- {
- error ("node differs from node->decl->decl_with_vis.symtab_node");
- error_found = true;
- }
- }
- if (symtab->assembler_name_hash)
- {
- hashed_node = symtab_node::get_for_asmname (DECL_ASSEMBLER_NAME (decl));
- if (hashed_node && hashed_node->previous_sharing_asm_name)
- {
- error ("assembler name hash list corrupted");
- error_found = true;
- }
- while (hashed_node)
- {
- if (hashed_node == this)
- break;
- hashed_node = hashed_node->next_sharing_asm_name;
- }
- if (!hashed_node
- && !(is_a <varpool_node *> (this)
- || DECL_HARD_REGISTER (decl)))
- {
- error ("node not found in symtab assembler name hash");
- error_found = true;
- }
- }
- if (previous_sharing_asm_name
- && previous_sharing_asm_name->next_sharing_asm_name != this)
- {
- error ("double linked list of assembler names corrupted");
- error_found = true;
- }
- if (body_removed && definition)
- {
- error ("node has body_removed but is definition");
- error_found = true;
- }
- if (analyzed && !definition)
- {
- error ("node is analyzed byt it is not a definition");
- error_found = true;
- }
- if (cpp_implicit_alias && !alias)
- {
- error ("node is alias but not implicit alias");
- error_found = true;
- }
- if (alias && !definition && !weakref)
- {
- error ("node is alias but not definition");
- error_found = true;
- }
- if (weakref && !alias)
- {
- error ("node is weakref but not an alias");
- error_found = true;
- }
- if (same_comdat_group)
- {
- symtab_node *n = same_comdat_group;
- if (!n->get_comdat_group ())
- {
- error ("node is in same_comdat_group list but has no comdat_group");
- error_found = true;
- }
- if (n->get_comdat_group () != get_comdat_group ())
- {
- error ("same_comdat_group list across different groups");
- error_found = true;
- }
- if (n->type != type)
- {
- error ("mixing different types of symbol in same comdat groups is not supported");
- error_found = true;
- }
- if (n == this)
- {
- error ("node is alone in a comdat group");
- error_found = true;
- }
- do
- {
- if (!n->same_comdat_group)
- {
- error ("same_comdat_group is not a circular list");
- error_found = true;
- break;
- }
- n = n->same_comdat_group;
- }
- while (n != this);
- if (comdat_local_p ())
- {
- ipa_ref *ref = NULL;
- for (int i = 0; iterate_referring (i, ref); ++i)
- {
- if (!in_same_comdat_group_p (ref->referring))
- {
- error ("comdat-local symbol referred to by %s outside its "
- "comdat",
- identifier_to_locale (ref->referring->name()));
- error_found = true;
- }
- }
- }
- }
- if (implicit_section && !get_section ())
- {
- error ("implicit_section flag is set but section isn't");
- error_found = true;
- }
- if (get_section () && get_comdat_group ()
- && !implicit_section
- && !lookup_attribute ("section", DECL_ATTRIBUTES (decl)))
- {
- error ("Both section and comdat group is set");
- error_found = true;
- }
- /* TODO: Add string table for sections, so we do not keep holding duplicated
- strings. */
- if (alias && definition
- && get_section () != get_alias_target ()->get_section ()
- && (!get_section()
- || !get_alias_target ()->get_section ()
- || strcmp (get_section(),
- get_alias_target ()->get_section ())))
- {
- error ("Alias and target's section differs");
- get_alias_target ()->dump (stderr);
- error_found = true;
- }
- if (alias && definition
- && get_comdat_group () != get_alias_target ()->get_comdat_group ())
- {
- error ("Alias and target's comdat groups differs");
- get_alias_target ()->dump (stderr);
- error_found = true;
- }
- return error_found;
- }
- /* Verify consistency of NODE. */
- DEBUG_FUNCTION void
- symtab_node::verify (void)
- {
- if (seen_error ())
- return;
- timevar_push (TV_CGRAPH_VERIFY);
- if (cgraph_node *node = dyn_cast <cgraph_node *> (this))
- node->verify_node ();
- else
- if (verify_base ())
- {
- debug ();
- internal_error ("symtab_node::verify failed");
- }
- timevar_pop (TV_CGRAPH_VERIFY);
- }
- /* Verify symbol table for internal consistency. */
- DEBUG_FUNCTION void
- symtab_node::verify_symtab_nodes (void)
- {
- symtab_node *node;
- hash_map<tree, symtab_node *> comdat_head_map (251);
- FOR_EACH_SYMBOL (node)
- {
- node->verify ();
- if (node->get_comdat_group ())
- {
- symtab_node **entry, *s;
- bool existed;
- entry = &comdat_head_map.get_or_insert (node->get_comdat_group (),
- &existed);
- if (!existed)
- *entry = node;
- else if (!DECL_EXTERNAL (node->decl))
- {
- for (s = (*entry)->same_comdat_group;
- s != NULL && s != node && s != *entry;
- s = s->same_comdat_group)
- ;
- if (!s || s == *entry)
- {
- error ("Two symbols with same comdat_group are not linked by "
- "the same_comdat_group list.");
- (*entry)->debug ();
- node->debug ();
- internal_error ("symtab_node::verify failed");
- }
- }
- }
- }
- }
- /* Make DECL local. FIXME: We shouldn't need to mess with rtl this early,
- but other code such as notice_global_symbol generates rtl. */
- void
- symtab_node::make_decl_local (void)
- {
- rtx rtl, symbol;
- /* Avoid clearing comdat_groups on comdat-local decls. */
- if (TREE_PUBLIC (decl) == 0)
- return;
- if (TREE_CODE (decl) == VAR_DECL)
- {
- DECL_COMMON (decl) = 0;
- /* ADDRESSABLE flag is not defined for public symbols. */
- TREE_ADDRESSABLE (decl) = 1;
- }
- else gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
- DECL_COMDAT (decl) = 0;
- DECL_WEAK (decl) = 0;
- DECL_EXTERNAL (decl) = 0;
- DECL_VISIBILITY_SPECIFIED (decl) = 0;
- DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
- TREE_PUBLIC (decl) = 0;
- DECL_DLLIMPORT_P (decl) = 0;
- if (!DECL_RTL_SET_P (decl))
- return;
- /* Update rtl flags. */
- make_decl_rtl (decl);
- rtl = DECL_RTL (decl);
- if (!MEM_P (rtl))
- return;
- symbol = XEXP (rtl, 0);
- if (GET_CODE (symbol) != SYMBOL_REF)
- return;
- SYMBOL_REF_WEAK (symbol) = DECL_WEAK (decl);
- }
- /* Walk the alias chain to return the symbol NODE is alias of.
- If NODE is not an alias, return NODE.
- Assumes NODE is known to be alias. */
- symtab_node *
- symtab_node::ultimate_alias_target_1 (enum availability *availability)
- {
- bool weakref_p = false;
- /* To determine visibility of the target, we follow ELF semantic of aliases.
- Here alias is an alternative assembler name of a given definition. Its
- availability prevails the availability of its target (i.e. static alias of
- weak definition is available.
- Weakref is a different animal (and not part of ELF per se). It is just
- alternative name of a given symbol used within one complation unit
- and is translated prior hitting the object file. It inherits the
- visibility of its target (i.e. weakref of non-overwritable definition
- is non-overwritable, while weakref of weak definition is weak).
- If we ever get into supporting targets with different semantics, a target
- hook will be needed here. */
- if (availability)
- {
- weakref_p = weakref;
- if (!weakref_p)
- *availability = get_availability ();
- else
- *availability = AVAIL_LOCAL;
- }
- symtab_node *node = this;
- while (node)
- {
- if (node->alias && node->analyzed)
- node = node->get_alias_target ();
- else
- {
- if (!availability)
- ;
- else if (node->analyzed)
- {
- if (weakref_p)
- {
- enum availability a = node->get_availability ();
- if (a < *availability)
- *availability = a;
- }
- }
- else
- *availability = AVAIL_NOT_AVAILABLE;
- return node;
- }
- if (node && availability && weakref_p)
- {
- enum availability a = node->get_availability ();
- if (a < *availability)
- *availability = a;
- weakref_p = node->weakref;
- }
- }
- if (availability)
- *availability = AVAIL_NOT_AVAILABLE;
- return NULL;
- }
- /* C++ FE sometimes change linkage flags after producing same body aliases.
- FIXME: C++ produce implicit aliases for virtual functions and vtables that
- are obviously equivalent. The way it is doing so is however somewhat
- kludgy and interferes with the visibility code. As a result we need to
- copy the visibility from the target to get things right. */
- void
- symtab_node::fixup_same_cpp_alias_visibility (symtab_node *target)
- {
- if (is_a <cgraph_node *> (this))
- {
- DECL_DECLARED_INLINE_P (decl)
- = DECL_DECLARED_INLINE_P (target->decl);
- DECL_DISREGARD_INLINE_LIMITS (decl)
- = DECL_DISREGARD_INLINE_LIMITS (target->decl);
- }
- /* FIXME: It is not really clear why those flags should not be copied for
- functions, too. */
- else
- {
- DECL_WEAK (decl) = DECL_WEAK (target->decl);
- DECL_EXTERNAL (decl) = DECL_EXTERNAL (target->decl);
- DECL_VISIBILITY (decl) = DECL_VISIBILITY (target->decl);
- }
- DECL_VIRTUAL_P (decl) = DECL_VIRTUAL_P (target->decl);
- if (TREE_PUBLIC (decl))
- {
- tree group;
- DECL_EXTERNAL (decl) = DECL_EXTERNAL (target->decl);
- DECL_COMDAT (decl) = DECL_COMDAT (target->decl);
- group = target->get_comdat_group ();
- set_comdat_group (group);
- if (group && !same_comdat_group)
- add_to_same_comdat_group (target);
- }
- externally_visible = target->externally_visible;
- }
- /* Set section, do not recurse into aliases.
- When one wants to change section of symbol and its aliases,
- use set_section. */
- void
- symtab_node::set_section_for_node (const char *section)
- {
- const char *current = get_section ();
- section_hash_entry **slot;
- if (current == section
- || (current && section
- && !strcmp (current, section)))
- return;
- if (current)
- {
- x_section->ref_count--;
- if (!x_section->ref_count)
- {
- hashval_t hash = htab_hash_string (x_section->name);
- slot = symtab->section_hash->find_slot_with_hash (x_section->name,
- hash, INSERT);
- ggc_free (x_section);
- symtab->section_hash->clear_slot (slot);
- }
- x_section = NULL;
- }
- if (!section)
- {
- implicit_section = false;
- return;
- }
- if (!symtab->section_hash)
- symtab->section_hash = hash_table<section_name_hasher>::create_ggc (10);
- slot = symtab->section_hash->find_slot_with_hash (section,
- htab_hash_string (section),
- INSERT);
- if (*slot)
- x_section = (section_hash_entry *)*slot;
- else
- {
- int len = strlen (section);
- *slot = x_section = ggc_cleared_alloc<section_hash_entry> ();
- x_section->name = ggc_vec_alloc<char> (len + 1);
- memcpy (x_section->name, section, len + 1);
- }
- x_section->ref_count++;
- }
- /* Worker for set_section. */
- bool
- symtab_node::set_section (symtab_node *n, void *s)
- {
- n->set_section_for_node ((char *)s);
- return false;
- }
- /* Set section of symbol and its aliases. */
- void
- symtab_node::set_section (const char *section)
- {
- gcc_assert (!this->alias);
- call_for_symbol_and_aliases
- (symtab_node::set_section, const_cast<char *>(section), true);
- }
- /* Return the initialization priority. */
- priority_type
- symtab_node::get_init_priority ()
- {
- if (!this->in_init_priority_hash)
- return DEFAULT_INIT_PRIORITY;
- symbol_priority_map *h = symtab->init_priority_hash->get (this);
- return h ? h->init : DEFAULT_INIT_PRIORITY;
- }
- /* Return the finalization priority. */
- priority_type
- cgraph_node::get_fini_priority ()
- {
- if (!this->in_init_priority_hash)
- return DEFAULT_INIT_PRIORITY;
- symbol_priority_map *h = symtab->init_priority_hash->get (this);
- return h ? h->fini : DEFAULT_INIT_PRIORITY;
- }
- /* Return the initialization and finalization priority information for
- DECL. If there is no previous priority information, a freshly
- allocated structure is returned. */
- symbol_priority_map *
- symtab_node::priority_info (void)
- {
- if (!symtab->init_priority_hash)
- symtab->init_priority_hash = hash_map<symtab_node *, symbol_priority_map>::create_ggc (13);
- bool existed;
- symbol_priority_map *h
- = &symtab->init_priority_hash->get_or_insert (this, &existed);
- if (!existed)
- {
- h->init = DEFAULT_INIT_PRIORITY;
- h->fini = DEFAULT_INIT_PRIORITY;
- in_init_priority_hash = true;
- }
- return h;
- }
- /* Set initialization priority to PRIORITY. */
- void
- symtab_node::set_init_priority (priority_type priority)
- {
- symbol_priority_map *h;
- if (is_a <cgraph_node *> (this))
- gcc_assert (DECL_STATIC_CONSTRUCTOR (this->decl));
- if (priority == DEFAULT_INIT_PRIORITY)
- {
- gcc_assert (get_init_priority() == priority);
- return;
- }
- h = priority_info ();
- h->init = priority;
- }
- /* Set fialization priority to PRIORITY. */
- void
- cgraph_node::set_fini_priority (priority_type priority)
- {
- symbol_priority_map *h;
- gcc_assert (DECL_STATIC_DESTRUCTOR (this->decl));
- if (priority == DEFAULT_INIT_PRIORITY)
- {
- gcc_assert (get_fini_priority() == priority);
- return;
- }
- h = priority_info ();
- h->fini = priority;
- }
- /* Worker for symtab_resolve_alias. */
- bool
- symtab_node::set_implicit_section (symtab_node *n,
- void *data ATTRIBUTE_UNUSED)
- {
- n->implicit_section = true;
- return false;
- }
- /* Add reference recording that symtab node is alias of TARGET.
- The function can fail in the case of aliasing cycles; in this case
- it returns false. */
- bool
- symtab_node::resolve_alias (symtab_node *target)
- {
- symtab_node *n;
- gcc_assert (!analyzed && !vec_safe_length (ref_list.references));
- /* Never let cycles to creep into the symbol table alias references;
- those will make alias walkers to be infinite. */
- for (n = target; n && n->alias;
- n = n->analyzed ? n->get_alias_target () : NULL)
- if (n == this)
- {
- if (is_a <cgraph_node *> (this))
- error ("function %q+D part of alias cycle", decl);
- else if (is_a <varpool_node *> (this))
- error ("variable %q+D part of alias cycle", decl);
- else
- gcc_unreachable ();
- alias = false;
- return false;
- }
- /* "analyze" the node - i.e. mark the reference. */
- definition = true;
- alias = true;
- analyzed = true;
- create_reference (target, IPA_REF_ALIAS, NULL);
- /* Add alias into the comdat group of its target unless it is already there. */
- if (same_comdat_group)
- remove_from_same_comdat_group ();
- set_comdat_group (NULL);
- if (target->get_comdat_group ())
- add_to_same_comdat_group (target);
- if ((get_section () != target->get_section ()
- || target->get_comdat_group ()) && get_section () && !implicit_section)
- {
- error ("section of alias %q+D must match section of its target", decl);
- }
- call_for_symbol_and_aliases (symtab_node::set_section,
- const_cast<char *>(target->get_section ()), true);
- if (target->implicit_section)
- call_for_symbol_and_aliases (set_implicit_section, NULL, true);
- /* Alias targets become redundant after alias is resolved into an reference.
- We do not want to keep it around or we would have to mind updating them
- when renaming symbols. */
- alias_target = NULL;
- if (cpp_implicit_alias && symtab->state >= CONSTRUCTION)
- fixup_same_cpp_alias_visibility (target);
- /* If alias has address taken, so does the target. */
- if (address_taken)
- target->ultimate_alias_target ()->address_taken = true;
- /* All non-weakref aliases of THIS are now in fact aliases of TARGET. */
- ipa_ref *ref;
- for (unsigned i = 0; iterate_direct_aliases (i, ref);)
- {
- struct symtab_node *alias_alias = ref->referring;
- if (!alias_alias->weakref)
- {
- alias_alias->remove_all_references ();
- alias_alias->create_reference (target, IPA_REF_ALIAS, NULL);
- }
- else i++;
- }
- return true;
- }
- /* Worker searching noninterposable alias. */
- bool
- symtab_node::noninterposable_alias (symtab_node *node, void *data)
- {
- if (decl_binds_to_current_def_p (node->decl))
- {
- symtab_node *fn = node->ultimate_alias_target ();
- /* Ensure that the alias is well formed this may not be the case
- of user defined aliases and currently it is not always the case
- of C++ same body aliases (that is a bug). */
- if (TREE_TYPE (node->decl) != TREE_TYPE (fn->decl)
- || DECL_CONTEXT (node->decl) != DECL_CONTEXT (fn->decl)
- || (TREE_CODE (node->decl) == FUNCTION_DECL
- && flags_from_decl_or_type (node->decl)
- != flags_from_decl_or_type (fn->decl))
- || DECL_ATTRIBUTES (node->decl) != DECL_ATTRIBUTES (fn->decl))
- return false;
- *(symtab_node **)data = node;
- return true;
- }
- return false;
- }
- /* If node can not be overwriten by static or dynamic linker to point to
- different definition, return NODE. Otherwise look for alias with such
- property and if none exists, introduce new one. */
- symtab_node *
- symtab_node::noninterposable_alias (void)
- {
- tree new_decl;
- symtab_node *new_node = NULL;
- /* First try to look up existing alias or base object
- (if that is already non-overwritable). */
- symtab_node *node = ultimate_alias_target ();
- gcc_assert (!node->alias && !node->weakref);
- node->call_for_symbol_and_aliases (symtab_node::noninterposable_alias,
- (void *)&new_node, true);
- if (new_node)
- return new_node;
- #ifndef ASM_OUTPUT_DEF
- /* If aliases aren't supported by the assembler, fail. */
- return NULL;
- #endif
- /* Otherwise create a new one. */
- new_decl = copy_node (node->decl);
- DECL_DLLIMPORT_P (new_decl) = 0;
- DECL_NAME (new_decl) = clone_function_name (node->decl, "localalias");
- if (TREE_CODE (new_decl) == FUNCTION_DECL)
- DECL_STRUCT_FUNCTION (new_decl) = NULL;
- DECL_INITIAL (new_decl) = NULL;
- SET_DECL_ASSEMBLER_NAME (new_decl, DECL_NAME (new_decl));
- SET_DECL_RTL (new_decl, NULL);
- /* Update the properties. */
- DECL_EXTERNAL (new_decl) = 0;
- TREE_PUBLIC (new_decl) = 0;
- DECL_COMDAT (new_decl) = 0;
- DECL_WEAK (new_decl) = 0;
- /* Since the aliases can be added to vtables, keep DECL_VIRTUAL flag. */
- DECL_VIRTUAL_P (new_decl) = DECL_VIRTUAL_P (node->decl);
- if (TREE_CODE (new_decl) == FUNCTION_DECL)
- {
- DECL_STATIC_CONSTRUCTOR (new_decl) = 0;
- DECL_STATIC_DESTRUCTOR (new_decl) = 0;
- new_node = cgraph_node::create_alias (new_decl, node->decl);
- }
- else
- {
- TREE_READONLY (new_decl) = TREE_READONLY (node->decl);
- DECL_INITIAL (new_decl) = error_mark_node;
- new_node = varpool_node::create_alias (new_decl, node->decl);
- }
- new_node->resolve_alias (node);
- gcc_assert (decl_binds_to_current_def_p (new_decl)
- && targetm.binds_local_p (new_decl));
- return new_node;
- }
- /* Return true if symtab node and TARGET represents
- semantically equivalent symbols. */
- bool
- symtab_node::semantically_equivalent_p (symtab_node *target)
- {
- enum availability avail;
- symtab_node *ba;
- symtab_node *bb;
- /* Equivalent functions are equivalent. */
- if (decl == target->decl)
- return true;
- /* If symbol is not overwritable by different implementation,
- walk to the base object it defines. */
- ba = ultimate_alias_target (&avail);
- if (avail >= AVAIL_AVAILABLE)
- {
- if (target == ba)
- return true;
- }
- else
- ba = this;
- bb = target->ultimate_alias_target (&avail);
- if (avail >= AVAIL_AVAILABLE)
- {
- if (this == bb)
- return true;
- }
- else
- bb = target;
- return bb == ba;
- }
- /* Classify symbol symtab node for partitioning. */
- enum symbol_partitioning_class
- symtab_node::get_partitioning_class (void)
- {
- /* Inline clones are always duplicated.
- This include external delcarations. */
- cgraph_node *cnode = dyn_cast <cgraph_node *> (this);
- if (DECL_ABSTRACT_P (decl))
- return SYMBOL_EXTERNAL;
- if (cnode && cnode->global.inlined_to)
- return SYMBOL_DUPLICATE;
- /* Weakref aliases are always duplicated. */
- if (weakref)
- return SYMBOL_DUPLICATE;
- /* External declarations are external. */
- if (DECL_EXTERNAL (decl))
- return SYMBOL_EXTERNAL;
- if (varpool_node *vnode = dyn_cast <varpool_node *> (this))
- {
- if (alias && definition && !ultimate_alias_target ()->definition)
- return SYMBOL_EXTERNAL;
- /* Constant pool references use local symbol names that can not
- be promoted global. We should never put into a constant pool
- objects that can not be duplicated across partitions. */
- if (DECL_IN_CONSTANT_POOL (decl))
- return SYMBOL_DUPLICATE;
- if (DECL_HARD_REGISTER (decl))
- return SYMBOL_DUPLICATE;
- gcc_checking_assert (vnode->definition);
- }
- /* Functions that are cloned may stay in callgraph even if they are unused.
- Handle them as external; compute_ltrans_boundary take care to make
- proper things to happen (i.e. to make them appear in the boundary but
- with body streamed, so clone can me materialized). */
- else if (!dyn_cast <cgraph_node *> (this)->function_symbol ()->definition)
- return SYMBOL_EXTERNAL;
- /* Linker discardable symbols are duplicated to every use unless they are
- keyed. */
- if (DECL_ONE_ONLY (decl)
- && !force_output
- && !forced_by_abi
- && !used_from_object_file_p ())
- return SYMBOL_DUPLICATE;
- return SYMBOL_PARTITION;
- }
- /* Return true when symbol is known to be non-zero. */
- bool
- symtab_node::nonzero_address ()
- {
- /* Weakrefs may be NULL when their target is not defined. */
- if (alias && weakref)
- {
- if (analyzed)
- {
- symtab_node *target = ultimate_alias_target ();
- if (target->alias && target->weakref)
- return false;
- /* We can not recurse to target::nonzero. It is possible that the
- target is used only via the alias.
- We may walk references and look for strong use, but we do not know
- if this strong use will survive to final binary, so be
- conservative here.
- ??? Maybe we could do the lookup during late optimization that
- could be useful to eliminate the NULL pointer checks in LTO
- programs. */
- if (target->definition && !DECL_EXTERNAL (target->decl))
- return true;
- if (target->resolution != LDPR_UNKNOWN
- && target->resolution != LDPR_UNDEF
- && flag_delete_null_pointer_checks)
- return true;
- return false;
- }
- else
- return false;
- }
- /* With !flag_delete_null_pointer_checks we assume that symbols may
- bind to NULL. This is on by default on embedded targets only.
- Otherwise all non-WEAK symbols must be defined and thus non-NULL or
- linking fails. Important case of WEAK we want to do well are comdats.
- Those are handled by later check for definition.
- When parsing, beware the cases when WEAK attribute is added later. */
- if (!DECL_WEAK (decl)
- && flag_delete_null_pointer_checks)
- {
- refuse_visibility_changes = true;
- return true;
- }
- /* If target is defined and not extern, we know it will be output and thus
- it will bind to non-NULL.
- Play safe for flag_delete_null_pointer_checks where weak definition maye
- be re-defined by NULL. */
- if (definition && !DECL_EXTERNAL (decl)
- && (flag_delete_null_pointer_checks || !DECL_WEAK (decl)))
- {
- if (!DECL_WEAK (decl))
- refuse_visibility_changes = true;
- return true;
- }
- /* As the last resort, check the resolution info. */
- if (resolution != LDPR_UNKNOWN
- && resolution != LDPR_UNDEF
- && flag_delete_null_pointer_checks)
- return true;
- return false;
- }
- /* Return 0 if symbol is known to have different address than S2,
- Return 1 if symbol is known to have same address as S2,
- return 2 otherwise. */
- int
- symtab_node::equal_address_to (symtab_node *s2)
- {
- enum availability avail1, avail2;
- /* A Shortcut: equivalent symbols are always equivalent. */
- if (this == s2)
- return 1;
- /* For non-interposable aliases, lookup and compare their actual definitions.
- Also check if the symbol needs to bind to given definition. */
- symtab_node *rs1 = ultimate_alias_target (&avail1);
- symtab_node *rs2 = s2->ultimate_alias_target (&avail2);
- bool binds_local1 = rs1->analyzed && decl_binds_to_current_def_p (this->decl);
- bool binds_local2 = rs2->analyzed && decl_binds_to_current_def_p (s2->decl);
- bool really_binds_local1 = binds_local1;
- bool really_binds_local2 = binds_local2;
- /* Addresses of vtables and virtual functions can not be used by user
- code and are used only within speculation. In this case we may make
- symbol equivalent to its alias even if interposition may break this
- rule. Doing so will allow us to turn speculative inlining into
- non-speculative more agressively. */
- if (DECL_VIRTUAL_P (this->decl) && avail1 >= AVAIL_AVAILABLE)
- binds_local1 = true;
- if (DECL_VIRTUAL_P (s2->decl) && avail2 >= AVAIL_AVAILABLE)
- binds_local2 = true;
- /* If both definitions are available we know that even if they are bound
- to other unit they must be defined same way and therefore we can use
- equivalence test. */
- if (rs1 != rs2 && avail1 >= AVAIL_AVAILABLE && avail2 >= AVAIL_AVAILABLE)
- binds_local1 = binds_local2 = true;
- if ((binds_local1 ? rs1 : this)
- == (binds_local2 ? rs2 : s2))
- {
- /* We made use of the fact that alias is not weak. */
- if (binds_local1 && rs1 != this)
- refuse_visibility_changes = true;
- if (binds_local2 && rs2 != s2)
- s2->refuse_visibility_changes = true;
- return 1;
- }
- /* If both symbols may resolve to NULL, we can not really prove them different. */
- if (!nonzero_address () && !s2->nonzero_address ())
- return 2;
- /* Except for NULL, functions and variables never overlap. */
- if (TREE_CODE (decl) != TREE_CODE (s2->decl))
- return 0;
- /* If one of the symbols is unresolved alias, punt. */
- if (rs1->alias || rs2->alias)
- return 2;
- /* If we have a non-interposale definition of at least one of the symbols
- and the other symbol is different, we know other unit can not interpose
- it to the first symbol; all aliases of the definition needs to be
- present in the current unit. */
- if (((really_binds_local1 || really_binds_local2)
- /* If we have both definitions and they are different, we know they
- will be different even in units they binds to. */
- || (binds_local1 && binds_local2))
- && rs1 != rs2)
- {
- /* We make use of the fact that one symbol is not alias of the other
- and that the definition is non-interposable. */
- refuse_visibility_changes = true;
- s2->refuse_visibility_changes = true;
- rs1->refuse_visibility_changes = true;
- rs2->refuse_visibility_changes = true;
- return 0;
- }
- /* TODO: Alias oracle basically assume that addresses of global variables
- are different unless they are declared as alias of one to another.
- We probably should be consistent and use this fact here, too, and update
- alias oracle to use this predicate. */
- return 2;
- }
- /* Worker for call_for_symbol_and_aliases. */
- bool
- symtab_node::call_for_symbol_and_aliases_1 (bool (*callback) (symtab_node *,
- void *),
- void *data,
- bool include_overwritable)
- {
- ipa_ref *ref;
- FOR_EACH_ALIAS (this, ref)
- {
- symtab_node *alias = ref->referring;
- if (include_overwritable
- || alias->get_availability () > AVAIL_INTERPOSABLE)
- if (alias->call_for_symbol_and_aliases (callback, data,
- include_overwritable))
- return true;
- }
- return false;
- }
- /* Return ture if address of N is possibly compared. */
- static bool
- address_matters_1 (symtab_node *n, void *)
- {
- struct ipa_ref *ref;
- if (!n->address_can_be_compared_p ())
- return false;
- if (n->externally_visible || n->force_output)
- return true;
- for (unsigned int i = 0; n->iterate_referring (i, ref); i++)
- if (ref->address_matters_p ())
- return true;
- return false;
- }
- /* Return true if symbol's address may possibly be compared to other
- symbol's address. */
- bool
- symtab_node::address_matters_p ()
- {
- gcc_assert (!alias);
- return call_for_symbol_and_aliases (address_matters_1, NULL, true);
- }
- /* Return ture if symbol's alignment may be increased. */
- bool
- symtab_node::can_increase_alignment_p (void)
- {
- symtab_node *target = ultimate_alias_target ();
- /* For now support only variables. */
- if (TREE_CODE (decl) != VAR_DECL)
- return false;
- /* With -fno-toplevel-reorder we may have already output the constant. */
- if (TREE_ASM_WRITTEN (target->decl))
- return false;
- /* If target is already placed in an anchor, we can not touch its
- alignment. */
- if (DECL_RTL_SET_P (target->decl)
- && MEM_P (DECL_RTL (target->decl))
- && SYMBOL_REF_HAS_BLOCK_INFO_P (XEXP (DECL_RTL (target->decl), 0)))
- return false;
- /* Constant pool entries may be shared. */
- if (DECL_IN_CONSTANT_POOL (target->decl))
- return false;
- /* We cannot change alignment of symbols that may bind to symbols
- in other translation unit that may contain a definition with lower
- alignment. */
- if (!decl_binds_to_current_def_p (decl))
- return false;
- /* When compiling partition, be sure the symbol is not output by other
- partition. */
- if (flag_ltrans
- && (target->in_other_partition
- || target->get_partitioning_class () == SYMBOL_DUPLICATE))
- return false;
- /* Do not override the alignment as specified by the ABI when the used
- attribute is set. */
- if (DECL_PRESERVE_P (decl) || DECL_PRESERVE_P (target->decl))
- return false;
- /* Do not override explicit alignment set by the user when an explicit
- section name is also used. This is a common idiom used by many
- software projects. */
- if (DECL_SECTION_NAME (target->decl) != NULL && !target->implicit_section)
- return false;
- return true;
- }
- /* Worker for symtab_node::increase_alignment. */
- static bool
- increase_alignment_1 (symtab_node *n, void *v)
- {
- unsigned int align = (size_t)v;
- if (DECL_ALIGN (n->decl) < align
- && n->can_increase_alignment_p ())
- {
- DECL_ALIGN (n->decl) = align;
- DECL_USER_ALIGN (n->decl) = 1;
- }
- return false;
- }
- /* Increase alignment of THIS to ALIGN. */
- void
- symtab_node::increase_alignment (unsigned int align)
- {
- gcc_assert (can_increase_alignment_p () && align < MAX_OFILE_ALIGNMENT);
- ultimate_alias_target()->call_for_symbol_and_aliases (increase_alignment_1,
- (void *)(size_t) align,
- true);
- gcc_assert (DECL_ALIGN (decl) >= align);
- }
- /* Helper for symtab_node::definition_alignment. */
- static bool
- get_alignment_1 (symtab_node *n, void *v)
- {
- *((unsigned int *)v) = MAX (*((unsigned int *)v), DECL_ALIGN (n->decl));
- return false;
- }
- /* Return desired alignment of the definition. This is NOT alignment useful
- to access THIS, because THIS may be interposable and DECL_ALIGN should
- be used instead. It however must be guaranteed when output definition
- of THIS. */
- unsigned int
- symtab_node::definition_alignment ()
- {
- unsigned int align = 0;
- gcc_assert (!alias);
- call_for_symbol_and_aliases (get_alignment_1, &align, true);
- return align;
- }
|