Generalized IPA predicate on parameter reference
authorFeng Xue <fxue@os.amperecomputing.com>
Wed, 16 Oct 2019 07:27:50 +0000 (07:27 +0000)
committerFeng Xue <fxue@gcc.gnu.org>
Wed, 16 Oct 2019 07:27:50 +0000 (07:27 +0000)
2019-10-16  Feng Xue  <fxue@os.amperecomputing.com>

        PR ipa/91088
        * doc/invoke.texi (ipa-max-param-expr-ops): Document new option.
        * params.def (PARAM_IPA_MAX_PARAM_EXPR_OPS): New.
        * ipa-predicat.h (struct expr_eval_op): New struct.
        (expr_eval_ops): New typedef.
        (struct condition): Add type and param_ops fields, remove size field.
        (add_condition): Replace size parameter with type parameter, add
        param_ops parameter.
        * ipa-predicat.c (expr_eval_ops_equal_p): New function.
        (predicate::add_clause): Add comparisons on type and param_ops.
        (dump_condition): Add debug dump for param_ops.
        (remap_after_inlining): Adjust call arguments to add_condition.
        (add_condition): Replace size parameter with type parameter, add
        param_ops parameter. Unshare constant value used in conditions.
        * 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.
        (will_be_nonconstant_expr_predicate): Likewise. Replace usage of size
        with type.
        (inline_read_section): Read param_ops from summary stream.
        (ipa_fn_summary_write): Write param_ops to summary stream.

2019-10-16  Feng Xue  <fxue@os.amperecomputing.com>

        PR ipa/91088
        * gcc.dg/ipa/pr91088.c: New test.
        * gcc.dg/ipa/pr91089.c: Add sub-test for range analysis.
        * g++.dg/tree-ssa/ivopts-3.C: Force a function to be noinline.

From-SVN: r277054

gcc/ChangeLog
gcc/doc/invoke.texi
gcc/ipa-fnsummary.c
gcc/ipa-predicate.c
gcc/ipa-predicate.h
gcc/params.def
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/tree-ssa/ivopts-3.C
gcc/testsuite/gcc.dg/ipa/pr91088.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/ipa/pr91089.c

index 175ecd9224f43d517ad8154ee57816bdc4d50a43..28629582a023a38740936aab36ffc5b775bddb37 100644 (file)
@@ -1,3 +1,30 @@
+2019-10-16  Feng Xue  <fxue@os.amperecomputing.com>
+
+       PR ipa/91088
+       * doc/invoke.texi (ipa-max-param-expr-ops): Document new option.
+       * params.def (PARAM_IPA_MAX_PARAM_EXPR_OPS): New.
+       * ipa-predicat.h (struct expr_eval_op): New struct.
+       (expr_eval_ops): New typedef.
+       (struct condition): Add type and param_ops fields, remove size field.
+       (add_condition): Replace size parameter with type parameter, add
+       param_ops parameter.
+       * ipa-predicat.c (expr_eval_ops_equal_p): New function.
+       (predicate::add_clause): Add comparisons on type and param_ops.
+       (dump_condition): Add debug dump for param_ops.
+       (remap_after_inlining): Adjust call arguments to add_condition.
+       (add_condition): Replace size parameter with type parameter, add
+       param_ops parameter. Unshare constant value used in conditions.
+       * 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.
+       (will_be_nonconstant_expr_predicate): Likewise. Replace usage of size
+       with type.
+       (inline_read_section): Read param_ops from summary stream.
+       (ipa_fn_summary_write): Write param_ops to summary stream.
+
 2019-10-15  Segher Boessenkool  <segher@kernel.crashing.org>
 
        PR rtl-optimization/92107
 2019-10-15  Segher Boessenkool  <segher@kernel.crashing.org>
 
        PR rtl-optimization/92107
index 47769262b8e7bece23fd9253f428afebc9fcdc39..1407d019d1404ebbdb9630d6f541eab2e7a1bd01 100644 (file)
@@ -12034,6 +12034,13 @@ For switch exceeding this limit, IPA-CP will not construct cloning cost
 predicate, which is used to estimate cloning benefit, for default case
 of the switch statement.
 
 predicate, which is used to estimate cloning benefit, for default case
 of the switch statement.
 
+@item ipa-max-param-expr-ops
+IPA-CP will analyze conditional statement that references some function
+parameter to estimate benefit for cloning upon certain constant value.
+But if number of operations in a parameter expression exceeds
+@option{ipa-max-param-expr-ops}, the expression is treated as complicated
+one, and is not handled by IPA analysis.
+
 @item lto-partitions
 Specify desired number of partitions produced during WHOPR compilation.
 The number of partitions should exceed the number of CPUs used for compilation.
 @item lto-partitions
 Specify desired number of partitions produced during WHOPR compilation.
 The number of partitions should exceed the number of CPUs used for compilation.
