https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110852

--- Comment #9 from Jan Hubicka <hubicka at ucw dot cz> ---
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110852
> 
> --- Comment #7 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
> So, what about following patch (which also fixes the ICE, would of course need
> to add the testcase) and doesn't regress any predict-*.c tests)?
> 
> --- gcc/predict.cc.jj   2024-01-03 11:51:32.000000000 +0100
> +++ gcc/predict.cc      2024-01-04 16:28:55.041507010 +0100
> @@ -2583,44 +2583,36 @@ expr_expected_value_1 (tree type, tree o
>    if (get_gimple_rhs_class (code) == GIMPLE_BINARY_RHS)
>      {
>        tree res;
> -      tree nop0 = op0;
> -      tree nop1 = op1;
> -      if (TREE_CODE (op0) != INTEGER_CST)
> -       {
> -         /* See if expected value of op0 is good enough to determine the
> result.  */
> -         nop0 = expr_expected_value (op0, visited, predictor, probability);
> -         if (nop0
> -             && (res = fold_build2 (code, type, nop0, op1)) != NULL
> -             && TREE_CODE (res) == INTEGER_CST)
> -           return res;
> -         if (!nop0)
> -           nop0 = op0;
> -        }

By removing the logic we lose ability to optimize things like
  a = b * c;
where b is predicted to value 0 and c has no useful prediction on it.
> @@ -2631,6 +2623,9 @@ expr_expected_value_1 (tree type, tree o
> 
>           if (predictor2 < *predictor)
>             *predictor = predictor2;
> +         if (*predictor != PRED_BUILTIN_EXPECT
> +             && *predictor != PRED_BUILTIN_EXPECT_WITH_PROBABILITY)
> +           *probability = -1;

This still can "upgrade" prediction to a predictor of lower enm value
but higher probability that is not conservative thing to do.
> 
>           return res;
>         }
I ended up with the folloing patch that also takes care of various cases
of phi merging and downgrading the predictor to new
PRED_COMBINED_VALUE_PREDICTION which can, like PRED_BUILTIN_EXPECT hold
custom probability but it is not trued as FIRST_MATCH.
What do you think?

gcc/ChangeLog:

        * predict.cc (expr_expected_value_1):
        (get_predictor_value):
        * predict.def (PRED_COMBINED_VALUE_PREDICTIONS):

diff --git a/gcc/predict.cc b/gcc/predict.cc
index 2e9b7dd07a7..cdfaea1e607 100644
--- a/gcc/predict.cc
+++ b/gcc/predict.cc
@@ -2404,16 +2404,29 @@ expr_expected_value_1 (tree type, tree op0, enum
tree_code code,
       if (!bitmap_set_bit (visited, SSA_NAME_VERSION (op0)))
        return NULL;

-      if (gimple_code (def) == GIMPLE_PHI)
+      if (gphi *phi = dyn_cast <gphi *> (def))
        {
          /* All the arguments of the PHI node must have the same constant
             length.  */
-         int i, n = gimple_phi_num_args (def);
-         tree val = NULL, new_val;
+         int i, n = gimple_phi_num_args (phi);
+         tree val = NULL;
+         bool has_nonzero_edge = false;
+
+         /* If we already proved that given edge is unlikely, we do not need
+            to handle merging of the probabilities.  */
+         for (i = 0; i < n && !has_nonzero_edge; i++)
+           {
+             tree arg = PHI_ARG_DEF (phi, i);
+             if (arg == PHI_RESULT (phi))
+               continue;
+             profile_count cnt = gimple_phi_arg_edge (phi, i)->count ();
+             if (!cnt.initialized_p () || cnt.nonzero_p ())
+               has_nonzero_edge = true;
+           }

          for (i = 0; i < n; i++)
            {
-             tree arg = PHI_ARG_DEF (def, i);
+             tree arg = PHI_ARG_DEF (phi, i);
              enum br_predictor predictor2;

              /* If this PHI has itself as an argument, we cannot
@@ -2422,26 +2435,50 @@ expr_expected_value_1 (tree type, tree op0, enum
tree_code code,
                 PHI args then we can still be sure that this is
                 likely a constant.  So be optimistic and just
                 continue with the next argument.  */
-             if (arg == PHI_RESULT (def))
+             if (arg == PHI_RESULT (phi))
                continue;

+             /* Skip edges which we already predicted as unlikely.  */
+             if (has_nonzero_edge)
+               {
+                 profile_count cnt = gimple_phi_arg_edge (phi, i)->count ();
+                 if (cnt.initialized_p () && !cnt.nonzero_p ())
+                   continue;
+               }
              HOST_WIDE_INT probability2;
-             new_val = expr_expected_value (arg, visited, &predictor2,
-                                            &probability2);
+             tree new_val = expr_expected_value (arg, visited, &predictor2,
+                                                 &probability2);
+             /* If we know nothing about value, give up.  */
+             if (!new_val)
+               return NULL;

-             /* It is difficult to combine value predictors.  Simply assume
-                that later predictor is weaker and take its prediction.  */
-             if (*predictor < predictor2)
+             /* If this is a first edge, trust its prediction.  */
+             if (!val)
                {
+                 val = new_val;
                  *predictor = predictor2;
                  *probability = probability2;
+                 continue;
                }
-             if (!new_val)
-               return NULL;
-             if (!val)
-               val = new_val;
-             else if (!operand_equal_p (val, new_val, false))
+             /* If there are two different values, give up.  */
+             if (!operand_equal_p (val, new_val, false))
                return NULL;
+
+             int p1 = get_predictor_value (*predictor, *probability);
+             int p2 = get_predictor_value (predictor2, probability2);
+             /* If both predictors agrees, it does not matter from which
+                edge we enter the basic block.  */
+             if (*predictor == predictor2 && p1 == p2)
+               continue;
+             /* The general case has no precise solution, since we do not
+                know probabilities of incomming edges, yet.
+                Still if value is predicted over all incomming edges, we
+                can hope it will be indeed the case.  Conservatively
+                downgrade prediction quality (so first match merging is not
+                performed) and take least successful prediction.  */
+
+             *predictor = PRED_COMBINED_VALUE_PREDICTIONS;
+             *probability = MIN (p1, p2);
            }
          return val;
        }
@@ -2596,8 +2633,8 @@ expr_expected_value_1 (tree type, tree op0, enum
tree_code code,
          if (!nop0)
            nop0 = op0;
         }
-      enum br_predictor predictor2;
-      HOST_WIDE_INT probability2;
+      enum br_predictor predictor2 = PRED_UNCONDITIONAL;
+      HOST_WIDE_INT probability2 = -1;
       if (TREE_CODE (op1) != INTEGER_CST)
        {
          /* See if expected value of op1 is good enough to determine the
result.  */
@@ -2613,24 +2650,39 @@ expr_expected_value_1 (tree type, tree op0, enum
tree_code code,
          if (!nop1)
            nop1 = op1;
         }
+      /* We already checked if folding one of arguments to constant is good
enough.
+         Consequently failing to fold both means that we will not suceed
determinging
+        the value.  */
       if (nop0 == op0 || nop1 == op1)
        return NULL;
       /* Finally see if we have two known values.  */
       res = fold_build2 (code, type, nop0, nop1);
-      if (TREE_CODE (res) == INTEGER_CST
-         && TREE_CODE (nop0) == INTEGER_CST
-         && TREE_CODE (nop1) == INTEGER_CST)
+      if (TREE_CODE (res) == INTEGER_CST)
        {
-         /* Combine binary predictions.  */
-         if (*probability != -1 || probability2 != -1)
+         HOST_WIDE_INT p1 = get_predictor_value (*predictor, *probability);
+         HOST_WIDE_INT p2 = get_predictor_value (predictor2, probability2);
+
+         /* If one of predictions is sure, such as PRED_UNCONDITIONAL, we
+            can ignore it.  */
+         if (p2 == PROB_ALWAYS)
+           return res;
+         if (p1 == PROB_ALWAYS)
            {
-             HOST_WIDE_INT p1 = get_predictor_value (*predictor,
*probability);
-             HOST_WIDE_INT p2 = get_predictor_value (predictor2,
probability2);
-             *probability = RDIV (p1 * p2, REG_BR_PROB_BASE);
+             *predictor = predictor2;
+             *probability = probability2;
+             return res;
            }
-
-         if (predictor2 < *predictor)
-           *predictor = predictor2;
+         /* Combine binary predictions.
+            Since we do not know about independence of predictors, we   */
+         *probability = RDIV (p1 * p2, REG_BR_PROB_BASE);
+         /* If we no longer track useful information, give up.  */
+         if (!*probability)
+           return NULL;
+         /* Otherwise mark that prediction is a result of combining
+            different heuristics, since we do not want it to participate
+            in first match merging.  It is no longer reliable since
+            we do not know if the probabilities are indpenendet.  */
+         *predictor = PRED_COMBINED_VALUE_PREDICTIONS;

          return res;
        }
@@ -2690,6 +2742,7 @@ get_predictor_value (br_predictor predictor,
HOST_WIDE_INT probability)
     {
     case PRED_BUILTIN_EXPECT:
     case PRED_BUILTIN_EXPECT_WITH_PROBABILITY:
+    case PRED_COMBINED_VALUE_PREDICTIONS:
       gcc_assert (probability != -1);
       return probability;
     default:
diff --git a/gcc/predict.def b/gcc/predict.def
index ae7dd8239c5..4f3e519356d 100644
--- a/gcc/predict.def
+++ b/gcc/predict.def
@@ -94,6 +94,10 @@ DEF_PREDICTOR (PRED_LOOP_ITERATIONS_GUESSED, "guessed loop
iterations",
 DEF_PREDICTOR (PRED_LOOP_ITERATIONS_MAX, "guessed loop iterations",
               PROB_UNINITIALIZED, PRED_FLAG_FIRST_MATCH)

+/* Prediction which is an outcome of combining multiple value predictions.  */
+DEF_PREDICTOR (PRED_COMBINED_VALUE_PREDICTIONS,
+              "combined value predictions", PROB_UNINITIALIZED, 0)
+
 /* Branch containing goto is probably not taken.  */
 DEF_PREDICTOR (PRED_CONTINUE, "continue", HITRATE (67), 0)

Reply via email to