Add EAF_NODIRECTESCAPE flag
authorJan Hubicka <jh@suse.cz>
Wed, 25 Nov 2020 19:51:26 +0000 (20:51 +0100)
committerJan Hubicka <jh@suse.cz>
Wed, 25 Nov 2020 19:51:26 +0000 (20:51 +0100)
Main limitation of modref is the fact that it does not
track anything in memory. This is intentional - I wanted the initial
implementation to be cheap. However it also makes it very limited when it comes
to detecting noescape especially because it is paranoid about what memory
accesses may be used to copy (bits of) pointers.

This patch adds EAF_NODIRECTSCAPE that is weaker vairant of EAF_NOESCAPE where
we only know that the pointer itself does not escape, but memory pointed to
may.  This is a lot more reliable to auto-detect that EAF_NOESCAPE and still
enables additional optimization.  With patch we get nodirectscape flag for b
that enables in practice similar optimization as EAF_NOESCAPE for arrays of
integers that points nowhere :)

gcc/ChangeLog:
* gimple.c (gimple_call_arg_flags): Also imply EAF_NODIRECTESCAPE.
* tree-core.h (EAF_NODRECTESCAPE): New flag.
* tree-ssa-structalias.c (make_indirect_escape_constraint): New
function.
(handle_rhs_call): Hanlde EAF_NODIRECTESCAPE.
* ipa-modref.c (dump_eaf_flags): Print EAF_NODIRECTESCAPE.
(deref_flags): Dereference is always EAF_NODIRECTESCAPE.
(modref_lattice::init): Also set EAF_NODIRECTESCAPE.
(analyze_ssa_name_flags): Pure functions do not affect
EAF_NODIRECTESCAPE.
(analyze_params): Likewise.
(ipa_merge_modref_summary_after_inlining): Likewise.
(modref_merge_call_site_flags): Likewise.

gcc/gimple.c
gcc/ipa-modref.c
gcc/tree-core.h
gcc/tree-ssa-structalias.c

index e3e508daf2fe9248c7cf17cd6c97b8cfb322d134..e8246b72cc983e53e44afe93add3b61d7d9179f9 100644 (file)
@@ -1543,7 +1543,7 @@ gimple_call_arg_flags (const gcall *stmt, unsigned arg)
          if (fnspec.arg_direct_p (arg))
            flags |= EAF_DIRECT;
          if (fnspec.arg_noescape_p (arg))
-           flags |= EAF_NOESCAPE;
+           flags |= EAF_NOESCAPE | EAF_NODIRECTESCAPE;
          if (fnspec.arg_readonly_p (arg))
            flags |= EAF_NOCLOBBER;
        }
index 0ba1a748257a7489b45244d0def3fdf6ccc83947..d1d4ba786a4829a92c34faa272f2c03d3a57006f 100644 (file)
@@ -151,6 +151,8 @@ dump_eaf_flags (FILE *out, int flags, bool newline = true)
     fprintf (out, " noclobber");
   if (flags & EAF_NOESCAPE)
     fprintf (out, " noescape");
+  if (flags & EAF_NODIRECTESCAPE)
+    fprintf (out, " nodirectescape");
   if (flags & EAF_UNUSED)
     fprintf (out, " unused");
   if (newline)
