| /* Interprocedural reference lists. |
| Copyright (C) 2010-2017 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 "target.h" |
| #include "tree.h" |
| #include "cgraph.h" |
| |
| /* Remove reference. */ |
| |
| void |
| ipa_ref::remove_reference () |
| { |
| struct ipa_ref_list *list = referred_ref_list (); |
| struct ipa_ref_list *list2 = referring_ref_list (); |
| vec<ipa_ref_t, va_gc> *old_references = list2->references; |
| struct ipa_ref *last; |
| |
| gcc_assert (list->referring[referred_index] == this); |
| |
| last = list->referring.last (); |
| if (this != last) |
| { |
| if (use == IPA_REF_ALIAS) |
| { |
| /* If deleted item is IPA_REF_ALIAS, we have to move last |
| item of IPA_REF_LIST type to the deleted position. After that |
| we replace last node with deletion slot. */ |
| struct ipa_ref *last_alias = list->last_alias (); |
| |
| if (last_alias && referred_index < last_alias->referred_index |
| && last_alias != last) |
| { |
| unsigned last_alias_index = last_alias->referred_index; |
| |
| list->referring[referred_index] = last_alias; |
| list->referring[referred_index]->referred_index = referred_index; |
| |
| /* New position for replacement is previous index |
| of the last_alias. */ |
| referred_index = last_alias_index; |
| } |
| } |
| |
| list->referring[referred_index] = list->referring.last (); |
| list->referring[referred_index]->referred_index= referred_index; |
| } |
| list->referring.pop (); |
| |
| last = &list2->references->last (); |
| |
| struct ipa_ref *ref = this; |
| |
| if (ref != last) |
| { |
| *ref = *last; |
| ref->referred_ref_list ()->referring[referred_index] = ref; |
| } |
| list2->references->pop (); |
| gcc_assert (list2->references == old_references); |
| } |
| |
| /* Return true when execution of reference can lead to return from |
| function. */ |
| |
| bool |
| ipa_ref::cannot_lead_to_return () |
| { |
| return dyn_cast <cgraph_node *> (referring)->cannot_return_p (); |
| } |
| |
| /* Return reference list this reference is in. */ |
| |
| struct ipa_ref_list * |
| ipa_ref::referring_ref_list (void) |
| { |
| return &referring->ref_list; |
| } |
| |
| /* Return reference list this reference is in. */ |
| |
| struct ipa_ref_list * |
| ipa_ref::referred_ref_list (void) |
| { |
| return &referred->ref_list; |
| } |