index a43867937bda7fe68eabd980df1327ddb4e2b731..40a9e0f3ee3872cdeb63b8aee500cec65a48dee8 100644 (file)
@@ -331,6 +331,8 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
     {
       tree val;
       tree res;
     {
       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
 
       /* We allow call stmt to have fewer arguments than the callee function
          (especially for K&R style programs).  So bound check here (we assume
@@ -382,7 +384,7 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
          continue;
        }
 
          continue;
        }
 
-      if (maybe_ne (tree_to_poly_int64 (TYPE_SIZE (TREE_TYPE (val))), c->size))
+      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);
        {
          clause |= 1 << (i + predicate::first_dynamic_condition);
          nonspec_clause |= 1 << (i + predicate::first_dynamic_condition);
@@ -394,7 +396,30 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
          continue;
        }
 
          continue;
        }
 
-      val = fold_unary (VIEW_CONVERT_EXPR, TREE_TYPE (c->val), 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;
       res = val
        ? fold_binary_to_constant (c->code, boolean_type_node, val, c->val)
        : NULL;
@@ -1155,6 +1180,127 @@ eliminated_by_inlining_prob (ipa_func_body_info *fbi, gimple *stmt)
     }
 }
 
     }
 }
 
+/* Analyze EXPR if it represents a series of simple operations performed on
+   a function parameter and return true if so.  FBI, STMT, EXPR, INDEX_P and
+   AGGPOS have the same meaning like in unmodified_parm_or_parm_agg_item.
+   Type of the parameter or load from an aggregate via the parameter is
+   stored in *TYPE_P.  Operations on the parameter are recorded to
+   PARAM_OPS_P if it is not NULL.  */
+
+static bool
+decompose_param_expr (struct ipa_func_body_info *fbi,
+                     gimple *stmt, tree expr,
+                     int *index_p, tree *type_p,
+                     struct agg_position_info *aggpos,
+                     expr_eval_ops *param_ops_p = NULL)
+{
+  int op_limit = PARAM_VALUE (PARAM_IPA_MAX_PARAM_EXPR_OPS);
+  int op_count = 0;
+
+  if (param_ops_p)
+    *param_ops_p = NULL;
+
+  while (true)
+    {
+      expr_eval_op eval_op;
+      unsigned rhs_count;
+      unsigned cst_count = 0;
+
+      if (unmodified_parm_or_parm_agg_item (fbi, stmt, expr, index_p, NULL,
+                                           aggpos))
+       {
+         tree type = TREE_TYPE (expr);
+
+         if (aggpos->agg_contents)
+           {
+             /* Stop if containing bit-field.  */
+             if (TREE_CODE (expr) == BIT_FIELD_REF
+                 || contains_bitfld_component_ref_p (expr))
+               break;
+           }
+
+         *type_p = type;
+         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;
+
+      switch (gimple_assign_rhs_class (stmt))
+       {
+       case GIMPLE_SINGLE_RHS:
+         expr = gimple_assign_rhs1 (stmt);
+         continue;
+
+       case GIMPLE_UNARY_RHS:
+         rhs_count = 1;
+         break;
+
+       case GIMPLE_BINARY_RHS:
+         rhs_count = 2;
+         break;
+
+       case GIMPLE_TERNARY_RHS:
+         rhs_count = 3;
+         break;
+
+       default:
+         goto fail;
+       }
+
+      /* Stop if expression is too complex.  */
+      if (op_count++ == op_limit)
+       break;
+
+      if (param_ops_p)
+       {
+         eval_op.code = gimple_assign_rhs_code (stmt);
+         eval_op.type = TREE_TYPE (gimple_assign_lhs (stmt));
+         eval_op.val[0] = NULL_TREE;
+         eval_op.val[1] = NULL_TREE;
+       }
+
+      expr = NULL_TREE;
+      for (unsigned i = 0; i < rhs_count; i++)
+       {
+         tree op = gimple_op (stmt, i + 1);
+
+         gcc_assert (op && !TYPE_P (op));
+         if (is_gimple_ip_invariant (op))
+           {
+             if (++cst_count == rhs_count)
+               goto fail;
+
+             eval_op.val[cst_count - 1] = op;
+           }
+         else if (!expr)
+           {
+             /* Found a non-constant operand, and record its index in rhs
+                operands.  */
+             eval_op.index = i;
+             expr = op;
+           }
+         else
+           {
+             /* Found more than one non-constant operands.  */
+             goto fail;
+           }
+       }
+
+      if (param_ops_p)
+       vec_safe_insert (*param_ops_p, 0, eval_op);
+    }
+
+  /* Failed to decompose, free resource and return.  */
+fail:
+  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.   */
 
 /* If BB ends by a conditional we can turn into predicates, attach corresponding
    predicates to the CFG edges.   */
@@ -1165,15 +1311,15 @@ set_cond_stmt_execution_predicate (struct ipa_func_body_info *fbi,
                                   basic_block bb)
 {
   gimple *last;
                                   basic_block bb)
 {
   gimple *last;
-  tree op;
+  tree op, op2;
   int index;
   int index;
-  poly_int64 size;
   struct agg_position_info aggpos;
   enum tree_code code, inverted_code;
   edge e;
   edge_iterator ei;
   gimple *set_stmt;
   struct agg_position_info aggpos;
   enum tree_code code, inverted_code;
   edge e;
   edge_iterator ei;
   gimple *set_stmt;
-  tree op2;
+  tree param_type;
+  expr_eval_ops param_ops;
 
   last = last_stmt (bb);
   if (!last || gimple_code (last) != GIMPLE_COND)
 
   last = last_stmt (bb);
   if (!last || gimple_code (last) != GIMPLE_COND)
@@ -1181,10 +1327,9 @@ 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);
   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, &param_type, &aggpos,
+                           &param_ops))
     {
       code = gimple_cond_code (last);
       inverted_code = invert_tree_comparison (code, HONOR_NANS (op));
     {
       code = gimple_cond_code (last);
       inverted_code = invert_tree_comparison (code, HONOR_NANS (op));
@@ -1205,13 +1350,13 @@ set_cond_stmt_execution_predicate (struct ipa_func_body_info *fbi,
              && !dominated_by_p (CDI_POST_DOMINATORS, bb, e->dest))
            {
              predicate p
              && !dominated_by_p (CDI_POST_DOMINATORS, bb, e->dest))
            {
              predicate p
-               = add_condition (summary, index, size, &aggpos, this_code,
-                                unshare_expr_without_location
-                                (gimple_cond_rhs (last)));
+               = add_condition (summary, index, param_type, &aggpos,
+                                this_code, gimple_cond_rhs (last), param_ops);
              e->aux = edge_predicate_pool.allocate ();
              *(predicate *) e->aux = p;
            }
        }
              e->aux = edge_predicate_pool.allocate ();
              *(predicate *) e->aux = p;
            }
        }
+      vec_free (param_ops);
     }
 
   if (TREE_CODE (op) != SSA_NAME)
     }
 
   if (TREE_CODE (op) != SSA_NAME)
