The following fixes behavior of IPA PTA with IFUNCs.  Those were
treated as simple aliases (since ->alias is set) and thus we
just considered the ifunc resolver as body.  The following instead
associates an IFUNC call with an indirect call to a var initialized
from the resolver result.

Bootstrapped on x86_64-unknown-linux-gnu, testing in progress.
LTO bootstrapped with -fipa-pta in BOOT_CFLAGS on 
x86_64-unknown-linux-gnu.

Testing coverage isn't too big with IPA PTA so I'm not considering
to backport this for the moment.

Richard.

2018-05-30  Richard Biener  <rguent...@suse.de>

        PR ipa/85960
        * tree-ssa-structalias.c (get_function_part_constraint):
        Handle NULL fi->decl.
        (find_func_aliases_for_call): Properly handle indirect
        fi from direct call.
        (find_func_clobbers): Likewise.
        (ipa_pta_execute): Likewise.
        (create_variable_info_for): For functions that are ifunc_resolver
        resolve to a varinfo that contains the result of the resolver
        call.
        (associate_varinfo_to_alias): Do not treat ifunc resolvers as
        aliases.

        * gcc.dg/ipa/ipa-pta-19.c: New testcase.

Index: gcc/tree-ssa-structalias.c
===================================================================
--- gcc/tree-ssa-structalias.c  (revision 260950)
+++ gcc/tree-ssa-structalias.c  (working copy)
@@ -3903,7 +3903,7 @@ get_function_part_constraint (varinfo_t
       c.offset = 0;
       c.type = SCALAR;
     }
-  else if (TREE_CODE (fi->decl) == FUNCTION_DECL)
+  else if (fi->decl && TREE_CODE (fi->decl) == FUNCTION_DECL)
     {
       varinfo_t ai = first_vi_for_offset (fi, part);
       if (ai)
@@ -4733,7 +4733,7 @@ find_func_aliases_for_call (struct funct
 
   fi = get_fi_for_callee (t);
   if (!in_ipa_mode
-      || (fndecl && !fi->is_fn_info))
+      || (fi->decl && fndecl && !fi->is_fn_info))
     {
       auto_vec<ce_s, 16> rhsc;
       int flags = gimple_call_flags (t);
@@ -5350,7 +5350,7 @@ find_func_clobbers (struct function *fn,
 
       /* For callees without function info (that's external functions),
         ESCAPED is clobbered and used.  */
-      if (gimple_call_fndecl (t)
+      if (cfi->decl
          && !cfi->is_fn_info)
        {
          varinfo_t vi;
@@ -6113,6 +6113,27 @@ create_variable_info_for_1 (tree decl, c
 static unsigned int
 create_variable_info_for (tree decl, const char *name, bool add_id)
 {
+  /* First see if we are dealing with an ifunc resolver call and
+     assiociate that with a call to the resolver function result.  */
+  cgraph_node *node;
+  if (in_ipa_mode
+      && TREE_CODE (decl) == FUNCTION_DECL
+      && (node = cgraph_node::get (decl))->ifunc_resolver)
+    {
+      varinfo_t fi = get_vi_for_tree (node->get_alias_target ()->decl);
+      constraint_expr rhs
+       = get_function_part_constraint (fi, fi_result);
+      fi = new_var_info (NULL_TREE, "ifuncres", true);
+      fi->is_reg_var = true;
+      constraint_expr lhs;
+      lhs.type = SCALAR;
+      lhs.var = fi->id;
+      lhs.offset = 0;
+      process_constraint (new_constraint (lhs, rhs));
+      insert_vi_for_tree (decl, fi);
+      return fi->id;
+    }
+
   varinfo_t vi = create_variable_info_for_1 (decl, name, add_id, false, NULL);
   unsigned int id = vi->id;
 
@@ -7713,7 +7734,8 @@ associate_varinfo_to_alias (struct cgrap
   if ((node->alias
        || (node->thunk.thunk_p
           && ! node->global.inlined_to))
-      && node->analyzed)
+      && node->analyzed
+      && !node->ifunc_resolver)
     insert_vi_for_tree (node->decl, (varinfo_t)data);
   return false;
 }
@@ -8085,7 +8107,7 @@ ipa_pta_execute (void)
                         (node->decl, first_vi_for_offset (fi, fi_uses));
                }
              /* Handle direct calls to external functions.  */
-             else if (decl)
+             else if (decl && (!fi || fi->decl))
                {
                  pt = gimple_call_use_set (stmt);
                  if (gimple_call_flags (stmt) & ECF_CONST)
@@ -8130,8 +8152,7 @@ ipa_pta_execute (void)
                    }
                }
              /* Handle indirect calls.  */
-             else if (!decl
-                      && (fi = get_fi_for_callee (stmt)))
+             else if ((fi = get_fi_for_callee (stmt)))
                {
                  /* We need to accumulate all clobbers/uses of all possible
                     callees.  */
@@ -8187,6 +8208,8 @@ ipa_pta_execute (void)
                        }
                    }
                }
+             else
+               gcc_unreachable ();
            }
        }
 
Index: gcc/testsuite/gcc.dg/ipa/ipa-pta-19.c
===================================================================
--- gcc/testsuite/gcc.dg/ipa/ipa-pta-19.c       (nonexistent)
+++ gcc/testsuite/gcc.dg/ipa/ipa-pta-19.c       (working copy)
@@ -0,0 +1,46 @@
+/* { dg-do run } */
+/* { dg-require-ifunc "" } */
+/* { dg-options "-O2 -fipa-pta" } */
+
+#include <stdlib.h>
+#include <stdbool.h>
+
+#define hot __attribute__((hot))
+
+static hot void multiver_default(unsigned int in, bool *ret)
+{
+       if ( in & 1 ) {
+               *ret = false;
+       }else{
+               *ret = true;
+       }
+}
+
+static void (*resolve_multiver(void))(unsigned int in, bool *out)
+{
+       return &multiver_default;
+}
+
+__attribute__ ((ifunc("resolve_multiver")))
+static void multiver_test(unsigned int val, bool *ret);
+
+static hot bool do_test(unsigned int val)
+{
+       bool ret = false;
+
+       multiver_test(val, &ret);
+
+       return (ret == !(val & 0x1));
+}
+
+volatile unsigned int x = 2;
+int main()
+{
+  int i;
+  for(i = 1; i < x; i++) {
+      unsigned int val = x;
+      if ( !do_test(val) )
+       abort ();
+  }
+  return 0;
+}

Reply via email to