Current IPA-cp only generates cost-evaluating predicate for conditional 
statement like
"if (param cmp const_val)", it is too simple and conservative. This patch 
generalizes the
process to handle the form as T(param), a mathematical transformation on the 
function
parameter, in which the parameter occurs once, and other operands are constant 
value.

Feng

----
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 3d92250b520..0110446e09e 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,25 @@
+2019-07-12  Feng Xue  <f...@os.amperecomputing.com>
+
+       PR ipa/91088
+       * ipa-predicat.h (struct expr_eval_op): New struct.
+       (expr_eval_ops): New typedef.
+       (struct condition): Add param_ops member.
+       (add_condition): Add param_ops parameter.
+       * ipa-predicat.c (expr_eval_ops_equal_p): New function.
+       (predicate::add_clause): Add param_ops comparison.
+       (dump_condition): Add debug dump for param_ops.
+       (remap_after_inlining): Add param_ops argument to call to
+       add_condition.
+       (add_condition): Add parameter param_ops.
+       * ipa-fnsummary.c (evaluate_conditions_for_known_args): Fold
+       parameter expressions using param_ops.
+       (decompose_param_expr):  New function.
+       (set_cond_stmt_execution_predicate): Use call to decompose_param_expr
+       to replace call to unmodified_parm_or_parm_agg_item.
+       (set_switch_stmt_execution_predicate): Likewise.
+       (inline_read_section): Read param_ops from summary stream.
+       (ipa_fn_summary_write): Write param_ops to summary stream.
+
 2019-07-11  Sunil K Pandey  <sunil.k.pan...@intel.com>
 
        PR target/90980
diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c
index 09986211a1d..faf8bd39090 100644
--- a/gcc/ipa-fnsummary.c
+++ b/gcc/ipa-fnsummary.c
@@ -301,9 +301,9 @@ set_hint_predicate (predicate **p, predicate new_predicate)
 }
 
 
