*参照元 [#z4078de3] #backlinks *説明 [#fb84e348] -パス: [[gcc-8.3/gcc/cfgexpand.c]] -FIXME: これは何? --説明 **引数 [#b10473d8] -basic_block bb -- --[[gcc-8.3/gcc/basic_block]] -bool disable_tail_calls -- **返り値 [#v5b588dc] -basic_block -- **参考 [#nece80f4] *実装 [#u4c23f32] /* Expand basic block BB from GIMPLE trees to RTL. */ static basic_block expand_gimple_basic_block (basic_block bb, bool disable_tail_calls) { gimple_stmt_iterator gsi; gimple_seq stmts; gimple *stmt = NULL; rtx_note *note = NULL; rtx_insn *last; edge e; edge_iterator ei; - --[[gcc-8.3/gcc/gimple_stmt_iterator]] --[[gcc-8.3/gcc/gimple_seq]] --[[gcc-8.3/gcc/gimple]] --[[gcc-8.3/gcc/rtx_note]] --[[gcc-8.3/gcc/rtx_insn]] --[[gcc-8.3/gcc/edge]] --[[gcc-8.3/gcc/edge_iterator]] if (dump_file) fprintf (dump_file, "\n;; Generating RTL for gimple basic block %d\n", bb->index); /* Note that since we are now transitioning from GIMPLE to RTL, we cannot use the gsi_*_bb() routines because they expect the basic block to be in GIMPLE, instead of RTL. Therefore, we need to access the BB sequence directly. */ if (optimize) reorder_operands (bb); stmts = bb_seq (bb); bb->il.gimple.seq = NULL; bb->il.gimple.phi_nodes = NULL; rtl_profile_for_bb (bb); init_rtl_bb_info (bb); bb->flags |= BB_RTL; - --[[gcc-8.3/gcc/reorder_operands()]] --[[gcc-8.3/gcc/bb_seq()]] --[[gcc-8.3/gcc/rtl_profile_for_bb()]] --[[gcc-8.3/gcc/init_rtl_bb_info()]] /* Remove the RETURN_EXPR if we may fall though to the exit instead. */ gsi = gsi_last (stmts); if (!gsi_end_p (gsi) && gimple_code (gsi_stmt (gsi)) == GIMPLE_RETURN) { greturn *ret_stmt = as_a <greturn *> (gsi_stmt (gsi)); gcc_assert (single_succ_p (bb)); gcc_assert (single_succ (bb) == EXIT_BLOCK_PTR_FOR_FN (cfun)); if (bb->next_bb == EXIT_BLOCK_PTR_FOR_FN (cfun) && !gimple_return_retval (ret_stmt)) { gsi_remove (&gsi, false); single_succ_edge (bb)->flags |= EDGE_FALLTHRU; } } - --[[gcc-8.3/gcc/gsi_last()]] --[[gcc-8.3/gcc/gsi_end_p()]] --[[gcc-8.3/gcc/gimple_code()]] --[[gcc-8.3/gcc/gsi_stmt()]] --[[gcc-8.3/gcc/greturn]] --[[gcc-8.3/gcc/gcc_assert()]] --[[gcc-8.3/gcc/single_succ_p()]] --[[gcc-8.3/gcc/single_succ()]] --[[gcc-8.3/gcc/EXIT_BLOCK_PTR_FOR_FN()]] --[[gcc-8.3/gcc/gimple_return_retval()]] --[[gcc-8.3/gcc/gsi_remove()]] --[[gcc-8.3/gcc/single_succ_edge()]] gsi = gsi_start (stmts); if (!gsi_end_p (gsi)) { stmt = gsi_stmt (gsi); if (gimple_code (stmt) != GIMPLE_LABEL) stmt = NULL; } - --[[gcc-8.3/gcc/gsi_start()]] --[[gcc-8.3/gcc/gsi_end_p()]] --[[gcc-8.3/gcc/gsi_stmt()]] --[[gcc-8.3/gcc/gimple_code()]] rtx_code_label **elt = lab_rtx_for_bb->get (bb); if (stmt || elt) { gcc_checking_assert (!note); last = get_last_insn (); if (stmt) { expand_gimple_stmt (stmt); gsi_next (&gsi); } if (elt) emit_label (*elt); BB_HEAD (bb) = NEXT_INSN (last); if (NOTE_P (BB_HEAD (bb))) BB_HEAD (bb) = NEXT_INSN (BB_HEAD (bb)); gcc_assert (LABEL_P (BB_HEAD (bb))); note = emit_note_after (NOTE_INSN_BASIC_BLOCK, BB_HEAD (bb)); maybe_dump_rtl_for_gimple_stmt (stmt, last); } else BB_HEAD (bb) = note = emit_note (NOTE_INSN_BASIC_BLOCK); - --[[gcc-8.3/gcc/rtx_code_label]] --[[gcc-8.3/gcc/gcc_checking_assert()]] --[[gcc-8.3/gcc/get_last_insn()]] --[[gcc-8.3/gcc/gsi_next()]] --[[gcc-8.3/gcc/emit_label()]] --[[gcc-8.3/gcc/BB_HEAD()]] --[[gcc-8.3/gcc/NEXT_INSN()]] --[[gcc-8.3/gcc/NOTE_P()]] --[[gcc-8.3/gcc/gcc_assert()]] --[[gcc-8.3/gcc/LABEL_P()]] --[[gcc-8.3/gcc/emit_note_after()]] --[[gcc-8.3/gcc/maybe_dump_rtl_for_gimple_stmt()]] --[[gcc-8.3/gcc/emit_note()]] if (note) NOTE_BASIC_BLOCK (note) = bb; - --[[gcc-8.3/gcc/NOTE_BASIC_BLOCK()]] for (; !gsi_end_p (gsi); gsi_next (&gsi)) { basic_block new_bb; stmt = gsi_stmt (gsi); - --[[gcc-8.3/gcc/gsi_end_p()]] --[[gcc-8.3/gcc/gsi_next()]] --[[gcc-8.3/gcc/basic_block]] --[[gcc-8.3/gcc/gsi_stmt()]] /* If this statement is a non-debug one, and we generate debug insns, then this one might be the last real use of a TERed SSA_NAME, but where there are still some debug uses further down. Expanding the current SSA name in such further debug uses by their RHS might lead to wrong debug info, as coalescing might make the operands of such RHS be placed into the same pseudo as something else. Like so: a_1 = a_0 + 1; // Assume a_1 is TERed and a_0 is dead use(a_1); a_2 = ... #DEBUG ... => a_1 As a_0 and a_2 don't overlap in lifetime, assume they are coalesced. If we now would expand a_1 by it's RHS (a_0 + 1) in the debug use, the write to a_2 would actually have clobbered the place which formerly held a_0. So, instead of that, we recognize the situation, and generate debug temporaries at the last real use of TERed SSA names: a_1 = a_0 + 1; #DEBUG #D1 => a_1 use(a_1); a_2 = ... #DEBUG ... => #D1 */ if (MAY_HAVE_DEBUG_BIND_INSNS && SA.values && !is_gimple_debug (stmt)) { ssa_op_iter iter; tree op; gimple *def; location_t sloc = curr_insn_location (); - --[[gcc-8.3/gcc/is_gimple_debug()]] --[[gcc-8.3/gcc/ssa_op_iter]] --[[gcc-8.3/gcc/tree]] --[[gcc-8.3/gcc/gimple]] --[[gcc-8.3/gcc/location_t]] --[[gcc-8.3/gcc/curr_insn_location()]] /* Look for SSA names that have their last use here (TERed names always have only one real use). */ FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE) if ((def = get_gimple_for_ssa_name (op))) { imm_use_iterator imm_iter; use_operand_p use_p; bool have_debug_uses = false; FOR_EACH_IMM_USE_FAST (use_p, imm_iter, op) { if (gimple_debug_bind_p (USE_STMT (use_p))) { have_debug_uses = true; break; } } - --[[gcc-8.3/gcc/FOR_EACH_SSA_TREE_OPERAND()]] --[[gcc-8.3/gcc/get_gimple_for_ssa_name()]] --[[gcc-8.3/gcc/imm_use_iterator]] --[[gcc-8.3/gcc/use_operand_p]] --[[gcc-8.3/gcc/FOR_EACH_IMM_USE_FAST()]] --[[gcc-8.3/gcc/gimple_debug_bind_p()]] --[[gcc-8.3/gcc/USE_STMT()]] if (have_debug_uses) { /* OP is a TERed SSA name, with DEF its defining statement, and where OP is used in further debug instructions. Generate a debug temporary, and replace all uses of OP in debug insns with that temporary. */ gimple *debugstmt; tree value = gimple_assign_rhs_to_tree (def); tree vexpr = make_node (DEBUG_EXPR_DECL); rtx val; machine_mode mode; set_curr_insn_location (gimple_location (def)); - --[[gcc-8.3/gcc/gimple]] --[[gcc-8.3/gcc/tree]] --[[gcc-8.3/gcc/gimple_assign_rhs_to_tree()]] --[[gcc-8.3/gcc/make_node()]] --[[gcc-8.3/gcc/rtx]] --[[gcc-8.3/gcc/machine_mode]] --[[gcc-8.3/gcc/set_curr_insn_location()]] --[[gcc-8.3/gcc/gimple_location()]] DECL_ARTIFICIAL (vexpr) = 1; TREE_TYPE (vexpr) = TREE_TYPE (value); if (DECL_P (value)) mode = DECL_MODE (value); else mode = TYPE_MODE (TREE_TYPE (value)); SET_DECL_MODE (vexpr, mode); val = gen_rtx_VAR_LOCATION (mode, vexpr, (rtx)value, VAR_INIT_STATUS_INITIALIZED); emit_debug_insn (val); - --[[gcc-8.3/gcc/DECL_ARTIFICIAL()]] --[[gcc-8.3/gcc/TREE_TYPE()]] --[[gcc-8.3/gcc/DECL_P()]] --[[gcc-8.3/gcc/DECL_MODE()]] --[[gcc-8.3/gcc/TYPE_MODE()]] --[[gcc-8.3/gcc/TREE_TYPE()]] --[[gcc-8.3/gcc/SET_DECL_MODE()]] --[[gcc-8.3/gcc/gen_rtx_VAR_LOCATION()]] --[[gcc-8.3/gcc/emit_debug_insn()]] FOR_EACH_IMM_USE_STMT (debugstmt, imm_iter, op) { if (!gimple_debug_bind_p (debugstmt)) continue; FOR_EACH_IMM_USE_ON_STMT (use_p, imm_iter) SET_USE (use_p, vexpr); update_stmt (debugstmt); } } } set_curr_insn_location (sloc); } - --[[gcc-8.3/gcc/FOR_EACH_IMM_USE_STMT()]] --[[gcc-8.3/gcc/gimple_debug_bind_p()]] --[[gcc-8.3/gcc/FOR_EACH_IMM_USE_ON_STMT()]] --[[gcc-8.3/gcc/SET_USE()]] --[[gcc-8.3/gcc/update_stmt()]] --[[gcc-8.3/gcc/set_curr_insn_location()]] currently_expanding_gimple_stmt = stmt; /* Expand this statement, then evaluate the resulting RTL and fixup the CFG accordingly. */ if (gimple_code (stmt) == GIMPLE_COND) { new_bb = expand_gimple_cond (bb, as_a <gcond *> (stmt)); if (new_bb) return new_bb; } - --[[gcc-8.3/gcc/gimple_code()]] --[[gcc-8.3/gcc/expand_gimple_cond()]] else if (is_gimple_debug (stmt)) { location_t sloc = curr_insn_location (); gimple_stmt_iterator nsi = gsi; for (;;) { tree var; tree value = NULL_TREE; rtx val = NULL_RTX; machine_mode mode; - --[[gcc-8.3/gcc/tree]] --[[gcc-8.3/gcc/rtx]] --[[gcc-8.3/gcc/machine_mode]] if (!gimple_debug_nonbind_marker_p (stmt)) { if (gimple_debug_bind_p (stmt)) { var = gimple_debug_bind_get_var (stmt); if (TREE_CODE (var) != DEBUG_EXPR_DECL && TREE_CODE (var) != LABEL_DECL && !target_for_debug_bind (var)) goto delink_debug_stmt; if (DECL_P (var)) mode = DECL_MODE (var); else mode = TYPE_MODE (TREE_TYPE (var)); if (gimple_debug_bind_has_value_p (stmt)) value = gimple_debug_bind_get_value (stmt); val = gen_rtx_VAR_LOCATION (mode, var, (rtx)value, VAR_INIT_STATUS_INITIALIZED); } else if (gimple_debug_source_bind_p (stmt)) { var = gimple_debug_source_bind_get_var (stmt); value = gimple_debug_source_bind_get_value (stmt); mode = DECL_MODE (var); val = gen_rtx_VAR_LOCATION (mode, var, (rtx)value, VAR_INIT_STATUS_UNINITIALIZED); } else gcc_unreachable (); } - --[[gcc-8.3/gcc/gimple_debug_nonbind_marker_p()]] --[[gcc-8.3/gcc/gimple_debug_bind_p()]] --[[gcc-8.3/gcc/gimple_debug_bind_get_var()]] --[[gcc-8.3/gcc/TREE_CODE()]] --[[gcc-8.3/gcc/target_for_debug_bind()]] --[[gcc-8.3/gcc/DECL_P()]] --[[gcc-8.3/gcc/DECL_MODE()]] --[[gcc-8.3/gcc/TYPE_MODE()]] --[[gcc-8.3/gcc/TREE_TYPE()]] --[[gcc-8.3/gcc/gimple_debug_bind_has_value_p()]] --[[gcc-8.3/gcc/gimple_debug_bind_get_value()]] --[[gcc-8.3/gcc/gen_rtx_VAR_LOCATION()]] --[[gcc-8.3/gcc/gimple_debug_source_bind_p()]] --[[gcc-8.3/gcc/gimple_debug_source_bind_get_var()]] --[[gcc-8.3/gcc/gimple_debug_source_bind_get_value()]] --[[gcc-8.3/gcc/gcc_unreachable()]] /* If this function was first compiled with markers enabled, but they're now disable (e.g. LTO), drop them on the floor. */ else if (gimple_debug_nonbind_marker_p (stmt) && !MAY_HAVE_DEBUG_MARKER_INSNS) goto delink_debug_stmt; else if (gimple_debug_begin_stmt_p (stmt)) val = GEN_RTX_DEBUG_MARKER_BEGIN_STMT_PAT (); else if (gimple_debug_inline_entry_p (stmt)) { tree block = gimple_block (stmt); if (block) val = GEN_RTX_DEBUG_MARKER_INLINE_ENTRY_PAT (); else goto delink_debug_stmt; } else gcc_unreachable (); - --[[gcc-8.3/gcc/gimple_debug_nonbind_marker_p()]] --[[gcc-8.3/gcc/gimple_debug_begin_stmt_p()]] --[[gcc-8.3/gcc/GEN_RTX_DEBUG_MARKER_BEGIN_STMT_PAT()]] --[[gcc-8.3/gcc/gimple_debug_inline_entry_p()]] --[[gcc-8.3/gcc/tree]] --[[gcc-8.3/gcc/gimple_block()]] --[[gcc-8.3/gcc/GEN_RTX_DEBUG_MARKER_INLINE_ENTRY_PAT()]] --[[gcc-8.3/gcc/gcc_unreachable()]] last = get_last_insn (); set_curr_insn_location (gimple_location (stmt)); emit_debug_insn (val); if (dump_file && (dump_flags & TDF_DETAILS)) { /* We can't dump the insn with a TREE where an RTX is expected. */ if (GET_CODE (val) == VAR_LOCATION) { gcc_checking_assert (PAT_VAR_LOCATION_LOC (val) == (rtx)value); PAT_VAR_LOCATION_LOC (val) = const0_rtx; } maybe_dump_rtl_for_gimple_stmt (stmt, last); if (GET_CODE (val) == VAR_LOCATION) PAT_VAR_LOCATION_LOC (val) = (rtx)value; } - --[[gcc-8.3/gcc/get_last_insn()]] --[[gcc-8.3/gcc/set_curr_insn_location()]] --[[gcc-8.3/gcc/gimple_location()]] --[[gcc-8.3/gcc/emit_debug_insn()]] --[[gcc-8.3/gcc/GET_CODE()]] --[[gcc-8.3/gcc/gcc_checking_assert()]] --[[gcc-8.3/gcc/PAT_VAR_LOCATION_LOC()]] --[[gcc-8.3/gcc/maybe_dump_rtl_for_gimple_stmt()]] delink_debug_stmt: /* In order not to generate too many debug temporaries, we delink all uses of debug statements we already expanded. Therefore debug statements between definition and real use of TERed SSA names will continue to use the SSA name, and not be replaced with debug temps. */ delink_stmt_imm_use (stmt); gsi = nsi; gsi_next (&nsi); if (gsi_end_p (nsi)) break; stmt = gsi_stmt (nsi); if (!is_gimple_debug (stmt)) break; } set_curr_insn_location (sloc); } - --[[gcc-8.3/gcc/delink_stmt_imm_use()]] --[[gcc-8.3/gcc/gsi_next()]] --[[gcc-8.3/gcc/gsi_end_p()]] --[[gcc-8.3/gcc/gsi_stmt()]] --[[gcc-8.3/gcc/is_gimple_debug()]] --[[gcc-8.3/gcc/set_curr_insn_location()]] else { gcall *call_stmt = dyn_cast <gcall *> (stmt); if (call_stmt && gimple_call_tail_p (call_stmt) && disable_tail_calls) gimple_call_set_tail (call_stmt, false); if (call_stmt && gimple_call_tail_p (call_stmt)) { bool can_fallthru; new_bb = expand_gimple_tailcall (bb, call_stmt, &can_fallthru); if (new_bb) { if (can_fallthru) bb = new_bb; else return new_bb; } } else { def_operand_p def_p; def_p = SINGLE_SSA_DEF_OPERAND (stmt, SSA_OP_DEF); if (def_p != NULL) { /* Ignore this stmt if it is in the list of replaceable expressions. */ if (SA.values && bitmap_bit_p (SA.values, SSA_NAME_VERSION (DEF_FROM_PTR (def_p)))) continue; } last = expand_gimple_stmt (stmt); maybe_dump_rtl_for_gimple_stmt (stmt, last); } } } - --[[gcc-8.3/gcc/gcall]] --[[gcc-8.3/gcc/gimple_call_tail_p()]] --[[gcc-8.3/gcc/gimple_call_set_tail()]] --[[gcc-8.3/gcc/expand_gimple_tailcall()]] --[[gcc-8.3/gcc/def_operand_p]] --[[gcc-8.3/gcc/SINGLE_SSA_DEF_OPERAND()]] --[[gcc-8.3/gcc/bitmap_bit_p()]] --[[gcc-8.3/gcc/SSA_NAME_VERSION()]] --[[gcc-8.3/gcc/DEF_FROM_PTR()]] --[[gcc-8.3/gcc/expand_gimple_stmt()]] --[[gcc-8.3/gcc/maybe_dump_rtl_for_gimple_stmt()]] currently_expanding_gimple_stmt = NULL; /* Expand implicit goto and convert goto_locus. */ FOR_EACH_EDGE (e, ei, bb->succs) { if (e->goto_locus != UNKNOWN_LOCATION) set_curr_insn_location (e->goto_locus); if ((e->flags & EDGE_FALLTHRU) && e->dest != bb->next_bb) { emit_jump (label_rtx_for_bb (e->dest)); e->flags &= ~EDGE_FALLTHRU; } } - --[[gcc-8.3/gcc/FOR_EACH_EDGE()]] --[[gcc-8.3/gcc/set_curr_insn_location()]] --[[gcc-8.3/gcc/emit_jump()]] --[[gcc-8.3/gcc/label_rtx_for_bb()]] /* Expanded RTL can create a jump in the last instruction of block. This later might be assumed to be a jump to successor and break edge insertion. We need to insert dummy move to prevent this. PR41440. */ if (single_succ_p (bb) && (single_succ_edge (bb)->flags & EDGE_FALLTHRU) && (last = get_last_insn ()) && (JUMP_P (last) || (DEBUG_INSN_P (last) && JUMP_P (prev_nondebug_insn (last))))) { rtx dummy = gen_reg_rtx (SImode); emit_insn_after_noloc (gen_move_insn (dummy, dummy), last, NULL); } do_pending_stack_adjust (); - --[[gcc-8.3/gcc/single_succ_p()]] --[[gcc-8.3/gcc/single_succ_edge()]] --[[gcc-8.3/gcc/get_last_insn()]] --[[gcc-8.3/gcc/JUMP_P()]] --[[gcc-8.3/gcc/DEBUG_INSN_P()]] --[[gcc-8.3/gcc/prev_nondebug_insn()]] --[[gcc-8.3/gcc/rtx]] --[[gcc-8.3/gcc/gen_reg_rtx()]] --[[gcc-8.3/gcc/emit_insn_after_noloc()]] --[[gcc-8.3/gcc/gen_move_insn()]] --[[gcc-8.3/gcc/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; } - --[[gcc-8.3/gcc/get_last_insn()]] --[[gcc-8.3/gcc/BARRIER_P()]] --[[gcc-8.3/gcc/PREV_INSN()]] --[[gcc-8.3/gcc/JUMP_TABLE_DATA_P()]] --[[gcc-8.3/gcc/BB_END()]] --[[gcc-8.3/gcc/update_bb_for_insn()]] *コメント [#u956edad]