diff options
author | Martin Liska <mliska@suse.cz> | 2018-10-04 16:36:55 +0200 |
---|---|---|
committer | Martin Liska <marxin@gcc.gnu.org> | 2018-10-04 14:36:55 +0000 |
commit | b8ce8129a560f64f8b2855c4a3812b7c3c0ebf3f (patch) | |
tree | 02aaab6f5293cdf28242006b5feaf40288117680 /gcc/multiple_target.c | |
parent | 5d98e5a6bc715cc865b9110ff0255572ac22570d (diff) | |
download | gcc-b8ce8129a560f64f8b2855c4a3812b7c3c0ebf3f.zip gcc-b8ce8129a560f64f8b2855c4a3812b7c3c0ebf3f.tar.gz gcc-b8ce8129a560f64f8b2855c4a3812b7c3c0ebf3f.tar.bz2 |
Redirect call within specific target attribute among MV clones (PR ipa/82625).
2018-10-04 Martin Liska <mliska@suse.cz>
PR ipa/82625
* multiple_target.c (redirect_to_specific_clone): New function.
(ipa_target_clone): Use it.
* tree-inline.c: Fix comment.
2018-10-04 Martin Liska <mliska@suse.cz>
PR ipa/82625
* g++.dg/ext/pr82625.C: New test.
From-SVN: r264845
Diffstat (limited to 'gcc/multiple_target.c')
-rw-r--r-- | gcc/multiple_target.c | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/gcc/multiple_target.c b/gcc/multiple_target.c index a610d9a..2d892f2 100644 --- a/gcc/multiple_target.c +++ b/gcc/multiple_target.c @@ -451,6 +451,54 @@ expand_target_clones (struct cgraph_node *node, bool definition) return ret; } +/* When NODE is a target clone, consider all callees and redirect + to a clone with equal target attributes. That prevents multiple + multi-versioning dispatches and a call-chain can be optimized. */ + +static void +redirect_to_specific_clone (cgraph_node *node) +{ + cgraph_function_version_info *fv = node->function_version (); + if (fv == NULL) + return; + + tree attr_target = lookup_attribute ("target", DECL_ATTRIBUTES (node->decl)); + if (attr_target == NULL_TREE) + return; + + /* We need to remember NEXT_CALLER as it could be modified in the loop. */ + for (cgraph_edge *e = node->callees; e ; e = e->next_callee) + { + cgraph_function_version_info *fv2 = e->callee->function_version (); + if (!fv2) + continue; + + tree attr_target2 = lookup_attribute ("target", + DECL_ATTRIBUTES (e->callee->decl)); + + /* Function is not calling proper target clone. */ + if (!attribute_list_equal (attr_target, attr_target2)) + { + while (fv2->prev != NULL) + fv2 = fv2->prev; + + /* Try to find a clone with equal target attribute. */ + for (; fv2 != NULL; fv2 = fv2->next) + { + cgraph_node *callee = fv2->this_node; + attr_target2 = lookup_attribute ("target", + DECL_ATTRIBUTES (callee->decl)); + if (attribute_list_equal (attr_target, attr_target2)) + { + e->redirect_callee (callee); + e->redirect_call_stmt_to_callee (); + break; + } + } + } + } +} + static unsigned int ipa_target_clone (void) { @@ -464,6 +512,9 @@ ipa_target_clone (void) for (unsigned i = 0; i < to_dispatch.length (); i++) create_dispatcher_calls (to_dispatch[i]); + FOR_EACH_FUNCTION (node) + redirect_to_specific_clone (node); + return 0; } |