static void construct_exit_block (void) { rtx head = get_last_insn (); rtx end; basic_block exit_block; edge e, e2; unsigned ix; edge_iterator ei; /* Make sure the locus is set to the end of the function, so that epilogue line numbers and warnings are set properly. */ #ifdef USE_MAPPED_LOCATION if (cfun->function_end_locus != UNKNOWN_LOCATION) #else if (cfun->function_end_locus.file) #endif input_location = cfun->function_end_locus; /* The following insns belong to the top scope. */ record_block_change (DECL_INITIAL (current_function_decl)); /* Generate rtl for function exit. */ expand_function_end (); end = get_last_insn (); if (head == end) return; while (NEXT_INSN (head) && NOTE_P (NEXT_INSN (head))) head = NEXT_INSN (head); exit_block = create_basic_block (NEXT_INSN (head), end, EXIT_BLOCK_PTR->prev_bb); exit_block->frequency = EXIT_BLOCK_PTR->frequency; exit_block->count = EXIT_BLOCK_PTR->count; ix = 0; while (ix < EDGE_COUNT (EXIT_BLOCK_PTR->preds)) { e = EDGE_I (EXIT_BLOCK_PTR->preds, ix); if (!(e->flags & EDGE_ABNORMAL)) redirect_edge_succ (e, exit_block); else ix++; } e = make_edge (exit_block, EXIT_BLOCK_PTR, EDGE_FALLTHRU); e->probability = REG_BR_PROB_BASE; e->count = EXIT_BLOCK_PTR->count; FOR_EACH_EDGE (e2, ei, EXIT_BLOCK_PTR->preds) if (e2 != e) { e->count -= e2->count; exit_block->count -= e2->count; exit_block->frequency -= EDGE_FREQUENCY (e2); } if (e->count < 0) e->count = 0; if (exit_block->count < 0) exit_block->count = 0; if (exit_block->frequency < 0) exit_block->frequency = 0; update_bb_for_insn (exit_block); }
static basic_block expand_gimple_basic_block (basic_block bb, FILE * dump_file) { block_stmt_iterator bsi = bsi_start (bb); tree stmt = NULL; rtx note, last; edge e; edge_iterator ei; if (dump_file) { fprintf (dump_file, "\n;; Generating RTL for tree basic block %d\n", bb->index); } if (!bsi_end_p (bsi)) stmt = bsi_stmt (bsi); if (stmt && TREE_CODE (stmt) == LABEL_EXPR) { last = get_last_insn (); expand_expr_stmt (stmt); /* Java emits line number notes in the top of labels. ??? Make this go away once line number notes are obsoleted. */ BB_HEAD (bb) = NEXT_INSN (last); if (NOTE_P (BB_HEAD (bb))) BB_HEAD (bb) = NEXT_INSN (BB_HEAD (bb)); bsi_next (&bsi); note = emit_note_after (NOTE_INSN_BASIC_BLOCK, BB_HEAD (bb)); maybe_dump_rtl_for_tree_stmt (stmt, last); } else note = BB_HEAD (bb) = emit_note (NOTE_INSN_BASIC_BLOCK); NOTE_BASIC_BLOCK (note) = bb; for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); ) { /* Clear EDGE_EXECUTABLE. This flag is never used in the backend. */ e->flags &= ~EDGE_EXECUTABLE; /* At the moment not all abnormal edges match the RTL representation. It is safe to remove them here as find_sub_basic_blocks will rediscover them. In the future we should get this fixed properly. */ if (e->flags & EDGE_ABNORMAL) remove_edge (e); else ei_next (&ei); } for (; !bsi_end_p (bsi); bsi_next (&bsi)) { tree stmt = bsi_stmt (bsi); basic_block new_bb; if (!stmt) continue; /* Expand this statement, then evaluate the resulting RTL and fixup the CFG accordingly. */ if (TREE_CODE (stmt) == COND_EXPR) { new_bb = expand_gimple_cond_expr (bb, stmt); if (new_bb) return new_bb; } else { tree call = get_call_expr_in (stmt); if (call && CALL_EXPR_TAILCALL (call)) { bool can_fallthru; new_bb = expand_gimple_tailcall (bb, stmt, &can_fallthru); if (new_bb) { if (can_fallthru) bb = new_bb; else return new_bb; } } else { last = get_last_insn (); expand_expr_stmt (stmt); maybe_dump_rtl_for_tree_stmt (stmt, last); } } } do_pending_stack_adjust (); /* Find the block tail. The last insn in the block is the insn before a barrier and/or table jump insn. */ last = get_last_insn (); if (BARRIER_P (last)) last = PREV_INSN (last); if (JUMP_TABLE_DATA_P (last)) last = PREV_INSN (PREV_INSN (last)); BB_END (bb) = last; update_bb_for_insn (bb); return bb; }
basic_block cfg_layout_duplicate_bb (basic_block bb, edge e) { rtx insn; edge s, n; basic_block new_bb; gcov_type new_count = e ? e->count : 0; if (bb->count < new_count) new_count = bb->count; if (!bb->pred) abort (); #ifdef ENABLE_CHECKING if (!cfg_layout_can_duplicate_bb_p (bb)) abort (); #endif insn = duplicate_insn_chain (BB_HEAD (bb), BB_END (bb)); new_bb = create_basic_block (insn, insn ? get_last_insn () : NULL, EXIT_BLOCK_PTR->prev_bb); if (bb->rbi->header) { insn = bb->rbi->header; while (NEXT_INSN (insn)) insn = NEXT_INSN (insn); insn = duplicate_insn_chain (bb->rbi->header, insn); if (insn) new_bb->rbi->header = unlink_insn_chain (insn, get_last_insn ()); } if (bb->rbi->footer) { insn = bb->rbi->footer; while (NEXT_INSN (insn)) insn = NEXT_INSN (insn); insn = duplicate_insn_chain (bb->rbi->footer, insn); if (insn) new_bb->rbi->footer = unlink_insn_chain (insn, get_last_insn ()); } if (bb->global_live_at_start) { new_bb->global_live_at_start = OBSTACK_ALLOC_REG_SET (&flow_obstack); new_bb->global_live_at_end = OBSTACK_ALLOC_REG_SET (&flow_obstack); COPY_REG_SET (new_bb->global_live_at_start, bb->global_live_at_start); COPY_REG_SET (new_bb->global_live_at_end, bb->global_live_at_end); } new_bb->loop_depth = bb->loop_depth; new_bb->flags = bb->flags; for (s = bb->succ; s; s = s->succ_next) { /* Since we are creating edges from a new block to successors of another block (which therefore are known to be disjoint), there is no need to actually check for duplicated edges. */ n = unchecked_make_edge (new_bb, s->dest, s->flags); n->probability = s->probability; if (e && bb->count) { /* Take care for overflows! */ n->count = s->count * (new_count * 10000 / bb->count) / 10000; s->count -= n->count; } else n->count = s->count; n->aux = s->aux; } if (e) { new_bb->count = new_count; bb->count -= new_count; new_bb->frequency = EDGE_FREQUENCY (e); bb->frequency -= EDGE_FREQUENCY (e); redirect_edge_and_branch_force (e, new_bb); if (bb->count < 0) bb->count = 0; if (bb->frequency < 0) bb->frequency = 0; } else { new_bb->count = bb->count; new_bb->frequency = bb->frequency; } new_bb->rbi->original = bb; bb->rbi->copy = new_bb; return new_bb; }
static rtx duplicate_insn_chain (rtx from, rtx to) { rtx insn, last; /* Avoid updating of boundaries of previous basic block. The note will get removed from insn stream in fixup. */ last = emit_note (NOTE_INSN_DELETED); /* Create copy at the end of INSN chain. The chain will be reordered later. */ for (insn = from; insn != NEXT_INSN (to); insn = NEXT_INSN (insn)) { switch (GET_CODE (insn)) { case INSN: case CALL_INSN: case JUMP_INSN: /* Avoid copying of dispatch tables. We never duplicate tablejumps, so this can hit only in case the table got moved far from original jump. */ if (GET_CODE (PATTERN (insn)) == ADDR_VEC || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC) break; emit_copy_of_insn_after (insn, get_last_insn ()); break; case CODE_LABEL: break; case BARRIER: emit_barrier (); break; case NOTE: switch (NOTE_LINE_NUMBER (insn)) { /* In case prologue is empty and function contain label in first BB, we may want to copy the block. */ case NOTE_INSN_PROLOGUE_END: case NOTE_INSN_LOOP_VTOP: case NOTE_INSN_LOOP_CONT: case NOTE_INSN_LOOP_BEG: case NOTE_INSN_LOOP_END: /* Strip down the loop notes - we don't really want to keep them consistent in loop copies. */ case NOTE_INSN_DELETED: case NOTE_INSN_DELETED_LABEL: /* No problem to strip these. */ case NOTE_INSN_EPILOGUE_BEG: case NOTE_INSN_FUNCTION_END: /* Debug code expect these notes to exist just once. Keep them in the master copy. ??? It probably makes more sense to duplicate them for each epilogue copy. */ case NOTE_INSN_FUNCTION_BEG: /* There is always just single entry to function. */ case NOTE_INSN_BASIC_BLOCK: break; /* There is no purpose to duplicate prologue. */ case NOTE_INSN_BLOCK_BEG: case NOTE_INSN_BLOCK_END: /* The BLOCK_BEG/BLOCK_END notes should be eliminated when BB reordering is in the progress. */ case NOTE_INSN_EH_REGION_BEG: case NOTE_INSN_EH_REGION_END: /* Should never exist at BB duplication time. */ abort (); break; case NOTE_INSN_REPEATED_LINE_NUMBER: emit_note_copy (insn); break; default: if (NOTE_LINE_NUMBER (insn) < 0) abort (); /* It is possible that no_line_number is set and the note won't be emitted. */ emit_note_copy (insn); } break; default: abort (); } } insn = NEXT_INSN (last); delete_insn (last); return insn; }
void do_compare_rtx_and_jump (rtx op0, rtx op1, enum rtx_code code, int unsignedp, enum machine_mode mode, rtx size, rtx if_false_label, rtx if_true_label, int prob) { rtx tem; rtx dummy_label = NULL_RTX; rtx last; /* Reverse the comparison if that is safe and we want to jump if it is false. Also convert to the reverse comparison if the target can implement it. */ if ((! if_true_label || ! can_compare_p (code, mode, ccp_jump)) && (! FLOAT_MODE_P (mode) || code == ORDERED || code == UNORDERED || (! HONOR_NANS (mode) && (code == LTGT || code == UNEQ)) || (! HONOR_SNANS (mode) && (code == EQ || code == NE)))) { enum rtx_code rcode; if (FLOAT_MODE_P (mode)) rcode = reverse_condition_maybe_unordered (code); else rcode = reverse_condition (code); /* Canonicalize to UNORDERED for the libcall. */ if (can_compare_p (rcode, mode, ccp_jump) || (code == ORDERED && ! can_compare_p (ORDERED, mode, ccp_jump))) { tem = if_true_label; if_true_label = if_false_label; if_false_label = tem; code = rcode; prob = inv (prob); } } /* If one operand is constant, make it the second one. Only do this if the other operand is not constant as well. */ if (swap_commutative_operands_p (op0, op1)) { tem = op0; op0 = op1; op1 = tem; code = swap_condition (code); } do_pending_stack_adjust (); code = unsignedp ? unsigned_condition (code) : code; if (0 != (tem = simplify_relational_operation (code, mode, VOIDmode, op0, op1))) { if (CONSTANT_P (tem)) { rtx label = (tem == const0_rtx || tem == CONST0_RTX (mode)) ? if_false_label : if_true_label; if (label) emit_jump (label); return; } code = GET_CODE (tem); mode = GET_MODE (tem); op0 = XEXP (tem, 0); op1 = XEXP (tem, 1); unsignedp = (code == GTU || code == LTU || code == GEU || code == LEU); } if (! if_true_label) dummy_label = if_true_label = gen_label_rtx (); if (GET_MODE_CLASS (mode) == MODE_INT && ! can_compare_p (code, mode, ccp_jump)) { switch (code) { case LTU: do_jump_by_parts_greater_rtx (mode, 1, op1, op0, if_false_label, if_true_label, prob); break; case LEU: do_jump_by_parts_greater_rtx (mode, 1, op0, op1, if_true_label, if_false_label, inv (prob)); break; case GTU: do_jump_by_parts_greater_rtx (mode, 1, op0, op1, if_false_label, if_true_label, prob); break; case GEU: do_jump_by_parts_greater_rtx (mode, 1, op1, op0, if_true_label, if_false_label, inv (prob)); break; case LT: do_jump_by_parts_greater_rtx (mode, 0, op1, op0, if_false_label, if_true_label, prob); break; case LE: do_jump_by_parts_greater_rtx (mode, 0, op0, op1, if_true_label, if_false_label, inv (prob)); break; case GT: do_jump_by_parts_greater_rtx (mode, 0, op0, op1, if_false_label, if_true_label, prob); break; case GE: do_jump_by_parts_greater_rtx (mode, 0, op1, op0, if_true_label, if_false_label, inv (prob)); break; case EQ: do_jump_by_parts_equality_rtx (mode, op0, op1, if_false_label, if_true_label, prob); break; case NE: do_jump_by_parts_equality_rtx (mode, op0, op1, if_true_label, if_false_label, inv (prob)); break; default: gcc_unreachable (); } } else { if (SCALAR_FLOAT_MODE_P (mode) && ! can_compare_p (code, mode, ccp_jump) && can_compare_p (swap_condition (code), mode, ccp_jump)) { rtx tmp; code = swap_condition (code); tmp = op0; op0 = op1; op1 = tmp; } else if (SCALAR_FLOAT_MODE_P (mode) && ! can_compare_p (code, mode, ccp_jump) /* Never split ORDERED and UNORDERED. These must be implemented. */ && (code != ORDERED && code != UNORDERED) /* Split a floating-point comparison if we can jump on other conditions... */ && (have_insn_for (COMPARE, mode) /* ... or if there is no libcall for it. */ || code_to_optab (code) == unknown_optab)) { enum rtx_code first_code; bool and_them = split_comparison (code, mode, &first_code, &code); /* If there are no NaNs, the first comparison should always fall through. */ if (!HONOR_NANS (mode)) gcc_assert (first_code == (and_them ? ORDERED : UNORDERED)); else { if (and_them) { rtx dest_label; /* If we only jump if true, just bypass the second jump. */ if (! if_false_label) { if (! dummy_label) dummy_label = gen_label_rtx (); dest_label = dummy_label; } else dest_label = if_false_label; do_compare_rtx_and_jump (op0, op1, first_code, unsignedp, mode, size, dest_label, NULL_RTX, prob); } else do_compare_rtx_and_jump (op0, op1, first_code, unsignedp, mode, size, NULL_RTX, if_true_label, prob); } } last = get_last_insn (); emit_cmp_and_jump_insns (op0, op1, code, size, mode, unsignedp, if_true_label); if (prob != -1 && profile_status != PROFILE_ABSENT) { for (last = NEXT_INSN (last); last && NEXT_INSN (last); last = NEXT_INSN (last)) if (JUMP_P (last)) break; if (last && JUMP_P (last) && ! NEXT_INSN (last) && any_condjump_p (last)) { gcc_assert (!find_reg_note (last, REG_BR_PROB, 0)); add_reg_note (last, REG_BR_PROB, GEN_INT (prob)); } } } if (if_false_label) emit_jump (if_false_label); if (dummy_label) emit_label (dummy_label); }