-/* Compute what conditions may or may not hold given invormation about
+/* Compute what conditions may or may not hold given information about
    parameters.  RET_CLAUSE returns truths that may hold in a specialized copy,
-   whie RET_NONSPEC_CLAUSE returns truths that may hold in an nonspecialized
+   while RET_NONSPEC_CLAUSE returns truths that may hold in an nonspecialized
    copy when called in a given context.  It is a bitmask of conditions. Bit
    0 means that condition is known to be false, while bit 1 means that 
condition
    may or may not be true.  These differs - for example NOT_INLINED condition
@@ -336,6 +336,8 @@ evaluate_conditions_for_known_args (struct cgraph_node 
*node,
     {
       tree val;
       tree res;
+      int j;
+      struct expr_eval_op *op;
 
       /* We allow call stmt to have fewer arguments than the callee function
          (especially for K&R style programs).  So bound check here (we assume
@@ -399,7 +401,18 @@ evaluate_conditions_for_known_args (struct cgraph_node 
*node,
          continue;
        }
 
-      val = fold_unary (VIEW_CONVERT_EXPR, TREE_TYPE (c->val), val);
+      for (j = 0; vec_safe_iterate (c->param_ops, j, &op); j++)
+       {
+         if (!op->val)
+           val = fold_unary (op->code, op->type, val);
+         else if (op->val_is_rhs)
+           val = fold_binary_to_constant (op->code, op->type, val, op->val);
+         else
+           val = fold_binary_to_constant (op->code, op->type, op->val, val);
+         if (!val)
+           break;
+       }
+
       res = val
        ? fold_binary_to_constant (c->code, boolean_type_node, val, c->val)
        : NULL;
@@ -1177,6 +1190,105 @@ eliminated_by_inlining_prob (ipa_func_body_info *fbi, 
gimple *stmt)
     }
 }
 
+/* Flatten a tree expression on parameter into a set of sequential operations.
+   we only handle expression that is a mathematical transformation on the
+   parameter, and in the expression, parameter occurs only once, and other
+   operands are IPA invariant.  */
+
+static bool
+decompose_param_expr (struct ipa_func_body_info *fbi,
+                     gimple *stmt, tree expr,
+                     int *index_p, HOST_WIDE_INT *size_p,
+                     struct agg_position_info *aggpos,
+                     expr_eval_ops *param_ops_p)
+{
+  if (param_ops_p)
+    *param_ops_p = NULL;
+
+  while (true)
+    {
+      gimple_rhs_class rhs_class;
+      expr_eval_op eval_op;
+
+      if (unmodified_parm_or_parm_agg_item (fbi, stmt, expr, index_p,
+                                           size_p, aggpos))
+       {
+         if (param_ops_p)
+           {
+             /* Find use of parameter, add a convert operation to describe
+                result type, which may not be same as parameter type.  */
+             eval_op.val_is_rhs = false;
+             eval_op.val = NULL_TREE;
+             eval_op.code = VIEW_CONVERT_EXPR;
+             eval_op.type = TREE_TYPE (expr);
+
+             vec_safe_insert (*param_ops_p, 0, eval_op);
+           }
+         return true;
+       }
+
+      if (TREE_CODE (expr) != SSA_NAME || SSA_NAME_IS_DEFAULT_DEF (expr))
+       break;
+
+      if (!is_gimple_assign (stmt = SSA_NAME_DEF_STMT (expr)))
+       break;
+
+      rhs_class = gimple_assign_rhs_class (stmt);
+
+      if (rhs_class == GIMPLE_SINGLE_RHS)
+       expr = gimple_assign_rhs1 (stmt);
+      else if (rhs_class == GIMPLE_UNARY_RHS)
+       {
+         expr = gimple_assign_rhs1 (stmt);
+
+         if (param_ops_p)
+           {
+             eval_op.val_is_rhs = false;
+             eval_op.val = NULL_TREE;
+             eval_op.code = gimple_assign_rhs_code (stmt);
+             eval_op.type = TREE_TYPE (expr);
+
+             vec_safe_insert (*param_ops_p, 0, eval_op);
+           }
+       }
+      else if (rhs_class == GIMPLE_BINARY_RHS)
+       {
+         tree op1 = gimple_assign_rhs1 (stmt);
+         tree op2 = gimple_assign_rhs2 (stmt);
+
+         if (is_gimple_ip_invariant (op1))
+           {
+             eval_op.val_is_rhs = false;
+             eval_op.val = op1;
+             expr = op2;
+           }
+         else if (is_gimple_ip_invariant (op2))
+           {
+             eval_op.val_is_rhs = true;
+             eval_op.val = op2;
+             expr = op1;
+           }
+         else
+           break;
+
+         if (param_ops_p)
+           {
+             eval_op.code = gimple_assign_rhs_code (stmt);
+             eval_op.type = TREE_TYPE (expr);
+
+             vec_safe_insert (*param_ops_p, 0, eval_op);
+           }
+       }
+      else
+       break;
+    }
+
+  /* Failed to decompose, free resource and return.  */
+  if (param_ops_p)
+    vec_free (*param_ops_p);
+
+  return false;
+}
 
 /* If BB ends by a conditional we can turn into predicates, attach 
corresponding
    predicates to the CFG edges.   */
