basic_block * blocks_in_phiopt_order (void) { basic_block x, y; basic_block *order = XNEWVEC (basic_block, n_basic_blocks); unsigned n = n_basic_blocks - NUM_FIXED_BLOCKS; unsigned np, i; sbitmap visited = sbitmap_alloc (last_basic_block); #define MARK_VISITED(BB) (SET_BIT (visited, (BB)->index)) #define VISITED_P(BB) (TEST_BIT (visited, (BB)->index)) sbitmap_zero (visited); MARK_VISITED (ENTRY_BLOCK_PTR); FOR_EACH_BB (x) { if (VISITED_P (x)) continue; /* Walk the predecessors of x as long as they have precisely one predecessor and add them to the list, so that they get stored after x. */ for (y = x, np = 1; single_pred_p (y) && !VISITED_P (single_pred (y)); y = single_pred (y)) np++; for (y = x, i = n - np; single_pred_p (y) && !VISITED_P (single_pred (y)); y = single_pred (y), i++) { order[i] = y; MARK_VISITED (y); } order[i] = y; MARK_VISITED (y); gcc_assert (i == n - 1); n -= np; } sbitmap_free (visited); gcc_assert (n == 0); return order; #undef MARK_VISITED #undef VISITED_P }
static void emit_mfence_after_loop (struct loop *loop) { VEC (edge, heap) *exits = get_loop_exit_edges (loop); edge exit; gimple call; gimple_stmt_iterator bsi; unsigned i; for (i = 0; VEC_iterate (edge, exits, i, exit); i++) { call = gimple_build_call (FENCE_FOLLOWING_MOVNT, 0); if (!single_pred_p (exit->dest) /* If possible, we prefer not to insert the fence on other paths in cfg. */ && !(exit->flags & EDGE_ABNORMAL)) split_loop_exit_edge (exit); bsi = gsi_after_labels (exit->dest); gsi_insert_before (&bsi, call, GSI_NEW_STMT); mark_virtual_ops_for_renaming (call); } VEC_free (edge, heap, exits); update_ssa (TODO_update_ssa_only_virtuals); }
bool potentially_threadable_block (basic_block bb) { gimple_stmt_iterator gsi; /* Special case. We can get blocks that are forwarders, but are not optimized away because they forward from outside a loop to the loop header. We want to thread through them as we can sometimes thread to the loop exit, which is obviously profitable. the interesting case here is when the block has PHIs. */ if (gsi_end_p (gsi_start_nondebug_bb (bb)) && !gsi_end_p (gsi_start_phis (bb))) return true; /* If BB has a single successor or a single predecessor, then there is no threading opportunity. */ if (single_succ_p (bb) || single_pred_p (bb)) return false; /* If BB does not end with a conditional, switch or computed goto, then there is no threading opportunity. */ gsi = gsi_last_bb (bb); if (gsi_end_p (gsi) || ! gsi_stmt (gsi) || (gimple_code (gsi_stmt (gsi)) != GIMPLE_COND && gimple_code (gsi_stmt (gsi)) != GIMPLE_GOTO && gimple_code (gsi_stmt (gsi)) != GIMPLE_SWITCH)) return false; return true; }
static bool check_process_case (tree cs) { tree ldecl; basic_block label_bb, following_bb; edge e; ldecl = CASE_LABEL (cs); label_bb = label_to_block (ldecl); e = find_edge (info.switch_bb, label_bb); gcc_assert (e); if (CASE_LOW (cs) == NULL_TREE) { /* Default branch. */ info.default_prob = e->probability; info.default_count = e->count; } else info.other_count += e->count; if (!label_bb) { info.reason = " Bad case - cs BB label is NULL\n"; return false; } if (!single_pred_p (label_bb)) { if (info.final_bb && info.final_bb != label_bb) { info.reason = " Bad case - a non-final BB has two predecessors\n"; return false; /* sth complex going on in this branch */ } following_bb = label_bb; } else { if (!empty_block_p (label_bb)) { info.reason = " Bad case - a non-final BB not empty\n"; return false; } e = single_succ_edge (label_bb); following_bb = single_succ (label_bb); } if (!info.final_bb) info.final_bb = following_bb; else if (info.final_bb != following_bb) { info.reason = " Bad case - different final BB\n"; return false; /* the only successor is not common for all the branches */ } return true; }
static basic_block find_block_to_duplicate_for_splitting_paths (basic_block latch) { /* We should have simple latches at this point. So the latch should have a single successor. This implies the predecessor of the latch likely has the loop exit. And it's that predecessor we're most interested in. To keep things simple, we're going to require that the latch have a single predecessor too. */ if (single_succ_p (latch) && single_pred_p (latch)) { basic_block bb = get_immediate_dominator (CDI_DOMINATORS, latch); gcc_assert (single_pred_edge (latch)->src == bb); /* If BB has been marked as not to be duplicated, then honor that request. */ if (ignore_bb_p (bb)) return NULL; gimple *last = gsi_stmt (gsi_last_nondebug_bb (bb)); /* The immediate dominator of the latch must end in a conditional. */ if (!last || gimple_code (last) != GIMPLE_COND) return NULL; /* We're hoping that BB is a join point for an IF-THEN-ELSE diamond region. Verify that it is. First, verify that BB has two predecessors (each arm of the IF-THEN-ELSE) and two successors (the latch and exit). */ if (EDGE_COUNT (bb->preds) == 2 && EDGE_COUNT (bb->succs) == 2) { /* Now verify that BB's immediate dominator ends in a conditional as well. */ basic_block bb_idom = get_immediate_dominator (CDI_DOMINATORS, bb); gimple *last = gsi_stmt (gsi_last_nondebug_bb (bb_idom)); if (!last || gimple_code (last) != GIMPLE_COND) return NULL; /* And that BB's immediate dominator's successors are the predecessors of BB. */ if (!find_edge (bb_idom, EDGE_PRED (bb, 0)->src) || !find_edge (bb_idom, EDGE_PRED (bb, 1)->src)) return NULL; /* And that the predecessors of BB each have a single successor. */ if (!single_succ_p (EDGE_PRED (bb, 0)->src) || !single_succ_p (EDGE_PRED (bb, 1)->src)) return NULL; /* So at this point we have a simple diamond for an IF-THEN-ELSE construct starting at BB_IDOM, with a join point at BB. BB pass control outside the loop or to the loop latch. We're going to want to create two duplicates of BB, one for each successor of BB_IDOM. */ return bb; } } return NULL; }
/* Check if the given DEF is available in INSN. This would require full computation of available expressions; we check only restricted conditions: - if DEF is the sole definition of its register, go ahead; - in the same basic block, we check for no definitions killing the definition of DEF_INSN; - if USE's basic block has DEF's basic block as the sole predecessor, we check if the definition is killed after DEF_INSN or before TARGET_INSN insn, in their respective basic blocks. */ static bool use_killed_between (df_ref use, rtx_insn *def_insn, rtx_insn *target_insn) { basic_block def_bb = BLOCK_FOR_INSN (def_insn); basic_block target_bb = BLOCK_FOR_INSN (target_insn); int regno; df_ref def; /* We used to have a def reaching a use that is _before_ the def, with the def not dominating the use even though the use and def are in the same basic block, when a register may be used uninitialized in a loop. This should not happen anymore since we do not use reaching definitions, but still we test for such cases and assume that DEF is not available. */ if (def_bb == target_bb ? DF_INSN_LUID (def_insn) >= DF_INSN_LUID (target_insn) : !dominated_by_p (CDI_DOMINATORS, target_bb, def_bb)) return true; /* Check if the reg in USE has only one definition. We already know that this definition reaches use, or we wouldn't be here. However, this is invalid for hard registers because if they are live at the beginning of the function it does not mean that we have an uninitialized access. */ regno = DF_REF_REGNO (use); def = DF_REG_DEF_CHAIN (regno); if (def && DF_REF_NEXT_REG (def) == NULL && regno >= FIRST_PSEUDO_REGISTER) return false; /* Check locally if we are in the same basic block. */ if (def_bb == target_bb) return local_ref_killed_between_p (use, def_insn, target_insn); /* Finally, if DEF_BB is the sole predecessor of TARGET_BB. */ if (single_pred_p (target_bb) && single_pred (target_bb) == def_bb) { df_ref x; /* See if USE is killed between DEF_INSN and the last insn in the basic block containing DEF_INSN. */ x = df_bb_regno_last_def_find (def_bb, regno); if (x && DF_INSN_LUID (DF_REF_INSN (x)) >= DF_INSN_LUID (def_insn)) return true; /* See if USE is killed between TARGET_INSN and the first insn in the basic block containing TARGET_INSN. */ x = df_bb_regno_first_def_find (target_bb, regno); if (x && DF_INSN_LUID (DF_REF_INSN (x)) < DF_INSN_LUID (target_insn)) return true; return false; } /* Otherwise assume the worst case. */ return true; }
static bool should_duplicate_loop_header_p (basic_block header, struct loop *loop, int *limit) { gimple_stmt_iterator bsi; gimple last; /* Do not copy one block more than once (we do not really want to do loop peeling here). */ if (header->aux) return false; /* Loop header copying usually increases size of the code. This used not to be true, since quite often it is possible to verify that the condition is satisfied in the first iteration and therefore to eliminate it. Jump threading handles these cases now. */ if (optimize_loop_for_size_p (loop)) return false; gcc_assert (EDGE_COUNT (header->succs) > 0); if (single_succ_p (header)) return false; if (flow_bb_inside_loop_p (loop, EDGE_SUCC (header, 0)->dest) && flow_bb_inside_loop_p (loop, EDGE_SUCC (header, 1)->dest)) return false; /* If this is not the original loop header, we want it to have just one predecessor in order to match the && pattern. */ if (header != loop->header && !single_pred_p (header)) return false; last = last_stmt (header); if (gimple_code (last) != GIMPLE_COND) return false; /* Approximately copy the conditions that used to be used in jump.c -- at most 20 insns and no calls. */ for (bsi = gsi_start_bb (header); !gsi_end_p (bsi); gsi_next (&bsi)) { last = gsi_stmt (bsi); if (gimple_code (last) == GIMPLE_LABEL) continue; if (is_gimple_debug (last)) continue; if (is_gimple_call (last)) return false; *limit -= estimate_num_insns (last, &eni_size_weights); if (*limit < 0) return false; } return true; }
static bool tree_ssa_ifcombine_bb (basic_block inner_cond_bb) { basic_block then_bb = NULL, else_bb = NULL; if (!recognize_if_then_else (inner_cond_bb, &then_bb, &else_bb)) return false; /* Recognize && and || of two conditions with a common then/else block which entry edges we can merge. That is: if (a || b) ; and if (a && b) ; This requires a single predecessor of the inner cond_bb. */ if (single_pred_p (inner_cond_bb) && bb_no_side_effects_p (inner_cond_bb)) { basic_block outer_cond_bb = single_pred (inner_cond_bb); if (tree_ssa_ifcombine_bb_1 (inner_cond_bb, outer_cond_bb, then_bb, else_bb, inner_cond_bb)) return true; if (forwarder_block_to (else_bb, then_bb)) { /* Other possibilities for the && form, if else_bb is empty forwarder block to then_bb. Compared to the above simpler forms this can be treated as if then_bb and else_bb were swapped, and the corresponding inner_cond_bb not inverted because of that. For same_phi_args_p we look at equality of arguments between edge from outer_cond_bb and the forwarder block. */ if (tree_ssa_ifcombine_bb_1 (inner_cond_bb, outer_cond_bb, else_bb, then_bb, else_bb)) return true; } else if (forwarder_block_to (then_bb, else_bb)) { /* Other possibilities for the || form, if then_bb is empty forwarder block to else_bb. Compared to the above simpler forms this can be treated as if then_bb and else_bb were swapped, and the corresponding inner_cond_bb not inverted because of that. For same_phi_args_p we look at equality of arguments between edge from outer_cond_bb and the forwarder block. */ if (tree_ssa_ifcombine_bb_1 (inner_cond_bb, outer_cond_bb, else_bb, then_bb, then_bb)) return true; } } return false; }
static unsigned int copyprop_hardreg_forward (void) { struct value_data *all_vd; basic_block bb; sbitmap visited; bool analyze_called = false; all_vd = XNEWVEC (struct value_data, last_basic_block_for_fn (cfun)); visited = sbitmap_alloc (last_basic_block_for_fn (cfun)); bitmap_clear (visited); if (MAY_HAVE_DEBUG_INSNS) debug_insn_changes_pool = create_alloc_pool ("debug insn changes pool", sizeof (struct queued_debug_insn_change), 256); FOR_EACH_BB_FN (bb, cfun) { bitmap_set_bit (visited, bb->index); /* If a block has a single predecessor, that we've already processed, begin with the value data that was live at the end of the predecessor block. */ /* ??? Ought to use more intelligent queuing of blocks. */ if (single_pred_p (bb) && bitmap_bit_p (visited, single_pred (bb)->index) && ! (single_pred_edge (bb)->flags & (EDGE_ABNORMAL_CALL | EDGE_EH))) { all_vd[bb->index] = all_vd[single_pred (bb)->index]; if (all_vd[bb->index].n_debug_insn_changes) { unsigned int regno; for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) { if (all_vd[bb->index].e[regno].debug_insn_changes) { all_vd[bb->index].e[regno].debug_insn_changes = NULL; if (--all_vd[bb->index].n_debug_insn_changes == 0) break; } } } } else init_value_data (all_vd + bb->index); copyprop_hardreg_forward_1 (bb, all_vd + bb->index); }
static bool should_duplicate_loop_header_p (basic_block header, struct loop *loop, int *limit) { block_stmt_iterator bsi; tree last; /* Do not copy one block more than once (we do not really want to do loop peeling here). */ if (header->aux) return false; gcc_assert (EDGE_COUNT (header->succs) > 0); if (single_succ_p (header)) return false; if (flow_bb_inside_loop_p (loop, EDGE_SUCC (header, 0)->dest) && flow_bb_inside_loop_p (loop, EDGE_SUCC (header, 1)->dest)) return false; /* If this is not the original loop header, we want it to have just one predecessor in order to match the && pattern. */ if (header != loop->header && !single_pred_p (header)) return false; last = last_stmt (header); if (TREE_CODE (last) != COND_EXPR) return false; /* Approximately copy the conditions that used to be used in jump.c -- at most 20 insns and no calls. */ for (bsi = bsi_start (header); !bsi_end_p (bsi); bsi_next (&bsi)) { last = bsi_stmt (bsi); if (TREE_CODE (last) == LABEL_EXPR) continue; if (get_call_expr_in (last)) return false; *limit -= estimate_num_insns (last); if (*limit < 0) return false; } return true; }
static bool check_final_bb (void) { gimple_stmt_iterator gsi; info.phi_count = 0; for (gsi = gsi_start_phis (info.final_bb); !gsi_end_p (gsi); gsi_next (&gsi)) { gimple phi = gsi_stmt (gsi); unsigned int i; info.phi_count++; for (i = 0; i < gimple_phi_num_args (phi); i++) { basic_block bb = gimple_phi_arg_edge (phi, i)->src; if (bb == info.switch_bb || (single_pred_p (bb) && single_pred (bb) == info.switch_bb)) { tree reloc, val; val = gimple_phi_arg_def (phi, i); if (!is_gimple_ip_invariant (val)) { info.reason = " Non-invariant value from a case\n"; return false; /* Non-invariant argument. */ } reloc = initializer_constant_valid_p (val, TREE_TYPE (val)); if ((flag_pic && reloc != null_pointer_node) || (!flag_pic && reloc == NULL_TREE)) { if (reloc) info.reason = " Value from a case would need runtime relocations\n"; else info.reason = " Value from a case is not a valid initializer\n"; return false; } } } } return true; }
static void update_profile_after_ifcombine (basic_block inner_cond_bb, basic_block outer_cond_bb) { edge outer_to_inner = find_edge (outer_cond_bb, inner_cond_bb); edge outer2 = (EDGE_SUCC (outer_cond_bb, 0) == outer_to_inner ? EDGE_SUCC (outer_cond_bb, 1) : EDGE_SUCC (outer_cond_bb, 0)); edge inner_taken = EDGE_SUCC (inner_cond_bb, 0); edge inner_not_taken = EDGE_SUCC (inner_cond_bb, 1); if (inner_taken->dest != outer2->dest) std::swap (inner_taken, inner_not_taken); gcc_assert (inner_taken->dest == outer2->dest); /* In the following we assume that inner_cond_bb has single predecessor. */ gcc_assert (single_pred_p (inner_cond_bb)); /* Path outer_cond_bb->(outer2) needs to be merged into path outer_cond_bb->(outer_to_inner)->inner_cond_bb->(inner_taken) and probability of inner_not_taken updated. */ outer_to_inner->count = outer_cond_bb->count; inner_cond_bb->count = outer_cond_bb->count; inner_taken->count += outer2->count; outer2->count = 0; inner_taken->probability = outer2->probability + RDIV (outer_to_inner->probability * inner_taken->probability, REG_BR_PROB_BASE); if (inner_taken->probability > REG_BR_PROB_BASE) inner_taken->probability = REG_BR_PROB_BASE; inner_not_taken->probability = REG_BR_PROB_BASE - inner_taken->probability; outer_to_inner->probability = REG_BR_PROB_BASE; inner_cond_bb->frequency = outer_cond_bb->frequency; outer2->probability = 0; }
bool potentially_threadable_block (basic_block bb) { gimple_stmt_iterator gsi; /* If BB has a single successor or a single predecessor, then there is no threading opportunity. */ if (single_succ_p (bb) || single_pred_p (bb)) return false; /* If BB does not end with a conditional, switch or computed goto, then there is no threading opportunity. */ gsi = gsi_last_bb (bb); if (gsi_end_p (gsi) || ! gsi_stmt (gsi) || (gimple_code (gsi_stmt (gsi)) != GIMPLE_COND && gimple_code (gsi_stmt (gsi)) != GIMPLE_GOTO && gimple_code (gsi_stmt (gsi)) != GIMPLE_SWITCH)) return false; return true; }
bool potentially_threadable_block (basic_block bb) { block_stmt_iterator bsi; /* If BB has a single successor or a single predecessor, then there is no threading opportunity. */ if (single_succ_p (bb) || single_pred_p (bb)) return false; /* If BB does not end with a conditional, switch or computed goto, then there is no threading opportunity. */ bsi = bsi_last (bb); if (bsi_end_p (bsi) || ! bsi_stmt (bsi) || (TREE_CODE (bsi_stmt (bsi)) != COND_EXPR && TREE_CODE (bsi_stmt (bsi)) != GOTO_EXPR && TREE_CODE (bsi_stmt (bsi)) != SWITCH_EXPR)) return false; return true; }
static void set_location_for_edge (edge e) { if (e->goto_locus) { set_curr_insn_source_location (e->goto_locus); set_curr_insn_block (e->goto_block); } else { basic_block bb = e->src; gimple_stmt_iterator gsi; do { for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi)) { gimple stmt = gsi_stmt (gsi); if (is_gimple_debug (stmt)) continue; if (gimple_has_location (stmt) || gimple_block (stmt)) { set_curr_insn_source_location (gimple_location (stmt)); set_curr_insn_block (gimple_block (stmt)); return; } } /* Nothing found in this basic block. Make a half-assed attempt to continue with another block. */ if (single_pred_p (bb)) bb = single_pred (bb); else bb = e->src; } while (bb != e->src); } }
static void emit_case_bit_tests (gimple swtch, tree index_expr, tree minval, tree range) { struct case_bit_test test[MAX_CASE_BIT_TESTS]; unsigned int i, j, k; unsigned int count; basic_block switch_bb = gimple_bb (swtch); basic_block default_bb, new_default_bb, new_bb; edge default_edge; bool update_dom = dom_info_available_p (CDI_DOMINATORS); vec<basic_block> bbs_to_fix_dom = vNULL; tree index_type = TREE_TYPE (index_expr); tree unsigned_index_type = unsigned_type_for (index_type); unsigned int branch_num = gimple_switch_num_labels (swtch); gimple_stmt_iterator gsi; gimple shift_stmt; tree idx, tmp, csui; tree word_type_node = lang_hooks.types.type_for_mode (word_mode, 1); tree word_mode_zero = fold_convert (word_type_node, integer_zero_node); tree word_mode_one = fold_convert (word_type_node, integer_one_node); memset (&test, 0, sizeof (test)); /* Get the edge for the default case. */ tmp = gimple_switch_default_label (swtch); default_bb = label_to_block (CASE_LABEL (tmp)); default_edge = find_edge (switch_bb, default_bb); /* Go through all case labels, and collect the case labels, profile counts, and other information we need to build the branch tests. */ count = 0; for (i = 1; i < branch_num; i++) { unsigned int lo, hi; tree cs = gimple_switch_label (swtch, i); tree label = CASE_LABEL (cs); edge e = find_edge (switch_bb, label_to_block (label)); for (k = 0; k < count; k++) if (e == test[k].target_edge) break; if (k == count) { gcc_checking_assert (count < MAX_CASE_BIT_TESTS); test[k].hi = 0; test[k].lo = 0; test[k].target_edge = e; test[k].label = label; test[k].bits = 1; count++; } else test[k].bits++; lo = tree_to_uhwi (int_const_binop (MINUS_EXPR, CASE_LOW (cs), minval)); if (CASE_HIGH (cs) == NULL_TREE) hi = lo; else hi = tree_to_uhwi (int_const_binop (MINUS_EXPR, CASE_HIGH (cs), minval)); for (j = lo; j <= hi; j++) if (j >= HOST_BITS_PER_WIDE_INT) test[k].hi |= (HOST_WIDE_INT) 1 << (j - HOST_BITS_PER_INT); else test[k].lo |= (HOST_WIDE_INT) 1 << j; } qsort (test, count, sizeof (*test), case_bit_test_cmp); /* We generate two jumps to the default case label. Split the default edge, so that we don't have to do any PHI node updating. */ new_default_bb = split_edge (default_edge); if (update_dom) { bbs_to_fix_dom.create (10); bbs_to_fix_dom.quick_push (switch_bb); bbs_to_fix_dom.quick_push (default_bb); bbs_to_fix_dom.quick_push (new_default_bb); } /* Now build the test-and-branch code. */ gsi = gsi_last_bb (switch_bb); /* idx = (unsigned)x - minval. */ idx = fold_convert (unsigned_index_type, index_expr); idx = fold_build2 (MINUS_EXPR, unsigned_index_type, idx, fold_convert (unsigned_index_type, minval)); idx = force_gimple_operand_gsi (&gsi, idx, /*simple=*/true, NULL_TREE, /*before=*/true, GSI_SAME_STMT); /* if (idx > range) goto default */ range = force_gimple_operand_gsi (&gsi, fold_convert (unsigned_index_type, range), /*simple=*/true, NULL_TREE, /*before=*/true, GSI_SAME_STMT); tmp = fold_build2 (GT_EXPR, boolean_type_node, idx, range); new_bb = hoist_edge_and_branch_if_true (&gsi, tmp, default_edge, update_dom); if (update_dom) bbs_to_fix_dom.quick_push (new_bb); gcc_assert (gimple_bb (swtch) == new_bb); gsi = gsi_last_bb (new_bb); /* Any blocks dominated by the GIMPLE_SWITCH, but that are not successors of NEW_BB, are still immediately dominated by SWITCH_BB. Make it so. */ if (update_dom) { vec<basic_block> dom_bbs; basic_block dom_son; dom_bbs = get_dominated_by (CDI_DOMINATORS, new_bb); FOR_EACH_VEC_ELT (dom_bbs, i, dom_son) { edge e = find_edge (new_bb, dom_son); if (e && single_pred_p (e->dest)) continue; set_immediate_dominator (CDI_DOMINATORS, dom_son, switch_bb); bbs_to_fix_dom.safe_push (dom_son); } dom_bbs.release (); }
static unsigned int tree_ssa_phiopt (void) { basic_block bb; basic_block *bb_order; unsigned n, i; bool cfgchanged = false; /* Search every basic block for COND_EXPR we may be able to optimize. We walk the blocks in order that guarantees that a block with a single predecessor is processed before the predecessor. This ensures that we collapse inner ifs before visiting the outer ones, and also that we do not try to visit a removed block. */ bb_order = blocks_in_phiopt_order (); n = n_basic_blocks - NUM_FIXED_BLOCKS; for (i = 0; i < n; i++) { tree cond_expr; tree phi; basic_block bb1, bb2; edge e1, e2; tree arg0, arg1; bb = bb_order[i]; cond_expr = last_stmt (bb); /* Check to see if the last statement is a COND_EXPR. */ if (!cond_expr || TREE_CODE (cond_expr) != COND_EXPR) continue; e1 = EDGE_SUCC (bb, 0); bb1 = e1->dest; e2 = EDGE_SUCC (bb, 1); bb2 = e2->dest; /* We cannot do the optimization on abnormal edges. */ if ((e1->flags & EDGE_ABNORMAL) != 0 || (e2->flags & EDGE_ABNORMAL) != 0) continue; /* If either bb1's succ or bb2 or bb2's succ is non NULL. */ if (EDGE_COUNT (bb1->succs) == 0 || bb2 == NULL || EDGE_COUNT (bb2->succs) == 0) continue; /* Find the bb which is the fall through to the other. */ if (EDGE_SUCC (bb1, 0)->dest == bb2) ; else if (EDGE_SUCC (bb2, 0)->dest == bb1) { basic_block bb_tmp = bb1; edge e_tmp = e1; bb1 = bb2; bb2 = bb_tmp; e1 = e2; e2 = e_tmp; } else continue; e1 = EDGE_SUCC (bb1, 0); /* Make sure that bb1 is just a fall through. */ if (!single_succ_p (bb1) || (e1->flags & EDGE_FALLTHRU) == 0) continue; /* Also make sure that bb1 only have one predecessor and that it is bb. */ if (!single_pred_p (bb1) || single_pred (bb1) != bb) continue; phi = phi_nodes (bb2); /* Check to make sure that there is only one PHI node. TODO: we could do it with more than one iff the other PHI nodes have the same elements for these two edges. */ if (!phi || PHI_CHAIN (phi) != NULL) continue; arg0 = PHI_ARG_DEF_TREE (phi, e1->dest_idx); arg1 = PHI_ARG_DEF_TREE (phi, e2->dest_idx); /* Something is wrong if we cannot find the arguments in the PHI node. */ gcc_assert (arg0 != NULL && arg1 != NULL); /* Do the replacement of conditional if it can be done. */ if (conditional_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) cfgchanged = true; else if (value_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) cfgchanged = true; else if (abs_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) cfgchanged = true; else if (minmax_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) cfgchanged = true; } free (bb_order); /* If the CFG has changed, we should cleanup the CFG. */ return cfgchanged ? TODO_cleanup_cfg : 0; }
static bool tree_ssa_ifcombine_bb (basic_block inner_cond_bb) { basic_block then_bb = NULL, else_bb = NULL; if (!recognize_if_then_else (inner_cond_bb, &then_bb, &else_bb)) return false; /* Recognize && and || of two conditions with a common then/else block which entry edges we can merge. That is: if (a || b) ; and if (a && b) ; This requires a single predecessor of the inner cond_bb. */ if (single_pred_p (inner_cond_bb)) { basic_block outer_cond_bb = single_pred (inner_cond_bb); /* The && form is characterized by a common else_bb with the two edges leading to it mergable. The latter is guaranteed by matching PHI arguments in the else_bb and the inner cond_bb having no side-effects. */ if (recognize_if_then_else (outer_cond_bb, &inner_cond_bb, &else_bb) && same_phi_args_p (outer_cond_bb, inner_cond_bb, else_bb) && bb_no_side_effects_p (inner_cond_bb)) { /* We have <outer_cond_bb> if (q) goto inner_cond_bb; else goto else_bb; <inner_cond_bb> if (p) goto ...; else goto else_bb; ... <else_bb> ... */ return ifcombine_ifandif (inner_cond_bb, outer_cond_bb); } /* The || form is characterized by a common then_bb with the two edges leading to it mergable. The latter is guaranteed by matching PHI arguments in the then_bb and the inner cond_bb having no side-effects. */ if (recognize_if_then_else (outer_cond_bb, &then_bb, &inner_cond_bb) && same_phi_args_p (outer_cond_bb, inner_cond_bb, then_bb) && bb_no_side_effects_p (inner_cond_bb)) { /* We have <outer_cond_bb> if (q) goto then_bb; else goto inner_cond_bb; <inner_cond_bb> if (q) goto then_bb; else goto ...; <then_bb> ... */ return ifcombine_iforif (inner_cond_bb, outer_cond_bb); } } return false; }
static bool gimple_find_edge_insert_loc (edge e, gimple_stmt_iterator *gsi, basic_block *new_bb) { basic_block dest, src; gimple *tmp; dest = e->dest; /* If the destination has one predecessor which has no PHI nodes, insert there. Except for the exit block. The requirement for no PHI nodes could be relaxed. Basically we would have to examine the PHIs to prove that none of them used the value set by the statement we want to insert on E. That hardly seems worth the effort. */ restart: if (single_pred_p (dest) && gimple_seq_empty_p (phi_nodes (dest)) && dest != EXIT_BLOCK_PTR_FOR_FN (cfun)) { *gsi = gsi_start_bb (dest); if (gsi_end_p (*gsi)) return true; /* Make sure we insert after any leading labels. */ tmp = gsi_stmt (*gsi); while (gimple_code (tmp) == GIMPLE_LABEL) { gsi_next (gsi); if (gsi_end_p (*gsi)) break; tmp = gsi_stmt (*gsi); } if (gsi_end_p (*gsi)) { *gsi = gsi_last_bb (dest); return true; } else return false; } /* If the source has one successor, the edge is not abnormal and the last statement does not end a basic block, insert there. Except for the entry block. */ src = e->src; if ((e->flags & EDGE_ABNORMAL) == 0 && single_succ_p (src) && src != ENTRY_BLOCK_PTR_FOR_FN (cfun)) { *gsi = gsi_last_bb (src); if (gsi_end_p (*gsi)) return true; tmp = gsi_stmt (*gsi); if (!stmt_ends_bb_p (tmp)) return true; switch (gimple_code (tmp)) { case GIMPLE_RETURN: case GIMPLE_RESX: return false; default: break; } } /* Otherwise, create a new basic block, and split this edge. */ dest = split_edge (e); if (new_bb) *new_bb = dest; e = single_pred_edge (dest); goto restart; }
void find_comparison_dom_walker::before_dom_children (basic_block bb) { struct comparison *last_cmp; rtx insn, next, last_clobber; bool last_cmp_valid; bool need_purge = false; bitmap killed; killed = BITMAP_ALLOC (NULL); /* The last comparison that was made. Will be reset to NULL once the flags are clobbered. */ last_cmp = NULL; /* True iff the last comparison has not been clobbered, nor have its inputs. Used to eliminate duplicate compares. */ last_cmp_valid = false; /* The last insn that clobbered the flags, if that insn is of a form that may be valid for eliminating a following compare. To be reset to NULL once the flags are set otherwise. */ last_clobber = NULL; /* Propagate the last live comparison throughout the extended basic block. */ if (single_pred_p (bb)) { last_cmp = (struct comparison *) single_pred (bb)->aux; if (last_cmp) last_cmp_valid = last_cmp->inputs_valid; } for (insn = BB_HEAD (bb); insn; insn = next) { rtx src; next = (insn == BB_END (bb) ? NULL_RTX : NEXT_INSN (insn)); if (!NONDEBUG_INSN_P (insn)) continue; /* Compute the set of registers modified by this instruction. */ bitmap_clear (killed); df_simulate_find_defs (insn, killed); src = conforming_compare (insn); if (src) { enum machine_mode src_mode = GET_MODE (src); rtx eh_note = NULL; if (flag_non_call_exceptions) eh_note = find_reg_note (insn, REG_EH_REGION, NULL); if (!last_cmp_valid) goto dont_delete; /* Take care that it's in the same EH region. */ if (flag_non_call_exceptions && !rtx_equal_p (eh_note, last_cmp->eh_note)) goto dont_delete; /* Make sure the compare is redundant with the previous. */ if (!rtx_equal_p (last_cmp->in_a, XEXP (src, 0)) || !rtx_equal_p (last_cmp->in_b, XEXP (src, 1))) goto dont_delete; /* New mode must be compatible with the previous compare mode. */ { enum machine_mode new_mode = targetm.cc_modes_compatible (last_cmp->orig_mode, src_mode); if (new_mode == VOIDmode) goto dont_delete; if (new_mode != last_cmp->orig_mode) { rtx x, flags = gen_rtx_REG (src_mode, targetm.flags_regnum); /* Generate new comparison for substitution. */ x = gen_rtx_COMPARE (new_mode, XEXP (src, 0), XEXP (src, 1)); x = gen_rtx_SET (VOIDmode, flags, x); if (!validate_change (last_cmp->insn, &PATTERN (last_cmp->insn), x, false)) goto dont_delete; last_cmp->orig_mode = new_mode; } } /* All tests and substitutions succeeded! */ if (eh_note) need_purge = true; delete_insn (insn); continue; dont_delete: last_cmp = XCNEW (struct comparison); last_cmp->insn = insn; last_cmp->prev_clobber = last_clobber; last_cmp->in_a = XEXP (src, 0); last_cmp->in_b = XEXP (src, 1); last_cmp->eh_note = eh_note; last_cmp->orig_mode = src_mode; all_compares.safe_push (last_cmp); /* It's unusual, but be prepared for comparison patterns that also clobber an input, or perhaps a scratch. */ last_clobber = NULL; last_cmp_valid = true; } /* Notice if this instruction kills the flags register. */ else if (bitmap_bit_p (killed, targetm.flags_regnum)) { /* See if this insn could be the "clobber" that eliminates a future comparison. */ last_clobber = (arithmetic_flags_clobber_p (insn) ? insn : NULL); /* In either case, the previous compare is no longer valid. */ last_cmp = NULL; last_cmp_valid = false; continue; } /* Notice if this instruction uses the flags register. */ else if (last_cmp) find_flags_uses_in_insn (last_cmp, insn); /* Notice if any of the inputs to the comparison have changed. */ if (last_cmp_valid && (bitmap_bit_p (killed, REGNO (last_cmp->in_a)) || (REG_P (last_cmp->in_b) && bitmap_bit_p (killed, REGNO (last_cmp->in_b))))) last_cmp_valid = false; }
static unsigned int copyprop_hardreg_forward (void) { struct value_data *all_vd; basic_block bb; sbitmap visited; bool analyze_called = false; all_vd = XNEWVEC (struct value_data, last_basic_block); visited = sbitmap_alloc (last_basic_block); sbitmap_zero (visited); if (MAY_HAVE_DEBUG_INSNS) debug_insn_changes_pool = create_alloc_pool ("debug insn changes pool", sizeof (struct queued_debug_insn_change), 256); FOR_EACH_BB (bb) { SET_BIT (visited, bb->index); /* If a block has a single predecessor, that we've already processed, begin with the value data that was live at the end of the predecessor block. */ /* ??? Ought to use more intelligent queuing of blocks. */ if (single_pred_p (bb) && TEST_BIT (visited, single_pred (bb)->index) && ! (single_pred_edge (bb)->flags & (EDGE_ABNORMAL_CALL | EDGE_EH))) { all_vd[bb->index] = all_vd[single_pred (bb)->index]; if (all_vd[bb->index].n_debug_insn_changes) { unsigned int regno; for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) { if (all_vd[bb->index].e[regno].debug_insn_changes) { all_vd[bb->index].e[regno].debug_insn_changes = NULL; if (--all_vd[bb->index].n_debug_insn_changes == 0) break; } } } } else init_value_data (all_vd + bb->index); copyprop_hardreg_forward_1 (bb, all_vd + bb->index); } if (MAY_HAVE_DEBUG_INSNS) { FOR_EACH_BB (bb) if (TEST_BIT (visited, bb->index) && all_vd[bb->index].n_debug_insn_changes) { unsigned int regno; bitmap live; if (!analyze_called) { df_analyze (); analyze_called = true; } live = df_get_live_out (bb); for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) if (all_vd[bb->index].e[regno].debug_insn_changes) { if (REGNO_REG_SET_P (live, regno)) apply_debug_insn_changes (all_vd + bb->index, regno); if (all_vd[bb->index].n_debug_insn_changes == 0) break; } } free_alloc_pool (debug_insn_changes_pool); } sbitmap_free (visited); free (all_vd); return 0; }
/* The core routine of conditional store replacement and normal phi optimizations. Both share much of the infrastructure in how to match applicable basic block patterns. DO_STORE_ELIM is true when we want to do conditional store replacement, false otherwise. DO_HOIST_LOADS is true when we want to hoist adjacent loads out of diamond control flow patterns, false otherwise. */ static unsigned int tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads) { basic_block bb; basic_block *bb_order; unsigned n, i; bool cfgchanged = false; hash_set<tree> *nontrap = 0; if (do_store_elim) /* Calculate the set of non-trapping memory accesses. */ nontrap = get_non_trapping (); /* Search every basic block for COND_EXPR we may be able to optimize. We walk the blocks in order that guarantees that a block with a single predecessor is processed before the predecessor. This ensures that we collapse inner ifs before visiting the outer ones, and also that we do not try to visit a removed block. */ bb_order = single_pred_before_succ_order (); n = n_basic_blocks_for_fn (cfun) - NUM_FIXED_BLOCKS; for (i = 0; i < n; i++) { gimple cond_stmt; gphi *phi; basic_block bb1, bb2; edge e1, e2; tree arg0, arg1; bb = bb_order[i]; cond_stmt = last_stmt (bb); /* Check to see if the last statement is a GIMPLE_COND. */ if (!cond_stmt || gimple_code (cond_stmt) != GIMPLE_COND) continue; e1 = EDGE_SUCC (bb, 0); bb1 = e1->dest; e2 = EDGE_SUCC (bb, 1); bb2 = e2->dest; /* We cannot do the optimization on abnormal edges. */ if ((e1->flags & EDGE_ABNORMAL) != 0 || (e2->flags & EDGE_ABNORMAL) != 0) continue; /* If either bb1's succ or bb2 or bb2's succ is non NULL. */ if (EDGE_COUNT (bb1->succs) == 0 || bb2 == NULL || EDGE_COUNT (bb2->succs) == 0) continue; /* Find the bb which is the fall through to the other. */ if (EDGE_SUCC (bb1, 0)->dest == bb2) ; else if (EDGE_SUCC (bb2, 0)->dest == bb1) { std::swap (bb1, bb2); std::swap (e1, e2); } else if (do_store_elim && EDGE_SUCC (bb1, 0)->dest == EDGE_SUCC (bb2, 0)->dest) { basic_block bb3 = EDGE_SUCC (bb1, 0)->dest; if (!single_succ_p (bb1) || (EDGE_SUCC (bb1, 0)->flags & EDGE_FALLTHRU) == 0 || !single_succ_p (bb2) || (EDGE_SUCC (bb2, 0)->flags & EDGE_FALLTHRU) == 0 || EDGE_COUNT (bb3->preds) != 2) continue; if (cond_if_else_store_replacement (bb1, bb2, bb3)) cfgchanged = true; continue; } else if (do_hoist_loads && EDGE_SUCC (bb1, 0)->dest == EDGE_SUCC (bb2, 0)->dest) { basic_block bb3 = EDGE_SUCC (bb1, 0)->dest; if (!FLOAT_TYPE_P (TREE_TYPE (gimple_cond_lhs (cond_stmt))) && single_succ_p (bb1) && single_succ_p (bb2) && single_pred_p (bb1) && single_pred_p (bb2) && EDGE_COUNT (bb->succs) == 2 && EDGE_COUNT (bb3->preds) == 2 /* If one edge or the other is dominant, a conditional move is likely to perform worse than the well-predicted branch. */ && !predictable_edge_p (EDGE_SUCC (bb, 0)) && !predictable_edge_p (EDGE_SUCC (bb, 1))) hoist_adjacent_loads (bb, bb1, bb2, bb3); continue; } else continue; e1 = EDGE_SUCC (bb1, 0); /* Make sure that bb1 is just a fall through. */ if (!single_succ_p (bb1) || (e1->flags & EDGE_FALLTHRU) == 0) continue; /* Also make sure that bb1 only have one predecessor and that it is bb. */ if (!single_pred_p (bb1) || single_pred (bb1) != bb) continue; if (do_store_elim) { /* bb1 is the middle block, bb2 the join block, bb the split block, e1 the fallthrough edge from bb1 to bb2. We can't do the optimization if the join block has more than two predecessors. */ if (EDGE_COUNT (bb2->preds) > 2) continue; if (cond_store_replacement (bb1, bb2, e1, e2, nontrap)) cfgchanged = true; } else { gimple_seq phis = phi_nodes (bb2); gimple_stmt_iterator gsi; bool candorest = true; /* Value replacement can work with more than one PHI so try that first. */ for (gsi = gsi_start (phis); !gsi_end_p (gsi); gsi_next (&gsi)) { phi = as_a <gphi *> (gsi_stmt (gsi)); arg0 = gimple_phi_arg_def (phi, e1->dest_idx); arg1 = gimple_phi_arg_def (phi, e2->dest_idx); if (value_replacement (bb, bb1, e1, e2, phi, arg0, arg1) == 2) { candorest = false; cfgchanged = true; break; } } if (!candorest) continue; phi = single_non_singleton_phi_for_edges (phis, e1, e2); if (!phi) continue; arg0 = gimple_phi_arg_def (phi, e1->dest_idx); arg1 = gimple_phi_arg_def (phi, e2->dest_idx); /* Something is wrong if we cannot find the arguments in the PHI node. */ gcc_assert (arg0 != NULL && arg1 != NULL); if (factor_out_conditional_conversion (e1, e2, phi, arg0, arg1)) { /* factor_out_conditional_conversion may create a new PHI in BB2 and eliminate an existing PHI in BB2. Recompute values that may be affected by that change. */ phis = phi_nodes (bb2); phi = single_non_singleton_phi_for_edges (phis, e1, e2); gcc_assert (phi); arg0 = gimple_phi_arg_def (phi, e1->dest_idx); arg1 = gimple_phi_arg_def (phi, e2->dest_idx); gcc_assert (arg0 != NULL && arg1 != NULL); } /* Do the replacement of conditional if it can be done. */ if (conditional_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) cfgchanged = true; else if (abs_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) cfgchanged = true; else if (minmax_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) cfgchanged = true; } } free (bb_order); if (do_store_elim) delete nontrap; /* If the CFG has changed, we should cleanup the CFG. */ if (cfgchanged && do_store_elim) { /* In cond-store replacement we have added some loads on edges and new VOPS (as we moved the store, and created a load). */ gsi_commit_edge_inserts (); return TODO_cleanup_cfg | TODO_update_ssa_only_virtuals; } else if (cfgchanged) return TODO_cleanup_cfg; return 0; }
static unsigned int copy_loop_headers (void) { struct loops *loops; unsigned i; struct loop *loop; basic_block header; edge exit, entry; basic_block *bbs, *copied_bbs; unsigned n_bbs; unsigned bbs_size; loops = loop_optimizer_init (LOOPS_HAVE_PREHEADERS | LOOPS_HAVE_SIMPLE_LATCHES); if (!loops) return 0; #ifdef ENABLE_CHECKING verify_loop_structure (loops); #endif bbs = XNEWVEC (basic_block, n_basic_blocks); copied_bbs = XNEWVEC (basic_block, n_basic_blocks); bbs_size = n_basic_blocks; for (i = 1; i < loops->num; i++) { /* Copy at most 20 insns. */ int limit = 20; loop = loops->parray[i]; if (!loop) continue; header = loop->header; /* If the loop is already a do-while style one (either because it was written as such, or because jump threading transformed it into one), we might be in fact peeling the first iteration of the loop. This in general is not a good idea. */ if (do_while_loop_p (loop)) continue; /* Iterate the header copying up to limit; this takes care of the cases like while (a && b) {...}, where we want to have both of the conditions copied. TODO -- handle while (a || b) - like cases, by not requiring the header to have just a single successor and copying up to postdominator. */ exit = NULL; n_bbs = 0; while (should_duplicate_loop_header_p (header, loop, &limit)) { /* Find a successor of header that is inside a loop; i.e. the new header after the condition is copied. */ if (flow_bb_inside_loop_p (loop, EDGE_SUCC (header, 0)->dest)) exit = EDGE_SUCC (header, 0); else exit = EDGE_SUCC (header, 1); bbs[n_bbs++] = header; gcc_assert (bbs_size > n_bbs); header = exit->dest; } if (!exit) continue; if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "Duplicating header of the loop %d up to edge %d->%d.\n", loop->num, exit->src->index, exit->dest->index); /* Ensure that the header will have just the latch as a predecessor inside the loop. */ if (!single_pred_p (exit->dest)) exit = single_pred_edge (loop_split_edge_with (exit, NULL)); entry = loop_preheader_edge (loop); if (!tree_duplicate_sese_region (entry, exit, bbs, n_bbs, copied_bbs)) { fprintf (dump_file, "Duplication failed.\n"); continue; } /* If the loop has the form "for (i = j; i < j + 10; i++)" then this copying can introduce a case where we rely on undefined signed overflow to eliminate the preheader condition, because we assume that "j < j + 10" is true. We don't want to warn about that case for -Wstrict-overflow, because in general we don't warn about overflow involving loops. Prevent the warning by setting TREE_NO_WARNING. */ if (warn_strict_overflow > 0) { unsigned int i; for (i = 0; i < n_bbs; ++i) { tree last; last = last_stmt (copied_bbs[i]); if (TREE_CODE (last) == COND_EXPR) TREE_NO_WARNING (last) = 1; } } /* Ensure that the latch and the preheader is simple (we know that they are not now, since there was the loop exit condition. */ loop_split_edge_with (loop_preheader_edge (loop), NULL); loop_split_edge_with (loop_latch_edge (loop), NULL); } free (bbs); free (copied_bbs); loop_optimizer_finalize (loops); return 0; }
static void emit_case_bit_tests (gswitch *swtch, tree index_expr, tree minval, tree range, tree maxval) { struct case_bit_test test[MAX_CASE_BIT_TESTS]; unsigned int i, j, k; unsigned int count; basic_block switch_bb = gimple_bb (swtch); basic_block default_bb, new_default_bb, new_bb; edge default_edge; bool update_dom = dom_info_available_p (CDI_DOMINATORS); vec<basic_block> bbs_to_fix_dom = vNULL; tree index_type = TREE_TYPE (index_expr); tree unsigned_index_type = unsigned_type_for (index_type); unsigned int branch_num = gimple_switch_num_labels (swtch); gimple_stmt_iterator gsi; gassign *shift_stmt; tree idx, tmp, csui; tree word_type_node = lang_hooks.types.type_for_mode (word_mode, 1); tree word_mode_zero = fold_convert (word_type_node, integer_zero_node); tree word_mode_one = fold_convert (word_type_node, integer_one_node); int prec = TYPE_PRECISION (word_type_node); wide_int wone = wi::one (prec); memset (&test, 0, sizeof (test)); /* Get the edge for the default case. */ tmp = gimple_switch_default_label (swtch); default_bb = label_to_block (CASE_LABEL (tmp)); default_edge = find_edge (switch_bb, default_bb); /* Go through all case labels, and collect the case labels, profile counts, and other information we need to build the branch tests. */ count = 0; for (i = 1; i < branch_num; i++) { unsigned int lo, hi; tree cs = gimple_switch_label (swtch, i); tree label = CASE_LABEL (cs); edge e = find_edge (switch_bb, label_to_block (label)); for (k = 0; k < count; k++) if (e == test[k].target_edge) break; if (k == count) { gcc_checking_assert (count < MAX_CASE_BIT_TESTS); test[k].mask = wi::zero (prec); test[k].target_edge = e; test[k].label = label; test[k].bits = 1; count++; } else test[k].bits++; lo = tree_to_uhwi (int_const_binop (MINUS_EXPR, CASE_LOW (cs), minval)); if (CASE_HIGH (cs) == NULL_TREE) hi = lo; else hi = tree_to_uhwi (int_const_binop (MINUS_EXPR, CASE_HIGH (cs), minval)); for (j = lo; j <= hi; j++) test[k].mask |= wi::lshift (wone, j); } qsort (test, count, sizeof (*test), case_bit_test_cmp); /* If all values are in the 0 .. BITS_PER_WORD-1 range, we can get rid of the minval subtractions, but it might make the mask constants more expensive. So, compare the costs. */ if (compare_tree_int (minval, 0) > 0 && compare_tree_int (maxval, GET_MODE_BITSIZE (word_mode)) < 0) { int cost_diff; HOST_WIDE_INT m = tree_to_uhwi (minval); rtx reg = gen_raw_REG (word_mode, 10000); bool speed_p = optimize_bb_for_speed_p (gimple_bb (swtch)); cost_diff = set_rtx_cost (gen_rtx_PLUS (word_mode, reg, GEN_INT (-m)), speed_p); for (i = 0; i < count; i++) { rtx r = immed_wide_int_const (test[i].mask, word_mode); cost_diff += set_src_cost (gen_rtx_AND (word_mode, reg, r), word_mode, speed_p); r = immed_wide_int_const (wi::lshift (test[i].mask, m), word_mode); cost_diff -= set_src_cost (gen_rtx_AND (word_mode, reg, r), word_mode, speed_p); } if (cost_diff > 0) { for (i = 0; i < count; i++) test[i].mask = wi::lshift (test[i].mask, m); minval = build_zero_cst (TREE_TYPE (minval)); range = maxval; } } /* We generate two jumps to the default case label. Split the default edge, so that we don't have to do any PHI node updating. */ new_default_bb = split_edge (default_edge); if (update_dom) { bbs_to_fix_dom.create (10); bbs_to_fix_dom.quick_push (switch_bb); bbs_to_fix_dom.quick_push (default_bb); bbs_to_fix_dom.quick_push (new_default_bb); } /* Now build the test-and-branch code. */ gsi = gsi_last_bb (switch_bb); /* idx = (unsigned)x - minval. */ idx = fold_convert (unsigned_index_type, index_expr); idx = fold_build2 (MINUS_EXPR, unsigned_index_type, idx, fold_convert (unsigned_index_type, minval)); idx = force_gimple_operand_gsi (&gsi, idx, /*simple=*/true, NULL_TREE, /*before=*/true, GSI_SAME_STMT); /* if (idx > range) goto default */ range = force_gimple_operand_gsi (&gsi, fold_convert (unsigned_index_type, range), /*simple=*/true, NULL_TREE, /*before=*/true, GSI_SAME_STMT); tmp = fold_build2 (GT_EXPR, boolean_type_node, idx, range); new_bb = hoist_edge_and_branch_if_true (&gsi, tmp, default_edge, update_dom); if (update_dom) bbs_to_fix_dom.quick_push (new_bb); gcc_assert (gimple_bb (swtch) == new_bb); gsi = gsi_last_bb (new_bb); /* Any blocks dominated by the GIMPLE_SWITCH, but that are not successors of NEW_BB, are still immediately dominated by SWITCH_BB. Make it so. */ if (update_dom) { vec<basic_block> dom_bbs; basic_block dom_son; dom_bbs = get_dominated_by (CDI_DOMINATORS, new_bb); FOR_EACH_VEC_ELT (dom_bbs, i, dom_son) { edge e = find_edge (new_bb, dom_son); if (e && single_pred_p (e->dest)) continue; set_immediate_dominator (CDI_DOMINATORS, dom_son, switch_bb); bbs_to_fix_dom.safe_push (dom_son); } dom_bbs.release (); }
static bool check_process_case (tree cs, struct switch_conv_info *info) { tree ldecl; basic_block label_bb, following_bb; edge e; ldecl = CASE_LABEL (cs); label_bb = label_to_block (ldecl); e = find_edge (info->switch_bb, label_bb); gcc_assert (e); if (CASE_LOW (cs) == NULL_TREE) { /* Default branch. */ info->default_prob = e->probability; info->default_count = e->count; } else { int i; info->other_count += e->count; for (i = 0; i < 2; i++) if (info->bit_test_bb[i] == label_bb) break; else if (info->bit_test_bb[i] == NULL) { info->bit_test_bb[i] = label_bb; info->bit_test_uniq++; break; } if (i == 2) info->bit_test_uniq = 3; if (CASE_HIGH (cs) != NULL_TREE && ! tree_int_cst_equal (CASE_LOW (cs), CASE_HIGH (cs))) info->bit_test_count += 2; else info->bit_test_count++; } if (!label_bb) { info->reason = "bad case - cs BB label is NULL"; return false; } if (!single_pred_p (label_bb)) { if (info->final_bb && info->final_bb != label_bb) { info->reason = "bad case - a non-final BB has two predecessors"; return false; /* sth complex going on in this branch */ } following_bb = label_bb; } else { if (!empty_block_p (label_bb)) { info->reason = "bad case - a non-final BB not empty"; return false; } e = single_succ_edge (label_bb); following_bb = single_succ (label_bb); } if (!info->final_bb) info->final_bb = following_bb; else if (info->final_bb != following_bb) { info->reason = "bad case - different final BB"; return false; /* the only successor is not common for all the branches */ } return true; }
/* The core routine of conditional store replacement and normal phi optimizations. Both share much of the infrastructure in how to match applicable basic block patterns. DO_STORE_ELIM is true when we want to do conditional store replacement, false otherwise. */ static unsigned int tree_ssa_phiopt_worker (bool do_store_elim) { basic_block bb; basic_block *bb_order; unsigned n, i; bool cfgchanged = false; struct pointer_set_t *nontrap = 0; if (do_store_elim) { condstoretemp = NULL_TREE; /* Calculate the set of non-trapping memory accesses. */ nontrap = get_non_trapping (); } /* Search every basic block for COND_EXPR we may be able to optimize. We walk the blocks in order that guarantees that a block with a single predecessor is processed before the predecessor. This ensures that we collapse inner ifs before visiting the outer ones, and also that we do not try to visit a removed block. */ bb_order = blocks_in_phiopt_order (); n = n_basic_blocks - NUM_FIXED_BLOCKS; for (i = 0; i < n; i++) { gimple cond_stmt, phi; basic_block bb1, bb2; edge e1, e2; tree arg0, arg1; bb = bb_order[i]; cond_stmt = last_stmt (bb); /* Check to see if the last statement is a GIMPLE_COND. */ if (!cond_stmt || gimple_code (cond_stmt) != GIMPLE_COND) continue; e1 = EDGE_SUCC (bb, 0); bb1 = e1->dest; e2 = EDGE_SUCC (bb, 1); bb2 = e2->dest; /* We cannot do the optimization on abnormal edges. */ if ((e1->flags & EDGE_ABNORMAL) != 0 || (e2->flags & EDGE_ABNORMAL) != 0) continue; /* If either bb1's succ or bb2 or bb2's succ is non NULL. */ if (EDGE_COUNT (bb1->succs) == 0 || bb2 == NULL || EDGE_COUNT (bb2->succs) == 0) continue; /* Find the bb which is the fall through to the other. */ if (EDGE_SUCC (bb1, 0)->dest == bb2) ; else if (EDGE_SUCC (bb2, 0)->dest == bb1) { basic_block bb_tmp = bb1; edge e_tmp = e1; bb1 = bb2; bb2 = bb_tmp; e1 = e2; e2 = e_tmp; } else continue; e1 = EDGE_SUCC (bb1, 0); /* Make sure that bb1 is just a fall through. */ if (!single_succ_p (bb1) || (e1->flags & EDGE_FALLTHRU) == 0) continue; /* Also make sure that bb1 only have one predecessor and that it is bb. */ if (!single_pred_p (bb1) || single_pred (bb1) != bb) continue; if (do_store_elim) { /* bb1 is the middle block, bb2 the join block, bb the split block, e1 the fallthrough edge from bb1 to bb2. We can't do the optimization if the join block has more than two predecessors. */ if (EDGE_COUNT (bb2->preds) > 2) continue; if (cond_store_replacement (bb1, bb2, e1, e2, nontrap)) cfgchanged = true; } else { gimple_seq phis = phi_nodes (bb2); /* Check to make sure that there is only one PHI node. TODO: we could do it with more than one iff the other PHI nodes have the same elements for these two edges. */ if (! gimple_seq_singleton_p (phis)) continue; phi = gsi_stmt (gsi_start (phis)); arg0 = gimple_phi_arg_def (phi, e1->dest_idx); arg1 = gimple_phi_arg_def (phi, e2->dest_idx); /* Something is wrong if we cannot find the arguments in the PHI node. */ gcc_assert (arg0 != NULL && arg1 != NULL); /* Do the replacement of conditional if it can be done. */ if (conditional_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) cfgchanged = true; else if (value_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) cfgchanged = true; else if (abs_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) cfgchanged = true; else if (minmax_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) cfgchanged = true; } } free (bb_order); if (do_store_elim) pointer_set_destroy (nontrap); /* If the CFG has changed, we should cleanup the CFG. */ if (cfgchanged && do_store_elim) { /* In cond-store replacement we have added some loads on edges and new VOPS (as we moved the store, and created a load). */ gsi_commit_edge_inserts (); return TODO_cleanup_cfg | TODO_update_ssa_only_virtuals; } else if (cfgchanged) return TODO_cleanup_cfg; return 0; }
void find_comparison_dom_walker::before_dom_children (basic_block bb) { struct comparison *last_cmp; rtx_insn *insn, *next, *last_clobber; bool last_cmp_valid; bool need_purge = false; bitmap killed; killed = BITMAP_ALLOC (NULL); /* The last comparison that was made. Will be reset to NULL once the flags are clobbered. */ last_cmp = NULL; /* True iff the last comparison has not been clobbered, nor have its inputs. Used to eliminate duplicate compares. */ last_cmp_valid = false; /* The last insn that clobbered the flags, if that insn is of a form that may be valid for eliminating a following compare. To be reset to NULL once the flags are set otherwise. */ last_clobber = NULL; /* Propagate the last live comparison throughout the extended basic block. */ if (single_pred_p (bb)) { last_cmp = (struct comparison *) single_pred (bb)->aux; if (last_cmp) last_cmp_valid = last_cmp->inputs_valid; } for (insn = BB_HEAD (bb); insn; insn = next) { rtx src; next = (insn == BB_END (bb) ? NULL : NEXT_INSN (insn)); if (!NONDEBUG_INSN_P (insn)) continue; /* Compute the set of registers modified by this instruction. */ bitmap_clear (killed); df_simulate_find_defs (insn, killed); src = conforming_compare (insn); if (src) { rtx eh_note = NULL; if (cfun->can_throw_non_call_exceptions) eh_note = find_reg_note (insn, REG_EH_REGION, NULL); if (last_cmp_valid && can_eliminate_compare (src, eh_note, last_cmp)) { if (eh_note) need_purge = true; delete_insn (insn); continue; } last_cmp = XCNEW (struct comparison); last_cmp->insn = insn; last_cmp->prev_clobber = last_clobber; last_cmp->in_a = XEXP (src, 0); last_cmp->in_b = XEXP (src, 1); last_cmp->eh_note = eh_note; last_cmp->orig_mode = GET_MODE (src); all_compares.safe_push (last_cmp); /* It's unusual, but be prepared for comparison patterns that also clobber an input, or perhaps a scratch. */ last_clobber = NULL; last_cmp_valid = true; } /* Notice if this instruction kills the flags register. */ else if (bitmap_bit_p (killed, targetm.flags_regnum)) { /* See if this insn could be the "clobber" that eliminates a future comparison. */ last_clobber = (arithmetic_flags_clobber_p (insn) ? insn : NULL); /* In either case, the previous compare is no longer valid. */ last_cmp = NULL; last_cmp_valid = false; } /* Notice if this instruction uses the flags register. */ else if (last_cmp) find_flags_uses_in_insn (last_cmp, insn); /* Notice if any of the inputs to the comparison have changed. */ if (last_cmp_valid && (bitmap_bit_p (killed, REGNO (last_cmp->in_a)) || (REG_P (last_cmp->in_b) && bitmap_bit_p (killed, REGNO (last_cmp->in_b))))) last_cmp_valid = false; }
static bool should_duplicate_loop_header_p (basic_block header, struct loop *loop, int *limit) { gimple_stmt_iterator bsi; gimple *last; gcc_assert (!header->aux); /* Loop header copying usually increases size of the code. This used not to be true, since quite often it is possible to verify that the condition is satisfied in the first iteration and therefore to eliminate it. Jump threading handles these cases now. */ if (optimize_loop_for_size_p (loop)) { if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " Not duplicating bb %i: optimizing for size.\n", header->index); return false; } gcc_assert (EDGE_COUNT (header->succs) > 0); if (single_succ_p (header)) { if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " Not duplicating bb %i: it is single succ.\n", header->index); return false; } if (flow_bb_inside_loop_p (loop, EDGE_SUCC (header, 0)->dest) && flow_bb_inside_loop_p (loop, EDGE_SUCC (header, 1)->dest)) { if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " Not duplicating bb %i: both sucessors are in loop.\n", loop->num); return false; } /* If this is not the original loop header, we want it to have just one predecessor in order to match the && pattern. */ if (header != loop->header && !single_pred_p (header)) { if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " Not duplicating bb %i: it has mutiple predecestors.\n", header->index); return false; } last = last_stmt (header); if (gimple_code (last) != GIMPLE_COND) { if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " Not duplicating bb %i: it does not end by conditional.\n", header->index); return false; } /* Count number of instructions and punt on calls. */ for (bsi = gsi_start_bb (header); !gsi_end_p (bsi); gsi_next (&bsi)) { last = gsi_stmt (bsi); if (gimple_code (last) == GIMPLE_LABEL) continue; if (is_gimple_debug (last)) continue; if (gimple_code (last) == GIMPLE_CALL && !gimple_inexpensive_call_p (as_a <gcall *> (last))) { if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " Not duplicating bb %i: it contains call.\n", header->index); return false; } *limit -= estimate_num_insns (last, &eni_size_weights); if (*limit < 0) { if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " Not duplicating bb %i contains too many insns.\n", header->index); return false; } } if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " Will duplicate bb %i\n", header->index); return true; }