+/* Try to guess whether the value of return means error code. */
+static enum br_predictor
+return_prediction (tree val, enum prediction *prediction)
+{
+ /* VOID. */
+ if (!val)
+ return PRED_NO_PREDICTION;
+ /* Different heuristics for pointers and scalars. */
+ if (POINTER_TYPE_P (TREE_TYPE (val)))
+ {
+ /* NULL is usually not returned. */
+ if (integer_zerop (val))
+ {
+ *prediction = NOT_TAKEN;
+ return PRED_NULL_RETURN;
+ }
+ }
+ else if (INTEGRAL_TYPE_P (TREE_TYPE (val)))
+ {
+ /* Negative return values are often used to indicate
+ errors. */
+ if (TREE_CODE (val) == INTEGER_CST
+ && tree_int_cst_sgn (val) < 0)
+ {
+ *prediction = NOT_TAKEN;
+ return PRED_NEGATIVE_RETURN;
+ }
+ /* Constant return values seems to be commonly taken.
+ Zero/one often represent booleans so exclude them from the
+ heuristics. */
+ if (TREE_CONSTANT (val)
+ && (!integer_zerop (val) && !integer_onep (val)))
+ {
+ *prediction = TAKEN;
+ return PRED_NEGATIVE_RETURN;
+ }
+ }
+ return PRED_NO_PREDICTION;
+}
+
+/* Find the basic block with return expression and look up for possible
+ return value trying to apply RETURN_PREDICTION heuristics. */
+static void
+apply_return_prediction (int *heads)
+{
+ tree return_stmt;
+ tree return_val;
+ edge e;
+ tree phi;
+ int phi_num_args, i;
+ enum br_predictor pred;
+ enum prediction direction;
+ edge_iterator ei;
+
+ FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
+ {
+ return_stmt = last_stmt (e->src);
+ if (TREE_CODE (return_stmt) == RETURN_EXPR)
+ break;
+ }
+ if (!e)
+ return;
+ return_val = TREE_OPERAND (return_stmt, 0);
+ if (!return_val)
+ return;
+ if (TREE_CODE (return_val) == MODIFY_EXPR)
+ return_val = TREE_OPERAND (return_val, 1);
+ if (TREE_CODE (return_val) != SSA_NAME
+ || !SSA_NAME_DEF_STMT (return_val)
+ || TREE_CODE (SSA_NAME_DEF_STMT (return_val)) != PHI_NODE)
+ return;
+ phi = SSA_NAME_DEF_STMT (return_val);
+ while (phi)
+ {
+ tree next = PHI_CHAIN (phi);
+ if (PHI_RESULT (phi) == return_val)
+ break;
+ phi = next;
+ }
+ if (!phi)
+ return;
+ phi_num_args = PHI_NUM_ARGS (phi);
+ pred = return_prediction (PHI_ARG_DEF (phi, 0), &direction);
+
+ /* Avoid the degenerate case where all return values form the function
+ belongs to same category (ie they are all positive constants)
+ so we can hardly say something about them. */
+ for (i = 1; i < phi_num_args; i++)
+ if (pred != return_prediction (PHI_ARG_DEF (phi, i), &direction))
+ break;
+ if (i != phi_num_args)
+ for (i = 0; i < phi_num_args; i++)
+ {
+ pred = return_prediction (PHI_ARG_DEF (phi, i), &direction);
+ if (pred != PRED_NO_PREDICTION)
+ predict_paths_leading_to (PHI_ARG_EDGE (phi, i)->src, heads, pred,
+ direction);
+ }
+}
+
+/* Look for basic block that contains unlikely to happen events
+ (such as noreturn calls) and mark all paths leading to execution
+ of this basic blocks as unlikely. */
+
+static void
+tree_bb_level_predictions (void)
+{
+ basic_block bb;
+ int *heads;
+
+ heads = xmalloc (sizeof (int) * last_basic_block);
+ memset (heads, -1, sizeof (int) * last_basic_block);
+ heads[ENTRY_BLOCK_PTR->next_bb->index] = last_basic_block;
+
+ apply_return_prediction (heads);
+
+ FOR_EACH_BB (bb)
+ {
+ block_stmt_iterator bsi = bsi_last (bb);
+
+ for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+ {
+ tree stmt = bsi_stmt (bsi);
+ switch (TREE_CODE (stmt))
+ {
+ case MODIFY_EXPR:
+ if (TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR)
+ {
+ stmt = TREE_OPERAND (stmt, 1);
+ goto call_expr;
+ }
+ break;
+ case CALL_EXPR:
+call_expr:;
+ if (call_expr_flags (stmt) & ECF_NORETURN)
+ predict_paths_leading_to (bb, heads, PRED_NORETURN,
+ NOT_TAKEN);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ free (heads);
+}
+