@@ -1196,6 +1308,7 @@ set_cond_stmt_execution_predicate (struct 
ipa_func_body_info *fbi,
   edge_iterator ei;
   gimple *set_stmt;
   tree op2;
+  expr_eval_ops param_ops;
 
   last = last_stmt (bb);
   if (!last || gimple_code (last) != GIMPLE_COND)
@@ -1203,10 +1316,8 @@ set_cond_stmt_execution_predicate (struct 
ipa_func_body_info *fbi,
   if (!is_gimple_ip_invariant (gimple_cond_rhs (last)))
     return;
   op = gimple_cond_lhs (last);
-  /* TODO: handle conditionals like
-     var = op0 < 4;
-     if (var != 0).  */
-  if (unmodified_parm_or_parm_agg_item (fbi, last, op, &index, &size, &aggpos))
+
+  if (decompose_param_expr (fbi, last, op, &index, &size, &aggpos, &param_ops))
     {
       code = gimple_cond_code (last);
       inverted_code = invert_tree_comparison (code, HONOR_NANS (op));
@@ -1222,13 +1333,13 @@ set_cond_stmt_execution_predicate (struct 
ipa_func_body_info *fbi,
            {
              predicate p
                = add_condition (summary, index, size, &aggpos, this_code,
-                                unshare_expr_without_location
-                                (gimple_cond_rhs (last)));
+                                gimple_cond_rhs (last), param_ops);
              e->aux = edge_predicate_pool.allocate ();
              *(predicate *) e->aux = p;
            }
        }
     }
+  vec_free (param_ops);
 
   if (TREE_CODE (op) != SSA_NAME)
     return;
@@ -1240,7 +1351,7 @@ set_cond_stmt_execution_predicate (struct 
ipa_func_body_info *fbi,
      Here we can predicate nonconstant_code.  We can't
      really handle constant_code since we have no predicate
      for this and also the constant code is not known to be
-     optimized away when inliner doen't see operand is constant.
+     optimized away when inliner doesn't see operand is constant.
      Other optimizers might think otherwise.  */
   if (gimple_cond_code (last) != NE_EXPR
       || !integer_zerop (gimple_cond_rhs (last)))
@@ -1250,8 +1361,7 @@ set_cond_stmt_execution_predicate (struct 
ipa_func_body_info *fbi,
       || gimple_call_num_args (set_stmt) != 1)
     return;
   op2 = gimple_call_arg (set_stmt, 0);
-  if (!unmodified_parm_or_parm_agg_item (fbi, set_stmt, op2, &index, &size,
-                                        &aggpos))
+  if (!decompose_param_expr (fbi, set_stmt, op2, &index, &size, &aggpos, NULL))
     return;
   FOR_EACH_EDGE (e, ei, bb->succs) if (e->flags & EDGE_FALSE_VALUE)
     {
@@ -1280,13 +1390,15 @@ set_switch_stmt_execution_predicate (struct 
ipa_func_body_info *fbi,
   edge_iterator ei;
   size_t n;
   size_t case_idx;
+  expr_eval_ops param_ops;
 
   lastg = last_stmt (bb);
   if (!lastg || gimple_code (lastg) != GIMPLE_SWITCH)
     return;
   gswitch *last = as_a <gswitch *> (lastg);
   op = gimple_switch_index (last);
-  if (!unmodified_parm_or_parm_agg_item (fbi, last, op, &index, &size, 
&aggpos))
+  if (!decompose_param_expr (fbi, last, op, &index, &size, &aggpos,
+                            &param_ops))
     return;
 
   FOR_EACH_EDGE (e, ei, bb->succs)
@@ -1312,19 +1424,20 @@ set_switch_stmt_execution_predicate (struct 
ipa_func_body_info *fbi,
        p = true;
       else if (!max)
        p = add_condition (summary, index, size, &aggpos, EQ_EXPR,
-                          unshare_expr_without_location (min));
+                          min, param_ops);
       else
        {
          predicate p1, p2;
          p1 = add_condition (summary, index, size, &aggpos, GE_EXPR,
-                             unshare_expr_without_location (min));
+                             min, param_ops);
          p2 = add_condition (summary, index, size, &aggpos, LE_EXPR,
-                             unshare_expr_without_location (max));
+                             max, param_ops);
          p = p1 & p2;
        }
       *(class predicate *) e->aux
        = p.or_with (summary->conds, *(class predicate *) e->aux);
     }
+  vec_free (param_ops);
 }
 
 
