Support for value ranges in IPA predicates
authorJan Hubicka <hubicka@gcc.gnu.org>
Thu, 14 Nov 2019 12:41:55 +0000 (12:41 +0000)
committerJan Hubicka <hubicka@gcc.gnu.org>
Thu, 14 Nov 2019 12:41:55 +0000 (12:41 +0000)
        * ipa-cp.c (ipa_vr_operation_and_type_effects): Move up in file.
(ipa_value_range_from_jfunc): New function.
* ipa-fnsummary.c (evaluate_conditions_for_known_args): Add
known_value_ranges parameter; use it to evalulate conditions.
(evaluate_properties_for_edge): Compute known value ranges.
(ipa_fn_summary_t::duplicate): Update use of
evaluate_conditions_for_known_args.
(estimate_ipcp_clone_size_and_time): Likewise.
(ipa_merge_fn_summary_after_inlining): Likewise.
* ipa-prop.h (ipa_value_range_from_jfunc): Declare.

        * gcc.dg/ipa/inline-9.c: New testcase.

From-SVN: r278220

gcc/ChangeLog
gcc/ipa-cp.c
gcc/ipa-fnsummary.c
gcc/ipa-inline.c
gcc/ipa-prop.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/ipa/inline-9.c [new file with mode: 0644]

index 348cc4107decdaddd563b8958c9a077e2c370c49..f35db511057e9087cf1605b08673561596f61158 100644 (file)
@@ -1,3 +1,16 @@
+2019-11-14  Jan Hubicka  <hubicka@ucw.cz>
+
+       * ipa-cp.c (ipa_vr_operation_and_type_effects): Move up in file.
+       (ipa_value_range_from_jfunc): New function.
+       * ipa-fnsummary.c (evaluate_conditions_for_known_args): Add
+       known_value_ranges parameter; use it to evalulate conditions.
+       (evaluate_properties_for_edge): Compute known value ranges.
+       (ipa_fn_summary_t::duplicate): Update use of
+       evaluate_conditions_for_known_args.
+       (estimate_ipcp_clone_size_and_time): Likewise.
+       (ipa_merge_fn_summary_after_inlining): Likewise.
+       * ipa-prop.h (ipa_value_range_from_jfunc): Declare.
+
 2019-11-14  Martin Liska  <mliska@suse.cz>
 
        * ipa-inline.c (want_inline_small_function_p): Use
index 86c625355b6f389feb8e68ef342d1663cd0e32f3..8372dfaa7715f291e29848f621a3b84de53d2131 100644 (file)
@@ -1473,6 +1473,87 @@ ipa_context_from_jfunc (ipa_node_params *info, cgraph_edge *cs, int csidx,
   return ctx;
 }
 
