Hi,
this implements use of value ranges in ipa-predicates so inliner know
when some tests are going to be removed (especially NULL pointer
checks).

Bootstrapped/regtested x86_64-linux. Martin, I would apprechiate if you
look on the patch. 

Honza

        * 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.
Index: ipa-cp.c
===================================================================
--- ipa-cp.c    (revision 278094)
+++ ipa-cp.c    (working copy)
@@ -1459,6 +1459,87 @@ ipa_context_from_jfunc (ipa_node_params
   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 ((*sum->m_vr)[idx].type,
+                        wide_int_to_tree (vr_type, (*sum->m_vr)[idx].min),
+                        wide_int_to_tree (vr_type, (*sum->m_vr)[idx].max));
+
+      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;
+}
+
 /* If checking is enabled, verify that no lattice is in the TOP state, i.e. not
    bottom, not containing a variable component and without any known value at
    the same time.  */
@@ -1936,22 +2017,6 @@ propagate_bits_across_jump_function (cgr
     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: ipa-fnsummary.c
===================================================================
--- ipa-fnsummary.c     (revision 278094)
+++ ipa-fnsummary.c     (working copy)
@@ -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_jump_function_p>
                                    known_aggs,
                                    clause_t *ret_clause,
@@ -372,7 +373,9 @@ evaluate_conditions_for_known_args (stru
            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);
@@ -384,48 +387,101 @@ evaluate_conditions_for_known_args (stru
          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 (VR_RANGE, 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 (VR_RANGE, 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);
@@ -450,6 +506,7 @@ evaluate_properties_for_edge (struct cgr
   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_jump_function_p> known_aggs = vNULL;
   class ipa_edge_args *args;
 
@@ -477,6 +534,8 @@ evaluate_properties_for_edge (struct cgr
 
       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)
@@ -505,14 +564,18 @@ evaluate_properties_for_edge (struct cgr
            else if (inline_p && !es->param[i].change_prob)
              known_vals[i] = error_mark_node;
 
-           if (known_contexts_ptr)
-             (*known_contexts_ptr)[i]
-               = ipa_context_from_jfunc (caller_parms_info, e, i, jf);
-           /* TODO: When IPA-CP starts propagating and merging aggregate jump
-              functions, use its knowledge of the caller too, just like the
-              scalar case above.  */
-           known_aggs[i] = &jf->agg;
-         }
+            if (known_contexts_ptr)
+              (*known_contexts_ptr)[i]
+                = ipa_context_from_jfunc (caller_parms_info, e, i, jf);
+            /* TODO: When IPA-CP starts propagating and merging aggregate jump
+               functions, use its knowledge of the caller too, just like the
+               scalar case above.  */
+            known_aggs[i] = &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 cgr
     }
 
   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
       evaluate_conditions_for_known_args (dst, false,
                                          known_vals,
                                          vNULL,
+                                         vNULL,
                                          &possible_truths,
                                          /* We are going to specialize,
                                             so ignore nonspec truths.  */
@@ -3355,8 +3424,9 @@ estimate_ipcp_clone_size_and_time (struc
 {
   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);
@@ -3576,7 +3646,8 @@ ipa_merge_fn_summary_after_inlining (str
   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: ipa-prop.h
===================================================================
--- ipa-prop.h  (revision 278094)
+++ ipa-prop.h  (working copy)
@@ -918,6 +918,8 @@ ipa_polymorphic_call_context ipa_context
                                                     cgraph_edge *,
                                                     int,
                                                     ipa_jump_func *);
+value_range ipa_value_range_from_jfunc (ipa_node_params *, cgraph_edge *,
+                                       ipa_jump_func *, tree);
 void ipa_dump_param (FILE *, class ipa_node_params *info, int i);
 void ipa_release_body_info (struct ipa_func_body_info *);
 tree ipa_get_callee_param_type (struct cgraph_edge *e, int i);
Index: testsuite/gcc.dg/ipa/inline-9.c
===================================================================
--- testsuite/gcc.dg/ipa/inline-9.c     (nonexistent)
+++ testsuite/gcc.dg/ipa/inline-9.c     (working copy)
@@ -0,0 +1,21 @@
+/* { dg-options "-Os -fdump-ipa-inline"  } */
+int test(int a)
+{
+ if (a>100)
+   {
+     foo();
+     foo();
+     foo();
+     foo();
+     foo();
+     foo();
+     foo();
+     foo();
+   }
+}
+main()
+{
+  for (int i=0;i<100;i++)
+    test(i);
+}
+/* { dg-final { scan-tree-dump "Inlined 1 calls" "inline" } } */

Reply via email to