@@ -1234,12 +1379,11 @@ 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);
       || 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, &param_type, &aggpos))
     return;
   FOR_EACH_EDGE (e, ei, bb->succs) if (e->flags & EDGE_FALSE_VALUE)
     {
     return;
   FOR_EACH_EDGE (e, ei, bb->succs) if (e->flags & EDGE_FALSE_VALUE)
     {
-      predicate p = add_condition (summary, index, size, &aggpos,
+      predicate p = add_condition (summary, index, param_type, &aggpos,
                                   predicate::is_not_constant, NULL_TREE);
       e->aux = edge_predicate_pool.allocate ();
       *(predicate *) e->aux = p;
                                   predicate::is_not_constant, NULL_TREE);
       e->aux = edge_predicate_pool.allocate ();
       *(predicate *) e->aux = p;
@@ -1258,19 +1402,21 @@ set_switch_stmt_execution_predicate (struct ipa_func_body_info *fbi,
   gimple *lastg;
   tree op;
   int index;
   gimple *lastg;
   tree op;
   int index;
-  poly_int64 size;
   struct agg_position_info aggpos;
   edge e;
   edge_iterator ei;
   size_t n;
   size_t case_idx;
   struct agg_position_info aggpos;
   edge e;
   edge_iterator ei;
   size_t n;
   size_t case_idx;
+  tree param_type;
+  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);
 
   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, &param_type, &aggpos,
+                            &param_ops))
     return;
 
   auto_vec<std::pair<tree, tree> > ranges;
     return;
 
   auto_vec<std::pair<tree, tree> > ranges;
@@ -1302,6 +1448,8 @@ set_switch_stmt_execution_predicate (struct ipa_func_body_info *fbi,
       tree max = CASE_HIGH (cl);
       predicate p;
 
       tree max = CASE_HIGH (cl);
       predicate p;
 
+      e = gimple_switch_edge (cfun, last, case_idx);
+
       /* The case value might not have same type as switch expression,
         extend the value based on the expression type.  */
       if (TREE_TYPE (min) != type)
       /* The case value might not have same type as switch expression,
         extend the value based on the expression type.  */
       if (TREE_TYPE (min) != type)
@@ -1318,18 +1466,17 @@ set_switch_stmt_execution_predicate (struct ipa_func_body_info *fbi,
       if (dominated_by_p (CDI_POST_DOMINATORS, bb, e->dest))
        p = true;
       else if (min == max)
       if (dominated_by_p (CDI_POST_DOMINATORS, bb, e->dest))
        p = true;
       else if (min == max)
-       p = add_condition (summary, index, size, &aggpos, EQ_EXPR,
-                          unshare_expr_without_location (min));
+       p = add_condition (summary, index, param_type, &aggpos, EQ_EXPR,
+                          min, param_ops);
       else
        {
          predicate p1, p2;
       else
        {
          predicate p1, p2;
-         p1 = add_condition (summary, index, size, &aggpos, GE_EXPR,
-                             unshare_expr_without_location (min));
-         p2 = add_condition (summary, index, size, &aggpos, LE_EXPR,
-                             unshare_expr_without_location (max));
+         p1 = add_condition (summary, index, param_type, &aggpos, GE_EXPR,
+                             min, param_ops);
+         p2 = add_condition (summary, index, param_type, &aggpos, LE_EXPR,
+                             max, param_ops);
          p = p1 & p2;
        }
          p = p1 & p2;
        }
-      e = gimple_switch_edge (cfun, last, case_idx);
       *(class predicate *) e->aux
        = p.or_with (summary->conds, *(class predicate *) e->aux);
 
       *(class predicate *) e->aux
        = p.or_with (summary->conds, *(class predicate *) e->aux);
 
@@ -1378,6 +1525,7 @@ set_switch_stmt_execution_predicate (struct ipa_func_body_info *fbi,
   if (bound_count > bound_limit)
     {
       *(class predicate *) e->aux = true;
   if (bound_count > bound_limit)
     {
       *(class predicate *) e->aux = true;
+      vec_free (param_ops);
       return;
     }
 
       return;
     }
 
@@ -1407,16 +1555,16 @@ set_switch_stmt_execution_predicate (struct ipa_func_body_info *fbi,
       tree max = ranges[i].second;
 
       if (min == max)
       tree max = ranges[i].second;
 
       if (min == max)
-       p_seg &= add_condition (summary, index, size, &aggpos, NE_EXPR,
-                               unshare_expr_without_location (min));
+       p_seg &= add_condition (summary, index, param_type, &aggpos, NE_EXPR,
+                               min, param_ops);
       else
        {
          /* Do not create sub-predicate for range that is beyond low bound
             of switch index.  */
          if (wi::lt_p (vr_wmin, wi::to_wide (min), TYPE_SIGN (type)))
            {
       else
        {
          /* Do not create sub-predicate for range that is beyond low bound
             of switch index.  */
          if (wi::lt_p (vr_wmin, wi::to_wide (min), TYPE_SIGN (type)))
            {
-             p_seg &= add_condition (summary, index, size, &aggpos, LT_EXPR,
-                                     unshare_expr_without_location (min));
+             p_seg &= add_condition (summary, index, param_type, &aggpos,
+                                     LT_EXPR, min, param_ops);
              p_all = p_all.or_with (summary->conds, p_seg);
            }
 
              p_all = p_all.or_with (summary->conds, p_seg);
            }
 
@@ -1428,14 +1576,16 @@ set_switch_stmt_execution_predicate (struct ipa_func_body_info *fbi,
              break;
            }
 
              break;
            }
 
-         p_seg = add_condition (summary, index, size, &aggpos, GT_EXPR,
-                                unshare_expr_without_location (max));
+         p_seg = add_condition (summary, index, param_type, &aggpos, GT_EXPR,
+                                max, param_ops);
        }
     }
 
   p_all = p_all.or_with (summary->conds, p_seg);
   *(class predicate *) e->aux
     = p_all.or_with (summary->conds, *(class predicate *) e->aux);
        }
     }
 
   p_all = p_all.or_with (summary->conds, p_seg);
   *(class predicate *) e->aux
     = p_all.or_with (summary->conds, *(class predicate *) e->aux);
+
+  vec_free (param_ops);
 }
 
 
 }
 
 