+/* Emulate effects of unary OPERATION and/or conversion from SRC_TYPE to
+   DST_TYPE on value range in SRC_VR and store it to DST_VR.  Return true if
+   the result is a range or an anti-range.  */
+
+static bool
+ipa_vr_operation_and_type_effects (value_range *dst_vr,
+                                  value_range *src_vr,
+                                  enum tree_code operation,
+                                  tree dst_type, tree src_type)
+{
+  range_fold_unary_expr (dst_vr, operation, dst_type, src_vr, src_type);
+  if (dst_vr->varying_p () || dst_vr->undefined_p ())
+    return false;
+  return true;
+}
+
+/* Determine value_range of JFUNC given that INFO describes the caller node or
+   the one it is inlined to, CS is the call graph edge corresponding to JFUNC
+   and PARM_TYPE of the parameter.  */
+
+value_range
+ipa_value_range_from_jfunc (ipa_node_params *info, cgraph_edge *cs,
+                           ipa_jump_func *jfunc, tree parm_type)
+{
+  value_range vr;
+  return vr;
+  if (jfunc->m_vr)
+    ipa_vr_operation_and_type_effects (&vr,
+                                      jfunc->m_vr,
+                                      NOP_EXPR, parm_type,
+                                      jfunc->m_vr->type ());
+  if (vr.singleton_p ())
+    return vr;
+  if (jfunc->type == IPA_JF_PASS_THROUGH)
+    {
+      int idx;
+      ipcp_transformation *sum
+       = ipcp_get_transformation_summary (cs->caller->inlined_to
+                                          ? cs->caller->inlined_to
+                                          : cs->caller);
+      if (!sum || !sum->m_vr)
+       return vr;
+
+      idx = ipa_get_jf_pass_through_formal_id (jfunc);
+
+      if (!(*sum->m_vr)[idx].known)
+       return vr;
+      tree vr_type = ipa_get_type (info, idx);
+      value_range srcvr (wide_int_to_tree (vr_type, (*sum->m_vr)[idx].min),
+                        wide_int_to_tree (vr_type, (*sum->m_vr)[idx].max),
+                        (*sum->m_vr)[idx].type);
+
+      enum tree_code operation = ipa_get_jf_pass_through_operation (jfunc);
+
+      if (TREE_CODE_CLASS (operation) == tcc_unary)
+       {
+         value_range res;
+
+         if (ipa_vr_operation_and_type_effects (&res,
+                                                &srcvr,
+                                                operation, parm_type,
+                                                vr_type))
+           vr.intersect (res);
+       }
+      else
+       {
+         value_range op_res, res;
+         tree op = ipa_get_jf_pass_through_operand (jfunc);
+         value_range op_vr (op, op);
+
+         range_fold_binary_expr (&op_res, operation, vr_type, &srcvr, &op_vr);
+         if (ipa_vr_operation_and_type_effects (&res,
+                                                &op_res,
+                                                NOP_EXPR, parm_type,
+                                                vr_type))
+           vr.intersect (res);
+       }
+    }
+  return vr;
+}
+
 /* See if NODE is a clone with a known aggregate value at a given OFFSET of a
    parameter with the given INDEX.  */
 
@@ -2122,22 +2203,6 @@ propagate_bits_across_jump_function (cgraph_edge *cs, int idx,
     return dest_lattice->set_to_bottom ();
 }
 
-/* Emulate effects of unary OPERATION and/or conversion from SRC_TYPE to
-   DST_TYPE on value range in SRC_VR and store it to DST_VR.  Return true if
-   the result is a range or an anti-range.  */
-
-static bool
-ipa_vr_operation_and_type_effects (value_range *dst_vr,
-                                  value_range *src_vr,
-                                  enum tree_code operation,
-                                  tree dst_type, tree src_type)
-{
-  range_fold_unary_expr (dst_vr, operation, dst_type, src_vr, src_type);
-  if (dst_vr->varying_p () || dst_vr->undefined_p ())
-    return false;
-  return true;
-}
-
 /* Propagate value range across jump function JFUNC that is associated with
    edge CS with param of callee of PARAM_TYPE and update DEST_PLATS
    accordingly.  */
index 11879335990327696c4d6e7d4feca6a904c756c5..9d8e1a566e30a01d725258c4ceb795fbc2a579f4 100644 (file)
@@ -316,6 +316,7 @@ static void
 evaluate_conditions_for_known_args (struct cgraph_node *node,
                                    bool inline_p,
                                    vec<tree> known_vals,
+                                   vec<value_range> known_value_ranges,
                                    vec<ipa_agg_value_set> known_aggs,
                                    clause_t *ret_clause,
                                    clause_t *ret_nonspec_clause)
@@ -371,7 +372,9 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
            val = NULL_TREE;
        }
 
-      if (!val)
+      if (!val
+         && (c->code == predicate::changed
+             || c->code == predicate::is_not_constant))
        {
          clause |= 1 << (i + predicate::first_dynamic_condition);
          nonspec_clause |= 1 << (i + predicate::first_dynamic_condition);
@@ -383,48 +386,101 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
          continue;
        }
 
