Fix target clone indirection elimination
authorYichao Yu <yyc1992@gmail.com>
Fri, 26 Jun 2020 21:46:15 +0000 (15:46 -0600)
committerJeff Law <law@redhat.com>
Fri, 26 Jun 2020 21:49:52 +0000 (15:49 -0600)
The current logic seems to be comparing the whole attribute tree between
the callee and caller (or at least the tree starting from the target attribute).
This is unnecessary and causes strange dependency of the indirection
elimination on unrelated properties like `noinline`(PR95780) and
`visibility`(PR95778).

This changes the comparison to be only on the `target` attribute which should
be the intent of the code.

gcc

* multiple_target.c (redirect_to_specific_clone): Fix tests
to check individual attribute rather than an attribute list.

gcc/testsuite

* gcc.target/i386/pr95778-1.c: New test.
* gcc.target/i386/pr95778-2.c: New test.

gcc/multiple_target.c
gcc/testsuite/gcc.target/i386/pr95778-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/pr95778-2.c [new file with mode: 0644]

index c1cfe8f..b15d004 100644 (file)
@@ -483,7 +483,8 @@ redirect_to_specific_clone (cgraph_node *node)
                                            DECL_ATTRIBUTES (e->callee->decl));
 
       /* Function is not calling proper target clone.  */
-      if (!attribute_list_equal (attr_target, attr_target2))
+      if (attr_target2 == NULL_TREE
+         || !attribute_value_equal (attr_target, attr_target2))
        {
          while (fv2->prev != NULL)
            fv2 = fv2->prev;
@@ -494,7 +495,8 @@ redirect_to_specific_clone (cgraph_node *node)
              cgraph_node *callee = fv2->this_node;
              attr_target2 = lookup_attribute ("target",
                                               DECL_ATTRIBUTES (callee->decl));
-             if (attribute_list_equal (attr_target, attr_target2))
+             if (attr_target2 != NULL_TREE
+                 && attribute_value_equal (attr_target, attr_target2))
                {
                  e->redirect_callee (callee);
                  cgraph_edge::redirect_call_stmt_to_callee (e);
diff --git a/gcc/testsuite/gcc.target/i386/pr95778-1.c b/gcc/testsuite/gcc.target/i386/pr95778-1.c
new file mode 100644 (file)
index 0000000..3238303
--- /dev/null
@@ -0,0 +1,21 @@
+/* { dg-do compile { target fpic } } */
+/* { dg-options "-O3 -fPIC -fno-asynchronous-unwind-tables" } */
+/* { dg-require-ifunc "" } */
+
+__attribute__((target_clones("default,avx2")))
+static int
+f2(int *p)
+{
+  asm volatile ("" :: "r"(p) : "memory");
+  return *p;
+}
+
+__attribute__((target_clones("default,avx2")))
+int
+g2(int *p)
+{
+  return f2(p);
+}
+
+/* { dg-final { scan-assembler "g2.default.1:\n\tjmp\tf2.default.1\n" } } */
+/* { dg-final { scan-assembler "g2.avx2.0:\n\tjmp\tf2.avx2.0\n" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr95778-2.c b/gcc/testsuite/gcc.target/i386/pr95778-2.c
new file mode 100644 (file)
index 0000000..e88702d
--- /dev/null
@@ -0,0 +1,21 @@
+/* { dg-do compile { target fpic } } */
+/* { dg-options "-O3 -fPIC -fno-asynchronous-unwind-tables" } */
+/* { dg-require-ifunc "" } */
+
+__attribute__((visibility("internal"),target_clones("default,avx2")))
+int
+f2(int *p)
+{
+  asm volatile ("" :: "r"(p) : "memory");
+  return *p;
+}
+
+__attribute__((target_clones("default,avx2")))
+int
+g2(int *p)
+{
+  return f2(p);
+}
+
+/* { dg-final { scan-assembler "g2.default.1:\n\tjmp\tf2.default.1\n" } } */
+/* { dg-final { scan-assembler "g2.avx2.0:\n\tjmp\tf2.avx2.0\n" } } */