@@ -1552,15 +1702,14 @@ will_be_nonconstant_expr_predicate (ipa_func_body_info *fbi,
 {
   tree parm;
   int index;
 {
   tree parm;
   int index;
-  poly_int64 size;
 
   while (UNARY_CLASS_P (expr))
     expr = TREE_OPERAND (expr, 0);
 
 
   while (UNARY_CLASS_P (expr))
     expr = TREE_OPERAND (expr, 0);
 
-  parm = unmodified_parm (fbi, NULL, expr, &size);
+  parm = unmodified_parm (fbi, NULL, expr, NULL);
   if (parm && (index = ipa_get_param_decl_index (fbi->info, parm)) >= 0)
   if (parm && (index = ipa_get_param_decl_index (fbi->info, parm)) >= 0)
-    return add_condition (summary, index, size, NULL, predicate::changed,
-                         NULL_TREE);
+    return add_condition (summary, index, TREE_TYPE (parm), NULL,
+                         predicate::changed, NULL_TREE);
   if (is_gimple_min_invariant (expr))
     return false;
   if (TREE_CODE (expr) == SSA_NAME)
   if (is_gimple_min_invariant (expr))
     return false;
   if (TREE_CODE (expr) == SSA_NAME)
@@ -1624,10 +1773,10 @@ will_be_nonconstant_predicate (struct ipa_func_body_info *fbi,
   predicate p = true;
   ssa_op_iter iter;
   tree use;
   predicate p = true;
   ssa_op_iter iter;
   tree use;
+  tree param_type = NULL_TREE;
   predicate op_non_const;
   bool is_load;
   int base_index;
   predicate op_non_const;
   bool is_load;
   int base_index;
-  poly_int64 size;
   struct agg_position_info aggpos;
 
   /* What statments might be optimized away
   struct agg_position_info aggpos;
 
   /* What statments might be optimized away
@@ -1648,11 +1797,9 @@ will_be_nonconstant_predicate (struct ipa_func_body_info *fbi,
   /* Loads can be optimized when the value is known.  */
   if (is_load)
     {
   /* Loads can be optimized when the value is known.  */
   if (is_load)
     {
-      tree op;
-      gcc_assert (gimple_assign_single_p (stmt));
-      op = gimple_assign_rhs1 (stmt);
-      if (!unmodified_parm_or_parm_agg_item (fbi, stmt, op, &base_index, &size,
-                                            &aggpos))
+      tree op = gimple_assign_rhs1 (stmt);
+      if (!decompose_param_expr (fbi, stmt, op, &base_index, &param_type,
+                                &aggpos))
        return p;
     }
   else
        return p;
     }
   else
@@ -1677,21 +1824,20 @@ will_be_nonconstant_predicate (struct ipa_func_body_info *fbi,
 
   if (is_load)
     op_non_const =
 
   if (is_load)
     op_non_const =
-      add_condition (summary, base_index, size, &aggpos, predicate::changed,
-                    NULL);
+      add_condition (summary, base_index, param_type, &aggpos,
+                    predicate::changed, NULL_TREE);
   else
     op_non_const = false;
   FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
     {
   else
     op_non_const = false;
   FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
     {
-      poly_int64 size;
-      tree parm = unmodified_parm (fbi, stmt, use, &size);
+      tree parm = unmodified_parm (fbi, stmt, use, NULL);
       int index;
 
       if (parm && (index = ipa_get_param_decl_index (fbi->info, parm)) >= 0)
        {
          if (index != base_index)
       int index;
 
       if (parm && (index = ipa_get_param_decl_index (fbi->info, parm)) >= 0)
        {
          if (index != base_index)
-           p = add_condition (summary, index, size, NULL, predicate::changed,
-                              NULL_TREE);
+           p = add_condition (summary, index, TREE_TYPE (parm), NULL,
+                              predicate::changed, NULL_TREE);
          else
            continue;
        }
          else
            continue;
        }
@@ -1823,7 +1969,7 @@ param_change_prob (ipa_func_body_info *fbi, gimple *stmt, int i)
        return REG_BR_PROB_BASE;
       if (dump_file)
        {
        return REG_BR_PROB_BASE;
       if (dump_file)
        {
-         fprintf (dump_file, "     Analyzing param change probablity of ");
+         fprintf (dump_file, "     Analyzing param change probability of ");
           print_generic_expr (dump_file, op, TDF_SLIM);
          fprintf (dump_file, "\n");
        }
           print_generic_expr (dump_file, op, TDF_SLIM);
          fprintf (dump_file, "\n");
        }
@@ -3452,15 +3598,49 @@ inline_read_section (struct lto_file_decl_data *file_data, const char *data,
       for (j = 0; j < count2; j++)
        {
          struct condition c;
       for (j = 0; j < count2; j++)
        {
          struct condition c;
+         unsigned int k, count3;
          c.operand_num = streamer_read_uhwi (&ib);
          c.operand_num = streamer_read_uhwi (&ib);
-         c.size = streamer_read_poly_uint64 (&ib);
          c.code = (enum tree_code) streamer_read_uhwi (&ib);
          c.code = (enum tree_code) streamer_read_uhwi (&ib);
+         c.type = stream_read_tree (&ib, data_in);
          c.val = stream_read_tree (&ib, data_in);
          bp = streamer_read_bitpack (&ib);
          c.agg_contents = bp_unpack_value (&bp, 1);
          c.by_ref = bp_unpack_value (&bp, 1);
          if (c.agg_contents)
            c.offset = streamer_read_uhwi (&ib);
          c.val = stream_read_tree (&ib, data_in);
          bp = streamer_read_bitpack (&ib);
          c.agg_contents = bp_unpack_value (&bp, 1);
          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;
+             enum gimple_rhs_class rhs_class;
+             op.code = (enum tree_code) streamer_read_uhwi (&ib);
+             op.type = stream_read_tree (&ib, data_in);
+             switch (rhs_class = get_gimple_rhs_class (op.code))
+               {
+               case GIMPLE_UNARY_RHS:
+                 op.index = 0;
+                 op.val[0] = NULL_TREE;
+                 op.val[1] = NULL_TREE;
+                 break;
+
+               case GIMPLE_BINARY_RHS:
+               case GIMPLE_TERNARY_RHS:
+                 bp = streamer_read_bitpack (&ib);
+                 op.index = bp_unpack_value (&bp, 2);
+                 op.val[0] = stream_read_tree (&ib, data_in);
+                 if (rhs_class == GIMPLE_BINARY_RHS)
+                   op.val[1] = NULL_TREE;
+                 else
+                   op.val[1] = stream_read_tree (&ib, data_in);
+                 break;
+
+               default:
+                 fatal_error (UNKNOWN_LOCATION,
+                              "invalid fnsummary in LTO stream");
+               }
+             vec_safe_push (c.param_ops, op);
+           }
          if (info)
            vec_safe_push (info->conds, c);
        }
          if (info)
            vec_safe_push (info->conds, c);
        }
@@ -3606,9 +3786,12 @@ 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++)
            {
          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->operand_num);
-             streamer_write_poly_uint64 (ob, c->size);
              streamer_write_uhwi (ob, c->code);
              streamer_write_uhwi (ob, c->code);
+             stream_write_tree (ob, c->type, true);
              stream_write_tree (ob, c->val, true);
              bp = bitpack_create (ob->main_stream);
              bp_pack_value (&bp, c->agg_contents, 1);
              stream_write_tree (ob, c->val, true);
              bp = bitpack_create (ob->main_stream);
              bp_pack_value (&bp, c->agg_contents, 1);
@@ -3616,6 +3799,21 @@ ipa_fn_summary_write (void)
              streamer_write_bitpack (&bp);
              if (c->agg_contents)
                streamer_write_uhwi (ob, c->offset);
              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);
+                 stream_write_tree (ob, op->type, true);
+                 if (op->val[0])
+                   {
+                     bp = bitpack_create (ob->main_stream);
+                     bp_pack_value (&bp, op->index, 2);
+                     streamer_write_bitpack (&bp);
+                     stream_write_tree (ob, op->val[0], true);
+                     if (op->val[1])
+                       stream_write_tree (ob, op->val[1], 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++)
            }
          streamer_write_uhwi (ob, vec_safe_length (info->size_time_table));
          for (i = 0; vec_safe_iterate (info->size_time_table, i, &e); i++)
index 8a9851a2040d53d166ecba548464c9c8ac43cc4c..b5e3cf44323896849709e738962a93a0c5af9723 100644 (file)
@@ -33,9 +33,36 @@ along with GCC; see the file COPYING3.  If not see
 #include "fold-const.h"
 #include "tree-pretty-print.h"
 #include "gimple.h"
 #include "fold-const.h"
 #include "tree-pretty-print.h"
 #include "gimple.h"
+#include "gimplify.h"
 #include "data-streamer.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.index != op2.index
+             || !vrp_operand_equal_p (op1.val[0], op2.val[0])
+             || !vrp_operand_equal_p (op1.val[1], op2.val[1])
+             || !types_compatible_p (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
 /* 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 +137,16 @@ predicate::add_clause (conditions conditions, clause_t new_clause)
        for (c2 = c1 + 1; c2 < num_conditions; c2++)
          if (new_clause & (1 << c2))
            {
        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
              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 != is_not_constant
-                 && cc2->code != predicate::changed
+                 && cc2->code != changed
+                 && expr_eval_ops_equal_p (cc1->param_ops, cc2->param_ops)
+                 && cc2->agg_contents == cc1->agg_contents
+                 && cc2->by_ref == cc1->by_ref
+                 && types_compatible_p (cc2->type, cc1->type)
                  && cc1->code == invert_tree_comparison (cc2->code,
                                                          HONOR_NANS (cc1->val)))
                return;
                  && cc1->code == invert_tree_comparison (cc2->code,
                                                          HONOR_NANS (cc1->val)))
                return;
@@ -300,6 +329,83 @@ 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);
       if (c->agg_contents)
        fprintf (f, "[%soffset: " HOST_WIDE_INT_PRINT_DEC "]",
                 c->by_ref ? "ref " : "", c->offset);
+
+      for (unsigned i = 0; 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[0])
+           {
+             switch (op.code)
+               {
+               case FLOAT_EXPR:
+               case FIX_TRUNC_EXPR:
+               case FIXED_CONVERT_EXPR:
+               case VIEW_CONVERT_EXPR:
+               CASE_CONVERT:
+                 if (op.code == VIEW_CONVERT_EXPR)
+                   fprintf (f, "VCE");
+                 fprintf (f, "(");
+                 print_generic_expr (f, op.type);
+                 fprintf (f, ")" );
+                 break;
+
+               default:
+                 fprintf (f, "%s", op_name);
+               }
+             fprintf (f, " #");
+           }
+         else if (!op.val[1])
+           {
+             if (op.index)
+               {
+                 print_generic_expr (f, op.val[0]);
+                 fprintf (f, " %s #", op_name);
+               }
+             else
+               {
+                 fprintf (f, "# %s ", op_name);
+                 print_generic_expr (f, op.val[0]);
+               }
+           }
+         else
+           {
+             fprintf (f, "%s ", op_name);
+             switch (op.index)
+               {
+               case 0:
+                 fprintf (f, "#, ");
+                 print_generic_expr (f, op.val[0]);
+                 fprintf (f, ", ");
+                 print_generic_expr (f, op.val[1]);
+                 break;
+
+               case 1:
+                 print_generic_expr (f, op.val[0]);
+                 fprintf (f, ", #, ");
+                 print_generic_expr (f, op.val[1]);
+                 break;
+
+               case 2:
+                 print_generic_expr (f, op.val[0]);
+                 fprintf (f, ", ");
+                 print_generic_expr (f, op.val[1]);
+                 fprintf (f, ", #");
+                 break;
+
+               default:
+                 fprintf (f, "*, *, *");
+               }
+           }
+         fprintf (f, ")");
+       }
+
       if (c->code == predicate::is_not_constant)
        {
          fprintf (f, " not constant");
       if (c->code == predicate::is_not_constant)
        {
          fprintf (f, " not constant");
@@ -462,8 +568,8 @@ predicate::remap_after_inlining (class ipa_fn_summary *info,
                    ap.by_ref = c->by_ref;
                    cond_predicate = add_condition (info,
                                                    operand_map[c->operand_num],
                    ap.by_ref = c->by_ref;
                    cond_predicate = add_condition (info,
                                                    operand_map[c->operand_num],
-                                                   c->size, &ap, c->code,
-                                                   c->val);
+                                                   c->type, &ap, c->code,
+                                                   c->val, c->param_ops);
                  }
              }
            /* Fixed conditions remains same, construct single
                  }
              }
            /* Fixed conditions remains same, construct single
@@ -516,21 +622,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, TYPE, 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,
 
 predicate
 add_condition (class ipa_fn_summary *summary, int operand_num,
-              poly_int64 size, struct agg_position_info *aggpos,
-              enum tree_code code, tree val)
+              tree type, struct agg_position_info *aggpos,
+              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;
   struct condition *c;
   struct condition new_cond;
   HOST_WIDE_INT offset;
   bool agg_contents, by_ref;
+  expr_eval_op *op;
 
   if (aggpos)
     {
 
   if (aggpos)
     {
@@ -549,10 +657,11 @@ add_condition (class ipa_fn_summary *summary, int operand_num,
   for (i = 0; vec_safe_iterate (summary->conds, i, &c); i++)
     {
       if (c->operand_num == operand_num
   for (i = 0; vec_safe_iterate (summary->conds, i, &c); i++)
     {
       if (c->operand_num == operand_num
-         && known_eq (c->size, size)
          && c->code == code
          && c->code == code
-         && c->val == val
+         && types_compatible_p (c->type, type)
+         && vrp_operand_equal_p (c->val, val)
          && c->agg_contents == agg_contents
          && 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);
     }
          && (!agg_contents || (c->offset == offset && c->by_ref == by_ref)))
        return predicate::predicate_testing_cond (i);
     }
@@ -562,11 +671,21 @@ add_condition (class ipa_fn_summary *summary, int operand_num,
 
   new_cond.operand_num = operand_num;
   new_cond.code = code;
 
   new_cond.operand_num = operand_num;
   new_cond.code = code;
-  new_cond.val = val;
+  new_cond.type = unshare_expr_without_location (type);
+  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.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[0])
+       op->val[0] = unshare_expr_without_location (op->val[0]);
+      if (op->val[1])
+       op->val[1] = unshare_expr_without_location (op->val[1]);
+    }
+
   vec_safe_push (summary->conds, new_cond);
 
   return predicate::predicate_testing_cond (i);
   vec_safe_push (summary->conds, new_cond);
 
   return predicate::predicate_testing_cond (i);
index 237306dc9fe5b837e7687517b14602fdc4a919ba..4121218ac041c631cc9751e9458b8fead6f37a27 100644 (file)
@@ -22,16 +22,36 @@ 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
    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, for unary, binary and ternary
+   operation.  Computations on parameter are decomposed to a series of this
+   kind of structure.  */
+struct GTY(()) expr_eval_op
+{
+  /* Result type of expression.  */
+  tree type;
+  /* Constant operands in expression, there are at most two.  */
+  tree val[2];
+  /* Index of parameter operand in expression.  */
+  unsigned index : 2;
+  /* Operation code of expression.  */
+  ENUM_BITFIELD(tree_code) code : 16;
+};
+
+typedef vec<expr_eval_op, va_gc> *expr_eval_ops;
 
 struct GTY(()) condition
 {
   /* If agg_contents is set, this is the offset from which the used data was
      loaded.  */
   HOST_WIDE_INT offset;
 
 struct GTY(()) condition
 {
   /* If agg_contents is set, this is the offset from which the used data was
      loaded.  */
   HOST_WIDE_INT offset;
-  /* Size of the access reading the data (or the PARM_DECL SSA_NAME).  */
-  poly_int64 size;
+  /* Type of the access reading the data (or the PARM_DECL SSA_NAME).  */
+  tree type;
   tree val;
   int operand_num;
   ENUM_BITFIELD(tree_code) code : 16;
   tree val;
   int operand_num;
   ENUM_BITFIELD(tree_code) code : 16;
@@ -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;
   /* If agg_contents is set, this differentiates between loads from data
      passed by reference and by value.  */
   unsigned by_ref : 1;
+  /* A set of 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.  */
 };
 
 /* Information kept about parameter of call site.  */
@@ -228,5 +251,6 @@ private:
 
 void dump_condition (FILE *f, conditions conditions, int cond);
 predicate add_condition (class ipa_fn_summary *summary, int operand_num,
 
 void dump_condition (FILE *f, conditions conditions, int cond);
 predicate add_condition (class ipa_fn_summary *summary, int operand_num,
-                        poly_int64 size, struct agg_position_info *aggpos,
-                        enum tree_code code, tree val);
+                        tree type, struct agg_position_info *aggpos,
+                        enum tree_code code, tree val,
+                        expr_eval_ops param_ops = NULL);
index e4b70bac22a43a9b6098fde1d819f12d3cf9f08b..322c37f8b96c7c5ade92529b7e725ccb92787903 100644 (file)
@@ -1165,6 +1165,12 @@ DEFPARAM (PARAM_IPA_MAX_SWITCH_PREDICATE_BOUNDS,
          "statement used during IPA functoin summary generation.",
          5, 0, 0)
 
          "statement used during IPA functoin summary generation.",
          5, 0, 0)
 
+DEFPARAM (PARAM_IPA_MAX_PARAM_EXPR_OPS,
+         "ipa-max-param-expr-ops",
+         "Maximum number of operations in a parameter expression that can "
+         "be handled by IPA analysis.",
+         10, 0, 0)
+
 /* WHOPR partitioning configuration.  */
 
 DEFPARAM (PARAM_LTO_PARTITIONS,
 /* WHOPR partitioning configuration.  */
 
 DEFPARAM (PARAM_LTO_PARTITIONS,
index 6dc4f00276913b239a2d84e28d27e55510987a52..b2b92deb1340346413e48b58acd1e62bf0800936 100644 (file)
@@ -1,3 +1,10 @@
+2019-10-16  Feng Xue  <fxue@os.amperecomputing.com>
+
+       PR ipa/91088
+       * gcc.dg/ipa/pr91088.c: New test.
+       * gcc.dg/ipa/pr91089.c: Add sub-test for range analysis.
+       * g++.dg/tree-ssa/ivopts-3.C: Force a function to be noinline.
+
 2019-10-15  Andrew Pinski  <apinski@marvell.com>
 
        * gcc.c-torture/compile/20191015-1.c: New test.
 2019-10-15  Andrew Pinski  <apinski@marvell.com>
 
        * gcc.c-torture/compile/20191015-1.c: New test.
index 6760a5b185176e781afb3dded2e09793b3cf7ba6..b0da5e68abcc18d484d5176f0f43759f078c59b6 100644 (file)
@@ -25,7 +25,7 @@ protected:
   double stuff;
 
 public:
   double stuff;
 
 public:
-  explicit MinimalVector ( int length ) {
+  __attribute__((noinline)) explicit MinimalVector ( int length ) {
     _pData = new double[length];
     for (int i = 0; i < length; ++i) _pData[i] = 0.;
   }
     _pData = new double[length];
     for (int i = 0; i < length; ++i) _pData[i] = 0.;
   }
diff --git a/gcc/testsuite/gcc.dg/ipa/pr91088.c b/gcc/testsuite/gcc.dg/ipa/pr91088.c
new file mode 100644 (file)
index 0000000..a81c59f
--- /dev/null
@@ -0,0 +1,120 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fdump-ipa-cp-details -fno-inline" } */
+
+int foo();
+
+#define large_code \
+do { \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+  foo (); \
+} while (1)
+
+
+struct A
+{
+  char  f1;
+  short f2 : 5;
+  int   f3;
+};
+
+int callee1 (struct A a)
+{
+  if ((a.f2 + 7) & 17)
+    foo ();
+
+  if ((1300 / (short)a.f3) == 19)
+    large_code;
+
+  return 1;
+}
+
+int callee2 (short *p)
+{
+  if ((*p ^ 1)  <  8)
+    large_code;      
+
+  return 2;
+}
+
+int callee3 (int v)
+{
+  if ((27 % ((1 - (char) v) * 3)) < 6)
+    {
+      large_code;
+      return v + 2;
+    }
+  else
+    return v + 1;
+}
+
+int caller ()
+{
+  struct A a;
+  short b;
+
+  a.f2 = -7;
+  a.f3 = 68;
+  if (callee1 (a))
+    foo ();
+
+  a.f2 = 3;
+  a.f3 = 10;
+  if (callee1 (a))
+    foo ();
+
+  b = 9;
+  if (callee2 (&b))
+    foo ();
+
+  b = 2;
+  if (callee2 (&b))
+    foo ();
+
+  return callee3 (-5) +
+        callee3 (0); 
+}
+
+/* { dg-final { scan-ipa-dump-times "Creating a specialized node of callee1" 1 "cp" } } */
+/* { dg-final { scan-ipa-dump-times "Creating a specialized node of callee2" 1 "cp" } } */
+/* { dg-final { scan-ipa-dump-times "Creating a specialized node of callee3" 1 "cp" } } */
+/* { dg-final { scan-ipa-dump "op0\\\[offset: 32],\\(\\(short int\\) #\\),\\(\\(int\\) #\\),\\(1300 / #\\) == 19" "cp" } } */
+/* { dg-final { scan-ipa-dump "op0\\\[ref offset: 0],\\(# \\^ 1\\) <" "cp" } } */
+/* { dg-final { scan-ipa-dump "op0,\\(\\(char\\) #\\),\\(\\(int\\) #\\),\\(1 - #\\),\\(# \\* 3\\),\\(27 % #\\) <" "cp" } } */
index 7509c6222632ceacf3edc77296ab36d461928a87..a54cbdf5390b20304cf805d1b21606c81d698459 100644 (file)
@@ -7,7 +7,7 @@ int data;
 
 int callee (int i)
 {
 
 int callee (int i)
 {
-  switch (i)
+  switch (i % 128)
     {
       case -126:  return i + 13;
       case -127:  return i + 5;
     {
       case -126:  return i + 13;
       case -127:  return i + 5;
@@ -45,7 +45,7 @@ int fn2 ();
 
 int callee_complex_predicate (int i)
 {
 
 int callee_complex_predicate (int i)
 {
-  switch (i )
+  switch (i)
     {
       case 0:
        fn ();
     {
       case 0:
        fn ();
@@ -100,10 +100,10 @@ int caller ()
 }
  
 /* { dg-final { scan-ipa-dump-times "Creating a specialized node of callee" 7 "cp" } } */
 }
  
 /* { dg-final { scan-ipa-dump-times "Creating a specialized node of callee" 7 "cp" } } */
-/* { dg-final { scan-ipa-dump "op0 < -127" "fnsummary" } } */
-/* { dg-final { scan-ipa-dump "op0 > -126" "fnsummary" } } */
-/* { dg-final { scan-ipa-dump "op0 != -8"  "fnsummary" } } */
-/* { dg-final { scan-ipa-dump "op0 != 0"   "fnsummary" } } */
-/* { dg-final { scan-ipa-dump "op0 < 5"    "fnsummary" } } */
-/* { dg-final { scan-ipa-dump "op0 > 7"    "fnsummary" } } */
+/* { dg-final { scan-ipa-dump-not "op0,\\(# % 128\\) < -127" "fnsummary" } } */
+/* { dg-final { scan-ipa-dump "op0,\\(# % 128\\) > -126" "fnsummary" } } */
+/* { dg-final { scan-ipa-dump "op0,\\(# % 128\\) != -8"  "fnsummary" } } */
+/* { dg-final { scan-ipa-dump "op0,\\(# % 128\\) != 0"   "fnsummary" } } */
+/* { dg-final { scan-ipa-dump "op0,\\(# % 128\\) < 5"    "fnsummary" } } */
+/* { dg-final { scan-ipa-dump "op0,\\(# % 128\\) > 7"    "fnsummary" } } */
 /* { dg-final { scan-ipa-dump "loop depth: 1 .+ time:\[ \]*\[0-9\]+ predicate: \\(op0 == 1000\\)\[\r\n]+" "fnsummary" } } */
 /* { dg-final { scan-ipa-dump "loop depth: 1 .+ time:\[ \]*\[0-9\]+ predicate: \\(op0 == 1000\\)\[\r\n]+" "fnsummary" } } */