@@ -1303,7 +1305,7 @@ memory_access_to (tree op, tree ssa_name)
 static int
 deref_flags (int flags, bool ignore_stores)
 {
-  int ret = 0;
+  int ret = EAF_NODIRECTESCAPE;
   if (flags & EAF_UNUSED)
     ret |= EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE;
   else
@@ -1361,7 +1363,8 @@ public:
 void
 modref_lattice::init ()
 {
-  flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_UNUSED;
+  flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_UNUSED
+         | EAF_NODIRECTESCAPE;
   open = true;
   known = false;
 }
@@ -1653,7 +1656,8 @@ analyze_ssa_name_flags (tree name, vec<modref_lattice> &lattice, int depth,
                      {
                        int call_flags = gimple_call_arg_flags (call, i);
                        if (ignore_stores)
-                         call_flags |= EAF_NOCLOBBER | EAF_NOESCAPE;
+                         call_flags |= EAF_NOCLOBBER | EAF_NOESCAPE
+                                       | EAF_NODIRECTESCAPE;
 
                        if (!record_ipa)
                          lattice[index].merge (call_flags);
@@ -1829,7 +1833,7 @@ analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto,
       /* For pure functions we have implicit NOCLOBBER
         and NOESCAPE.  */
       if (ecf_flags & ECF_PURE)
-       flags &= ~(EAF_NOCLOBBER | EAF_NOESCAPE);
+       flags &= ~(EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NODIRECTESCAPE);
 
       if (flags)
        {
@@ -3102,7 +3106,7 @@ ipa_merge_modref_summary_after_inlining (cgraph_edge *edge)
            if (!ee->direct)
              flags = deref_flags (flags, ignore_stores);
            else if (ignore_stores)
-             flags |= EAF_NOCLOBBER | EAF_NOESCAPE;
+             flags |= EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NODIRECTESCAPE;
            flags |= ee->min_flags;
            to_info->arg_flags[ee->parm_index] &= flags;
            if (to_info->arg_flags[ee->parm_index])
@@ -3116,7 +3120,7 @@ ipa_merge_modref_summary_after_inlining (cgraph_edge *edge)
            if (!ee->direct)
              flags = deref_flags (flags, ignore_stores);
            else if (ignore_stores)
-             flags |= EAF_NOCLOBBER | EAF_NOESCAPE;
+             flags |= EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NODIRECTESCAPE;
            flags |= ee->min_flags;
            to_info_lto->arg_flags[ee->parm_index] &= flags;
            if (to_info_lto->arg_flags[ee->parm_index])
@@ -3627,8 +3631,8 @@ modref_merge_call_site_flags (escape_summary *sum,
        }
       else if (ignore_stores)
        {
-         flags |= EAF_NOESCAPE | EAF_NOCLOBBER;
-         flags_lto |= EAF_NOESCAPE | EAF_NOCLOBBER;
+         flags |= EAF_NOESCAPE | EAF_NOCLOBBER | EAF_NODIRECTESCAPE;
+         flags_lto |= EAF_NOESCAPE | EAF_NOCLOBBER | EAF_NODIRECTESCAPE;
        }
       flags |= ee->min_flags;
       flags_lto |= ee->min_flags;
index 313a6af2253454491f1f0d743ef496e4590a11cb..e457b917b98e08a2fe83adc0610ef364169bc9de 100644 (file)
@@ -110,6 +110,10 @@ struct die_struct;
 /* Nonzero if the argument is not used by the function.  */
 #define EAF_UNUSED             (1 << 3)
 
+/* Nonzero if the argument itself does not escape but memory
+   referenced by it can escape.  */
+#define EAF_NODIRECTESCAPE     (1 << 4)
+
 /* Call return flags.  */
 /* Mask for the argument number that is returned.  Lower two bits of
    the return flags, encodes argument slots zero to three.  */
index a4832b7543639224f734c804382f3d4b2de1ac4f..9f4de96d5442593ec291a62ff00008307a6afff9 100644 (file)
@@ -3851,6 +3851,23 @@ make_escape_constraint (tree op)
   make_constraint_to (escaped_id, op);
 }
 
+/* Make constraint necessary to make all indirect references
+   from VI escape.  */
+
+static void
+make_indirect_escape_constraint (varinfo_t vi)
+{
+  struct constraint_expr lhs, rhs;
+  /* escaped = *(VAR + UNKNOWN);  */
+  lhs.type = SCALAR;
+  lhs.var = escaped_id;
+  lhs.offset = 0;
+  rhs.type = DEREF;
+  rhs.var = vi->id;
+  rhs.offset = UNKNOWN_OFFSET;
+  process_constraint (new_constraint (lhs, rhs));
+}
+
 /* Add constraints to that the solution of VI is transitively closed.  */
 
 static void
@@ -4026,7 +4043,7 @@ handle_rhs_call (gcall *stmt, vec<ce_s> *results)
         set.  The argument would still get clobbered through the
         escape solution.  */
       if ((flags & EAF_NOCLOBBER)
-          && (flags & EAF_NOESCAPE))
+          && (flags & (EAF_NOESCAPE | EAF_NODIRECTESCAPE)))
        {
          varinfo_t uses = get_call_use_vi (stmt);
          varinfo_t tem = new_var_info (NULL_TREE, "callarg", true);
@@ -4036,9 +4053,11 @@ handle_rhs_call (gcall *stmt, vec<ce_s> *results)
          if (!(flags & EAF_DIRECT))
            make_transitive_closure_constraints (tem);
          make_copy_constraint (uses, tem->id);
+         if (!(flags & (EAF_NOESCAPE | EAF_DIRECT)))
+           make_indirect_escape_constraint (tem);
          returns_uses = true;
        }
-      else if (flags & EAF_NOESCAPE)
+      else if (flags & (EAF_NOESCAPE | EAF_NODIRECTESCAPE))
        {
          struct constraint_expr lhs, rhs;
          varinfo_t uses = get_call_use_vi (stmt);
@@ -4061,6 +4080,8 @@ handle_rhs_call (gcall *stmt, vec<ce_s> *results)
          rhs.var = nonlocal_id;
          rhs.offset = 0;
          process_constraint (new_constraint (lhs, rhs));
+         if (!(flags & (EAF_NOESCAPE | EAF_DIRECT)))
+           make_indirect_escape_constraint (tem);
          returns_uses = true;
        }
       else