-      if (TYPE_SIZE (c->type) != TYPE_SIZE (TREE_TYPE (val)))
-       {
-         clause |= 1 << (i + predicate::first_dynamic_condition);
-         nonspec_clause |= 1 << (i + predicate::first_dynamic_condition);
-         continue;
-       }
       if (c->code == predicate::is_not_constant)
        {
          nonspec_clause |= 1 << (i + predicate::first_dynamic_condition);
          continue;
        }
 
-      val = fold_unary (VIEW_CONVERT_EXPR, c->type, val);
-      for (j = 0; vec_safe_iterate (c->param_ops, j, &op); j++)
+      if (val && TYPE_SIZE (c->type) == TYPE_SIZE (TREE_TYPE (val)))
        {
-         if (!val)
-           break;
-         if (!op->val[0])
-           val = fold_unary (op->code, op->type, val);
-         else if (!op->val[1])
-           val = fold_binary (op->code, op->type,
-                              op->index ? op->val[0] : val,
-                              op->index ? val : op->val[0]);
-         else if (op->index == 0)
-           val = fold_ternary (op->code, op->type,
-                               val, op->val[0], op->val[1]);
-         else if (op->index == 1)
-           val = fold_ternary (op->code, op->type,
-                               op->val[0], val, op->val[1]);
-         else if (op->index == 2)
-           val = fold_ternary (op->code, op->type,
-                               op->val[0], op->val[1], val);
-         else
-           val = NULL_TREE;
+         if (c->type != TREE_TYPE (val))
+           val = fold_unary (VIEW_CONVERT_EXPR, c->type, val);
+         for (j = 0; vec_safe_iterate (c->param_ops, j, &op); j++)
+           {
+             if (!val)
+               break;
+             if (!op->val[0])
+               val = fold_unary (op->code, op->type, val);
+             else if (!op->val[1])
+               val = fold_binary (op->code, op->type,
+                                  op->index ? op->val[0] : val,
+                                  op->index ? val : op->val[0]);
+             else if (op->index == 0)
+               val = fold_ternary (op->code, op->type,
+                                   val, op->val[0], op->val[1]);
+             else if (op->index == 1)
+               val = fold_ternary (op->code, op->type,
+                                   op->val[0], val, op->val[1]);
+             else if (op->index == 2)
+               val = fold_ternary (op->code, op->type,
+                                   op->val[0], op->val[1], val);
+             else
+               val = NULL_TREE;
+           }
+
+         res = val
+           ? fold_binary_to_constant (c->code, boolean_type_node, val, c->val)
+           : NULL;
+
+         if (res && integer_zerop (res))
+           continue;
+         if (res && integer_onep (res))
+           {
+             clause |= 1 << (i + predicate::first_dynamic_condition);
+             nonspec_clause |= 1 << (i + predicate::first_dynamic_condition);
+             continue;
+           }
        }
+      if (c->operand_num < (int) known_value_ranges.length ()
+         && !c->agg_contents
+         && !known_value_ranges[c->operand_num].undefined_p ()
+         && !known_value_ranges[c->operand_num].varying_p ()
+         && TYPE_SIZE (c->type)
+                == TYPE_SIZE (known_value_ranges[c->operand_num].type ())
+         && (!val || TREE_CODE (val) != INTEGER_CST))
+       {
+         value_range vr = known_value_ranges[c->operand_num];
+         if (!useless_type_conversion_p (c->type, vr.type ()))
+           {
+             value_range res;
+             range_fold_unary_expr (&res, NOP_EXPR,
+                                    c->type, &vr, vr.type ());
+             vr = res;
+           }
+         tree type = c->type;
 
-      res = val
-       ? fold_binary_to_constant (c->code, boolean_type_node, val, c->val)
-       : NULL;
+         for (j = 0; vec_safe_iterate (c->param_ops, j, &op); j++)
+           {
+             if (vr.varying_p () || vr.undefined_p ())
+               break;
 
-      if (res && integer_zerop (res))
-       continue;
+             value_range res;
+             if (!op->val[0])
+               range_fold_unary_expr (&res, op->code, op->type, &vr, type);
+             else if (!op->val[1])
+               {
+                 value_range op0 (op->val[0], op->val[0]);
+                 range_fold_binary_expr (&res, op->code, op->type,
+                                         op->index ? &op0 : &vr,
+                                         op->index ? &vr : &op0);
+               }
+             else
+               gcc_unreachable ();
+             type = op->type;
+             vr = res;
+           }
+         if (!vr.varying_p () && !vr.undefined_p ())
+           {
+             value_range res;
+             value_range val_vr (c->val, c->val);
+             range_fold_binary_expr (&res, c->code, boolean_type_node,
+                                     &vr,
+                                     &val_vr);
+             if (res.zero_p ())
+               continue;
+           }
+       }
 
       clause |= 1 << (i + predicate::first_dynamic_condition);
       nonspec_clause |= 1 << (i + predicate::first_dynamic_condition);
