void reemit_insn_block_notes (void) { tree cur_block = DECL_INITIAL (cfun->decl); rtx insn, note; insn = get_insns (); if (!active_insn_p (insn)) insn = next_active_insn (insn); for (; insn; insn = next_active_insn (insn)) { tree this_block; /* Avoid putting scope notes between jump table and its label. */ if (JUMP_P (insn) && (GET_CODE (PATTERN (insn)) == ADDR_VEC || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)) continue; this_block = insn_scope (insn); /* For sequences compute scope resulting from merging all scopes of instructions nested inside. */ if (GET_CODE (PATTERN (insn)) == SEQUENCE) { int i; rtx body = PATTERN (insn); this_block = NULL; for (i = 0; i < XVECLEN (body, 0); i++) this_block = choose_inner_scope (this_block, insn_scope (XVECEXP (body, 0, i))); } if (! this_block) continue; if (this_block != cur_block) { change_scope (insn, cur_block, this_block); cur_block = this_block; } } /* change_scope emits before the insn, not after. */ note = emit_note (NOTE_INSN_DELETED); change_scope (note, cur_block, DECL_INITIAL (cfun->decl)); delete_insn (note); reorder_blocks (); }
void genrtl_scope_stmt (tree t) { tree block = SCOPE_STMT_BLOCK (t); if (!SCOPE_NO_CLEANUPS_P (t)) { if (SCOPE_BEGIN_P (t)) expand_start_bindings_and_block (2 * SCOPE_NULLIFIED_P (t), block); else if (SCOPE_END_P (t)) expand_end_bindings (NULL_TREE, !SCOPE_NULLIFIED_P (t), 0); } else if (!SCOPE_NULLIFIED_P (t)) { rtx note = emit_note (SCOPE_BEGIN_P (t) ? NOTE_INSN_BLOCK_BEG : NOTE_INSN_BLOCK_END); NOTE_BLOCK (note) = block; } /* If we're at the end of a scope that contains inlined nested functions, we have to decide whether or not to write them out. */ if (block && SCOPE_END_P (t)) { tree fn; for (fn = BLOCK_VARS (block); fn; fn = TREE_CHAIN (fn)) { if (TREE_CODE (fn) == FUNCTION_DECL && DECL_CONTEXT (fn) == current_function_decl && DECL_SAVED_INSNS (fn) && DECL_SAVED_INSNS (fn)->saved_for_inline && !TREE_ASM_WRITTEN (fn) && TREE_ADDRESSABLE (fn)) { push_function_context (); output_inline_function (fn); pop_function_context (); } } } }
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; }
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 expand_stmt (tree t) { while (t && t != error_mark_node) { int saved_stmts_are_full_exprs_p; /* Set up context appropriately for handling this statement. */ saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p (); prep_stmt (t); switch (TREE_CODE (t)) { case FILE_STMT: input_filename = FILE_STMT_FILENAME (t); break; case RETURN_STMT: genrtl_return_stmt (t); t = expand_unreachable_stmt (TREE_CHAIN (t), warn_notreached); goto process_t; case EXPR_STMT: genrtl_expr_stmt_value (EXPR_STMT_EXPR (t), TREE_ADDRESSABLE (t), TREE_CHAIN (t) == NULL || (TREE_CODE (TREE_CHAIN (t)) == SCOPE_STMT && TREE_CHAIN (TREE_CHAIN (t)) == NULL)); break; case DECL_STMT: genrtl_decl_stmt (t); break; case FOR_STMT: genrtl_for_stmt (t); break; case WHILE_STMT: genrtl_while_stmt (t); break; case DO_STMT: genrtl_do_stmt (t); break; case IF_STMT: genrtl_if_stmt (t); break; case COMPOUND_STMT: genrtl_compound_stmt (t); break; case BREAK_STMT: genrtl_break_stmt (); t = expand_unreachable_stmt (TREE_CHAIN (t), warn_notreached); goto process_t; case CONTINUE_STMT: genrtl_continue_stmt (); t = expand_unreachable_stmt (TREE_CHAIN (t), warn_notreached); goto process_t; case SWITCH_STMT: genrtl_switch_stmt (t); break; case CASE_LABEL: genrtl_case_label (t); break; case LABEL_STMT: expand_label (LABEL_STMT_LABEL (t)); break; case GOTO_STMT: /* Emit information for branch prediction. */ if (!GOTO_FAKE_P (t) && TREE_CODE (GOTO_DESTINATION (t)) == LABEL_DECL && flag_guess_branch_prob) { rtx note = emit_note (NOTE_INSN_PREDICTION); NOTE_PREDICTION (note) = NOTE_PREDICT (PRED_GOTO, NOT_TAKEN); } genrtl_goto_stmt (GOTO_DESTINATION (t)); t = expand_unreachable_stmt (TREE_CHAIN (t), warn_notreached); goto process_t; case ASM_STMT: genrtl_asm_stmt (ASM_CV_QUAL (t), ASM_STRING (t), ASM_OUTPUTS (t), ASM_INPUTS (t), ASM_CLOBBERS (t), ASM_INPUT_P (t)); break; case SCOPE_STMT: genrtl_scope_stmt (t); break; case CLEANUP_STMT: genrtl_cleanup_stmt (t); break; default: if (lang_expand_stmt) (*lang_expand_stmt) (t); else abort (); break; } /* Go on to the next statement in this scope. */ t = TREE_CHAIN (t); process_t: /* Restore saved state. */ current_stmt_tree ()->stmts_are_full_exprs_p = saved_stmts_are_full_exprs_p; } }