@@ -1491,7 +1604,7 @@ will_be_nonconstant_predicate (struct ipa_func_body_info 
*fbi,
   HOST_WIDE_INT size;
   struct agg_position_info aggpos;
 
-  /* What statments might be optimized away
+  /* What statements might be optimized away
      when their arguments are constant.  */
   if (gimple_code (stmt) != GIMPLE_ASSIGN
       && gimple_code (stmt) != GIMPLE_COND
@@ -1539,7 +1652,7 @@ will_be_nonconstant_predicate (struct ipa_func_body_info 
*fbi,
   if (is_load)
     op_non_const =
       add_condition (summary, base_index, size, &aggpos, predicate::changed,
-                    NULL);
+                    NULL_TREE);
   else
     op_non_const = false;
   FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
@@ -3333,6 +3446,7 @@ inline_read_section (struct lto_file_decl_data 
*file_data, const char *data,
       for (j = 0; j < count2; j++)
        {
          struct condition c;
+         unsigned int k, count3;
          c.operand_num = streamer_read_uhwi (&ib);
          c.size = streamer_read_uhwi (&ib);
          c.code = (enum tree_code) streamer_read_uhwi (&ib);
@@ -3342,6 +3456,18 @@ inline_read_section (struct lto_file_decl_data 
*file_data, const char *data,
          c.by_ref = bp_unpack_value (&bp, 1);
          if (c.agg_contents)
            c.offset = streamer_read_uhwi (&ib);
+         c.param_ops = NULL;
+         count3 = streamer_read_uhwi (&ib);
+         for (k = 0; k < count3; k++)
+           {
+             struct expr_eval_op op;
+             op.code = (enum tree_code) streamer_read_uhwi (&ib);
+             bp = streamer_read_bitpack (&ib);
+             op.val_is_rhs = bp_unpack_value (&bp, 1);
+             op.val = stream_read_tree (&ib, data_in);
+             op.type = stream_read_tree (&ib, data_in);
+             vec_safe_push (c.param_ops, op);
+           }
          if (info)
            vec_safe_push (info->conds, c);
        }
@@ -3490,6 +3616,9 @@ ipa_fn_summary_write (void)
          streamer_write_uhwi (ob, vec_safe_length (info->conds));
          for (i = 0; vec_safe_iterate (info->conds, i, &c); i++)
            {
+             int j;
+             struct expr_eval_op *op;
+
              streamer_write_uhwi (ob, c->operand_num);
              streamer_write_uhwi (ob, c->size);
              streamer_write_uhwi (ob, c->code);
@@ -3500,6 +3629,16 @@ ipa_fn_summary_write (void)
              streamer_write_bitpack (&bp);
              if (c->agg_contents)
                streamer_write_uhwi (ob, c->offset);
+             streamer_write_uhwi (ob, vec_safe_length (c->param_ops));
+             for (j = 0; vec_safe_iterate (c->param_ops, j, &op); j++)
+               {
+                 streamer_write_uhwi (ob, op->code);
+                 bp = bitpack_create (ob->main_stream);
+                 bp_pack_value (&bp, op->val_is_rhs, 1);
+                 streamer_write_bitpack (&bp);
+                 stream_write_tree (ob, op->val, true);
+                 stream_write_tree (ob, op->type, true);
+               }
            }
          streamer_write_uhwi (ob, vec_safe_length (info->size_time_table));
          for (i = 0; vec_safe_iterate (info->size_time_table, i, &e); i++)
diff --git a/gcc/ipa-predicate.c b/gcc/ipa-predicate.c
index 49622e9cd33..537dd81685f 100644
--- a/gcc/ipa-predicate.c
+++ b/gcc/ipa-predicate.c
@@ -33,9 +33,35 @@ along with GCC; see the file COPYING3.  If not see
 #include "fold-const.h"
 #include "tree-pretty-print.h"
 #include "gimple.h"
+#include "gimplify.h"
 #include "data-streamer.h"
 
 
+/* Check whether two set of operations have same effects.  */
+static bool
+expr_eval_ops_equal_p (expr_eval_ops ops1, expr_eval_ops ops2)
+{
+  if (ops1)
+    {
+      if (!ops2 || ops1->length () != ops2->length ())
+       return false;
+
+      for (unsigned i = 0; i < ops1->length (); i++)
+       {
+         expr_eval_op &op1 = (*ops1)[i];
+         expr_eval_op &op2 = (*ops2)[i];
+
+         if (op1.code != op2.code
+             || op1.val_is_rhs != op2.val_is_rhs
+             || !vrp_operand_equal_p (op1.val, op2.val)
+             || op1.type != op2.type)
+           return false;
+       }
+      return true;
+    }
+  return !ops2;
+}
+
 /* Add clause CLAUSE into the predicate P.
    When CONDITIONS is NULL do not perform checking whether NEW_CLAUSE
    is obviously true.  This is useful only when NEW_CLAUSE is known to be
@@ -110,14 +136,13 @@ predicate::add_clause (conditions conditions, clause_t 
new_clause)
        for (c2 = c1 + 1; c2 < num_conditions; c2++)
          if (new_clause & (1 << c2))
            {
-             condition *cc1 =
-               &(*conditions)[c1 - predicate::first_dynamic_condition];
              condition *cc2 =
                &(*conditions)[c2 - predicate::first_dynamic_condition];
              if (cc1->operand_num == cc2->operand_num
-                 && cc1->val == cc2->val
+                 && vrp_operand_equal_p (cc1->val, cc2->val)
                  && cc2->code != is_not_constant
-                 && cc2->code != predicate::changed
+                 && cc2->code != changed
+                 && expr_eval_ops_equal_p (cc1->param_ops, cc2->param_ops)
                  && cc1->code == invert_tree_comparison (cc2->code,
                                                          HONOR_NANS 
(cc1->val)))
                return;
@@ -300,6 +325,46 @@ dump_condition (FILE *f, conditions conditions, int cond)
       if (c->agg_contents)
        fprintf (f, "[%soffset: " HOST_WIDE_INT_PRINT_DEC "]",
                 c->by_ref ? "ref " : "", c->offset);
+
+      for (unsigned i = 1; i < vec_safe_length (c->param_ops); i++)
+       {
+         expr_eval_op &op = (*(c->param_ops))[i];
+         const char *op_name = op_symbol_code (op.code);
+
+         if (op_name == op_symbol_code (ERROR_MARK))
+           op_name = get_tree_code_name (op.code);
+
+         fprintf (f, ":(");
+
+         if (!op.val)
+           {
+             switch (op.code)
+               {
+                 case VIEW_CONVERT_EXPR:
+                 CASE_CONVERT:
+                   fprintf (f, "(");
+                   print_generic_expr (f, op.type);
+                   fprintf (f, ")" );
+                   break;
+
+                 default:
+                   fprintf (f, "%s ", op_name);
+               }
+             fprintf (f, "@%u", i);
+           }
+         else if (op.val_is_rhs)
+           {
+             fprintf (f, "@%u %s ", i, op_name);
+             print_generic_expr (f, op.val);
+           }
+         else
+           {
+             print_generic_expr (f, op.val);
+             fprintf (f, " %s @%u", op_name, i);
+           }
+         fprintf (f, ")");
+       }
+
       if (c->code == predicate::is_not_constant)
        {
          fprintf (f, " not constant");
@@ -338,8 +403,8 @@ dump_clause (FILE *f, conditions conds, clause_t clause)
 }
 
 
-/* Dump THIS to F. CONDS a vector of conditions used when evauating
-   predicats. When NL is true new line is output at the end of dump.  */
+/* Dump THIS to F. CONDS a vector of conditions used when evaluating
+   predicates. When NL is true new line is output at the end of dump.  */
 
 void
 predicate::dump (FILE *f, conditions conds, bool nl) const
@@ -389,7 +454,7 @@ predicate::remap_after_duplication (clause_t 
possible_truths)
 
    INFO is ipa_fn_summary of function we are adding predicate into, CALLEE_INFO
    is summary of function predicate P is from. OPERAND_MAP is array giving
-   callee formal IDs the caller formal IDs. POSSSIBLE_TRUTHS is clausule of all
+   callee formal IDs the caller formal IDs. POSSSIBLE_TRUTHS is clause of all
    callee conditions that may be true in caller context.  TOPLEV_PREDICATE is
    predicate under which callee is executed.  OFFSET_MAP is an array of of
    offsets that need to be added to conditions, negative offset means that
@@ -463,7 +528,7 @@ predicate::remap_after_inlining (class ipa_fn_summary *info,
                    cond_predicate = add_condition (info,
                                                    operand_map[c->operand_num],
                                                    c->size, &ap, c->code,
-                                                   c->val);
+                                                   c->val, c->param_ops);
                  }
              }
            /* Fixed conditions remains same, construct single
@@ -516,21 +581,23 @@ predicate::stream_out (struct output_block *ob)
 }
 
 
-/* Add condition to condition list SUMMARY. OPERAND_NUM, SIZE, CODE and VAL
-   correspond to fields of condition structure.  AGGPOS describes whether the
-   used operand is loaded from an aggregate and where in the aggregate it is.
-   It can be NULL, which means this not a load from an aggregate.  */
+/* Add condition to condition list SUMMARY. OPERAND_NUM, SIZE, CODE, VAL and
+   PARAM_OPS correspond to fields of condition structure.  AGGPOS describes
+   whether the used operand is loaded from an aggregate and where in the
+   aggregate it is.  It can be NULL, which means this not a load from an
+   aggregate.  */
 
 predicate
 add_condition (class ipa_fn_summary *summary, int operand_num,
               HOST_WIDE_INT size, struct agg_position_info *aggpos,
-              enum tree_code code, tree val)
+              enum tree_code code, tree val, expr_eval_ops param_ops)
 {
-  int i;
+  int i, j;
   struct condition *c;
   struct condition new_cond;
   HOST_WIDE_INT offset;
   bool agg_contents, by_ref;
+  expr_eval_op *op;
 
   if (aggpos)
     {
@@ -551,8 +618,9 @@ add_condition (class ipa_fn_summary *summary, int 
operand_num,
       if (c->operand_num == operand_num
          && c->size == size
          && c->code == code
-         && c->val == val
+         && vrp_operand_equal_p (c->val, val)
          && c->agg_contents == agg_contents
+         && expr_eval_ops_equal_p (c->param_ops, param_ops)
          && (!agg_contents || (c->offset == offset && c->by_ref == by_ref)))
        return predicate::predicate_testing_cond (i);
     }
@@ -562,11 +630,17 @@ add_condition (class ipa_fn_summary *summary, int 
operand_num,
 
   new_cond.operand_num = operand_num;
   new_cond.code = code;
-  new_cond.val = val;
+  new_cond.val = val ? unshare_expr_without_location (val) : val;
   new_cond.agg_contents = agg_contents;
   new_cond.by_ref = by_ref;
   new_cond.offset = offset;
   new_cond.size = size;
+  new_cond.param_ops = vec_safe_copy (param_ops);
+
+  for (j = 0; vec_safe_iterate (new_cond.param_ops, j, &op); j++)
+    if (op->val)
+      op->val = unshare_expr_without_location (op->val);
+
   vec_safe_push (summary->conds, new_cond);
 
   return predicate::predicate_testing_cond (i);
diff --git a/gcc/ipa-predicate.h b/gcc/ipa-predicate.h
index c2adba30551..f00a64f3a59 100644
--- a/gcc/ipa-predicate.h
+++ b/gcc/ipa-predicate.h
@@ -22,8 +22,28 @@ along with GCC; see the file COPYING3.  If not see
    inlined into (i.e. known constant values of function parameters.
 
    Conditions that are interesting for function body are collected into CONDS
-   vector.  They are of simple for  function_param OP VAL, where VAL is
-   IPA invariant.  The conditions are then referred by predicates.  */
+   vector.  They are of simple as kind of a mathematical transformation on
+   function parameter, T(function_param), in which the parameter occurs only
+   once, and other operands are IPA invariant.  The conditions are then
+   referred by predicates.  */
+
+
+/* A simplified representation of tree node, only for unary and binary
+   operation.  A tree expression is flattened to a vector of this kind
+   of structure.  */
+struct GTY(()) expr_eval_op
+{
+  /* Operation code of expression.  */
+  ENUM_BITFIELD(tree_code) code : 16;
+  /* For binary expression, the below constant operand is rhs or lhs.  */
+  unsigned val_is_rhs : 1;
+  /* For binary expression, this is a constant value.  */
+  tree val;
+  /* Result type of expression.  */
+  tree type;
+};
+
+typedef vec<expr_eval_op, va_gc> *expr_eval_ops;
 
 struct GTY(()) condition
 {
@@ -41,6 +61,9 @@ struct GTY(()) condition
   /* If agg_contents is set, this differentiates between loads from data
      passed by reference and by value.  */
   unsigned by_ref : 1;
+  /* A set sequential operations on the parameter, which can be seen as
+     a mathmatical function on the parameter.  */
+  expr_eval_ops param_ops;
 };
 
 /* Information kept about parameter of call site.  */
@@ -58,7 +81,7 @@ struct inline_param_summary
 
 typedef vec<condition, va_gc> *conditions;
 
-/* Predicates are used to repesent function parameters (such as runtime)
+/* Predicates are used to represent function parameters (such as runtime)
    which depend on a context function is called in.
 
    Predicates are logical formulas in conjunctive-disjunctive form consisting
@@ -229,4 +252,5 @@ private:
 void dump_condition (FILE *f, conditions conditions, int cond);
 predicate add_condition (class ipa_fn_summary *summary, int operand_num,
                         HOST_WIDE_INT size, struct agg_position_info *aggpos,
-                        enum tree_code code, tree val);
+                        enum tree_code code, tree val,
+                        expr_eval_ops param_ops = NULL);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 6c40496db9c..39886498305 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2019-07-12  Feng Xue  <f...@os.amperecomputing.com>
+
+       PR ipa/91088
+       * gcc.dg/ipa/pr91088.c: New test.
+
 2019-07-11  Sunil K Pandey  <sunil.k.pan...@intel.com>
 
        PR target/90980
diff --git a/gcc/testsuite/gcc.dg/ipa/pr91088.c 
b/gcc/testsuite/gcc.dg/ipa/pr91088.c
new file mode 100644
index 00000000000..1cbf0d2fa23
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/pr91088.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fdump-ipa-cp-details -fdump-ipa-fnsummary-details 
-fno-inline" } */
+
+int foo();
+
+int callee(int v)
+{
+  if ((27 % ((1 - v) * 3)) < 6)
+    {
+      foo();
+      foo();
+      foo();
+      foo();
+      foo();
+      foo();
+      foo();
+      foo();
+      foo();
+    }
+  else
+    return 1;
+}
+
+int caller()
+{
+  return callee (-5);
+}
+
+/* { dg-final { scan-ipa-dump "Creating a specialized node of callee" "cp" } } 
*/
-- 
2.17.1

Reply via email to