@@ -449,6 +505,7 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
   struct cgraph_node *callee = e->callee->ultimate_alias_target ();
   class ipa_fn_summary *info = ipa_fn_summaries->get (callee);
   vec<tree> known_vals = vNULL;
+  auto_vec<value_range, 32> known_value_ranges;
   vec<ipa_agg_value_set> known_aggs = vNULL;
   class ipa_edge_args *args;
 
@@ -478,6 +535,8 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
 
       if (count && (info->conds || known_vals_ptr))
        known_vals.safe_grow_cleared (count);
+      if (count && info->conds)
+       known_value_ranges.safe_grow_cleared (count);
       if (count && (info->conds || known_aggs_ptr))
        known_aggs.safe_grow_cleared (count);
       if (count && known_contexts_ptr)
@@ -512,6 +571,10 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
        
            known_aggs[i] = ipa_agg_value_set_from_jfunc (caller_parms_info,
                                                          caller, &jf->agg);
+            if (info->conds)
+              known_value_ranges[i] 
+                = ipa_value_range_from_jfunc (caller_parms_info, e, jf,
+                                              ipa_get_type (callee_pi, i));
          }
        else
          gcc_assert (callee->thunk.thunk_p);
@@ -534,7 +597,9 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
     }
 
   evaluate_conditions_for_known_args (callee, inline_p,
-                                     known_vals, known_aggs, clause_ptr,
+                                     known_vals,
+                                     known_value_ranges,
+                                     known_aggs, clause_ptr,
                                      nonspec_clause_ptr);
 
   if (known_vals_ptr)
@@ -657,6 +722,7 @@ ipa_fn_summary_t::duplicate (cgraph_node *src,
       evaluate_conditions_for_known_args (dst, false,
                                          known_vals,
                                          vNULL,
+                                         vNULL,
                                          &possible_truths,
                                          /* We are going to specialize,
                                             so ignore nonspec truths.  */
@@ -3358,8 +3424,9 @@ estimate_ipcp_clone_size_and_time (struct cgraph_node *node,
 {
   clause_t clause, nonspec_clause;
 
-  evaluate_conditions_for_known_args (node, false, known_vals, known_aggs,
-                                     &clause, &nonspec_clause);
+  /* TODO: Also pass known value ranges.  */
+  evaluate_conditions_for_known_args (node, false, known_vals, vNULL,
+                                     known_aggs, &clause, &nonspec_clause);
   ipa_call_context ctx (node, clause, nonspec_clause,
                        known_vals, known_contexts,
                        known_aggs, vNULL);
@@ -3579,7 +3646,8 @@ ipa_merge_fn_summary_after_inlining (struct cgraph_edge *edge)
   info->fp_expressions |= callee_info->fp_expressions;
 
   if (callee_info->conds)
-    evaluate_properties_for_edge (edge, true, &clause, NULL, NULL, NULL, NULL);
+    evaluate_properties_for_edge (edge, true, &clause,
+                                 NULL, NULL, NULL, NULL);
   if (ipa_node_params_sum && callee_info->conds)
     {
       class ipa_edge_args *args = IPA_EDGE_REF (edge);
index e27859ba5d3634beed89117d53e3bd0257c8d659..b5e009696b7769acdbfbe52eaa031a81dc9347aa 100644 (file)
@@ -1163,6 +1163,7 @@ edge_badness (struct cgraph_edge *edge, bool dump)
 
       overall_growth = callee_info->growth;
 
+#if 1
       /* Look for inliner wrappers of the form:
 
         inline_caller ()
@@ -1214,6 +1215,7 @@ edge_badness (struct cgraph_edge *edge, bool dump)
              overall_growth = caller_growth;
            }
        }
+#endif
       if (overall_growth > 0)
         {
          /* Strongly preffer functions with few callers that can be inlined
@@ -2132,12 +2134,23 @@ inline_small_functions (void)
            fprintf (dump_file, " Peeling recursion with depth %i\n", depth);
 
          gcc_checking_assert (!callee->inlined_to);
+
+         int old_size = ipa_size_summaries->get (where)->size;
+         sreal old_time = ipa_fn_summaries->get (where)->time;
+
          inline_call (edge, true, &new_indirect_edges, &overall_size, true);
          add_new_edges_to_heap (&edge_heap, new_indirect_edges);
 
          reset_edge_caches (edge->callee);
 
-         update_callee_keys (&edge_heap, where, updated_nodes);
+         /* If caller's size and time increased we do not need to update
+            all edges becuase badness is not going to decrease.  */
+         if (old_size <= ipa_size_summaries->get (where)->size
+             && old_time <= ipa_fn_summaries->get (where)->time
+             && 0)
+           update_callee_keys (&edge_heap, edge->callee, updated_nodes);
+         else
+           update_callee_keys (&edge_heap, where, updated_nodes);
        }
       where = edge->caller;
       if (where->inlined_to)
index 7eb96a057fef1d69b24070bf575cf6066499b9d6..9e85ef8aacea0c756d6ba5953772bdc9313b3216 100644 (file)
@@ -1029,6 +1029,8 @@ ipa_polymorphic_call_context ipa_context_from_jfunc (ipa_node_params *,
                                                     cgraph_edge *,
                                                     int,
                                                     ipa_jump_func *);
+value_range ipa_value_range_from_jfunc (ipa_node_params *, cgraph_edge *,
+                                       ipa_jump_func *, tree);
 ipa_agg_value_set ipa_agg_value_set_from_jfunc (ipa_node_params *,
                                                cgraph_node *,
                                                ipa_agg_jump_function *);
index 914f00593ff8fd41848ca40d2b87000ef5bf3b83..e0535b32247126341ce321d51c7544a611e9c9d8 100644 (file)
@@ -1,3 +1,7 @@
+2019-11-14  Jan Hubicka  <jh@suse.cz>
+
+       * gcc.dg/ipa/inline-9.c: New testcase.
+
 2019-11-14  Martin Liska  <mliska@suse.cz>
 
        * c-c++-common/asan/memcmp-1.c: Update expected backtrace.
diff --git a/gcc/testsuite/gcc.dg/ipa/inline-9.c b/gcc/testsuite/gcc.dg/ipa/inline-9.c
new file mode 100644 (file)
index 0000000..4bf751b
--- /dev/null
@@ -0,0 +1,23 @@
+/* { dg-options "-Os -fdump-ipa-inline"  } */
+int foo (void);
+int test(int a)
+{
+ if (a>100)
+   {
+     foo();
+     foo();
+     foo();
+     foo();
+     foo();
+     foo();
+     foo();
+     foo();
+   }
+}
+int
+main()
+{
+  for (int i=0;i<100;i++)
+    test(i);
+}
+/* { dg-final { scan-tree-dump "Inlined 1 calls" "inline" } } */