@@ -76,6 +76,27 @@ pop_stmt_list (tree t)
free_stmt_list (t);
t = u;
}
+ /* If the statement list contained a debug begin stmt and a
+ statement list, move the debug begin stmt into the statement
+ list and return it. */
+ else if (!tsi_end_p (i)
+ && TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
+ {
+ u = tsi_stmt (i);
+ tsi_next (&i);
+ if (tsi_one_before_end_p (i)
+ && TREE_CODE (tsi_stmt (i)) == STATEMENT_LIST)
+ {
+ tree l = tsi_stmt (i);
+ tsi_prev (&i);
+ tsi_delink (&i);
+ tsi_delink (&i);
+ i = tsi_start (l);
+ free_stmt_list (t);
+ t = l;
+ tsi_link_before (&i, u, TSI_SAME_STMT);
+ }
+ }
}
return t;
@@ -60,6 +60,8 @@ along with GCC; see the file COPYING3. If not see
#define LANG_HOOKS_BUILTIN_FUNCTION c_builtin_function
#undef LANG_HOOKS_BUILTIN_FUNCTION_EXT_SCOPE
#define LANG_HOOKS_BUILTIN_FUNCTION_EXT_SCOPE c_builtin_function_ext_scope
+#undef LANG_HOOKS_EMITS_BEGIN_STMT
+#define LANG_HOOKS_EMITS_BEGIN_STMT true
/* Attribute hooks. */
#undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE
@@ -1476,6 +1476,19 @@ c_parser_external_declaration (c_parser *parser)
static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token>);
static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
+/* Build and add a DEBUG_BEGIN_STMT statement with location LOC. */
+
+static void
+add_debug_begin_stmt (location_t loc)
+{
+ if (!debug_statement_frontiers)
+ return;
+
+ tree stmt = build0 (DEBUG_BEGIN_STMT, void_type_node);
+ SET_EXPR_LOCATION (stmt, loc);
+ add_stmt (stmt);
+}
+
/* Parse a declaration or function definition (C90 6.5, 6.7.1, C99
6.7, 6.9.1, C11 6.7, 6.9.1). If FNDEF_OK is true, a function definition
is accepted; otherwise (old-style parameter declarations) only other
@@ -1576,6 +1589,8 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
bool diagnosed_no_specs = false;
location_t here = c_parser_peek_token (parser)->location;
+ add_debug_begin_stmt (c_parser_peek_token (parser)->location);
+
if (static_assert_ok
&& c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT))
{
@@ -4777,6 +4792,7 @@ c_parser_compound_statement_nostart (c_parser *parser)
location_t label_loc = UNKNOWN_LOCATION; /* Quiet warning. */
if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
{
+ add_debug_begin_stmt (c_parser_peek_token (parser)->location);
c_parser_consume_token (parser);
return;
}
@@ -5231,6 +5247,10 @@ c_parser_statement_after_labels (c_parser *parser, bool *if_p,
parser->in_if_block = false;
if (if_p != NULL)
*if_p = false;
+
+ if (c_parser_peek_token (parser)->type != CPP_OPEN_BRACE)
+ add_debug_begin_stmt (loc);
+
switch (c_parser_peek_token (parser)->type)
{
case CPP_OPEN_BRACE:
@@ -10573,6 +10573,10 @@ c_finish_stmt_expr (location_t loc, tree body)
}
else
i = tsi_last (last);
+ if (TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
+ do
+ tsi_prev (&i);
+ while (TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT);
last_p = tsi_stmt_ptr (i);
last = *last_p;
}
@@ -10592,7 +10596,9 @@ c_finish_stmt_expr (location_t loc, tree body)
/* In the case that the BIND_EXPR is not necessary, return the
expression out from inside it. */
- if (last == BIND_EXPR_BODY (body)
+ if ((last == BIND_EXPR_BODY (body)
+ /* Skip nested debug stmts. */
+ || last == expr_first (BIND_EXPR_BODY (body)))
&& BIND_EXPR_VARS (body) == NULL)
{
/* Even if this looks constant, do not allow it in a constant
@@ -443,6 +443,7 @@ find_bb_boundaries (basic_block bb)
rtx_jump_table_data *table;
rtx_insn *flow_transfer_insn = NULL;
edge fallthru = NULL;
+ bool only_header_debug_insns_p = true;
if (insn == BB_END (bb))
return;
@@ -460,6 +461,13 @@ find_bb_boundaries (basic_block bb)
if ((flow_transfer_insn || code == CODE_LABEL)
&& inside_basic_block_p (insn))
{
+ if (only_header_debug_insns_p)
+ {
+ gcc_assert (!flow_transfer_insn);
+ BB_HEAD (bb) = insn;
+ goto end;
+ }
+
fallthru = split_block (bb, PREV_INSN (insn));
if (flow_transfer_insn)
{
@@ -471,6 +479,7 @@ find_bb_boundaries (basic_block bb)
x = NEXT_INSN (x))
if (!BARRIER_P (x))
set_block_for_insn (x, NULL);
+ only_header_debug_insns_p = true;
}
bb = fallthru->dest;
@@ -489,13 +498,16 @@ find_bb_boundaries (basic_block bb)
the middle of a BB. We need to split it in the same manner as
if the barrier were preceded by a control_flow_insn_p insn. */
if (!flow_transfer_insn)
- flow_transfer_insn = prev_nonnote_insn_bb (insn);
+ flow_transfer_insn = prev_nonnote_nondebug_insn_bb (insn);
}
if (control_flow_insn_p (insn))
flow_transfer_insn = insn;
+ end:
if (insn == end)
break;
+ if (!DEBUG_INSN_P (insn))
+ only_header_debug_insns_p = false;
insn = NEXT_INSN (insn);
}
@@ -2312,6 +2312,9 @@ label_rtx_for_bb (basic_block bb ATTRIBUTE_UNUSED)
{
glabel *lab_stmt;
+ if (is_gimple_debug (gsi_stmt (gsi)))
+ continue;
+
lab_stmt = dyn_cast <glabel *> (gsi_stmt (gsi));
if (!lab_stmt)
break;
@@ -5428,7 +5431,7 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
gimple_stmt_iterator gsi;
gimple_seq stmts;
gimple *stmt = NULL;
- rtx_note *note;
+ rtx_note *note = NULL;
rtx_insn *last;
edge e;
edge_iterator ei;
@@ -5469,18 +5472,26 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
}
}
- gsi = gsi_start (stmts);
+ gsi = gsi_start_nondebug (stmts);
if (!gsi_end_p (gsi))
{
stmt = gsi_stmt (gsi);
if (gimple_code (stmt) != GIMPLE_LABEL)
stmt = NULL;
}
+ gsi = gsi_start (stmts);
+ gimple *label_stmt = stmt;
rtx_code_label **elt = lab_rtx_for_bb->get (bb);
- if (stmt || elt)
+ if (stmt)
+ /* We'll get to it in the loop below, and get back to
+ emit_label_and_note then. */
+ ;
+ else if (stmt || elt)
{
+ emit_label_and_note:
+ gcc_checking_assert (!note);
last = get_last_insn ();
if (stmt)
@@ -5497,6 +5508,7 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
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);
@@ -5504,7 +5516,8 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
else
BB_HEAD (bb) = note = emit_note (NOTE_INSN_BASIC_BLOCK);
- NOTE_BASIC_BLOCK (note) = bb;
+ if (note)
+ NOTE_BASIC_BLOCK (note) = bb;
for (; !gsi_end_p (gsi); gsi_next (&gsi))
{
@@ -5512,6 +5525,9 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
stmt = gsi_stmt (gsi);
+ if (stmt == label_stmt)
+ goto emit_label_and_note;
+
/* 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
@@ -5617,37 +5633,81 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
if (new_bb)
return new_bb;
}
- else if (gimple_debug_bind_p (stmt))
+ else if (gimple_debug_source_bind_p (stmt))
+ {
+ location_t sloc = curr_insn_location ();
+ tree var = gimple_debug_source_bind_get_var (stmt);
+ tree value = gimple_debug_source_bind_get_value (stmt);
+ rtx val;
+ machine_mode mode;
+
+ last = get_last_insn ();
+
+ set_curr_insn_location (gimple_location (stmt));
+
+ mode = DECL_MODE (var);
+
+ val = gen_rtx_VAR_LOCATION (mode, var, (rtx)value,
+ VAR_INIT_STATUS_UNINITIALIZED);
+
+ 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. */
+ PAT_VAR_LOCATION_LOC (val) = const0_rtx;
+ maybe_dump_rtl_for_gimple_stmt (stmt, last);
+ PAT_VAR_LOCATION_LOC (val) = (rtx)value;
+ }
+
+ set_curr_insn_location (sloc);
+ }
+ else if (is_gimple_debug (stmt))
{
location_t sloc = curr_insn_location ();
gimple_stmt_iterator nsi = gsi;
for (;;)
{
- tree var = gimple_debug_bind_get_var (stmt);
+ tree var;
tree value;
rtx val;
machine_mode mode;
- if (TREE_CODE (var) != DEBUG_EXPR_DECL
- && TREE_CODE (var) != LABEL_DECL
- && !target_for_debug_bind (var))
- goto delink_debug_stmt;
+ if (gimple_debug_bind_p (stmt))
+ {
+ var = gimple_debug_bind_get_var (stmt);
- if (gimple_debug_bind_has_value_p (stmt))
- value = gimple_debug_bind_get_value (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);
+ else
+ value = NULL_TREE;
+ }
+ else if (gimple_debug_begin_stmt_p (stmt)
+ && !cfun->begin_stmt_markers)
+ goto delink_debug_stmt;
else
- value = NULL_TREE;
+ {
+ gcc_assert (gimple_debug_begin_stmt_p (stmt));
+ var = value = NULL_TREE;
+ mode = VOIDmode;
+ }
last = get_last_insn ();
set_curr_insn_location (gimple_location (stmt));
- if (DECL_P (var))
- mode = DECL_MODE (var);
- else
- mode = TYPE_MODE (TREE_TYPE (var));
-
val = gen_rtx_VAR_LOCATION
(mode, var, (rtx)value, VAR_INIT_STATUS_INITIALIZED);
@@ -5675,42 +5735,13 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
if (gsi_end_p (nsi))
break;
stmt = gsi_stmt (nsi);
- if (!gimple_debug_bind_p (stmt))
+ if (!gimple_debug_bind_p (stmt)
+ && !gimple_debug_begin_stmt_p (stmt))
break;
}
set_curr_insn_location (sloc);
}
- else if (gimple_debug_source_bind_p (stmt))
- {
- location_t sloc = curr_insn_location ();
- tree var = gimple_debug_source_bind_get_var (stmt);
- tree value = gimple_debug_source_bind_get_value (stmt);
- rtx val;
- machine_mode mode;
-
- last = get_last_insn ();
-
- set_curr_insn_location (gimple_location (stmt));
-
- mode = DECL_MODE (var);
-
- val = gen_rtx_VAR_LOCATION (mode, var, (rtx)value,
- VAR_INIT_STATUS_UNINITIALIZED);
-
- 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. */
- PAT_VAR_LOCATION_LOC (val) = const0_rtx;
- maybe_dump_rtl_for_gimple_stmt (stmt, last);
- PAT_VAR_LOCATION_LOC (val) = (rtx)value;
- }
-
- set_curr_insn_location (sloc);
- }
else
{
gcall *call_stmt = dyn_cast <gcall *> (stmt);
@@ -6349,6 +6380,11 @@ pass_expand::execute (function *fun)
FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR_FOR_FN (fun)->succs)
e->flags &= ~EDGE_EXECUTABLE;
+ /* If the function has too many markers, drop them while expanding. */
+ if (cfun->debug_marker_count
+ >= PARAM_VALUE (PARAM_MAX_DEBUG_MARKER_COUNT))
+ cfun->begin_stmt_markers = false;
+
lab_rtx_for_bb = new hash_map<basic_block, rtx_code_label *>;
FOR_BB_BETWEEN (bb, init_block->next_bb, EXIT_BLOCK_PTR_FOR_FN (fun),
next_bb)
@@ -1117,7 +1117,7 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
if (tablejump_p (insn, &label, &table))
delete_insn_chain (label, table, false);
- barrier = next_nonnote_insn (BB_END (src));
+ barrier = next_nonnote_nondebug_insn (BB_END (src));
if (!barrier || !BARRIER_P (barrier))
emit_barrier_after (BB_END (src));
else
@@ -1753,7 +1753,7 @@ rtl_tidy_fallthru_edge (edge e)
the head of block C and assert that we really do fall through. */
for (q = NEXT_INSN (BB_END (b)); q != BB_HEAD (c); q = NEXT_INSN (q))
- if (INSN_P (q))
+ if (NONDEBUG_INSN_P (q))
return;
/* Remove what will soon cease being the jump insn from the source block.
@@ -2272,11 +2272,11 @@ get_last_bb_insn (basic_block bb)
end = table;
/* Include any barriers that may follow the basic block. */
- tmp = next_nonnote_insn_bb (end);
+ tmp = next_nonnote_nondebug_insn_bb (end);
while (tmp && BARRIER_P (tmp))
{
end = tmp;
- tmp = next_nonnote_insn_bb (end);
+ tmp = next_nonnote_nondebug_insn_bb (end);
}
return end;
@@ -2893,7 +2893,7 @@ rtl_verify_fallthru (void)
else
for (insn = NEXT_INSN (BB_END (e->src)); insn != BB_HEAD (e->dest);
insn = NEXT_INSN (insn))
- if (BARRIER_P (insn) || INSN_P (insn))
+ if (BARRIER_P (insn) || NONDEBUG_INSN_P (insn))
{
error ("verify_flow_info: Incorrect fallthru %i->%i",
e->src->index, e->dest->index);
@@ -2915,7 +2915,7 @@ rtl_verify_bb_layout (void)
{
basic_block bb;
int err = 0;
- rtx_insn *x;
+ rtx_insn *x, *y;
int num_bb_notes;
rtx_insn * const rtx_first = get_insns ();
basic_block last_bb_seen = ENTRY_BLOCK_PTR_FOR_FN (cfun), curr_bb = NULL;
@@ -2942,6 +2942,7 @@ rtl_verify_bb_layout (void)
{
case BARRIER:
case NOTE:
+ case DEBUG_INSN:
break;
case CODE_LABEL:
@@ -2960,7 +2961,8 @@ rtl_verify_bb_layout (void)
if (JUMP_P (x)
&& returnjump_p (x) && ! condjump_p (x)
- && ! (next_nonnote_insn (x) && BARRIER_P (next_nonnote_insn (x))))
+ && ! ((y = next_nonnote_nondebug_insn (x))
+ && BARRIER_P (y)))
fatal_insn ("return not followed by barrier", x);
if (curr_bb && x == BB_END (curr_bb))
@@ -3381,6 +3383,9 @@ skip_insns_after_block (basic_block bb)
last_insn = insn;
continue;
+ case DEBUG_INSN:
+ continue;
+
case NOTE:
switch (NOTE_KIND (insn))
{
@@ -4133,7 +4138,8 @@ duplicate_insn_chain (rtx_insn *from, rtx_insn *to)
{
case DEBUG_INSN:
/* Don't duplicate label debug insns. */
- if (TREE_CODE (INSN_VAR_LOCATION_DECL (insn)) == LABEL_DECL)
+ if (INSN_VAR_LOCATION_DECL (insn)
+ && TREE_CODE (INSN_VAR_LOCATION_DECL (insn)) == LABEL_DECL)
break;
/* FALLTHRU */
case INSN:
@@ -2870,6 +2870,14 @@ gstabs+
Common Driver JoinedOrMissing Negative(gvms)
Generate debug information in extended STABS format.
+gno-statement-frontiers
+Common Driver RejectNegative Var(debug_statement_frontiers, 0) Init(2)
+Don't enforce progressive recommended breakpoint locations.
+
+gstatement-frontiers
+Common Driver RejectNegative Var(debug_statement_frontiers, 1)
+Emit progressive recommended breakpoint locations.
+
gno-strict-dwarf
Common Driver RejectNegative Var(dwarf_strict,0) Init(0)
Emit DWARF additions beyond selected version.
@@ -2882,6 +2890,14 @@ gtoggle
Common Driver Report Var(flag_gtoggle)
Toggle debug information generation.
+gno-variable-location-views
+Common Driver RejectNegative Var(debug_variable_location_views, 0) Init(2)
+Don't augment variable location lists with progressive views.
+
+gvariable-location-views
+Common Driver RejectNegative Var(debug_variable_location_views, 1)
+Augment variable location lists with progressive views.
+
gvms
Common Driver JoinedOrMissing Negative(gxcoff)
Generate debug information in VMS format.
@@ -352,6 +352,12 @@
#endif
+/* Define if your assembler supports views in dwarf2 .loc directives. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_AS_DWARF2_DEBUG_VIEW
+#endif
+
+
/* Define if your assembler supports the R_PPC64_ENTRY relocation. */
#ifndef USED_FOR_TARGET
#undef HAVE_AS_ENTRY_MARKERS
@@ -3958,7 +3958,7 @@ aarch64_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
insn = get_insns ();
shorten_branches (insn);
- final_start_function (insn, file, 1);
+ final_start_function (&insn, file, 1);
final (insn, file, 1);
final_end_function ();
@@ -8459,7 +8459,7 @@ alpha_output_mi_thunk_osf (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
assemble_start_function and assemble_end_function. */
insn = get_insns ();
shorten_branches (insn);
- final_start_function (insn, file, 1);
+ final_start_function (&insn, file, 1);
final (insn, file, 1);
final_end_function ();
}
@@ -26336,7 +26336,8 @@ arm_thumb1_mi_thunk (FILE *file, tree, HOST_WIDE_INT delta,
if (mi_delta < 0)
mi_delta = - mi_delta;
- final_start_function (emit_barrier (), file, 1);
+ rtx_insn *first = emit_barrier ();
+ final_start_function (&first, file, 1);
if (TARGET_THUMB1)
{
@@ -26513,7 +26514,7 @@ arm32_output_mi_thunk (FILE *file, tree, HOST_WIDE_INT delta,
insn = get_insns ();
shorten_branches (insn);
- final_start_function (insn, file, 1);
+ final_start_function (&insn, file, 1);
final (insn, file, 1);
final_end_function ();
@@ -2742,7 +2742,8 @@ cris_asm_output_mi_thunk (FILE *stream,
tree funcdecl)
{
/* Make sure unwind info is emitted for the thunk if needed. */
- final_start_function (emit_barrier (), stream, 1);
+ rtx_insn *first = emit_barrier ();
+ final_start_function (&first, stream, 1);
if (delta > 0)
fprintf (stream, "\tadd%s " HOST_WIDE_INT_PRINT_DEC ",$%s\n",
@@ -12399,8 +12399,9 @@ ix86_code_end (void)
emitting it directly; tell them we're a thunk, if they care. */
cfun->is_thunk = true;
first_function_block_is_cold = false;
+ rtx_insn *first = emit_barrier ();
/* Make sure unwind info is emitted for the thunk if needed. */
- final_start_function (emit_barrier (), asm_out_file, 1);
+ final_start_function (&first, asm_out_file, 1);
/* Pad stack IP move with 4 instructions (two NOPs count
as one instruction). */
@@ -42532,7 +42533,7 @@ x86_output_mi_thunk (FILE *file, tree, HOST_WIDE_INT delta,
Note that use_thunk calls assemble_start_function et al. */
insn = get_insns ();
shorten_branches (insn);
- final_start_function (insn, file, 1);
+ final_start_function (&insn, file, 1);
final (insn, file, 1);
final_end_function ();
}
@@ -10942,7 +10942,7 @@ ia64_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
emit_all_insn_group_barriers (NULL);
insn = get_insns ();
shorten_branches (insn);
- final_start_function (insn, file, 1);
+ final_start_function (&insn, file, 1);
final (insn, file, 1);
final_end_function ();
@@ -5129,7 +5129,7 @@ m68k_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
/* Run just enough of rest_of_compilation. */
insn = get_insns ();
split_all_insns_noflow ();
- final_start_function (insn, file, 1);
+ final_start_function (&insn, file, 1);
final (insn, file, 1);
final_end_function ();
@@ -3231,7 +3231,7 @@ microblaze_asm_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
"borrowed" from rs6000.c. */
insn = get_insns ();
shorten_branches (insn);
- final_start_function (insn, file, 1);
+ final_start_function (&insn, file, 1);
final (insn, file, 1);
final_end_function ();
@@ -19352,7 +19352,7 @@ mips_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
split_all_insns_noflow ();
mips16_lay_out_constants (true);
shorten_branches (insn);
- final_start_function (insn, file, 1);
+ final_start_function (&insn, file, 1);
final (insn, file, 1);
final_end_function ();
@@ -1633,7 +1633,8 @@ nds32_asm_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
int this_regno;
/* Make sure unwind info is emitted for the thunk if needed. */
- final_start_function (emit_barrier (), file, 1);
+ rtx_insn *first = emit_barrier ();
+ final_start_function (&first, file, 1);
this_regno = (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)
? 1
@@ -4058,7 +4058,7 @@ nios2_asm_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
assemble_start_function and assemble_end_function. */
insn = get_insns ();
shorten_branches (insn);
- final_start_function (insn, file, 1);
+ final_start_function (&insn, file, 1);
final (insn, file, 1);
final_end_function ();
@@ -8378,7 +8378,8 @@ pa_asm_output_mi_thunk (FILE *file, tree thunk_fndecl, HOST_WIDE_INT delta,
xoperands[1] = XEXP (DECL_RTL (thunk_fndecl), 0);
xoperands[2] = GEN_INT (delta);
- final_start_function (emit_barrier (), file, 1);
+ rtx_insn *first = emit_barrier ();
+ final_start_function (&first, file, 1);
/* Output the thunk. We know that the function is in the same
translation unit (i.e., the same space) as the thunk, and that
@@ -29485,7 +29485,7 @@ rs6000_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
assemble_start_function and assemble_end_function. */
insn = get_insns ();
shorten_branches (insn);
- final_start_function (insn, file, 1);
+ final_start_function (&insn, file, 1);
final (insn, file, 1);
final_end_function ();
@@ -37976,7 +37976,8 @@ rs6000_code_end (void)
init_function_start (decl);
first_function_block_is_cold = false;
/* Make sure unwind info is emitted for the thunk if needed. */
- final_start_function (emit_barrier (), asm_out_file, 1);
+ rtx_insn *first = emit_barrier ();
+ final_start_function (&first, asm_out_file, 1);
fputs ("\tblr\n", asm_out_file);
@@ -12825,7 +12825,8 @@ s390_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
int nonlocal = 0;
/* Make sure unwind info is emitted for the thunk if needed. */
- final_start_function (emit_barrier (), file, 1);
+ rtx_insn *first = emit_barrier ();
+ final_start_function (&first, file, 1);
/* Operand 0 is the target function. */
op[0] = XEXP (DECL_RTL (function), 0);
@@ -10882,7 +10882,7 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
sh_reorg ();
shorten_branches (insns);
- final_start_function (insns, file, 1);
+ final_start_function (&insns, file, 1);
final (insns, file, 1);
final_end_function ();
@@ -11694,7 +11694,7 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
assemble_start_function and assemble_end_function. */
insn = get_insns ();
shorten_branches (insn);
- final_start_function (insn, file, 1);
+ final_start_function (&insn, file, 1);
final (insn, file, 1);
final_end_function ();
@@ -7019,7 +7019,8 @@ spu_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
rtx op[8];
/* Make sure unwind info is emitted for the thunk if needed. */
- final_start_function (emit_barrier (), file, 1);
+ rtx_insn *insn = emit_barrier ();
+ final_start_function (&insn, file, 1);
/* Operand 0 is the target function. */
op[0] = XEXP (DECL_RTL (function), 0);
@@ -4998,7 +4998,7 @@ tilegx_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
*/
insn = get_insns ();
shorten_branches (insn);
- final_start_function (insn, file, 1);
+ final_start_function (&insn, file, 1);
final (insn, file, 1);
final_end_function ();
@@ -4421,7 +4421,7 @@ tilepro_asm_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
*/
insn = get_insns ();
shorten_branches (insn);
- final_start_function (insn, file, 1);
+ final_start_function (&insn, file, 1);
final (insn, file, 1);
final_end_function ();
@@ -27680,6 +27680,52 @@ $as_echo "$gcc_cv_as_dwarf2_file_buggy" >&6; }
$as_echo "#define HAVE_AS_DWARF2_DEBUG_LINE 1" >>confdefs.h
+
+ if test $gcc_cv_as_leb128 = yes; then
+ conftest_s="\
+ .file 1 \"conftest.s\"
+ .loc 1 3 0 view .LVU1
+ $insn
+ .data
+ .uleb128 .LVU1
+ .uleb128 .LVU1
+"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for dwarf2 debug_view support" >&5
+$as_echo_n "checking assembler for dwarf2 debug_view support... " >&6; }
+if test "${gcc_cv_as_dwarf2_debug_view+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ gcc_cv_as_dwarf2_debug_view=no
+ if test $in_tree_gas = yes; then
+ if test $in_tree_gas_is_elf = yes \
+ && test $gcc_cv_gas_vers -ge `expr \( \( 2 \* 1000 \) + 27 \) \* 1000 + 0`
+ then gcc_cv_as_dwarf2_debug_view=yes
+fi
+ elif test x$gcc_cv_as != x; then
+ $as_echo "$conftest_s" > conftest.s
+ if { ac_try='$gcc_cv_as $gcc_cv_as_flags -o conftest.o conftest.s >&5'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }
+ then
+ gcc_cv_as_dwarf2_debug_view=yes
+ else
+ echo "configure: failed program was" >&5
+ cat conftest.s >&5
+ fi
+ rm -f conftest.o conftest.s
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_dwarf2_debug_view" >&5
+$as_echo "$gcc_cv_as_dwarf2_debug_view" >&6; }
+if test $gcc_cv_as_dwarf2_debug_view = yes; then
+
+$as_echo "#define HAVE_AS_DWARF2_DEBUG_VIEW 1" >>confdefs.h
+
+fi
+ fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for --gdwarf2 option" >&5
@@ -4825,9 +4825,25 @@ if test x"$insn" != x; then
if test $gcc_cv_as_dwarf2_debug_line = yes \
&& test $gcc_cv_as_dwarf2_file_buggy = no; then
- AC_DEFINE(HAVE_AS_DWARF2_DEBUG_LINE, 1,
+ AC_DEFINE(HAVE_AS_DWARF2_DEBUG_LINE, 1,
[Define if your assembler supports dwarf2 .file/.loc directives,
and preserves file table indices exactly as given.])
+
+ if test $gcc_cv_as_leb128 = yes; then
+ conftest_s="\
+ .file 1 \"conftest.s\"
+ .loc 1 3 0 view .LVU1
+ $insn
+ .data
+ .uleb128 .LVU1
+ .uleb128 .LVU1
+"
+ gcc_GAS_CHECK_FEATURE([dwarf2 debug_view support],
+ gcc_cv_as_dwarf2_debug_view,
+ [elf,2,27,0],,[$conftest_s],,
+ [AC_DEFINE(HAVE_AS_DWARF2_DEBUG_VIEW, 1,
+ [Define if your assembler supports views in dwarf2 .loc directives.])])
+ fi
fi
gcc_GAS_CHECK_FEATURE([--gdwarf2 option],
@@ -306,6 +306,9 @@ build_data_member_initialization (tree t, vec<constructor_elt, va_gc> **vec)
tree_stmt_iterator i;
for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
{
+ if (TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
+ /* ??? Can we retain this information somehow? */
+ continue;
if (! build_data_member_initialization (tsi_stmt (i), vec))
return false;
}
@@ -448,6 +451,7 @@ check_constexpr_ctor_body_1 (tree last, tree list)
case USING_STMT:
case STATIC_ASSERT:
+ case DEBUG_BEGIN_STMT:
return true;
default:
@@ -586,6 +590,9 @@ build_constexpr_constructor_member_initializers (tree type, tree body)
tree_stmt_iterator i;
for (i = tsi_start (body); !tsi_end_p (i); tsi_next (&i))
{
+ if (TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
+ /* ??? Can we retain this information somehow? */
+ continue;
ok = build_data_member_initialization (tsi_stmt (i), &vec);
if (!ok)
break;
@@ -673,6 +680,7 @@ constexpr_fn_retval (tree body)
return constexpr_fn_retval (BIND_EXPR_BODY (body));
case USING_STMT:
+ case DEBUG_BEGIN_STMT:
return NULL_TREE;
default:
@@ -3765,6 +3773,8 @@ cxx_eval_statement_list (const constexpr_ctx *ctx, tree t,
for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
{
tree stmt = tsi_stmt (i);
+ if (TREE_CODE (stmt) == DEBUG_BEGIN_STMT)
+ continue;
r = cxx_eval_constant_expression (ctx, stmt, false,
non_constant_p, overflow_p,
jump_target);
@@ -5096,6 +5106,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
case CONTINUE_STMT:
case REQUIRES_EXPR:
case STATIC_ASSERT:
+ case DEBUG_BEGIN_STMT:
return true;
case AGGR_INIT_EXPR:
@@ -780,6 +780,31 @@ error:
return error_mark_node;
}
+/* Return a location associated with stmt. If it is an expresion,
+ that's the expression's location. If it is a STATEMENT_LIST,
+ instead of no location, use expr_first to skip any debug stmts and
+ take the location of the first nondebug stmt found. */
+
+static location_t
+stmt_location (tree stmt)
+{
+ location_t loc = UNKNOWN_LOCATION;
+
+ if (!stmt)
+ return loc;
+
+ loc = EXPR_LOCATION (stmt);
+
+ if (loc != UNKNOWN_LOCATION || TREE_CODE (stmt) != STATEMENT_LIST)
+ return loc;
+
+ stmt = expr_first (stmt);
+ if (stmt)
+ loc = EXPR_LOCATION (stmt);
+
+ return loc;
+}
+
/* Helper function for expand_conditonal_array_notations. Encloses the
conditional statement passed in ORIG_STMT with a loop around it and
replaces the condition in STMT with a ARRAY_REF tree-node to the array.
@@ -835,10 +860,12 @@ cp_expand_cond_array_notations (tree orig_stmt)
tree cond = IF_COND (orig_stmt);
if (!find_rank (EXPR_LOCATION (cond), cond, cond, true, &cond_rank)
|| (yes_expr
- && !find_rank (EXPR_LOCATION (yes_expr), yes_expr, yes_expr, true,
+ && !find_rank (stmt_location (yes_expr),
+ yes_expr, yes_expr, true,
&yes_rank))
|| (no_expr
- && !find_rank (EXPR_LOCATION (no_expr), no_expr, no_expr, true,
+ && !find_rank (stmt_location (no_expr),
+ no_expr, no_expr, true,
&no_rank)))
return error_mark_node;
@@ -847,13 +874,15 @@ cp_expand_cond_array_notations (tree orig_stmt)
return orig_stmt;
else if (cond_rank != yes_rank && yes_rank != 0)
{
- error_at (EXPR_LOCATION (yes_expr), "rank mismatch with controlling"
+ error_at (stmt_location (yes_expr),
+ "rank mismatch with controlling"
" expression of parent if-statement");
return error_mark_node;
}
else if (cond_rank != no_rank && no_rank != 0)
{
- error_at (EXPR_LOCATION (no_expr), "rank mismatch with controlling "
+ error_at (stmt_location (no_expr),
+ "rank mismatch with controlling "
"expression of parent if-statement");
return error_mark_node;
}
@@ -103,6 +103,8 @@ extern void cp_register_dumps (gcc::dump_manager *);
#define LANG_HOOKS_MISSING_NORETURN_OK_P cp_missing_noreturn_ok_p
#undef LANG_HOOKS_BLOCK_MAY_FALLTHRU
#define LANG_HOOKS_BLOCK_MAY_FALLTHRU cxx_block_may_fallthru
+#undef LANG_HOOKS_EMITS_BEGIN_STMT
+#define LANG_HOOKS_EMITS_BEGIN_STMT true
/* Attribute hooks. */
#undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE
@@ -10618,6 +10618,19 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
/* Statements [gram.stmt.stmt] */
+/* Build and add a DEBUG_BEGIN_STMT statement with location LOC. */
+
+static void
+add_debug_begin_stmt (location_t loc)
+{
+ if (!debug_statement_frontiers)
+ return;
+
+ tree stmt = build0 (DEBUG_BEGIN_STMT, void_type_node);
+ SET_EXPR_LOCATION (stmt, loc);
+ add_stmt (stmt);
+}
+
/* Parse a statement.
statement:
@@ -10693,6 +10706,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
token = cp_lexer_peek_token (parser->lexer);
/* Remember the location of the first token in the statement. */
statement_location = token->location;
+ add_debug_begin_stmt (statement_location);
/* If this is a keyword, then that will often determine what kind of
statement we have. */
if (token->type == CPP_KEYWORD)
@@ -15106,6 +15106,12 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
case BINARY_RIGHT_FOLD_EXPR:
return tsubst_binary_right_fold (t, args, complain, in_decl);
+ case DEBUG_BEGIN_STMT:
+ /* ??? There's no point in copying it for now, but maybe some
+ day it will contain more information, such as a pointer back
+ to the containing function, inlined copy or so. */
+ return t;
+
default:
/* We shouldn't get here, but keep going if !flag_checking. */
if (flag_checking)
@@ -6953,11 +6953,19 @@ insn_live_p (rtx_insn *insn, int *counts)
{
rtx_insn *next;
+ /* This is a debug begin stmt. */
+ if (!INSN_VAR_LOCATION_DECL (insn))
+ return true;
+
for (next = NEXT_INSN (insn); next; next = NEXT_INSN (next))
if (NOTE_P (next))
continue;
else if (!DEBUG_INSN_P (next))
return true;
+ /* If we find an inspection point, such as a debug begin stmt,
+ we want to keep the earlier debug insn. */
+ else if (!INSN_VAR_LOCATION_DECL (next))
+ return true;
else if (INSN_VAR_LOCATION_DECL (insn) == INSN_VAR_LOCATION_DECL (next))
return false;
@@ -945,7 +945,7 @@ df_insn_delete (rtx_insn *insn)
In any case, we expect BB to be non-NULL at least up to register
allocation, so disallow a non-NULL BB up to there. Not perfect
but better than nothing... */
- gcc_checking_assert (bb != NULL || reload_completed);
+ gcc_checking_assert (bb != NULL || DEBUG_INSN_P (insn) || reload_completed);
df_grow_bb_info (df_scan);
df_grow_reg_info ();
@@ -1930,6 +1930,11 @@ case 2 ... 5:
The first value will be @code{CASE_LOW}, while the second will be
@code{CASE_HIGH}.
+@item DEBUG_BEGIN_STMT
+
+Marks the beginning of a source statement, for purposes of debug
+information generation.
+
@end table
@@ -831,6 +831,11 @@ expression to a variable.
Return true if g is any of the OpenMP codes.
@end deftypefn
+@deftypefn {GIMPLE function} gimple_debug_begin_stmt_p (gimple g)
+Return true if g is a @code{GIMPLE_DEBUG} that marks the beginning of
+a source statement.
+@end deftypefn
+
@node Manipulating GIMPLE statements
@section Manipulating GIMPLE statements
@cindex Manipulating GIMPLE statements
@@ -1528,10 +1533,11 @@ Set the conditional @code{COND_STMT} to be of the form 'if (1 == 1)'.
@subsection @code{GIMPLE_DEBUG}
@cindex @code{GIMPLE_DEBUG}
@cindex @code{GIMPLE_DEBUG_BIND}
+@cindex @code{GIMPLE_DEBUG_BEGIN_STMT}
@deftypefn {GIMPLE function} gdebug *gimple_build_debug_bind (tree var, @
tree value, gimple stmt)
-Build a @code{GIMPLE_DEBUG} statement with @code{GIMPLE_DEBUG_BIND} of
+Build a @code{GIMPLE_DEBUG} statement with @code{GIMPLE_DEBUG_BIND}
@code{subcode}. The effect of this statement is to tell debug
information generation machinery that the value of user variable
@code{var} is given by @code{value} at that point, and to remain with
@@ -1602,6 +1608,14 @@ Return @code{TRUE} if @code{stmt} binds a user variable to a value,
and @code{FALSE} if it unbinds the variable.
@end deftypefn
+@deftypefn {GIMPLE function} gimple gimple_build_debug_begin_stmt (tree block, location_t location)
+Build a @code{GIMPLE_DEBUG} statement with
+@code{GIMPLE_DEBUG_BEGIN_STMT} @code{subcode}. The effect of this
+statement is to tell debug information generation machinery that the
+user statement at the given @code{location} and @code{block} starts at
+the point at which the statement is inserted.
+@end deftypefn
+
@node @code{GIMPLE_EH_FILTER}
@subsection @code{GIMPLE_EH_FILTER}
@cindex @code{GIMPLE_EH_FILTER}
@@ -344,10 +344,12 @@ Objective-C and Objective-C++ Dialects}.
-ggdb -grecord-gcc-switches -gno-record-gcc-switches @gol
-gstabs -gstabs+ -gstrict-dwarf -gno-strict-dwarf @gol
-gcolumn-info -gno-column-info @gol
--gvms -gxcoff -gxcoff+ -gz@r{[}=@var{type}@r{]} @gol
--fdebug-prefix-map=@var{old}=@var{new} -fdebug-types-section @gol
--feliminate-dwarf2-dups -fno-eliminate-unused-debug-types @gol
--femit-struct-debug-baseonly -femit-struct-debug-reduced @gol
+-gstatement-frontiers -gno-statement-frontiers @gol
+-gvariable-location-views -gno-variable-location-views @gol
+-gvms -gxcoff -gxcoff+ -gz@r{[}=@var{type}@r{]} @gol
+-fdebug-prefix-map=@var{old}=@var{new} -fdebug-types-section @gol
+-feliminate-dwarf2-dups -fno-eliminate-unused-debug-types @gol
+-femit-struct-debug-baseonly -femit-struct-debug-reduced @gol
-femit-struct-debug-detailed@r{[}=@var{spec-list}@r{]} @gol
-feliminate-unused-debug-symbols -femit-class-debug-always @gol
-fno-merge-debug-strings -fno-dwarf2-cfi-asm @gol
@@ -6987,6 +6989,35 @@ Emit location column information into DWARF debugging information, rather
than just file and line.
This option is disabled by default.
+@item -gstatement-frontiers
+@item -gno-statement-frontiers
+@opindex gstatement-frontiers
+@opindex gno-statement-frontiers
+This option causes GCC to create markers in the internal representation
+at the beginning of statements, and to keep them roughly in place
+throughout compilation, using them to guide the output of @code{is_stmt}
+markers in the line number table. This is enabled by default when
+compiling with optimization (@option{-Os}, @option{-O}, @option{-O2},
+@dots{}), and outputting DWARF 2 debug information at the normal level.
+
+@item -gvariable-location-views
+@item -gno-variable-location-views
+@opindex gvariable-location-views
+@opindex gno-variable-location-views
+Augment variable location lists with progressive view numbers implied
+from the line number table. This enables debug information consumers to
+inspect state at certain points of the program, even if no instructions
+associated with the corresponding source locations are present at that
+point. If the assembler lacks support for view numbers in line number
+tables, this will cause the compiler to emit the line number table,
+which generally makes them somewhat less compact. The augmented line
+number tables and location lists are fully backward-compatible, so they
+can be consumed by debug information consumers that are not aware of
+these augmentations, but they won't derive any benefit from them either.
+This is enabled by default when outputting DWARF 2 debug information at
+the normal level, as long as @code{-fvar-tracking-assignments} is
+enabled and @code{-gstrict-dwarf} is not.
+
@item -gz@r{[}=@var{type}@r{]}
@opindex gz
Produce compressed debug sections in DWARF format, if that is supported.
@@ -10406,6 +10437,13 @@ debug information may end up not being used; setting this higher may
enable the compiler to find more complex debug expressions, but compile
time and memory use may grow. The default is 12.
+@item max-debug-marker-count
+Sets a threshold on the number of debug markers (e.g. begin stmt
+markers) to avoid complexity explosion at inlining or expanding to RTL.
+If a function has more such gimple stmts than the set limit, such stmts
+will be dropped from the inlined copy of a function, and from its RTL
+expansion. The default is 100000.
+
@item min-nondebug-insn-uid
Use uids starting at this parameter for nondebug insns. The range below
the parameter is reserved exclusively for debug insns created by
@@ -3689,6 +3689,12 @@ can be computed by evaluating the RTL expression from that static
point in the program up to the next such note for the same user
variable.
+@findex NOTE_INSN_BEGIN_STMT
+@item NOTE_INSN_BEGIN_STMT
+This note is used to generate @code{is_stmt} markers in line number
+debuggign information. It indicates the beginning of a user
+statement.
+
@end table
These codes are printed symbolically when they appear in debugging dumps.
@@ -3704,17 +3710,22 @@ representation of @code{GIMPLE_DEBUG} statements
binds a user variable tree to an RTL representation of the
@code{value} in the corresponding statement. A @code{DEBUG_EXPR} in
it stands for the value bound to the corresponding
-@code{DEBUG_EXPR_DECL}.
-
-Throughout optimization passes, binding information is kept in
-pseudo-instruction form, so that, unlike notes, it gets the same
-treatment and adjustments that regular instructions would. It is the
-variable tracking pass that turns these pseudo-instructions into var
-location notes, analyzing control flow, value equivalences and changes
-to registers and memory referenced in value expressions, propagating
-the values of debug temporaries and determining expressions that can
-be used to compute the value of each user variable at as many points
-(ranges, actually) in the program as possible.
+@code{DEBUG_EXPR_DECL}. A @code{GIMPLE_DEBUG_BEGIN_STMT} is expanded
+to RTL as a @code{DEBUG_INSN} with a @code{NULL_TREE} in
+@code{INSN_VAR_LOCATION_DECL}.
+
+Throughout optimization passes, @code{DEBUG_INSN}s are not reordered
+with respect to each other, particularly during scheduling. Binding
+information is kept in pseudo-instruction form, so that, unlike notes,
+it gets the same treatment and adjustments that regular instructions
+would. It is the variable tracking pass that turns these
+pseudo-instructions into @code{NOTE_INSN_VAR_LOCATION} and
+@code{NOTE_INSN_BEGIN_STMT} notes, analyzing control flow, value
+equivalences and changes to registers and memory referenced in value
+expressions, propagating the values of debug temporaries and
+determining expressions that can be used to compute the value of each
+user variable at as many points (ranges, actually) in the program as
+possible.
Unlike @code{NOTE_INSN_VAR_LOCATION}, the value expression in an
@code{INSN_VAR_LOCATION} denotes a value at that specific point in the
@@ -766,6 +766,31 @@ dw2_asm_output_data_sleb128 (HOST_WIDE_INT value,
}
void
+dw2_asm_output_symname_uleb128 (const char *lab1 ATTRIBUTE_UNUSED,
+ const char *comment, ...)
+{
+ va_list ap;
+
+ va_start (ap, comment);
+
+#ifdef HAVE_AS_LEB128
+ fputs ("\t.uleb128 ", asm_out_file);
+ assemble_name (asm_out_file, lab1);
+#else
+ gcc_unreachable ();
+#endif
+
+ if (flag_debug_asm && comment)
+ {
+ fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
+ vfprintf (asm_out_file, comment, ap);
+ }
+ fputc ('\n', asm_out_file);
+
+ va_end (ap);
+}
+
+void
dw2_asm_output_delta_uleb128 (const char *lab1 ATTRIBUTE_UNUSED,
const char *lab2 ATTRIBUTE_UNUSED,
const char *comment, ...)
@@ -70,6 +70,10 @@ extern void dw2_asm_output_data_sleb128 (HOST_WIDE_INT,
const char *, ...)
ATTRIBUTE_NULL_PRINTF_2;
+extern void dw2_asm_output_symname_uleb128 (const char *,
+ const char *, ...)
+ ATTRIBUTE_NULL_PRINTF_2;
+
extern void dw2_asm_output_delta_uleb128 (const char *, const char *,
const char *, ...)
ATTRIBUTE_NULL_PRINTF_3;
@@ -83,6 +83,7 @@ along with GCC; see the file COPYING3. If not see
#include "toplev.h"
#include "md5.h"
#include "tree-pretty-print.h"
+#include "print-rtl.h"
#include "debug.h"
#include "common/common-target.h"
#include "langhooks.h"
@@ -1272,6 +1273,8 @@ struct GTY((for_user)) addr_table_entry {
GTY ((desc ("%1.kind"))) addr;
};
+typedef unsigned int var_loc_view;
+
/* Location lists are ranges + location descriptions for that range,
so you can track variables that are in different places over
their entire life. */
@@ -1281,9 +1284,11 @@ typedef struct GTY(()) dw_loc_list_struct {
addr_table_entry *begin_entry;
const char *end; /* Label for end of range */
char *ll_symbol; /* Label for beginning of location list.
- Only on head of list */
+ Only on head of list. */
+ char *vl_symbol; /* Label for beginning of view list. Ditto. */
const char *section; /* Section this loclist is relative to */
dw_loc_descr_ref expr;
+ var_loc_view vbegin, vend;
hashval_t hash;
/* True if all addresses in this and subsequent lists are known to be
resolved. */
@@ -1320,6 +1325,31 @@ dwarf_stack_op_name (unsigned int op)
return "OP_<unknown>";
}
+/* Return TRUE iff we're to output location view lists as a separate
+ attribute next to the location lists, as an extension compatible
+ with DWARF 2 and above. */
+
+static inline bool
+dwarf2out_locviews_in_attribute ()
+{
+ return debug_variable_location_views
+ && dwarf_version <= 5;
+}
+
+/* Return TRUE iff we're to output location view lists as part of the
+ location lists, as proposed for standardization after DWARF 5. */
+
+static inline bool
+dwarf2out_locviews_in_loclist ()
+{
+#ifndef DW_LLE_view_pair
+ return false;
+#else
+ return debug_variable_location_views
+ && dwarf_version >= 6;
+#endif
+}
+
/* Return a pointer to a newly allocated location description. Location
descriptions are simple expression terms that can be strung
together to form more complicated location (address) descriptions. */
@@ -1395,6 +1425,8 @@ dw_val_equal_p (dw_val_node *a, dw_val_node *b)
return a->v.val_loc == b->v.val_loc;
case dw_val_class_loc_list:
return a->v.val_loc_list == b->v.val_loc_list;
+ case dw_val_class_view_list:
+ return a->v.val_view_list == b->v.val_view_list;
case dw_val_class_die_ref:
return a->v.val_die_ref.die == b->v.val_die_ref.die;
case dw_val_class_fde_ref:
@@ -2832,7 +2864,15 @@ enum dw_line_info_opcode {
LI_set_epilogue_begin,
/* Emit a DW_LNE_set_discriminator. */
- LI_set_discriminator
+ LI_set_discriminator,
+
+ /* Output a Fixed Advance PC; the target PC is the label index; the
+ base PC is the previous LI_adv_address or LI_set_address entry.
+ We only use this when emitting debug views without assembler
+ support, at explicit user request. Ideally, we should only use
+ it when the offset might be zero but we can't tell: it's the only
+ way to maybe change the PC without resetting the view number. */
+ LI_adv_address
};
typedef struct GTY(()) dw_line_info_struct {
@@ -2854,6 +2894,25 @@ struct GTY(()) dw_line_info_table {
bool is_stmt;
bool in_use;
+ /* This denotes the NEXT view number.
+
+ If it is 0, it is known that the NEXT view will be the first view
+ at the given PC.
+
+ If it is -1, we've advanced PC but we haven't emitted a line location yet,
+ so we shouldn't use this view number.
+
+ The meaning of other nonzero values depends on whether we're
+ computing views internally or leaving it for the assembler to do
+ so. If we're emitting them internally, view denotes the view
+ number since the last known advance of PC. If we're leaving it
+ for the assembler, it denotes the LVU label number that we're
+ going to ask the assembler to assign. */
+ var_loc_view view;
+
+#define RESET_NEXT_VIEW(x) ((x) = (var_loc_view)0)
+#define RESETTING_VIEW_P(x) ((x) == (var_loc_view)0)
+
vec<dw_line_info_entry, va_gc> *entries;
};
@@ -3052,6 +3111,41 @@ skeleton_chain_node;
#endif
#endif
+/* Use assembler views in line directives if available. */
+#ifndef DWARF2_ASM_VIEW_DEBUG_INFO
+#ifdef HAVE_AS_DWARF2_DEBUG_VIEW
+#define DWARF2_ASM_VIEW_DEBUG_INFO 1
+#else
+#define DWARF2_ASM_VIEW_DEBUG_INFO 0
+#endif
+#endif
+
+/* A bit is set in ZERO_VIEW_P if we are using the assembler-supported
+ view computation, and it is refers to a view identifier for which
+ will not emit a label because it is known to map to a view number
+ zero. We won't allocate the bitmap if we're not using assembler
+ support for location views, but we have to make the variable
+ visible for GGC and for code that will be optimized out for lack of
+ support but that's still parsed and compiled. We could abstract it
+ out with macros, but it's not worth it. */
+static GTY(()) bitmap zero_view_p;
+
+/* Evaluate to TRUE iff N is known to identify the first location view
+ at its PC. When not using assembler location view computation,
+ that must be view number zero. Otherwise, ZERO_VIEW_P is allocated
+ and views label numbers recorded in it are the ones known to be
+ zero. */
+#define ZERO_VIEW_P(N) (zero_view_p \
+ ? bitmap_bit_p (zero_view_p, (N)) \
+ : (N) == 0)
+
+static bool
+output_asm_line_debug_info (void)
+{
+ return DWARF2_ASM_VIEW_DEBUG_INFO
+ || (DWARF2_ASM_LINE_DEBUG_INFO && !debug_variable_location_views);
+}
+
/* Minimum line offset in a special line info. opcode.
This value was chosen to give a reasonable range of values. */
#define DWARF_LINE_BASE -10
@@ -3161,6 +3255,7 @@ struct GTY ((chain_next ("%h.next"))) var_loc_node {
rtx GTY (()) loc;
const char * GTY (()) label;
struct var_loc_node * GTY (()) next;
+ var_loc_view view;
};
/* Variable location list. */
@@ -3369,6 +3464,8 @@ static inline dw_loc_descr_ref AT_loc (dw_attr_node *);
static void add_AT_loc_list (dw_die_ref, enum dwarf_attribute,
dw_loc_list_ref);
static inline dw_loc_list_ref AT_loc_list (dw_attr_node *);
+static void add_AT_view_list (dw_die_ref, enum dwarf_attribute);
+static inline dw_loc_list_ref AT_loc_list (dw_attr_node *);
static addr_table_entry *add_addr_table_entry (void *, enum ate_kind);
static void remove_addr_table_entry (addr_table_entry *);
static void add_AT_addr (dw_die_ref, enum dwarf_attribute, rtx, bool);
@@ -3405,7 +3502,7 @@ static void equate_type_number_to_die (tree, dw_die_ref);
static dw_die_ref lookup_decl_die (tree);
static var_loc_list *lookup_decl_loc (const_tree);
static void equate_decl_number_to_die (tree, dw_die_ref);
-static struct var_loc_node *add_var_loc_to_decl (tree, rtx, const char *);
+static struct var_loc_node *add_var_loc_to_decl (tree, rtx, const char *, var_loc_view);
static void print_spaces (FILE *);
static void print_die (dw_die_ref, FILE *);
static dw_die_ref push_new_compile_unit (dw_die_ref, dw_die_ref);
@@ -3613,8 +3710,8 @@ static void gen_tagged_type_die (tree, dw_die_ref, enum debug_info_usage);
static void gen_type_die_with_usage (tree, dw_die_ref, enum debug_info_usage);
static void splice_child_die (dw_die_ref, dw_die_ref);
static int file_info_cmp (const void *, const void *);
-static dw_loc_list_ref new_loc_list (dw_loc_descr_ref, const char *,
- const char *, const char *);
+static dw_loc_list_ref new_loc_list (dw_loc_descr_ref, const char *, var_loc_view,
+ const char *, var_loc_view, const char *);
static void output_loc_list (dw_loc_list_ref);
static char *gen_internal_sym (const char *);
static bool want_pubnames (void);
@@ -4536,11 +4633,55 @@ AT_loc_list (dw_attr_node *a)
return a->dw_attr_val.v.val_loc_list;
}
+static inline void
+add_AT_view_list (dw_die_ref die, enum dwarf_attribute attr_kind)
+{
+ dw_attr_node attr;
+
+ if (XCOFF_DEBUGGING_INFO && !HAVE_XCOFF_DWARF_EXTRAS)
+ return;
+
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_view_list;
+ attr.dw_attr_val.val_entry = NULL;
+ attr.dw_attr_val.v.val_view_list = die;
+ add_dwarf_attr (die, &attr);
+ gcc_checking_assert (get_AT (die, DW_AT_location));
+ gcc_assert (have_location_lists);
+}
+
static inline dw_loc_list_ref *
AT_loc_list_ptr (dw_attr_node *a)
{
- gcc_assert (a && AT_class (a) == dw_val_class_loc_list);
- return &a->dw_attr_val.v.val_loc_list;
+ gcc_assert (a);
+ switch (AT_class (a))
+ {
+ case dw_val_class_loc_list:
+ return &a->dw_attr_val.v.val_loc_list;
+ case dw_val_class_view_list:
+ {
+ dw_attr_node *l;
+ l = get_AT (a->dw_attr_val.v.val_view_list, DW_AT_location);
+ if (!l)
+ return NULL;
+ gcc_checking_assert (l + 1 == a);
+ return AT_loc_list_ptr (l);
+ }
+ default:
+ gcc_unreachable ();
+ }
+}
+
+static inline dw_val_node *
+view_list_to_loc_list_val_node (dw_val_node *val)
+{
+ gcc_assert (val->val_class == dw_val_class_view_list);
+ dw_attr_node *loc = get_AT (val->v.val_view_list, DW_AT_location);
+ if (!loc)
+ return NULL;
+ gcc_checking_assert (&(loc + 1)->dw_attr_val == val);
+ gcc_assert (AT_class (loc) == dw_val_class_loc_list);
+ return &loc->dw_attr_val;
}
struct addr_hasher : ggc_ptr_hash<addr_table_entry>
@@ -5612,7 +5753,7 @@ adjust_piece_list (rtx *dest, rtx *src, rtx *inner,
/* Add a variable location node to the linked list for DECL. */
static struct var_loc_node *
-add_var_loc_to_decl (tree decl, rtx loc_note, const char *label)
+add_var_loc_to_decl (tree decl, rtx loc_note, const char *label, var_loc_view view)
{
unsigned int decl_id;
var_loc_list *temp;
@@ -5703,7 +5844,7 @@ add_var_loc_to_decl (tree decl, rtx loc_note, const char *label)
/* TEMP->LAST here is either pointer to the last but one or
last element in the chained list, LAST is pointer to the
last element. */
- if (label && strcmp (last->label, label) == 0)
+ if (label && strcmp (last->label, label) == 0 && last->view == view)
{
/* For SRA optimized variables if there weren't any real
insns since last note, just modify the last node. */
@@ -5719,7 +5860,7 @@ add_var_loc_to_decl (tree decl, rtx loc_note, const char *label)
temp->last->next = NULL;
unused = last;
last = temp->last;
- gcc_assert (strcmp (last->label, label) != 0);
+ gcc_assert (strcmp (last->label, label) != 0 || last->view != view);
}
else
{
@@ -5854,6 +5995,12 @@ print_dw_val (dw_val_node *val, bool recurse, FILE *outfile)
fprintf (outfile, "location list -> label:%s",
val->v.val_loc_list->ll_symbol);
break;
+ case dw_val_class_view_list:
+ val = view_list_to_loc_list_val_node (val);
+ fprintf (outfile, "location list with views -> labels:%s and %s",
+ val->v.val_loc_list->ll_symbol,
+ val->v.val_loc_list->vl_symbol);
+ break;
case dw_val_class_range_list:
fprintf (outfile, "range list");
break;
@@ -8953,6 +9100,7 @@ size_of_die (dw_die_ref die)
}
break;
case dw_val_class_loc_list:
+ case dw_val_class_view_list:
if (dwarf_split_debug_info && dwarf_version >= 5)
{
gcc_assert (AT_loc_list (a)->num_assigned);
@@ -9324,6 +9472,7 @@ value_format (dw_attr_node *a)
gcc_unreachable ();
}
case dw_val_class_loc_list:
+ case dw_val_class_view_list:
if (dwarf_split_debug_info
&& dwarf_version >= 5
&& AT_loc_list (a)->num_assigned)
@@ -9619,7 +9768,8 @@ output_die_symbol (dw_die_ref die)
expression. */
static inline dw_loc_list_ref
-new_loc_list (dw_loc_descr_ref expr, const char *begin, const char *end,
+new_loc_list (dw_loc_descr_ref expr, const char *begin, var_loc_view vbegin,
+ const char *end, var_loc_view vend,
const char *section)
{
dw_loc_list_ref retlist = ggc_cleared_alloc<dw_loc_list_node> ();
@@ -9629,10 +9779,28 @@ new_loc_list (dw_loc_descr_ref expr, const char *begin, const char *end,
retlist->end = end;
retlist->expr = expr;
retlist->section = section;
+ retlist->vbegin = vbegin;
+ retlist->vend = vend;
return retlist;
}
+/* Return true iff there's any nonzero view number in the loc list. */
+
+static bool
+loc_list_has_views (dw_loc_list_ref list)
+{
+ if (!debug_variable_location_views)
+ return false;
+
+ for (dw_loc_list_ref loc = list;
+ loc != NULL; loc = loc->dw_loc_next)
+ if (!ZERO_VIEW_P (loc->vbegin) || !ZERO_VIEW_P (loc->vend))
+ return true;
+
+ return false;
+}
+
/* Generate a new internal symbol for this location list node, if it
hasn't got one yet. */
@@ -9641,6 +9809,94 @@ gen_llsym (dw_loc_list_ref list)
{
gcc_assert (!list->ll_symbol);
list->ll_symbol = gen_internal_sym ("LLST");
+
+ if (!loc_list_has_views (list))
+ return;
+
+ if (dwarf2out_locviews_in_attribute ())
+ {
+ /* Use the same label_num for the view list. */
+ label_num--;
+ list->vl_symbol = gen_internal_sym ("LVUS");
+ }
+ else
+ list->vl_symbol = list->ll_symbol;
+}
+
+/* Generate a symbol for the list, but only if we really want to emit
+ it as a list. */
+
+static inline void
+maybe_gen_llsym (dw_loc_list_ref list)
+{
+ if (!list || (!list->dw_loc_next && !loc_list_has_views (list)))
+ return;
+
+ gen_llsym (list);
+}
+
+/* Determine whether or not to skip loc_list entry CURR. If we're not
+ to skip it, and SIZEP is non-null, store the size of CURR->expr's
+ representation in *SIZEP. */
+
+static bool
+skip_loc_list_entry (dw_loc_list_ref curr, unsigned long *sizep = 0)
+{
+ /* Don't output an entry that starts and ends at the same address. */
+ if (strcmp (curr->begin, curr->end) == 0
+ && curr->vbegin == curr->vend && !curr->force)
+ return true;
+
+ unsigned long size = size_of_locs (curr->expr);
+
+ /* If the expression is too large, drop it on the floor. We could
+ perhaps put it into DW_TAG_dwarf_procedure and refer to that
+ in the expression, but >= 64KB expressions for a single value
+ in a single range are unlikely very useful. */
+ if (dwarf_version < 5 && size > 0xffff)
+ return true;
+
+ if (sizep)
+ *sizep = size;
+
+ return false;
+}
+
+/* Output a view pair loclist entry for CURR, if it requires one. */
+
+static void
+dwarf2out_maybe_output_loclist_view_pair (dw_loc_list_ref curr)
+{
+ if (!dwarf2out_locviews_in_loclist ())
+ return;
+
+ if (ZERO_VIEW_P (curr->vbegin) && ZERO_VIEW_P (curr->vend))
+ return;
+
+#ifdef DW_LLE_view_pair
+ dw2_asm_output_data (1, DW_LLE_view_pair,
+ "DW_LLE_view_pair");
+
+ if (ZERO_VIEW_P (curr->vbegin))
+ dw2_asm_output_data_uleb128 (0, "Location view begin");
+ else
+ {
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+ ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vbegin);
+ dw2_asm_output_symname_uleb128 (label, "Location view begin");
+ }
+
+ if (ZERO_VIEW_P (curr->vend))
+ dw2_asm_output_data_uleb128 (0, "Location view end");
+ else
+ {
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+ ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vend);
+ dw2_asm_output_symname_uleb128 (label, "Location view end");
+ }
+#endif
+
+ return;
}
/* Output the location list given to us. */
@@ -9648,34 +9904,85 @@ gen_llsym (dw_loc_list_ref list)
static void
output_loc_list (dw_loc_list_ref list_head)
{
+ int vcount = 0, lcount = 0;
+
if (list_head->emitted)
return;
list_head->emitted = true;
+ if (list_head->vl_symbol && dwarf2out_locviews_in_attribute ())
+ {
+ ASM_OUTPUT_LABEL (asm_out_file, list_head->vl_symbol);
+
+ for (dw_loc_list_ref curr = list_head; curr != NULL;
+ curr = curr->dw_loc_next)
+ {
+ if (skip_loc_list_entry (curr))
+ continue;
+
+ vcount++;
+
+ /* ?? dwarf_split_debug_info? */
+#if DWARF2_ASM_VIEW_DEBUG_INFO
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+
+ if (!ZERO_VIEW_P (curr->vbegin))
+ {
+ ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vbegin);
+ dw2_asm_output_symname_uleb128 (label,
+ "View list begin (%s)",
+ list_head->vl_symbol);
+ }
+ else
+ dw2_asm_output_data_uleb128 (0,
+ "View list begin (%s)",
+ list_head->vl_symbol);
+
+ if (!ZERO_VIEW_P (curr->vend))
+ {
+ ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vend);
+ dw2_asm_output_symname_uleb128 (label,
+ "View list end (%s)",
+ list_head->vl_symbol);
+ }
+ else
+ dw2_asm_output_data_uleb128 (0,
+ "View list end (%s)",
+ list_head->vl_symbol);
+#else /* !DWARF2_ASM_VIEW_DEBUG_INFO */
+ dw2_asm_output_data_uleb128 (curr->vbegin,
+ "View list begin (%s)",
+ list_head->vl_symbol);
+ dw2_asm_output_data_uleb128 (curr->vend,
+ "View list end (%s)",
+ list_head->vl_symbol);
+#endif
+ }
+ }
+
ASM_OUTPUT_LABEL (asm_out_file, list_head->ll_symbol);
- dw_loc_list_ref curr = list_head;
const char *last_section = NULL;
const char *base_label = NULL;
/* Walk the location list, and output each range + expression. */
- for (curr = list_head; curr != NULL; curr = curr->dw_loc_next)
+ for (dw_loc_list_ref curr = list_head; curr != NULL;
+ curr = curr->dw_loc_next)
{
unsigned long size;
- /* Don't output an entry that starts and ends at the same address. */
- if (strcmp (curr->begin, curr->end) == 0 && !curr->force)
- continue;
- size = size_of_locs (curr->expr);
- /* If the expression is too large, drop it on the floor. We could
- perhaps put it into DW_TAG_dwarf_procedure and refer to that
- in the expression, but >= 64KB expressions for a single value
- in a single range are unlikely very useful. */
- if (dwarf_version < 5 && size > 0xffff)
+
+ /* Skip this entry? If we skip it here, we must skip it in the
+ view list above as well. */
+ if (skip_loc_list_entry (curr, &size))
continue;
+
+ lcount++;
+
if (dwarf_version >= 5)
{
if (dwarf_split_debug_info)
{
+ dwarf2out_maybe_output_loclist_view_pair (curr);
/* For -gsplit-dwarf, emit DW_LLE_starx_length, which has
uleb128 index into .debug_addr and uleb128 length. */
dw2_asm_output_data (1, DW_LLE_startx_length,
@@ -9693,6 +10000,7 @@ output_loc_list (dw_loc_list_ref list_head)
}
else if (!have_multiple_function_sections && HAVE_AS_LEB128)
{
+ dwarf2out_maybe_output_loclist_view_pair (curr);
/* If all code is in .text section, the base address is
already provided by the CU attributes. Use
DW_LLE_offset_pair where both addresses are uleb128 encoded
@@ -9743,6 +10051,7 @@ output_loc_list (dw_loc_list_ref list_head)
length. */
if (last_section == NULL)
{
+ dwarf2out_maybe_output_loclist_view_pair (curr);
dw2_asm_output_data (1, DW_LLE_start_length,
"DW_LLE_start_length (%s)",
list_head->ll_symbol);
@@ -9757,6 +10066,7 @@ output_loc_list (dw_loc_list_ref list_head)
DW_LLE_base_address. */
else
{
+ dwarf2out_maybe_output_loclist_view_pair (curr);
dw2_asm_output_data (1, DW_LLE_offset_pair,
"DW_LLE_offset_pair (%s)",
list_head->ll_symbol);
@@ -9772,6 +10082,7 @@ output_loc_list (dw_loc_list_ref list_head)
DW_LLE_start_end with a pair of absolute addresses. */
else
{
+ dwarf2out_maybe_output_loclist_view_pair (curr);
dw2_asm_output_data (1, DW_LLE_start_end,
"DW_LLE_start_end (%s)",
list_head->ll_symbol);
@@ -9850,6 +10161,9 @@ output_loc_list (dw_loc_list_ref list_head)
"Location list terminator end (%s)",
list_head->ll_symbol);
}
+
+ gcc_assert (!list_head->vl_symbol
+ || vcount == lcount * (dwarf2out_locviews_in_attribute () ? 1 : 0));
}
/* Output a range_list offset into the .debug_ranges or .debug_rnglists
@@ -9914,6 +10228,22 @@ output_loc_list_offset (dw_attr_node *a)
"%s", dwarf_attr_name (a->dw_attr));
}
+/* Output the offset into the debug_loc section. */
+
+static void
+output_view_list_offset (dw_attr_node *a)
+{
+ char *sym = (*AT_loc_list_ptr (a))->vl_symbol;
+
+ gcc_assert (sym);
+ if (dwarf_split_debug_info)
+ dw2_asm_output_delta (DWARF_OFFSET_SIZE, sym, loc_section_label,
+ "%s", dwarf_attr_name (a->dw_attr));
+ else
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, debug_loc_section,
+ "%s", dwarf_attr_name (a->dw_attr));
+}
+
/* Output an attribute's index or value appropriately. */
static void
@@ -10144,6 +10474,10 @@ output_die (dw_die_ref die)
output_loc_list_offset (a);
break;
+ case dw_val_class_view_list:
+ output_view_list_offset (a);
+ break;
+
case dw_val_class_die_ref:
if (AT_ref_external (a))
{
@@ -11797,8 +12131,11 @@ output_one_line_info_table (dw_line_info_table *table)
char line_label[MAX_ARTIFICIAL_LABEL_BYTES];
unsigned int current_line = 1;
bool current_is_stmt = DWARF_LINE_DEFAULT_IS_STMT_START;
- dw_line_info_entry *ent;
+ dw_line_info_entry *ent, *prev_addr;
size_t i;
+ unsigned int view;
+
+ view = 0;
FOR_EACH_VEC_SAFE_ELT (table->entries, i, ent)
{
@@ -11813,14 +12150,36 @@ output_one_line_info_table (dw_line_info_table *table)
to determine when it is safe to use DW_LNS_fixed_advance_pc. */
ASM_GENERATE_INTERNAL_LABEL (line_label, LINE_CODE_LABEL, ent->val);
+ view = 0;
+
/* This can handle any delta. This takes
4+DWARF2_ADDR_SIZE bytes. */
- dw2_asm_output_data (1, 0, "set address %s", line_label);
+ dw2_asm_output_data (1, 0, "set address %s%s", line_label,
+ debug_variable_location_views
+ ? ", reset view to 0" : "");
dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
dw2_asm_output_data (1, DW_LNE_set_address, NULL);
dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
+
+ prev_addr = ent;
break;
+ case LI_adv_address:
+ {
+ ASM_GENERATE_INTERNAL_LABEL (line_label, LINE_CODE_LABEL, ent->val);
+ char prev_label[MAX_ARTIFICIAL_LABEL_BYTES];
+ ASM_GENERATE_INTERNAL_LABEL (prev_label, LINE_CODE_LABEL, prev_addr->val);
+
+ view++;
+
+ dw2_asm_output_data (1, DW_LNS_fixed_advance_pc, "fixed advance PC, increment view to %i", view);
+ dw2_asm_output_delta (2, line_label, prev_label,
+ "from %s to %s", prev_label, line_label);
+
+ prev_addr = ent;
+ break;
+ }
+
case LI_set_line:
if (ent->val == current_line)
{
@@ -16212,6 +16571,7 @@ static dw_loc_list_ref
dw_loc_list (var_loc_list *loc_list, tree decl, int want_address)
{
const char *endname, *secname;
+ var_loc_view endview;
rtx varloc;
enum var_init_status initialized;
struct var_loc_node *node;
@@ -16267,24 +16627,27 @@ dw_loc_list (var_loc_list *loc_list, tree decl, int want_address)
&& current_function_decl)
{
endname = cfun->fde->dw_fde_end;
+ endview = 0;
range_across_switch = true;
}
/* The variable has a location between NODE->LABEL and
NODE->NEXT->LABEL. */
else if (node->next)
- endname = node->next->label;
+ endname = node->next->label, endview = node->next->view;
/* If the variable has a location at the last label
it keeps its location until the end of function. */
else if (!current_function_decl)
- endname = text_end_label;
+ endname = text_end_label, endview = 0;
else
{
ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
current_function_funcdef_no);
endname = ggc_strdup (label_id);
+ endview = 0;
}
- *listp = new_loc_list (descr, node->label, endname, secname);
+ *listp = new_loc_list (descr, node->label, node->view,
+ endname, endview, secname);
if (TREE_CODE (decl) == PARM_DECL
&& node == loc_list->first
&& NOTE_P (node->loc)
@@ -16307,12 +16670,12 @@ dw_loc_list (var_loc_list *loc_list, tree decl, int want_address)
/* The variable has a location between NODE->LABEL and
NODE->NEXT->LABEL. */
if (node->next)
- endname = node->next->label;
+ endname = node->next->label, endview = node->next->view;
else
- endname = cfun->fde->dw_fde_second_end;
+ endname = cfun->fde->dw_fde_second_end, endview = 0;
*listp = new_loc_list (descr,
- cfun->fde->dw_fde_second_begin,
- endname, secname);
+ cfun->fde->dw_fde_second_begin, 0,
+ endname, endview, secname);
listp = &(*listp)->dw_loc_next;
}
}
@@ -16324,8 +16687,7 @@ dw_loc_list (var_loc_list *loc_list, tree decl, int want_address)
representable, we don't want to pretend a single entry that was
applies to the entire scope in which the variable is
available. */
- if (list && loc_list->first->next)
- gen_llsym (list);
+ maybe_gen_llsym (list);
return list;
}
@@ -17145,7 +17507,7 @@ loc_list_from_tree_1 (tree loc, int want_address,
{
if (dwarf_version >= 3 || !dwarf_strict)
return new_loc_list (new_loc_descr (DW_OP_push_object_address, 0, 0),
- NULL, NULL, NULL);
+ NULL, 0, NULL, 0, NULL);
else
return NULL;
}
@@ -17958,7 +18320,7 @@ loc_list_from_tree_1 (tree loc, int want_address,
add_loc_descr_to_each (list_ret, new_loc_descr (op, size, 0));
}
if (ret)
- list_ret = new_loc_list (ret, NULL, NULL, NULL);
+ list_ret = new_loc_list (ret, NULL, 0, NULL, 0, NULL);
return list_ret;
}
@@ -18287,7 +18649,13 @@ add_AT_location_description (dw_die_ref die, enum dwarf_attribute attr_kind,
if (single_element_loc_list_p (descr))
add_AT_loc (die, attr_kind, descr->expr);
else
- add_AT_loc_list (die, attr_kind, descr);
+ {
+ add_AT_loc_list (die, attr_kind, descr);
+ gcc_assert (descr->ll_symbol);
+ if (attr_kind == DW_AT_location && descr->vl_symbol
+ && dwarf2out_locviews_in_attribute ())
+ add_AT_view_list (die, DW_AT_GNU_locviews);
+ }
}
/* Add DW_AT_accessibility attribute to DIE if needed. */
@@ -19457,7 +19825,7 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset)
/* If the first partition contained no CFI adjustments, the
CIE opcodes apply to the whole first partition. */
*list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
- fde->dw_fde_begin, fde->dw_fde_end, section);
+ fde->dw_fde_begin, 0, fde->dw_fde_end, 0, section);
list_tail =&(*list_tail)->dw_loc_next;
start_label = last_label = fde->dw_fde_second_begin;
}
@@ -19473,7 +19841,7 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset)
if (!cfa_equal_p (&last_cfa, &next_cfa))
{
*list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
- start_label, last_label, section);
+ start_label, 0, last_label, 0, section);
list_tail = &(*list_tail)->dw_loc_next;
last_cfa = next_cfa;
@@ -19495,14 +19863,14 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset)
if (!cfa_equal_p (&last_cfa, &next_cfa))
{
*list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
- start_label, last_label, section);
+ start_label, 0, last_label, 0, section);
list_tail = &(*list_tail)->dw_loc_next;
last_cfa = next_cfa;
start_label = last_label;
}
*list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
- start_label, fde->dw_fde_end, section);
+ start_label, 0, fde->dw_fde_end, 0, section);
list_tail = &(*list_tail)->dw_loc_next;
start_label = last_label = fde->dw_fde_second_begin;
}
@@ -19511,19 +19879,18 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset)
if (!cfa_equal_p (&last_cfa, &next_cfa))
{
*list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
- start_label, last_label, section);
+ start_label, 0, last_label, 0, section);
list_tail = &(*list_tail)->dw_loc_next;
start_label = last_label;
}
*list_tail = new_loc_list (build_cfa_loc (&next_cfa, offset),
- start_label,
+ start_label, 0,
fde->dw_fde_second_begin
- ? fde->dw_fde_second_end : fde->dw_fde_end,
+ ? fde->dw_fde_second_end : fde->dw_fde_end, 0,
section);
- if (list && list->dw_loc_next)
- gen_llsym (list);
+ maybe_gen_llsym (list);
return list;
}
@@ -25946,7 +26313,7 @@ maybe_emit_file (struct dwarf_file_data * fd)
fd->emitted_number = 1;
last_emitted_file = fd;
- if (DWARF2_ASM_LINE_DEBUG_INFO)
+ if (output_asm_line_debug_info ())
{
fprintf (asm_out_file, "\t.file %u ", fd->emitted_number);
output_quoted_string (asm_out_file,
@@ -26106,6 +26473,22 @@ static bool maybe_at_text_label_p = true;
/* One above highest N where .LVLN label might be equal to .Ltext0 label. */
static unsigned int first_loclabel_num_not_at_text_label;
+/* Look ahead for a real insn, or for a begin stmt marker. */
+
+static rtx_insn *
+dwarf2out_next_real_insn (rtx_insn *loc_note)
+{
+ rtx_insn *next_real = NEXT_INSN (loc_note);
+
+ while (next_real)
+ if (INSN_P (next_real))
+ break;
+ else
+ next_real = NEXT_INSN (next_real);
+
+ return next_real;
+}
+
/* Called by the final INSN scan whenever we see a var location. We
use it to drop labels in the right places, and throw the location in
our lookup table. */
@@ -26123,11 +26506,13 @@ dwarf2out_var_location (rtx_insn *loc_note)
static rtx_insn *expected_next_loc_note;
tree decl;
bool var_loc_p;
+ var_loc_view view = 0;
if (!NOTE_P (loc_note))
{
if (CALL_P (loc_note))
{
+ RESET_NEXT_VIEW (cur_line_info_table->view);
call_site_count++;
if (SIBLING_CALL_P (loc_note))
tail_call_site_count++;
@@ -26154,13 +26539,25 @@ dwarf2out_var_location (rtx_insn *loc_note)
loc_note = NULL;
var_loc_p = false;
- next_real = next_real_insn (call_insn);
+ next_real = dwarf2out_next_real_insn (call_insn);
next_note = NULL;
cached_next_real_insn = NULL;
goto create_label;
}
}
}
+ else if (!debug_variable_location_views)
+ gcc_unreachable ();
+ else if (JUMP_TABLE_DATA_P (loc_note))
+ RESET_NEXT_VIEW (cur_line_info_table->view);
+ else if (GET_CODE (loc_note) == USE
+ || GET_CODE (loc_note) == CLOBBER
+ || GET_CODE (loc_note) == ASM_INPUT
+ || asm_noperands (loc_note) >= 0)
+ ;
+ else if (get_attr_min_length (loc_note) > 0)
+ RESET_NEXT_VIEW (cur_line_info_table->view);
+
return;
}
@@ -26184,11 +26581,12 @@ dwarf2out_var_location (rtx_insn *loc_note)
|| next_note->deleted ()
|| ! NOTE_P (next_note)
|| (NOTE_KIND (next_note) != NOTE_INSN_VAR_LOCATION
+ && NOTE_KIND (next_note) != NOTE_INSN_BEGIN_STMT
&& NOTE_KIND (next_note) != NOTE_INSN_CALL_ARG_LOCATION))
next_note = NULL;
if (! next_real)
- next_real = next_real_insn (loc_note);
+ next_real = dwarf2out_next_real_insn (loc_note);
if (next_note)
{
@@ -26223,10 +26621,11 @@ create_label:
if (var_loc_p)
{
+ const char *label = NOTE_DURING_CALL_P (loc_note)
+ ? last_postcall_label : last_label;
+ view = cur_line_info_table->view;
decl = NOTE_VAR_LOCATION_DECL (loc_note);
- newloc = add_var_loc_to_decl (decl, loc_note,
- NOTE_DURING_CALL_P (loc_note)
- ? last_postcall_label : last_label);
+ newloc = add_var_loc_to_decl (decl, loc_note, label, view);
if (newloc == NULL)
return;
}
@@ -26267,8 +26666,8 @@ create_label:
else if (GET_CODE (body) == ASM_INPUT
|| asm_noperands (body) >= 0)
continue;
-#ifdef HAVE_attr_length
- else if (get_attr_min_length (insn) == 0)
+#ifdef HAVE_ATTR_length /* ??? We don't include insn-attr.h. */
+ else if (HAVE_ATTR_length && get_attr_min_length (insn) == 0)
continue;
#endif
else
@@ -26336,7 +26735,10 @@ create_label:
call_arg_loc_last = ca_loc;
}
else if (loc_note != NULL_RTX && !NOTE_DURING_CALL_P (loc_note))
- newloc->label = last_label;
+ {
+ newloc->label = last_label;
+ newloc->view = view;
+ }
else
{
if (!last_postcall_label)
@@ -26345,6 +26747,23 @@ create_label:
last_postcall_label = ggc_strdup (loclabel);
}
newloc->label = last_postcall_label;
+ newloc->view = view;
+ }
+
+ if (var_loc_p && flag_debug_asm)
+ {
+ const char *name = NULL, *sep = " => ", *patstr = NULL;
+ if (decl && DECL_NAME (decl))
+ name = IDENTIFIER_POINTER (DECL_NAME (decl));
+ if (NOTE_VAR_LOCATION_LOC (loc_note))
+ patstr = str_pattern_slim (NOTE_VAR_LOCATION_LOC (loc_note));
+ else
+ {
+ sep = " ";
+ patstr = "RESET";
+ }
+ fprintf (asm_out_file, "\t%s DEBUG %s%s%s\n", ASM_COMMENT_START,
+ name, sep, patstr);
}
last_var_location_insn = next_real;
@@ -26395,6 +26814,7 @@ new_line_info_table (void)
table->file_num = 1;
table->line_num = 1;
table->is_stmt = DWARF_LINE_DEFAULT_IS_STMT_START;
+ RESET_NEXT_VIEW (table->view);
return table;
}
@@ -26443,7 +26863,7 @@ set_cur_line_info_table (section *sec)
vec_safe_push (separate_line_info, table);
}
- if (DWARF2_ASM_LINE_DEBUG_INFO)
+ if (output_asm_line_debug_info ())
table->is_stmt = (cur_line_info_table
? cur_line_info_table->is_stmt
: DWARF_LINE_DEFAULT_IS_STMT_START);
@@ -26624,7 +27044,7 @@ dwarf2out_source_line (unsigned int line, unsigned int column,
filename, line);
}
- if (DWARF2_ASM_LINE_DEBUG_INFO)
+ if (output_asm_line_debug_info ())
{
/* Emit the .loc directive understood by GNU as. */
/* "\t.loc %u %u 0 is_stmt %u discriminator %u",
@@ -26650,6 +27070,33 @@ dwarf2out_source_line (unsigned int line, unsigned int column,
fputs (" discriminator ", asm_out_file);
fprint_ul (asm_out_file, (unsigned long) discriminator);
}
+ if (debug_variable_location_views)
+ {
+ static var_loc_view lvugid;
+ if (!lvugid)
+ {
+ gcc_assert (!zero_view_p);
+ zero_view_p = BITMAP_GGC_ALLOC ();
+ bitmap_set_bit (zero_view_p, 0);
+ }
+ if (RESETTING_VIEW_P (table->view))
+ {
+ if (!table->in_use)
+ fputs (" view -0", asm_out_file);
+ else
+ fputs (" view 0", asm_out_file);
+ bitmap_set_bit (zero_view_p, lvugid);
+ table->view = ++lvugid;
+ }
+ else
+ {
+ fputs (" view ", asm_out_file);
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+ ASM_GENERATE_INTERNAL_LABEL (label, "LVU", table->view);
+ assemble_name (asm_out_file, label);
+ table->view = ++lvugid;
+ }
+ }
putc ('\n', asm_out_file);
}
else
@@ -26658,7 +27105,19 @@ dwarf2out_source_line (unsigned int line, unsigned int column,
targetm.asm_out.internal_label (asm_out_file, LINE_CODE_LABEL, label_num);
- push_dw_line_info_entry (table, LI_set_address, label_num);
+ if (debug_variable_location_views && table->view)
+ push_dw_line_info_entry (table, LI_adv_address, label_num);
+ else
+ push_dw_line_info_entry (table, LI_set_address, label_num);
+ if (debug_variable_location_views)
+ {
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s view %s%d\n",
+ ASM_COMMENT_START,
+ table->in_use ? "" : "-",
+ table->view);
+ table->view++;
+ }
if (file_num != table->file_num)
push_dw_line_info_entry (table, LI_set_file, file_num);
if (discriminator != table->discrim_num)
@@ -27240,7 +27699,7 @@ init_sections_and_labels (void)
SECTION_DEBUG, NULL);
debug_str_section = get_section (DEBUG_STR_SECTION,
DEBUG_STR_SECTION_FLAGS, NULL);
- if (!dwarf_split_debug_info && !DWARF2_ASM_LINE_DEBUG_INFO)
+ if (!dwarf_split_debug_info && !output_asm_line_debug_info ())
debug_line_str_section = get_section (DEBUG_LINE_STR_SECTION,
DEBUG_STR_SECTION_FLAGS, NULL);
@@ -27625,6 +28084,11 @@ prune_unused_types_walk_attribs (dw_die_ref die)
prune_unused_types_walk_loc_descr (list->expr);
break;
+ case dw_val_class_view_list:
+ /* This points to a loc_list in another attribute, so it's
+ already covered. */
+ break;
+
case dw_val_class_die_ref:
/* A reference to another DIE.
Make sure that it will get emitted.
@@ -28724,6 +29188,8 @@ optimize_string_length (dw_attr_node *a)
if (d->expr && non_dwarf_expression (d->expr))
non_dwarf_expr = true;
break;
+ case dw_val_class_view_list:
+ gcc_unreachable ();
case dw_val_class_loc:
lv = AT_loc (av);
if (lv == NULL)
@@ -28768,7 +29234,7 @@ optimize_string_length (dw_attr_node *a)
lv = copy_deref_exprloc (d->expr);
if (lv)
{
- *p = new_loc_list (lv, d->begin, d->end, d->section);
+ *p = new_loc_list (lv, d->begin, d->vbegin, d->end, d->vend, d->section);
p = &(*p)->dw_loc_next;
}
else if (!dwarf_strict && d->expr)
@@ -28838,6 +29304,7 @@ resolve_addr (dw_die_ref die)
{
gcc_assert (!next->ll_symbol);
next->ll_symbol = (*curr)->ll_symbol;
+ next->vl_symbol = (*curr)->vl_symbol;
}
if (dwarf_split_debug_info)
remove_loc_list_addr_table_entries (l);
@@ -28863,6 +29330,17 @@ resolve_addr (dw_die_ref die)
ix--;
}
break;
+ case dw_val_class_view_list:
+ {
+ gcc_checking_assert (a->dw_attr == DW_AT_GNU_locviews);
+ gcc_checking_assert (dwarf2out_locviews_in_attribute ());
+ if (!view_list_to_loc_list_val_node (&a->dw_attr_val))
+ {
+ remove_AT (die, a->dw_attr);
+ ix--;
+ }
+ break;
+ }
case dw_val_class_loc:
{
dw_loc_descr_ref l = AT_loc (a);
@@ -29259,6 +29737,8 @@ hash_loc_list (dw_loc_list_ref list_head)
{
hstate.add (curr->begin, strlen (curr->begin) + 1);
hstate.add (curr->end, strlen (curr->end) + 1);
+ hstate.add_object (curr->vbegin);
+ hstate.add_object (curr->vend);
if (curr->section)
hstate.add (curr->section, strlen (curr->section) + 1);
hash_locs (curr->expr, hstate);
@@ -29480,6 +29960,7 @@ loc_list_hasher::equal (const dw_loc_list_struct *a,
|| strcmp (a->end, b->end) != 0
|| (a->section == NULL) != (b->section == NULL)
|| (a->section && strcmp (a->section, b->section) != 0)
+ || a->vbegin != b->vbegin || a->vend != b->vend
|| !compare_locs (a->expr, b->expr))
break;
return a == NULL && b == NULL;
@@ -29537,7 +30018,7 @@ index_location_lists (dw_die_ref die)
/* Don't index an entry that has already been indexed
or won't be output. */
if (curr->begin_entry != NULL
- || (strcmp (curr->begin, curr->end) == 0 && !curr->force))
+ || skip_loc_list_entry (curr))
continue;
curr->begin_entry
@@ -29972,7 +30453,7 @@ dwarf2out_finish (const char *)
used by the debug_info section are marked as 'used'. */
switch_to_section (debug_line_section);
ASM_OUTPUT_LABEL (asm_out_file, debug_line_section_label);
- if (! DWARF2_ASM_LINE_DEBUG_INFO)
+ if (! output_asm_line_debug_info ())
output_line_info (false);
if (dwarf_split_debug_info && info_section_emitted)
@@ -157,7 +157,8 @@ enum dw_val_class
dw_val_class_discr_list,
dw_val_class_const_implicit,
dw_val_class_unsigned_const_implicit,
- dw_val_class_file_implicit
+ dw_val_class_file_implicit,
+ dw_val_class_view_list
};
/* Describe a floating point constant value, or a vector constant value. */
@@ -200,6 +201,7 @@ struct GTY(()) dw_val_node {
rtx GTY ((tag ("dw_val_class_addr"))) val_addr;
unsigned HOST_WIDE_INT GTY ((tag ("dw_val_class_offset"))) val_offset;
dw_loc_list_ref GTY ((tag ("dw_val_class_loc_list"))) val_loc_list;
+ dw_die_ref GTY ((tag ("dw_val_class_view_list"))) val_view_list;
dw_loc_descr_ref GTY ((tag ("dw_val_class_loc"))) val_loc;
HOST_WIDE_INT GTY ((default)) val_int;
unsigned HOST_WIDE_INT
@@ -3346,20 +3346,17 @@ next_nonnote_insn (rtx_insn *insn)
return insn;
}
-/* Return the next insn after INSN that is not a NOTE, but stop the
- search before we enter another basic block. This routine does not
- look inside SEQUENCEs. */
+/* Return the next insn after INSN that is not a DEBUG_INSN. This
+ routine does not look inside SEQUENCEs. */
rtx_insn *
-next_nonnote_insn_bb (rtx_insn *insn)
+next_nondebug_insn (rtx_insn *insn)
{
while (insn)
{
insn = NEXT_INSN (insn);
- if (insn == 0 || !NOTE_P (insn))
+ if (insn == 0 || !DEBUG_INSN_P (insn))
break;
- if (NOTE_INSN_BASIC_BLOCK_P (insn))
- return NULL;
}
return insn;
@@ -3381,67 +3378,70 @@ prev_nonnote_insn (rtx_insn *insn)
return insn;
}
-/* Return the previous insn before INSN that is not a NOTE, but stop
- the search before we enter another basic block. This routine does
- not look inside SEQUENCEs. */
+/* Return the previous insn before INSN that is not a DEBUG_INSN.
+ This routine does not look inside SEQUENCEs. */
rtx_insn *
-prev_nonnote_insn_bb (rtx_insn *insn)
+prev_nondebug_insn (rtx_insn *insn)
{
-
while (insn)
{
insn = PREV_INSN (insn);
- if (insn == 0 || !NOTE_P (insn))
+ if (insn == 0 || !DEBUG_INSN_P (insn))
break;
- if (NOTE_INSN_BASIC_BLOCK_P (insn))
- return NULL;
}
return insn;
}
-/* Return the next insn after INSN that is not a DEBUG_INSN. This
- routine does not look inside SEQUENCEs. */
+/* Return the next insn after INSN that is not a NOTE nor DEBUG_INSN.
+ This routine does not look inside SEQUENCEs. */
rtx_insn *
-next_nondebug_insn (rtx_insn *insn)
+next_nonnote_nondebug_insn (rtx_insn *insn)
{
while (insn)
{
insn = NEXT_INSN (insn);
- if (insn == 0 || !DEBUG_INSN_P (insn))
+ if (insn == 0 || (!NOTE_P (insn) && !DEBUG_INSN_P (insn)))
break;
}
return insn;
}
-/* Return the previous insn before INSN that is not a DEBUG_INSN.
- This routine does not look inside SEQUENCEs. */
+/* Return the next insn after INSN that is not a NOTE nor DEBUG_INSN,
+ but stop the search before we enter another basic block. This
+ routine does not look inside SEQUENCEs. */
rtx_insn *
-prev_nondebug_insn (rtx_insn *insn)
+next_nonnote_nondebug_insn_bb (rtx_insn *insn)
{
while (insn)
{
- insn = PREV_INSN (insn);
- if (insn == 0 || !DEBUG_INSN_P (insn))
+ insn = NEXT_INSN (insn);
+ if (insn == 0)
+ break;
+ if (DEBUG_INSN_P (insn))
+ continue;
+ if (!NOTE_P (insn))
break;
+ if (NOTE_INSN_BASIC_BLOCK_P (insn))
+ return NULL;
}
return insn;
}
-/* Return the next insn after INSN that is not a NOTE nor DEBUG_INSN.
+/* Return the previous insn before INSN that is not a NOTE nor DEBUG_INSN.
This routine does not look inside SEQUENCEs. */
rtx_insn *
-next_nonnote_nondebug_insn (rtx_insn *insn)
+prev_nonnote_nondebug_insn (rtx_insn *insn)
{
while (insn)
{
- insn = NEXT_INSN (insn);
+ insn = PREV_INSN (insn);
if (insn == 0 || (!NOTE_P (insn) && !DEBUG_INSN_P (insn)))
break;
}
@@ -3449,17 +3449,24 @@ next_nonnote_nondebug_insn (rtx_insn *insn)
return insn;
}
-/* Return the previous insn before INSN that is not a NOTE nor DEBUG_INSN.
- This routine does not look inside SEQUENCEs. */
+/* Return the previous insn before INSN that is not a NOTE nor
+ DEBUG_INSN, but stop the search before we enter another basic
+ block. This routine does not look inside SEQUENCEs. */
rtx_insn *
-prev_nonnote_nondebug_insn (rtx_insn *insn)
+prev_nonnote_nondebug_insn_bb (rtx_insn *insn)
{
while (insn)
{
insn = PREV_INSN (insn);
- if (insn == 0 || (!NOTE_P (insn) && !DEBUG_INSN_P (insn)))
+ if (insn == 0)
break;
+ if (DEBUG_INSN_P (insn))
+ continue;
+ if (!NOTE_P (insn))
+ break;
+ if (NOTE_INSN_BASIC_BLOCK_P (insn))
+ return NULL;
}
return insn;
@@ -79,6 +79,7 @@ along with GCC; see the file COPYING3. If not see
#include "asan.h"
#include "rtl-iter.h"
#include "print-rtl.h"
+#include "langhooks.h"
#ifdef XCOFF_DEBUGGING_INFO
#include "xcoffout.h" /* Needed for external data declarations. */
@@ -110,6 +111,7 @@ along with GCC; see the file COPYING3. If not see
/* Bitflags used by final_scan_insn. */
#define SEEN_NOTE 1
#define SEEN_EMITTED 2
+#define SEEN_NEXT_VIEW 4
/* Last insn processed by final_scan_insn. */
static rtx_insn *debug_insn;
@@ -1745,6 +1747,44 @@ get_some_local_dynamic_name ()
return 0;
}
+/* Arrange for us to emit a source location note before any further
+ real insns or section changes, by setting the SEEN_NEXT_VIEW bit in
+ *SEEN, as long as we are keeping track of location views. The bit
+ indicates we have referenced the next view at the current PC, so we
+ have to emit it. This should be called next to the var_location
+ debug hook. */
+
+static inline void
+set_next_view_needed (int *seen)
+{
+ if (debug_variable_location_views)
+ *seen |= SEEN_NEXT_VIEW;
+}
+
+/* Clear the flag in *SEEN indicating we need to emit the next view.
+ This should be called next to the source_line debug hook. */
+
+static inline void
+clear_next_view_needed (int *seen)
+{
+ *seen &= ~SEEN_NEXT_VIEW;
+}
+
+/* Test whether we have a pending request to emit the next view in
+ *SEEN, and emit it if needed, clearing the request bit. */
+
+static inline void
+maybe_output_next_view (int *seen)
+{
+ if ((*seen & SEEN_NEXT_VIEW) != 0)
+ {
+ clear_next_view_needed (seen);
+ (*debug_hooks->source_line) (last_linenum, last_columnnum,
+ last_filename, last_discriminator,
+ false);
+ }
+}
+
/* Output assembler code for the start of a function,
and initialize some of the variables in this file
for the new function. The label for the function and associated
@@ -1752,13 +1792,18 @@ get_some_local_dynamic_name ()
FIRST is the first insn of the rtl for the function being compiled.
FILE is the file to write assembler code to.
+ SEEN should be initially set to zero, and it may be updated to
+ indicate we have references to the next location view, that would
+ require us to emit it at the current PC.
OPTIMIZE_P is nonzero if we should eliminate redundant
test and compare insns. */
-void
-final_start_function (rtx_insn *first, FILE *file,
- int optimize_p ATTRIBUTE_UNUSED)
+static void
+final_start_function_1 (rtx_insn **firstp, FILE *file, int *seen,
+ int optimize_p ATTRIBUTE_UNUSED)
{
+ rtx_insn *first = *firstp;
+
block_depth = 0;
this_is_asm_operands = 0;
@@ -1776,7 +1821,28 @@ final_start_function (rtx_insn *first, FILE *file,
asan_function_start ();
if (!DECL_IGNORED_P (current_function_decl))
- debug_hooks->begin_prologue (last_linenum, last_columnnum, last_filename);
+ {
+ /* Emit param bindings (before the first begin_stmt) in the
+ initial view. We don't test whether the DECLs are
+ PARM_DECLs: the assumption is that there will be a
+ NOTE_INSN_BEGIN_STMT marker before any non-parameter
+ NOTE_INSN_VAR_LOCATION. It's ok if the marker is not there,
+ we'll just have more variable locations bound in the initial
+ view, which is consistent with their being bound without any
+ code that would give them a value. */
+ if (debug_variable_location_views)
+ {
+ rtx_insn *insn;
+ for (insn = first;
+ insn && GET_CODE (insn) == NOTE
+ && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION;
+ insn = NEXT_INSN (insn))
+ final_scan_insn (insn, file, 0, 0, seen);
+ *firstp = insn;
+ }
+ debug_hooks->begin_prologue (last_linenum, last_columnnum,
+ last_filename);
+ }
if (!dwarf2_debug_info_emitted_p (current_function_decl))
dwarf2out_begin_prologue (0, 0, NULL);
@@ -1851,6 +1917,17 @@ final_start_function (rtx_insn *first, FILE *file,
profile_after_prologue (file);
}
+/* This is an exported final_start_function_1, callable without SEEN. */
+
+void
+final_start_function (rtx_insn **firstp, FILE *file,
+ int optimize_p ATTRIBUTE_UNUSED)
+{
+ int seen = 0;
+ final_start_function_1 (firstp, file, &seen, optimize_p);
+ gcc_assert (seen == 0);
+}
+
static void
profile_after_prologue (FILE *file ATTRIBUTE_UNUSED)
{
@@ -1982,11 +2059,10 @@ dump_basic_block_info (FILE *file, rtx_insn *insn, basic_block *start_to_bb,
/* Output assembler code for some insns: all or part of a function.
For description of args, see `final_start_function', above. */
-void
-final (rtx_insn *first, FILE *file, int optimize_p)
+static void
+final_1 (rtx_insn *first, FILE *file, int seen, int optimize_p)
{
rtx_insn *insn, *next;
- int seen = 0;
/* Used for -dA dump. */
basic_block *start_to_bb = NULL;
@@ -2053,6 +2129,8 @@ final (rtx_insn *first, FILE *file, int optimize_p)
insn = final_scan_insn (insn, file, optimize_p, 0, &seen);
}
+ maybe_output_next_view (&seen);
+
if (flag_debug_asm)
{
free (start_to_bb);
@@ -2069,6 +2147,14 @@ final (rtx_insn *first, FILE *file, int optimize_p)
delete_insn (insn);
}
}
+
+/* This is an exported final_1, callable without SEEN. */
+
+void
+final (rtx_insn *first, FILE *file, int optimize_p)
+{
+ final_1 (first, file, 0, optimize_p);
+}
const char *
get_insn_template (int code, rtx insn)
@@ -2208,6 +2294,8 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
break;
case NOTE_INSN_SWITCH_TEXT_SECTIONS:
+ maybe_output_next_view (seen);
+
in_cold_section_p = !in_cold_section_p;
if (dwarf2out_do_frame ())
@@ -2348,6 +2436,8 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
break;
case NOTE_INSN_BLOCK_END:
+ maybe_output_next_view (seen);
+
if (debug_info_level == DINFO_LEVEL_NORMAL
|| debug_info_level == DINFO_LEVEL_VERBOSE
|| write_symbols == DWARF2_DEBUG
@@ -2405,7 +2495,22 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
case NOTE_INSN_VAR_LOCATION:
case NOTE_INSN_CALL_ARG_LOCATION:
if (!DECL_IGNORED_P (current_function_decl))
- debug_hooks->var_location (insn);
+ {
+ debug_hooks->var_location (insn);
+ set_next_view_needed (seen);
+ }
+ break;
+
+ case NOTE_INSN_BEGIN_STMT:
+ gcc_checking_assert (cfun->begin_stmt_markers);
+ if (!DECL_IGNORED_P (current_function_decl)
+ && notice_source_line (insn, NULL))
+ {
+ (*debug_hooks->source_line) (last_linenum, last_columnnum,
+ last_filename, last_discriminator,
+ true);
+ clear_next_view_needed (seen);
+ }
break;
default:
@@ -2495,7 +2600,15 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
rtx body = PATTERN (insn);
int insn_code_number;
const char *templ;
- bool is_stmt;
+ bool is_stmt, *is_stmt_p;
+
+ if (MAY_HAVE_DEBUG_INSNS && cfun->begin_stmt_markers)
+ {
+ is_stmt = false;
+ is_stmt_p = NULL;
+ }
+ else
+ is_stmt_p = &is_stmt;
/* Reset this early so it is correct for ASM statements. */
current_insn_predicate = NULL_RTX;
@@ -2593,19 +2706,28 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
switch_to_section (current_function_section ());
+ if (debug_variable_location_views
+ && !DECL_IGNORED_P (current_function_decl))
+ debug_hooks->var_location (insn);
+
break;
}
/* Output this line note if it is the first or the last line
note in a row. */
if (!DECL_IGNORED_P (current_function_decl)
- && notice_source_line (insn, &is_stmt))
+ && notice_source_line (insn, is_stmt_p))
{
if (flag_verbose_asm)
asm_show_source (last_filename, last_linenum);
(*debug_hooks->source_line) (last_linenum, last_columnnum,
last_filename, last_discriminator,
is_stmt);
+ clear_next_view_needed (seen);
}
+ else
+ maybe_output_next_view (seen);
+
+ gcc_checking_assert (!DEBUG_INSN_P (insn));
if (GET_CODE (body) == PARALLEL
&& GET_CODE (XVECEXP (body, 0, 0)) == ASM_INPUT)
@@ -3072,7 +3194,8 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
/* Let the debug info back-end know about this call. We do this only
after the instruction has been emitted because labels that may be
created to reference the call instruction must appear after it. */
- if (call_insn != NULL && !DECL_IGNORED_P (current_function_decl))
+ if ((debug_variable_location_views || call_insn != NULL)
+ && !DECL_IGNORED_P (current_function_decl))
debug_hooks->var_location (insn);
current_output_insn = debug_insn = 0;
@@ -3091,7 +3214,16 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
const char *filename;
int linenum, columnnum;
- if (override_filename)
+ if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_BEGIN_STMT)
+ {
+ expanded_location xloc
+ = expand_location (NOTE_BEGIN_STMT_LOCATION (insn));
+ filename = xloc.file;
+ linenum = xloc.line;
+ columnnum = xloc.column;
+ force_source_line = true;
+ }
+ else if (override_filename)
{
filename = override_filename;
linenum = override_linenum;
@@ -3124,7 +3256,8 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
last_linenum = linenum;
last_columnnum = columnnum;
last_discriminator = discriminator;
- *is_stmt = true;
+ if (is_stmt)
+ *is_stmt = true;
high_block_linenum = MAX (last_linenum, high_block_linenum);
high_function_linenum = MAX (last_linenum, high_function_linenum);
return true;
@@ -3136,7 +3269,8 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
output the line table entry with is_stmt false so the
debugger does not treat this as a breakpoint location. */
last_discriminator = discriminator;
- *is_stmt = false;
+ if (is_stmt)
+ *is_stmt = false;
return true;
}
@@ -4489,9 +4623,15 @@ rest_of_handle_final (void)
{
const char *fnname = get_fnname_from_decl (current_function_decl);
+ /* Turn debug markers into notes. */
+ if (!flag_var_tracking && MAY_HAVE_DEBUG_INSNS)
+ variable_tracking_main ();
+
assemble_start_function (current_function_decl, fnname);
- final_start_function (get_insns (), asm_out_file, optimize);
- final (get_insns (), asm_out_file, optimize);
+ rtx_insn *first = get_insns ();
+ int seen = 0;
+ final_start_function_1 (&first, asm_out_file, &seen, optimize);
+ final_1 (first, asm_out_file, seen, optimize);
if (flag_ipa_ra)
collect_fn_hard_reg_usage ();
final_end_function ();
@@ -4675,6 +4815,7 @@ rest_of_clean_state (void)
if (final_output
&& (!NOTE_P (insn) ||
(NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION
+ && NOTE_KIND (insn) != NOTE_INSN_BEGIN_STMT
&& NOTE_KIND (insn) != NOTE_INSN_CALL_ARG_LOCATION
&& NOTE_KIND (insn) != NOTE_INSN_BLOCK_BEG
&& NOTE_KIND (insn) != NOTE_INSN_BLOCK_END
@@ -4947,6 +4947,12 @@ allocate_struct_function (tree fndecl, bool abstract_p)
if (!profile_flag && !flag_instrument_function_entry_exit)
DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fndecl) = 1;
}
+
+ /* Don't enable begin stmt markers if var-tracking at assignments is
+ disabled. The markers make little sense without the variable
+ binding annotations among them. */
+ cfun->begin_stmt_markers = lang_hooks.emits_begin_stmt
+ && debug_statement_frontiers && MAY_HAVE_DEBUG_STMTS;
}
/* This is like allocate_struct_function, but pushes a new cfun for FNDECL
@@ -284,6 +284,12 @@ struct GTY(()) function {
/* Last statement uid. */
int last_stmt_uid;
+ /* Debug marker counter. Count begin stmt markers. We don't have
+ to keep it exact, it's more of a rough estimate to enable us to
+ decide whether they are too many to copy during inlining, or when
+ expanding to RTL. */
+ int debug_marker_count;
+
/* Function sequence number for profiling, debugging, etc. */
int funcdef_no;
@@ -387,6 +393,10 @@ struct GTY(()) function {
/* Set when the tail call has been identified. */
unsigned int tail_call_marked : 1;
+
+ /* Set when the function was compiled with generation of debug begin
+ stmt markers enabled. */
+ unsigned int begin_stmt_markers : 1;
};
/* Add the decl D to the local_decls list of FUN. */
@@ -573,6 +573,8 @@ gsi_remove (gimple_stmt_iterator *i, bool remove_permanently)
if (remove_permanently)
{
+ if (gimple_debug_begin_stmt_p (stmt))
+ cfun->debug_marker_count--;
require_eh_edge_purge = remove_stmt_from_eh_lp (stmt);
gimple_remove_stmt_histograms (cfun, stmt);
}
@@ -744,9 +746,13 @@ gimple_find_edge_insert_loc (edge e, gimple_stmt_iterator *gsi,
if (gsi_end_p (*gsi))
return true;
- /* Make sure we insert after any leading labels. */
+ /* Make sure we insert after any leading labels. We have to
+ skip debug stmts before or among them, though. We didn't
+ have to skip debug stmts after the last label, but it
+ shouldn't hurt if we do. */
tmp = gsi_stmt (*gsi);
- while (gimple_code (tmp) == GIMPLE_LABEL)
+ while (gimple_code (tmp) == GIMPLE_LABEL
+ || is_gimple_debug (tmp))
{
gsi_next (gsi);
if (gsi_end_p (*gsi))
@@ -776,7 +782,21 @@ gimple_find_edge_insert_loc (edge e, gimple_stmt_iterator *gsi,
return true;
tmp = gsi_stmt (*gsi);
- if (!stmt_ends_bb_p (tmp))
+ if (is_gimple_debug (tmp))
+ {
+ gimple_stmt_iterator si = *gsi;
+ gsi_prev_nondebug (&si);
+ if (!gsi_end_p (si))
+ tmp = gsi_stmt (si);
+ /* If we don't have a BB-ending nondebug stmt, we want to
+ insert after the trailing debug stmts. Otherwise, we may
+ insert before the BB-ending nondebug stmt, or split the
+ edge. */
+ if (!stmt_ends_bb_p (tmp))
+ return true;
+ *gsi = si;
+ }
+ else if (!stmt_ends_bb_p (tmp))
return true;
switch (gimple_code (tmp))
@@ -212,29 +212,28 @@ gsi_stmt (gimple_stmt_iterator i)
return i.ptr;
}
-/* Return a new iterator pointing to the first non-debug statement
- in basic block BB. */
-
-static inline gimple_stmt_iterator
-gsi_start_bb_nondebug (basic_block bb)
-{
- gimple_stmt_iterator gsi = gsi_start_bb (bb);
- while (!gsi_end_p (gsi) && is_gimple_debug (gsi_stmt (gsi)))
- gsi_next (&gsi);
-
- return gsi;
-}
-
-/* Return a block statement iterator that points to the first non-label
- statement in block BB. */
+/* Return a block statement iterator that points to the first
+ non-label statement in block BB. Skip debug stmts only if they
+ precede labels. */
static inline gimple_stmt_iterator
gsi_after_labels (basic_block bb)
{
gimple_stmt_iterator gsi = gsi_start_bb (bb);
- while (!gsi_end_p (gsi) && gimple_code (gsi_stmt (gsi)) == GIMPLE_LABEL)
- gsi_next (&gsi);
+ for (gimple_stmt_iterator gskip = gsi;
+ !gsi_end_p (gskip); )
+ {
+ if (is_gimple_debug (gsi_stmt (gskip)))
+ gsi_next (&gskip);
+ else if (gimple_code (gsi_stmt (gskip)) == GIMPLE_LABEL)
+ {
+ gsi_next (&gskip);
+ gsi = gskip;
+ }
+ else
+ break;
+ }
return gsi;
}
@@ -264,6 +263,19 @@ gsi_prev_nondebug (gimple_stmt_iterator *i)
}
/* Return a new iterator pointing to the first non-debug statement in
+ SEQ. */
+
+static inline gimple_stmt_iterator
+gsi_start_nondebug (gimple_seq seq)
+{
+ gimple_stmt_iterator gsi = gsi_start (seq);
+ if (!gsi_end_p (gsi) && is_gimple_debug (gsi_stmt (gsi)))
+ gsi_next_nondebug (&gsi);
+
+ return gsi;
+}
+
+/* Return a new iterator pointing to the first non-debug statement in
basic block BB. */
static inline gimple_stmt_iterator
@@ -110,6 +110,17 @@ lower_function_body (void)
i = gsi_last (lowered_body);
+ /* If we had begin stmt markers from e.g. PCH, but this compilation
+ doesn't want them, lower_stmt will have cleaned them up; we can
+ now clear the flag that indicates we had them. */
+ if (!MAY_HAVE_DEBUG_STMTS && cfun->begin_stmt_markers)
+ {
+ /* This counter needs not be exact, but before lowering it will
+ most certainly be. */
+ gcc_assert (cfun->debug_marker_count == 0);
+ cfun->begin_stmt_markers = false;
+ }
+
/* If the function falls off the end, we need a null return statement.
If we've already got one in the return_statements vector, we don't
need to do anything special. Otherwise build one by hand. */
@@ -296,6 +307,17 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
}
break;
+ case GIMPLE_DEBUG:
+ gcc_checking_assert (cfun->begin_stmt_markers);
+ /* Propagate fallthruness. */
+ /* If the function (e.g. from PCH) had debug stmts, but they're
+ disabled for this compilation, remove them. */
+ if (!MAY_HAVE_DEBUG_STMTS)
+ gsi_remove (gsi, true);
+ else
+ gsi_next (gsi);
+ return;
+
case GIMPLE_NOP:
case GIMPLE_ASM:
case GIMPLE_ASSIGN:
@@ -503,6 +525,10 @@ lower_try_catch (gimple_stmt_iterator *gsi, struct lower_data *data)
cannot_fallthru = false;
break;
+ case GIMPLE_DEBUG:
+ gcc_checking_assert (gimple_debug_begin_stmt_p (stmt));
+ break;
+
default:
/* This case represents statements to be executed when an
exception occurs. Those statements are implicitly followed
@@ -645,7 +671,7 @@ gimple_stmt_may_fallthru (gimple *stmt)
bool
gimple_seq_may_fallthru (gimple_seq seq)
{
- return gimple_stmt_may_fallthru (gimple_seq_last_stmt (seq));
+ return gimple_stmt_may_fallthru (gimple_seq_last_nondebug_stmt (seq));
}
@@ -1371,6 +1371,13 @@ dump_gimple_debug (pretty_printer *buffer, gdebug *gs, int spc,
gimple_debug_source_bind_get_value (gs));
break;
+ case GIMPLE_DEBUG_BEGIN_STMT:
+ if (flags & TDF_RAW)
+ dump_gimple_fmt (buffer, spc, flags, "%G BEGIN_STMT", gs);
+ else
+ dump_gimple_fmt (buffer, spc, flags, "# DEBUG BEGIN_STMT");
+ break;
+
default:
gcc_unreachable ();
}
@@ -834,6 +834,27 @@ gimple_build_debug_source_bind_stat (tree var, tree value,
}
+/* Build a new GIMPLE_DEBUG_BEGIN_STMT statement in BLOCK at
+ LOCATION. */
+
+gdebug *
+gimple_build_debug_begin_stmt_stat (tree block, location_t location
+ MEM_STAT_DECL)
+{
+ gdebug *p
+ = as_a <gdebug *> (
+ gimple_build_with_ops_stat (GIMPLE_DEBUG,
+ (unsigned)GIMPLE_DEBUG_BEGIN_STMT, 0
+ PASS_MEM_STAT));
+
+ gimple_set_block (p, block);
+ gimple_set_location (p, location);
+ cfun->debug_marker_count++;
+
+ return p;
+}
+
+
/* Build a GIMPLE_OMP_CRITICAL statement.
BODY is the sequence of statements for which only one thread can execute.
@@ -1872,6 +1893,9 @@ gimple_copy (gimple *stmt)
gimple_set_modified (copy, true);
}
+ if (gimple_debug_begin_stmt_p (stmt))
+ cfun->debug_marker_count++;
+
return copy;
}
@@ -198,13 +198,12 @@ enum gf_mask {
GF_PREDICT_TAKEN = 1 << 15
};
-/* Currently, there are only two types of gimple debug stmt. Others are
- envisioned, for example, to enable the generation of is_stmt notes
- in line number information, to mark sequence points, etc. This
- subcode is to be used to tell them apart. */
+/* This subcode tells apart different kinds of stmts that are not used
+ for codegen, but rather to retain debug information. */
enum gimple_debug_subcode {
GIMPLE_DEBUG_BIND = 0,
- GIMPLE_DEBUG_SOURCE_BIND = 1
+ GIMPLE_DEBUG_SOURCE_BIND = 1,
+ GIMPLE_DEBUG_BEGIN_STMT = 2
};
/* Masks for selecting a pass local flag (PLF) to work on. These
@@ -1460,6 +1459,9 @@ gdebug *gimple_build_debug_bind_stat (tree, tree, gimple * MEM_STAT_DECL);
gdebug *gimple_build_debug_source_bind_stat (tree, tree, gimple * MEM_STAT_DECL);
#define gimple_build_debug_source_bind(var,val,stmt) \
gimple_build_debug_source_bind_stat ((var), (val), (stmt) MEM_STAT_INFO)
+gdebug *gimple_build_debug_begin_stmt_stat (tree, location_t MEM_STAT_DECL);
+#define gimple_build_debug_begin_stmt(block,loc) \
+ gimple_build_debug_begin_stmt_stat ((block), (loc) MEM_STAT_INFO)
gomp_critical *gimple_build_omp_critical (gimple_seq, tree, tree);
gomp_for *gimple_build_omp_for (gimple_seq, int, tree, size_t, gimple_seq);
gomp_parallel *gimple_build_omp_parallel (gimple_seq, tree, tree, tree);
@@ -4564,6 +4566,22 @@ is_gimple_debug (const gimple *gs)
return gimple_code (gs) == GIMPLE_DEBUG;
}
+
+/* Return the last nondebug statement in GIMPLE sequence S. */
+
+static inline gimple *
+gimple_seq_last_nondebug_stmt (gimple_seq s)
+{
+ gimple_seq_node n;
+ for (n = gimple_seq_last (s);
+ n && is_gimple_debug (n);
+ n = n->prev)
+ if (n->prev == s)
+ return NULL;
+ return n;
+}
+
+
/* Return true if S is a GIMPLE_DEBUG BIND statement. */
static inline bool
@@ -4720,6 +4738,17 @@ gimple_debug_source_bind_set_value (gimple *dbg, tree value)
gimple_set_op (dbg, 1, value);
}
+/* Return true if S is a GIMPLE_DEBUG BEGIN_STMT statement. */
+
+static inline bool
+gimple_debug_begin_stmt_p (const gimple *s)
+{
+ if (is_gimple_debug (s))
+ return s->subcode == GIMPLE_DEBUG_BEGIN_STMT;
+
+ return false;
+}
+
/* Return the line number for EXPR, or return -1 if we have no line
number information for it. */
static inline int
@@ -985,6 +985,48 @@ unshare_expr_without_location (tree expr)
walk_tree (&expr, prune_expr_location, NULL, NULL);
return expr;
}
+
+/* Return the EXPR_LOCATION of EXPR, if it (maybe recursively) has
+ one, OR_ELSE otherwise. The location of a STATEMENT_LISTs
+ comprising at least one DEBUG_BEGIN_STMT followed by exactly one
+ EXPR is the location of the EXPR. */
+
+static location_t
+expr_location (tree expr, location_t or_else = UNKNOWN_LOCATION)
+{
+ if (!expr)
+ return or_else;
+
+ if (EXPR_HAS_LOCATION (expr))
+ return EXPR_LOCATION (expr);
+
+ if (TREE_CODE (expr) != STATEMENT_LIST)
+ return or_else;
+
+ tree_stmt_iterator i = tsi_start (expr);
+
+ bool found = false;
+ while (!tsi_end_p (i) && TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
+ {
+ found = true;
+ tsi_next (&i);
+ }
+
+ if (!found || !tsi_one_before_end_p (i))
+ return or_else;
+
+ return expr_location (tsi_stmt (i), or_else);
+}
+
+/* Return TRUE iff EXPR (maybe recursively) has a location; see
+ expr_location for the potential recursion. */
+
+static inline bool
+expr_has_location (tree expr)
+{
+ return expr_location (expr) != UNKNOWN_LOCATION;
+}
+
/* WRAPPER is a code such as BIND_EXPR or CLEANUP_POINT_EXPR which can both
contain statements and have a value. Assign its value to a temporary
@@ -1775,6 +1817,13 @@ warn_switch_unreachable_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p,
/* Walk the sub-statements. */
*handled_ops_p = false;
break;
+
+ case GIMPLE_DEBUG:
+ /* Ignore these. We may generate them before declarations that
+ are never executed. If there's something to warn about,
+ there will be non-debug stmts too, and we'll catch those. */
+ break;
+
case GIMPLE_CALL:
if (gimple_call_internal_p (stmt, IFN_ASAN_MARK))
{
@@ -1858,7 +1907,7 @@ case_label_p (const vec<tree> *cases, tree label)
return false;
}
-/* Find the last statement in a scope STMT. */
+/* Find the last nondebug statement in a scope STMT. */
static gimple *
last_stmt_in_scope (gimple *stmt)
@@ -1871,27 +1920,30 @@ last_stmt_in_scope (gimple *stmt)
case GIMPLE_BIND:
{
gbind *bind = as_a <gbind *> (stmt);
- stmt = gimple_seq_last_stmt (gimple_bind_body (bind));
+ stmt = gimple_seq_last_nondebug_stmt (gimple_bind_body (bind));
return last_stmt_in_scope (stmt);
}
case GIMPLE_TRY:
{
gtry *try_stmt = as_a <gtry *> (stmt);
- stmt = gimple_seq_last_stmt (gimple_try_eval (try_stmt));
+ stmt = gimple_seq_last_nondebug_stmt (gimple_try_eval (try_stmt));
gimple *last_eval = last_stmt_in_scope (stmt);
if (gimple_stmt_may_fallthru (last_eval)
&& (last_eval == NULL
|| !gimple_call_internal_p (last_eval, IFN_FALLTHROUGH))
&& gimple_try_kind (try_stmt) == GIMPLE_TRY_FINALLY)
{
- stmt = gimple_seq_last_stmt (gimple_try_cleanup (try_stmt));
+ stmt = gimple_seq_last_nondebug_stmt (gimple_try_cleanup (try_stmt));
return last_stmt_in_scope (stmt);
}
else
return last_eval;
}
+ case GIMPLE_DEBUG:
+ gcc_unreachable ();
+
default:
return stmt;
}
@@ -1995,7 +2047,7 @@ collect_fallthrough_labels (gimple_stmt_iterator *gsi_p,
}
else if (gimple_call_internal_p (gsi_stmt (*gsi_p), IFN_ASAN_MARK))
;
- else
+ else if (!is_gimple_debug (gsi_stmt (*gsi_p)))
prev = gsi_stmt (*gsi_p);
gsi_next (gsi_p);
}
@@ -2032,7 +2084,7 @@ should_warn_for_implicit_fallthrough (gimple_stmt_iterator *gsi_p, tree label)
&& gimple_code (gsi_stmt (gsi)) == GIMPLE_LABEL
&& (l = gimple_label_label (as_a <glabel *> (gsi_stmt (gsi))))
&& !case_label_p (&gimplify_ctxp->case_labels, l))
- gsi_next (&gsi);
+ gsi_next_nondebug (&gsi);
if (gsi_end_p (gsi) || gimple_code (gsi_stmt (gsi)) != GIMPLE_LABEL)
return false;
}
@@ -2043,7 +2095,7 @@ should_warn_for_implicit_fallthrough (gimple_stmt_iterator *gsi_p, tree label)
/* Skip all immediately following labels. */
while (!gsi_end_p (gsi) && gimple_code (gsi_stmt (gsi)) == GIMPLE_LABEL)
- gsi_next (&gsi);
+ gsi_next_nondebug (&gsi);
/* { ... something; default:; } */
if (gsi_end_p (gsi)
@@ -2090,7 +2142,7 @@ warn_implicit_fallthrough_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p,
/* Found a label. Skip all immediately following labels. */
while (!gsi_end_p (*gsi_p)
&& gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_LABEL)
- gsi_next (gsi_p);
+ gsi_next_nondebug (gsi_p);
/* There might be no more statements. */
if (gsi_end_p (*gsi_p))
@@ -2231,7 +2283,7 @@ expand_FALLTHROUGH_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p,
break;
}
}
- else
+ else if (!is_gimple_debug (stmt))
/* Something other than a label. That's not expected. */
break;
gsi_next (&gsi2);
@@ -3438,7 +3490,7 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,
append_to_statement_list (t, &expr);
/* Set the source location of the && on the second 'if'. */
- new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus;
+ new_locus = expr_location (pred, locus);
t = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p, false_label_p,
new_locus);
append_to_statement_list (t, &expr);
@@ -3461,7 +3513,7 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,
append_to_statement_list (t, &expr);
/* Set the source location of the || on the second 'if'. */
- new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus;
+ new_locus = expr_location (pred, locus);
t = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p, false_label_p,
new_locus);
append_to_statement_list (t, &expr);
@@ -3483,7 +3535,7 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,
/* Keep the original source location on the first 'if'. Set the source
location of the ? on the second 'if'. */
- new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus;
+ new_locus = expr_location (pred, locus);
expr = build3 (COND_EXPR, void_type_node, TREE_OPERAND (pred, 0),
shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p,
false_label_p, locus),
@@ -3507,6 +3559,45 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p,
return expr;
}
+/* If EXPR is a GOTO_EXPR, return it. If it is a STATEMENT_LIST, skip
+ any of its leading DEBUG_BEGIN_STMTS and recurse on the subsequent
+ statement, if it is the last one. Otherwise, return NULL. */
+
+static tree
+find_goto (tree expr)
+{
+ if (!expr)
+ return NULL_TREE;
+
+ if (TREE_CODE (expr) == GOTO_EXPR)
+ return expr;
+
+ if (TREE_CODE (expr) != STATEMENT_LIST)
+ return NULL_TREE;
+
+ tree_stmt_iterator i = tsi_start (expr);
+
+ while (!tsi_end_p (i) && TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
+ tsi_next (&i);
+
+ if (!tsi_one_before_end_p (i))
+ return NULL_TREE;
+
+ return find_goto (tsi_stmt (i));
+}
+
+/* Same as find_goto, except that it returns NULL if the destination
+ is not a LABEL_DECL. */
+
+static inline tree
+find_goto_label (tree expr)
+{
+ tree dest = find_goto (expr);
+ if (dest && TREE_CODE (GOTO_DESTINATION (dest)) == LABEL_DECL)
+ return dest;
+ return NULL_TREE;
+}
+
/* Given a conditional expression EXPR with short-circuit boolean
predicates using TRUTH_ANDIF_EXPR or TRUTH_ORIF_EXPR, break the
predicate apart into the equivalent sequence of conditionals. */
@@ -3537,8 +3628,8 @@ shortcut_cond_expr (tree expr)
location_t locus = EXPR_LOC_OR_LOC (expr, input_location);
TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
/* Set the source location of the && on the second 'if'. */
- if (EXPR_HAS_LOCATION (pred))
- SET_EXPR_LOCATION (expr, EXPR_LOCATION (pred));
+ if (expr_has_location (pred))
+ SET_EXPR_LOCATION (expr, expr_location (pred));
then_ = shortcut_cond_expr (expr);
then_se = then_ && TREE_SIDE_EFFECTS (then_);
pred = TREE_OPERAND (pred, 0);
@@ -3559,8 +3650,8 @@ shortcut_cond_expr (tree expr)
location_t locus = EXPR_LOC_OR_LOC (expr, input_location);
TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
/* Set the source location of the || on the second 'if'. */
- if (EXPR_HAS_LOCATION (pred))
- SET_EXPR_LOCATION (expr, EXPR_LOCATION (pred));
+ if (expr_has_location (pred))
+ SET_EXPR_LOCATION (expr, expr_location (pred));
else_ = shortcut_cond_expr (expr);
else_se = else_ && TREE_SIDE_EFFECTS (else_);
pred = TREE_OPERAND (pred, 0);
@@ -3587,20 +3678,16 @@ shortcut_cond_expr (tree expr)
/* If our arms just jump somewhere, hijack those labels so we don't
generate jumps to jumps. */
- if (then_
- && TREE_CODE (then_) == GOTO_EXPR
- && TREE_CODE (GOTO_DESTINATION (then_)) == LABEL_DECL)
+ if (tree then_goto = find_goto_label (then_))
{
- true_label = GOTO_DESTINATION (then_);
+ true_label = GOTO_DESTINATION (then_goto);
then_ = NULL;
then_se = false;
}
- if (else_
- && TREE_CODE (else_) == GOTO_EXPR
- && TREE_CODE (GOTO_DESTINATION (else_)) == LABEL_DECL)
+ if (tree else_goto = find_goto_label (else_))
{
- false_label = GOTO_DESTINATION (else_);
+ false_label = GOTO_DESTINATION (else_goto);
else_ = NULL;
else_se = false;
}
@@ -3664,8 +3751,8 @@ shortcut_cond_expr (tree expr)
{
tree last = expr_last (expr);
t = build_and_jump (&end_label);
- if (EXPR_HAS_LOCATION (last))
- SET_EXPR_LOCATION (t, EXPR_LOCATION (last));
+ if (expr_has_location (last))
+ SET_EXPR_LOCATION (t, expr_location (last));
append_to_statement_list (t, &expr);
}
if (emit_false)
@@ -3958,39 +4045,35 @@ gimplify_cond_expr (tree *expr_p, gimple_seq *pre_p, fallback_t fallback)
gimple_push_condition ();
have_then_clause_p = have_else_clause_p = false;
- if (TREE_OPERAND (expr, 1) != NULL
- && TREE_CODE (TREE_OPERAND (expr, 1)) == GOTO_EXPR
- && TREE_CODE (GOTO_DESTINATION (TREE_OPERAND (expr, 1))) == LABEL_DECL
- && (DECL_CONTEXT (GOTO_DESTINATION (TREE_OPERAND (expr, 1)))
- == current_function_decl)
+ label_true = find_goto_label (TREE_OPERAND (expr, 1));
+ if (label_true
+ && DECL_CONTEXT (GOTO_DESTINATION (label_true)) == current_function_decl
/* For -O0 avoid this optimization if the COND_EXPR and GOTO_EXPR
have different locations, otherwise we end up with incorrect
location information on the branches. */
&& (optimize
|| !EXPR_HAS_LOCATION (expr)
- || !EXPR_HAS_LOCATION (TREE_OPERAND (expr, 1))
- || EXPR_LOCATION (expr) == EXPR_LOCATION (TREE_OPERAND (expr, 1))))
+ || !expr_has_location (label_true)
+ || EXPR_LOCATION (expr) == expr_location (label_true)))
{
- label_true = GOTO_DESTINATION (TREE_OPERAND (expr, 1));
have_then_clause_p = true;
+ label_true = GOTO_DESTINATION (label_true);
}
else
label_true = create_artificial_label (UNKNOWN_LOCATION);
- if (TREE_OPERAND (expr, 2) != NULL
- && TREE_CODE (TREE_OPERAND (expr, 2)) == GOTO_EXPR
- && TREE_CODE (GOTO_DESTINATION (TREE_OPERAND (expr, 2))) == LABEL_DECL
- && (DECL_CONTEXT (GOTO_DESTINATION (TREE_OPERAND (expr, 2)))
- == current_function_decl)
+ label_false = find_goto_label (TREE_OPERAND (expr, 2));
+ if (label_false
+ && DECL_CONTEXT (GOTO_DESTINATION (label_false)) == current_function_decl
/* For -O0 avoid this optimization if the COND_EXPR and GOTO_EXPR
have different locations, otherwise we end up with incorrect
location information on the branches. */
&& (optimize
|| !EXPR_HAS_LOCATION (expr)
- || !EXPR_HAS_LOCATION (TREE_OPERAND (expr, 2))
- || EXPR_LOCATION (expr) == EXPR_LOCATION (TREE_OPERAND (expr, 2))))
+ || !expr_has_location (label_false)
+ || EXPR_LOCATION (expr) == expr_location (label_false)))
{
- label_false = GOTO_DESTINATION (TREE_OPERAND (expr, 2));
have_else_clause_p = true;
+ label_false = GOTO_DESTINATION (label_false);
}
else
label_false = create_artificial_label (UNKNOWN_LOCATION);
@@ -11775,6 +11858,18 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
ret = GS_ALL_DONE;
break;
+ case DEBUG_EXPR_DECL:
+ gcc_unreachable ();
+
+ case DEBUG_BEGIN_STMT:
+ gimplify_seq_add_stmt (pre_p,
+ gimple_build_debug_begin_stmt
+ (TREE_BLOCK (*expr_p),
+ EXPR_LOCATION (*expr_p)));
+ ret = GS_ALL_DONE;
+ *expr_p = NULL;
+ break;
+
case SSA_NAME:
/* Allow callbacks into the gimplifier during optimization. */
ret = GS_ALL_DONE;
@@ -1331,7 +1331,7 @@ gsi_insert_earliest (gimple_seq seq)
FOR_EACH_VEC_ELT (stmts, i, use_stmt)
{
gcc_assert (gimple_code (use_stmt) != GIMPLE_PHI);
- gimple_stmt_iterator gsi_def_stmt = gsi_start_bb_nondebug (begin_bb);
+ gimple_stmt_iterator gsi_def_stmt = gsi_start_nondebug_bb (begin_bb);
use_operand_p use_p;
ssa_op_iter op_iter;
@@ -1363,7 +1363,7 @@ gsi_insert_earliest (gimple_seq seq)
else if (gimple_code (gsi_stmt (gsi_def_stmt)) == GIMPLE_PHI)
{
gimple_stmt_iterator bsi
- = gsi_start_bb_nondebug (gsi_bb (gsi_def_stmt));
+ = gsi_start_nondebug_bb (gsi_bb (gsi_def_stmt));
/* Insert right after the PHI statements. */
gsi_insert_before (&bsi, use_stmt, GSI_NEW_STMT);
}
@@ -1646,7 +1646,8 @@ rename_uses (gimple *copy, gimple_stmt_iterator *gsi_tgt, basic_block old_bb,
{
if (gimple_debug_bind_p (copy))
gimple_debug_bind_reset_value (copy);
- else if (gimple_debug_source_bind_p (copy))
+ else if (gimple_debug_source_bind_p (copy)
+ || gimple_debug_begin_stmt_p (copy))
return false;
else
gcc_unreachable ();
@@ -261,7 +261,7 @@ trivially_empty_bb_p (basic_block bb)
gimple_stmt_iterator gsi;
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
- if (gimple_code (gsi_stmt (gsi)) != GIMPLE_DEBUG)
+ if (!is_gimple_debug (gsi_stmt (gsi)))
return false;
return true;
@@ -8160,7 +8160,7 @@ sched_extend_bb (void)
|| (!NOTE_P (insn)
&& !LABEL_P (insn)
/* Don't emit a NOTE if it would end up before a BARRIER. */
- && !BARRIER_P (NEXT_INSN (end))))
+ && !BARRIER_P (next_nondebug_insn (end))))
{
rtx_note *note = emit_note_after (NOTE_INSN_DELETED, end);
/* Make note appear outside BB. */
@@ -68,6 +68,9 @@ INSN_NOTE (VAR_LOCATION)
/* The values passed to callee. */
INSN_NOTE (CALL_ARG_LOCATION)
+/* The beginning of a statement. */
+INSN_NOTE (BEGIN_STMT)
+
/* Record the struct for the following basic block. Uses
NOTE_BASIC_BLOCK. FIXME: Redundant with the basic block pointer
now included in every insn. NOTE: If there's no CFG anymore, in other words,
@@ -629,8 +629,8 @@ func_checker::compare_bb (sem_bb *bb1, sem_bb *bb2)
gimple_stmt_iterator gsi1, gsi2;
gimple *s1, *s2;
- gsi1 = gsi_start_bb_nondebug (bb1->bb);
- gsi2 = gsi_start_bb_nondebug (bb2->bb);
+ gsi1 = gsi_start_nondebug_bb (bb1->bb);
+ gsi2 = gsi_start_nondebug_bb (bb2->bb);
while (!gsi_end_p (gsi1))
{
@@ -123,7 +123,7 @@ cleanup_barriers (void)
{
if (BARRIER_P (insn))
{
- rtx_insn *prev = prev_nonnote_insn (insn);
+ rtx_insn *prev = prev_nonnote_nondebug_insn (insn);
if (!prev)
continue;
@@ -130,6 +130,7 @@ extern int lhd_type_dwarf_attribute (const_tree, int);
#define LANG_HOOKS_EH_USE_CXA_END_CLEANUP false
#define LANG_HOOKS_DEEP_UNSHARING false
#define LANG_HOOKS_CUSTOM_FUNCTION_DESCRIPTORS false
+#define LANG_HOOKS_EMITS_BEGIN_STMT false
#define LANG_HOOKS_RUN_LANG_SELFTESTS lhd_do_nothing
#define LANG_HOOKS_GET_SUBSTRING_LOCATION lhd_get_substring_location
@@ -341,6 +342,7 @@ extern void lhd_end_section (void);
LANG_HOOKS_EH_USE_CXA_END_CLEANUP, \
LANG_HOOKS_DEEP_UNSHARING, \
LANG_HOOKS_CUSTOM_FUNCTION_DESCRIPTORS, \
+ LANG_HOOKS_EMITS_BEGIN_STMT, \
LANG_HOOKS_RUN_LANG_SELFTESTS, \
LANG_HOOKS_GET_SUBSTRING_LOCATION \
}
@@ -524,6 +524,9 @@ struct lang_hooks
instead of trampolines. */
bool custom_function_descriptors;
+ /* True if this language emits begin stmt notes. */
+ bool emits_begin_stmt;
+
/* Run all lang-specific selftests. */
void (*run_lang_selftests) (void);
@@ -2025,11 +2025,13 @@ apply_opt_in_copies (struct opt_info *opt_info,
{
if (!INSN_P (insn)
|| (DEBUG_INSN_P (insn)
+ && INSN_VAR_LOCATION_DECL (insn)
&& TREE_CODE (INSN_VAR_LOCATION_DECL (insn)) == LABEL_DECL))
continue;
while (!INSN_P (orig_insn)
|| (DEBUG_INSN_P (orig_insn)
+ && INSN_VAR_LOCATION_DECL (orig_insn)
&& (TREE_CODE (INSN_VAR_LOCATION_DECL (orig_insn))
== LABEL_DECL)))
orig_insn = NEXT_INSN (orig_insn);
@@ -5269,10 +5269,11 @@ inherit_reload_reg (bool def_p, int original_regno,
lra_update_insn_regno_info (as_a <rtx_insn *> (usage_insn));
if (lra_dump_file != NULL)
{
+ basic_block bb = BLOCK_FOR_INSN (usage_insn);
fprintf (lra_dump_file,
" Inheritance reuse change %d->%d (bb%d):\n",
original_regno, REGNO (new_reg),
- BLOCK_FOR_INSN (usage_insn)->index);
+ bb ? bb->index : -1);
dump_insn_slim (lra_dump_file, as_a <rtx_insn *> (usage_insn));
}
}
@@ -5816,6 +5817,13 @@ update_ebb_live_info (rtx_insn *head, rtx_insn *tail)
if (NOTE_P (curr_insn) && NOTE_KIND (curr_insn) != NOTE_INSN_BASIC_BLOCK)
continue;
curr_bb = BLOCK_FOR_INSN (curr_insn);
+ if (!curr_bb)
+ {
+ gcc_assert (DEBUG_INSN_P (curr_insn));
+ if (!INSN_VAR_LOCATION_DECL (curr_insn))
+ continue;
+ curr_bb = prev_bb;
+ }
if (curr_bb != prev_bb)
{
if (prev_bb != NULL)
@@ -1602,7 +1602,7 @@ lra_update_insn_regno_info (rtx_insn *insn)
return;
data = lra_get_insn_recog_data (insn);
static_data = data->insn_static_data;
- freq = get_insn_freq (insn);
+ freq = NONDEBUG_INSN_P (insn) ? get_insn_freq (insn) : 0;
invalidate_insn_data_regno_info (data, insn, freq);
uid = INSN_UID (insn);
for (i = static_data->n_operands - 1; i >= 0; i--)
@@ -1812,7 +1812,7 @@ push_insns (rtx_insn *from, rtx_insn *to)
static void
setup_sp_offset (rtx_insn *from, rtx_insn *last)
{
- rtx_insn *before = next_nonnote_insn_bb (last);
+ rtx_insn *before = next_nonnote_nondebug_insn_bb (last);
HOST_WIDE_INT offset = (before == NULL_RTX || ! INSN_P (before)
? 0 : lra_get_insn_recog_data (before)->sp_offset);
@@ -1169,6 +1169,13 @@ input_function (tree fn_decl, struct data_in *data_in,
{
gsi_next (&bsi);
stmts[gimple_uid (stmt)] = stmt;
+
+ /* Remember that the input function has begin stmt
+ markers, so that we know to expect them when emitting
+ debug info. */
+ if (!cfun->begin_stmt_markers
+ && gimple_debug_begin_stmt_p (stmt))
+ cfun->begin_stmt_markers = true;
}
}
}
@@ -658,7 +658,7 @@ expand_parallel_call (struct omp_region *region, basic_block bb,
false, GSI_CONTINUE_LINKING);
}
- gsi = gsi_last_bb (bb);
+ gsi = gsi_last_nondebug_bb (bb);
t = gimple_omp_parallel_data_arg (entry_stmt);
if (t == NULL)
t1 = null_pointer_node;
@@ -709,7 +709,7 @@ expand_cilk_for_call (basic_block bb, gomp_parallel *entry_stmt,
gcc_assert (count != NULL_TREE);
count = OMP_CLAUSE_OPERAND (count, 0);
- gsi = gsi_last_bb (bb);
+ gsi = gsi_last_nondebug_bb (bb);
t = gimple_omp_parallel_data_arg (entry_stmt);
if (t == NULL)
t1 = null_pointer_node;
@@ -835,7 +835,7 @@ expand_task_call (struct omp_region *region, basic_block bb,
else
priority = integer_zero_node;
- gsi = gsi_last_bb (bb);
+ gsi = gsi_last_nondebug_bb (bb);
tree t = gimple_omp_task_data_arg (entry_stmt);
if (t == NULL)
t2 = null_pointer_node;
@@ -912,15 +912,15 @@ remove_exit_barrier (struct omp_region *region)
statements that can appear in between are extremely limited -- no
memory operations at all. Here, we allow nothing at all, so the
only thing we allow to precede this GIMPLE_OMP_RETURN is a label. */
- gsi = gsi_last_bb (exit_bb);
+ gsi = gsi_last_nondebug_bb (exit_bb);
gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN);
- gsi_prev (&gsi);
+ gsi_prev_nondebug (&gsi);
if (!gsi_end_p (gsi) && gimple_code (gsi_stmt (gsi)) != GIMPLE_LABEL)
return;
FOR_EACH_EDGE (e, ei, exit_bb->preds)
{
- gsi = gsi_last_bb (e->src);
+ gsi = gsi_last_nondebug_bb (e->src);
if (gsi_end_p (gsi))
continue;
stmt = gsi_stmt (gsi);
@@ -1147,7 +1147,7 @@ expand_omp_taskreg (struct omp_region *region)
entry_succ_e = single_succ_edge (entry_bb);
- gsi = gsi_last_bb (entry_bb);
+ gsi = gsi_last_nondebug_bb (entry_bb);
gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_PARALLEL
|| gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_TASK);
gsi_remove (&gsi, true);
@@ -1260,7 +1260,7 @@ expand_omp_taskreg (struct omp_region *region)
/* Split ENTRY_BB at GIMPLE_OMP_PARALLEL or GIMPLE_OMP_TASK,
so that it can be moved to the child function. */
- gsi = gsi_last_bb (entry_bb);
+ gsi = gsi_last_nondebug_bb (entry_bb);
stmt = gsi_stmt (gsi);
gcc_assert (stmt && (gimple_code (stmt) == GIMPLE_OMP_PARALLEL
|| gimple_code (stmt) == GIMPLE_OMP_TASK));
@@ -1276,7 +1276,7 @@ expand_omp_taskreg (struct omp_region *region)
gcc_assert (e2->dest == region->exit);
remove_edge (BRANCH_EDGE (entry_bb));
set_immediate_dominator (CDI_DOMINATORS, e2->dest, e->src);
- gsi = gsi_last_bb (region->exit);
+ gsi = gsi_last_nondebug_bb (region->exit);
gcc_assert (!gsi_end_p (gsi)
&& gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN);
gsi_remove (&gsi, true);
@@ -1285,7 +1285,7 @@ expand_omp_taskreg (struct omp_region *region)
/* Convert GIMPLE_OMP_{RETURN,CONTINUE} into a RETURN_EXPR. */
if (exit_bb)
{
- gsi = gsi_last_bb (exit_bb);
+ gsi = gsi_last_nondebug_bb (exit_bb);
gcc_assert (!gsi_end_p (gsi)
&& (gimple_code (gsi_stmt (gsi))
== (e2 ? GIMPLE_OMP_CONTINUE : GIMPLE_OMP_RETURN)));
@@ -1747,7 +1747,7 @@ expand_omp_for_init_counts (struct omp_for_data *fd, gimple_stmt_iterator *gsi,
if (l2_dom_bb == NULL)
l2_dom_bb = entry_bb;
entry_bb = e->dest;
- *gsi = gsi_last_bb (entry_bb);
+ *gsi = gsi_last_nondebug_bb (entry_bb);
}
if (POINTER_TYPE_P (itype))
@@ -2552,7 +2552,7 @@ expand_omp_for_generic (struct omp_region *region,
l3_bb = BRANCH_EDGE (entry_bb)->dest;
exit_bb = region->exit;
- gsi = gsi_last_bb (entry_bb);
+ gsi = gsi_last_nondebug_bb (entry_bb);
gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
if (fd->ordered
@@ -2582,7 +2582,7 @@ expand_omp_for_generic (struct omp_region *region,
e = split_block (entry_bb, gsi_stmt (gsi));
entry_bb = e->dest;
make_edge (zero_iter1_bb, entry_bb, EDGE_FALLTHRU);
- gsi = gsi_last_bb (entry_bb);
+ gsi = gsi_last_nondebug_bb (entry_bb);
set_immediate_dominator (CDI_DOMINATORS, entry_bb,
get_immediate_dominator (CDI_DOMINATORS,
zero_iter1_bb));
@@ -2603,7 +2603,7 @@ expand_omp_for_generic (struct omp_region *region,
e = split_block (entry_bb, gsi_stmt (gsi));
entry_bb = e->dest;
make_edge (zero_iter2_bb, entry_bb, EDGE_FALLTHRU);
- gsi = gsi_last_bb (entry_bb);
+ gsi = gsi_last_nondebug_bb (entry_bb);
set_immediate_dominator (CDI_DOMINATORS, entry_bb,
get_immediate_dominator
(CDI_DOMINATORS, zero_iter2_bb));
@@ -3021,7 +3021,7 @@ expand_omp_for_generic (struct omp_region *region,
{
/* Code to control the increment and predicate for the sequential
loop goes in the CONT_BB. */
- gsi = gsi_last_bb (cont_bb);
+ gsi = gsi_last_nondebug_bb (cont_bb);
gomp_continue *cont_stmt = as_a <gomp_continue *> (gsi_stmt (gsi));
gcc_assert (gimple_code (cont_stmt) == GIMPLE_OMP_CONTINUE);
vmain = gimple_omp_continue_control_use (cont_stmt);
@@ -3087,7 +3087,7 @@ expand_omp_for_generic (struct omp_region *region,
}
/* Add the loop cleanup function. */
- gsi = gsi_last_bb (exit_bb);
+ gsi = gsi_last_nondebug_bb (exit_bb);
if (gimple_omp_return_nowait_p (gsi_stmt (gsi)))
t = builtin_decl_explicit (BUILT_IN_GOMP_LOOP_END_NOWAIT);
else if (gimple_omp_return_lhs (gsi_stmt (gsi)))
@@ -3307,7 +3307,7 @@ expand_omp_for_static_nochunk (struct omp_region *region,
exit_bb = region->exit;
/* Iteration space partitioning goes in ENTRY_BB. */
- gsi = gsi_last_bb (entry_bb);
+ gsi = gsi_last_nondebug_bb (entry_bb);
gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
if (fd->collapse > 1)
@@ -3439,7 +3439,7 @@ expand_omp_for_static_nochunk (struct omp_region *region,
gsi_insert_before (&gsi, cond_stmt, GSI_SAME_STMT);
second_bb = split_block (entry_bb, cond_stmt)->dest;
- gsi = gsi_last_bb (second_bb);
+ gsi = gsi_last_nondebug_bb (second_bb);
gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
gsi_insert_before (&gsi, gimple_build_assign (tt, build_int_cst (itype, 0)),
@@ -3449,7 +3449,7 @@ expand_omp_for_static_nochunk (struct omp_region *region,
gsi_insert_before (&gsi, assign_stmt, GSI_SAME_STMT);
third_bb = split_block (second_bb, assign_stmt)->dest;
- gsi = gsi_last_bb (third_bb);
+ gsi = gsi_last_nondebug_bb (third_bb);
gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
t = build2 (MULT_EXPR, itype, q, threadid);
@@ -3591,7 +3591,7 @@ expand_omp_for_static_nochunk (struct omp_region *region,
{
/* The code controlling the sequential loop replaces the
GIMPLE_OMP_CONTINUE. */
- gsi = gsi_last_bb (cont_bb);
+ gsi = gsi_last_nondebug_bb (cont_bb);
gomp_continue *cont_stmt = as_a <gomp_continue *> (gsi_stmt (gsi));
gcc_assert (gimple_code (cont_stmt) == GIMPLE_OMP_CONTINUE);
vmain = gimple_omp_continue_control_use (cont_stmt);
@@ -3624,7 +3624,7 @@ expand_omp_for_static_nochunk (struct omp_region *region,
}
/* Replace the GIMPLE_OMP_RETURN with a barrier, or nothing. */
- gsi = gsi_last_bb (exit_bb);
+ gsi = gsi_last_nondebug_bb (exit_bb);
if (!gimple_omp_return_nowait_p (gsi_stmt (gsi)))
{
t = gimple_omp_return_lhs (gsi_stmt (gsi));
@@ -3791,7 +3791,7 @@ expand_omp_for_static_chunk (struct omp_region *region,
exit_bb = region->exit;
/* Trip and adjustment setup goes in ENTRY_BB. */
- gsi = gsi_last_bb (entry_bb);
+ gsi = gsi_last_nondebug_bb (entry_bb);
gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
if (fd->collapse > 1)
@@ -4097,7 +4097,7 @@ expand_omp_for_static_chunk (struct omp_region *region,
{
/* The code controlling the sequential loop goes in CONT_BB,
replacing the GIMPLE_OMP_CONTINUE. */
- gsi = gsi_last_bb (cont_bb);
+ gsi = gsi_last_nondebug_bb (cont_bb);
gomp_continue *cont_stmt = as_a <gomp_continue *> (gsi_stmt (gsi));
vmain = gimple_omp_continue_control_use (cont_stmt);
vback = gimple_omp_continue_control_def (cont_stmt);
@@ -4141,7 +4141,7 @@ expand_omp_for_static_chunk (struct omp_region *region,
}
/* Replace the GIMPLE_OMP_RETURN with a barrier, or nothing. */
- gsi = gsi_last_bb (exit_bb);
+ gsi = gsi_last_nondebug_bb (exit_bb);
if (!gimple_omp_return_nowait_p (gsi_stmt (gsi)))
{
t = gimple_omp_return_lhs (gsi_stmt (gsi));
@@ -4348,7 +4348,7 @@ expand_cilk_for (struct omp_region *region, struct omp_for_data *fd)
basic_block exit_bb = region->exit;
basic_block l2_dom_bb = NULL;
- gimple_stmt_iterator gsi = gsi_last_bb (entry_bb);
+ gimple_stmt_iterator gsi = gsi_last_nondebug_bb (entry_bb);
/* Below statements until the "tree high_val = ..." are pseudo statements
used to pass information to be used by expand_omp_taskreg.
@@ -4393,7 +4393,7 @@ expand_cilk_for (struct omp_region *region, struct omp_for_data *fd)
if (!broken_loop)
{
/* Code to control the increment goes in the CONT_BB. */
- gsi = gsi_last_bb (cont_bb);
+ gsi = gsi_last_nondebug_bb (cont_bb);
stmt = gsi_stmt (gsi);
gcc_assert (gimple_code (stmt) == GIMPLE_OMP_CONTINUE);
stmt = gimple_build_assign (ind_var, PLUS_EXPR, ind_var,
@@ -4423,7 +4423,7 @@ expand_cilk_for (struct omp_region *region, struct omp_for_data *fd)
gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
/* Remove GIMPLE_OMP_RETURN. */
- gsi = gsi_last_bb (exit_bb);
+ gsi = gsi_last_nondebug_bb (exit_bb);
gsi_remove (&gsi, true);
/* Connect the new blocks. */
@@ -4597,7 +4597,7 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd)
exit_bb = region->exit;
l2_dom_bb = NULL;
- gsi = gsi_last_bb (entry_bb);
+ gsi = gsi_last_nondebug_bb (entry_bb);
gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
/* Not needed in SSA form right now. */
@@ -4692,7 +4692,7 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd)
if (!broken_loop)
{
/* Code to control the increment goes in the CONT_BB. */
- gsi = gsi_last_bb (cont_bb);
+ gsi = gsi_last_nondebug_bb (cont_bb);
stmt = gsi_stmt (gsi);
gcc_assert (gimple_code (stmt) == GIMPLE_OMP_CONTINUE);
@@ -4786,7 +4786,7 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd)
}
/* Remove GIMPLE_OMP_RETURN. */
- gsi = gsi_last_bb (exit_bb);
+ gsi = gsi_last_nondebug_bb (exit_bb);
gsi_remove (&gsi, true);
/* Connect the new blocks. */
@@ -4913,7 +4913,7 @@ expand_omp_taskloop_for_outer (struct omp_region *region,
gcc_assert (BRANCH_EDGE (entry_bb)->dest == FALLTHRU_EDGE (cont_bb)->dest);
exit_bb = region->exit;
- gsi = gsi_last_bb (entry_bb);
+ gsi = gsi_last_nondebug_bb (entry_bb);
gimple *for_stmt = gsi_stmt (gsi);
gcc_assert (gimple_code (for_stmt) == GIMPLE_OMP_FOR);
if (fd->collapse > 1)
@@ -5014,10 +5014,10 @@ expand_omp_taskloop_for_outer (struct omp_region *region,
gsi = gsi_for_stmt (for_stmt);
gsi_remove (&gsi, true);
- gsi = gsi_last_bb (cont_bb);
+ gsi = gsi_last_nondebug_bb (cont_bb);
gsi_remove (&gsi, true);
- gsi = gsi_last_bb (exit_bb);
+ gsi = gsi_last_nondebug_bb (exit_bb);
gsi_remove (&gsi, true);
FALLTHRU_EDGE (entry_bb)->probability = profile_probability::always ();
@@ -5091,7 +5091,7 @@ expand_omp_taskloop_for_inner (struct omp_region *region,
exit_bb = region->exit;
/* Iteration space partitioning goes in ENTRY_BB. */
- gsi = gsi_last_bb (entry_bb);
+ gsi = gsi_last_nondebug_bb (entry_bb);
gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
if (fd->collapse > 1)
@@ -5170,7 +5170,7 @@ expand_omp_taskloop_for_inner (struct omp_region *region,
{
/* The code controlling the sequential loop replaces the
GIMPLE_OMP_CONTINUE. */
- gsi = gsi_last_bb (cont_bb);
+ gsi = gsi_last_nondebug_bb (cont_bb);
gomp_continue *cont_stmt = as_a <gomp_continue *> (gsi_stmt (gsi));
gcc_assert (gimple_code (cont_stmt) == GIMPLE_OMP_CONTINUE);
vmain = gimple_omp_continue_control_use (cont_stmt);
@@ -5207,7 +5207,7 @@ expand_omp_taskloop_for_inner (struct omp_region *region,
gsi_remove (&gsi, true);
/* Remove the GIMPLE_OMP_RETURN statement. */
- gsi = gsi_last_bb (exit_bb);
+ gsi = gsi_last_nondebug_bb (exit_bb);
gsi_remove (&gsi, true);
FALLTHRU_EDGE (entry_bb)->probability = profile_probability::always ();
@@ -5388,7 +5388,7 @@ expand_oacc_for (struct omp_region *region, struct omp_for_data *fd)
entry_bb = split->src;
/* Chunk setup goes at end of entry_bb, replacing the omp_for. */
- gsi = gsi_last_bb (entry_bb);
+ gsi = gsi_last_nondebug_bb (entry_bb);
gomp_for *for_stmt = as_a <gomp_for *> (gsi_stmt (gsi));
loc = gimple_location (for_stmt);
@@ -5515,7 +5515,7 @@ expand_oacc_for (struct omp_region *region, struct omp_for_data *fd)
if (gimple_in_ssa_p (cfun))
{
- gsi = gsi_last_bb (cont_bb);
+ gsi = gsi_last_nondebug_bb (cont_bb);
gomp_continue *cont_stmt = as_a <gomp_continue *> (gsi_stmt (gsi));
offset = gimple_omp_continue_control_use (cont_stmt);
@@ -5639,7 +5639,7 @@ expand_oacc_for (struct omp_region *region, struct omp_for_data *fd)
occur, especially when noreturn routines are involved. */
if (cont_bb)
{
- gsi = gsi_last_bb (cont_bb);
+ gsi = gsi_last_nondebug_bb (cont_bb);
gomp_continue *cont_stmt = as_a <gomp_continue *> (gsi_stmt (gsi));
loc = gimple_location (cont_stmt);
@@ -5719,7 +5719,7 @@ expand_oacc_for (struct omp_region *region, struct omp_for_data *fd)
}
}
- gsi = gsi_last_bb (exit_bb);
+ gsi = gsi_last_nondebug_bb (exit_bb);
gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN);
loc = gimple_location (gsi_stmt (gsi));
@@ -5946,7 +5946,7 @@ expand_omp_sections (struct omp_region *region)
len = EDGE_COUNT (l0_bb->succs);
gcc_assert (len > 0);
e = EDGE_SUCC (l0_bb, len - 1);
- si = gsi_last_bb (e->dest);
+ si = gsi_last_nondebug_bb (e->dest);
l2 = NULL_TREE;
if (gsi_end_p (si)
|| gimple_code (gsi_stmt (si)) != GIMPLE_OMP_SECTION)
@@ -5954,7 +5954,7 @@ expand_omp_sections (struct omp_region *region)
else
FOR_EACH_EDGE (e, ei, l0_bb->succs)
{
- si = gsi_last_bb (e->dest);
+ si = gsi_last_nondebug_bb (e->dest);
if (gsi_end_p (si)
|| gimple_code (gsi_stmt (si)) != GIMPLE_OMP_SECTION)
{
@@ -5979,7 +5979,7 @@ expand_omp_sections (struct omp_region *region)
/* The call to GOMP_sections_start goes in ENTRY_BB, replacing the
GIMPLE_OMP_SECTIONS statement. */
- si = gsi_last_bb (entry_bb);
+ si = gsi_last_nondebug_bb (entry_bb);
sections_stmt = as_a <gomp_sections *> (gsi_stmt (si));
gcc_assert (gimple_code (sections_stmt) == GIMPLE_OMP_SECTIONS);
vin = gimple_omp_sections_control (sections_stmt);
@@ -6003,7 +6003,7 @@ expand_omp_sections (struct omp_region *region)
/* The switch() statement replacing GIMPLE_OMP_SECTIONS_SWITCH goes in
L0_BB. */
- switch_si = gsi_last_bb (l0_bb);
+ switch_si = gsi_last_nondebug_bb (l0_bb);
gcc_assert (gimple_code (gsi_stmt (switch_si)) == GIMPLE_OMP_SECTIONS_SWITCH);
if (exit_reachable)
{
@@ -6045,7 +6045,7 @@ expand_omp_sections (struct omp_region *region)
u = build_case_label (u, NULL, t);
label_vec.quick_push (u);
- si = gsi_last_bb (s_entry_bb);
+ si = gsi_last_nondebug_bb (s_entry_bb);
gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_SECTION);
gcc_assert (i < len || gimple_omp_section_last_p (gsi_stmt (si)));
gsi_remove (&si, true);
@@ -6054,7 +6054,7 @@ expand_omp_sections (struct omp_region *region)
if (s_exit_bb == NULL)
continue;
- si = gsi_last_bb (s_exit_bb);
+ si = gsi_last_nondebug_bb (s_exit_bb);
gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_RETURN);
gsi_remove (&si, true);
@@ -6080,7 +6080,7 @@ expand_omp_sections (struct omp_region *region)
tree bfn_decl;
/* Code to get the next section goes in L1_BB. */
- si = gsi_last_bb (l1_bb);
+ si = gsi_last_nondebug_bb (l1_bb);
gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_CONTINUE);
bfn_decl = builtin_decl_explicit (BUILT_IN_GOMP_SECTIONS_NEXT);
@@ -6093,7 +6093,7 @@ expand_omp_sections (struct omp_region *region)
}
/* Cleanup function replaces GIMPLE_OMP_RETURN in EXIT_BB. */
- si = gsi_last_bb (l2_bb);
+ si = gsi_last_nondebug_bb (l2_bb);
if (gimple_omp_return_nowait_p (gsi_stmt (si)))
t = builtin_decl_explicit (BUILT_IN_GOMP_SECTIONS_END_NOWAIT);
else if (gimple_omp_return_lhs (gsi_stmt (si)))
@@ -6121,12 +6121,12 @@ expand_omp_single (struct omp_region *region)
entry_bb = region->entry;
exit_bb = region->exit;
- si = gsi_last_bb (entry_bb);
+ si = gsi_last_nondebug_bb (entry_bb);
gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_SINGLE);
gsi_remove (&si, true);
single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU;
- si = gsi_last_bb (exit_bb);
+ si = gsi_last_nondebug_bb (exit_bb);
if (!gimple_omp_return_nowait_p (gsi_stmt (si)))
{
tree t = gimple_omp_return_lhs (gsi_stmt (si));
@@ -6149,7 +6149,7 @@ expand_omp_synch (struct omp_region *region)
entry_bb = region->entry;
exit_bb = region->exit;
- si = gsi_last_bb (entry_bb);
+ si = gsi_last_nondebug_bb (entry_bb);
gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_SINGLE
|| gimple_code (gsi_stmt (si)) == GIMPLE_OMP_MASTER
|| gimple_code (gsi_stmt (si)) == GIMPLE_OMP_TASKGROUP
@@ -6161,7 +6161,7 @@ expand_omp_synch (struct omp_region *region)
if (exit_bb)
{
- si = gsi_last_bb (exit_bb);
+ si = gsi_last_nondebug_bb (exit_bb);
gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_RETURN);
gsi_remove (&si, true);
single_succ_edge (exit_bb)->flags = EDGE_FALLTHRU;
@@ -6182,7 +6182,7 @@ expand_omp_atomic_load (basic_block load_bb, tree addr,
gimple *stmt;
tree decl, call, type, itype;
- gsi = gsi_last_bb (load_bb);
+ gsi = gsi_last_nondebug_bb (load_bb);
stmt = gsi_stmt (gsi);
gcc_assert (gimple_code (stmt) == GIMPLE_OMP_ATOMIC_LOAD);
loc = gimple_location (stmt);
@@ -6212,7 +6212,7 @@ expand_omp_atomic_load (basic_block load_bb, tree addr,
gsi_remove (&gsi, true);
store_bb = single_succ (load_bb);
- gsi = gsi_last_bb (store_bb);
+ gsi = gsi_last_nondebug_bb (store_bb);
gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_ATOMIC_STORE);
gsi_remove (&gsi, true);
@@ -6238,14 +6238,14 @@ expand_omp_atomic_store (basic_block load_bb, tree addr,
machine_mode imode;
bool exchange;
- gsi = gsi_last_bb (load_bb);
+ gsi = gsi_last_nondebug_bb (load_bb);
stmt = gsi_stmt (gsi);
gcc_assert (gimple_code (stmt) == GIMPLE_OMP_ATOMIC_LOAD);
/* If the load value is needed, then this isn't a store but an exchange. */
exchange = gimple_omp_atomic_need_value_p (stmt);
- gsi = gsi_last_bb (store_bb);
+ gsi = gsi_last_nondebug_bb (store_bb);
stmt = gsi_stmt (gsi);
gcc_assert (gimple_code (stmt) == GIMPLE_OMP_ATOMIC_STORE);
loc = gimple_location (stmt);
@@ -6290,7 +6290,7 @@ expand_omp_atomic_store (basic_block load_bb, tree addr,
gsi_remove (&gsi, true);
/* Remove the GIMPLE_OMP_ATOMIC_LOAD that we verified above. */
- gsi = gsi_last_bb (load_bb);
+ gsi = gsi_last_nondebug_bb (load_bb);
gsi_remove (&gsi, true);
if (gimple_in_ssa_p (cfun))
@@ -6337,10 +6337,17 @@ expand_omp_atomic_fetch_op (basic_block load_bb,
gsi = gsi_after_labels (store_bb);
stmt = gsi_stmt (gsi);
+ if (is_gimple_debug (stmt))
+ {
+ gsi_next_nondebug (&gsi);
+ if (gsi_end_p (gsi))
+ return false;
+ stmt = gsi_stmt (gsi);
+ }
loc = gimple_location (stmt);
if (!is_gimple_assign (stmt))
return false;
- gsi_next (&gsi);
+ gsi_next_nondebug (&gsi);
if (gimple_code (gsi_stmt (gsi)) != GIMPLE_OMP_ATOMIC_STORE)
return false;
need_new = gimple_omp_atomic_need_value_p (gsi_stmt (gsi));
@@ -6404,7 +6411,7 @@ expand_omp_atomic_fetch_op (basic_block load_bb,
if (!can_compare_and_swap_p (imode, true) || !can_atomic_load_p (imode))
return false;
- gsi = gsi_last_bb (load_bb);
+ gsi = gsi_last_nondebug_bb (load_bb);
gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_ATOMIC_LOAD);
/* OpenMP does not imply any barrier-like semantics on its atomic ops.
@@ -6427,10 +6434,10 @@ expand_omp_atomic_fetch_op (basic_block load_bb,
force_gimple_operand_gsi (&gsi, call, true, NULL_TREE, true, GSI_SAME_STMT);
gsi_remove (&gsi, true);
- gsi = gsi_last_bb (store_bb);
+ gsi = gsi_last_nondebug_bb (store_bb);
gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_ATOMIC_STORE);
gsi_remove (&gsi, true);
- gsi = gsi_last_bb (store_bb);
+ gsi = gsi_last_nondebug_bb (store_bb);
stmt = gsi_stmt (gsi);
gsi_remove (&gsi, true);
@@ -6483,7 +6490,7 @@ expand_omp_atomic_pipeline (basic_block load_bb, basic_block store_bb,
return false;
/* Load the initial value, replacing the GIMPLE_OMP_ATOMIC_LOAD. */
- si = gsi_last_bb (load_bb);
+ si = gsi_last_nondebug_bb (load_bb);
gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ATOMIC_LOAD);
/* For floating-point values, we'll need to view-convert them to integers
@@ -6563,7 +6570,7 @@ expand_omp_atomic_pipeline (basic_block load_bb, basic_block store_bb,
}
gsi_remove (&si, true);
- si = gsi_last_bb (store_bb);
+ si = gsi_last_nondebug_bb (store_bb);
gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ATOMIC_STORE);
if (iaddr == addr)
@@ -6666,7 +6673,7 @@ expand_omp_atomic_mutex (basic_block load_bb, basic_block store_bb,
gassign *stmt;
tree t;
- si = gsi_last_bb (load_bb);
+ si = gsi_last_nondebug_bb (load_bb);
gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ATOMIC_LOAD);
t = builtin_decl_explicit (BUILT_IN_GOMP_ATOMIC_START);
@@ -6677,7 +6684,7 @@ expand_omp_atomic_mutex (basic_block load_bb, basic_block store_bb,
gsi_insert_before (&si, stmt, GSI_SAME_STMT);
gsi_remove (&si, true);
- si = gsi_last_bb (store_bb);
+ si = gsi_last_nondebug_bb (store_bb);
gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ATOMIC_STORE);
stmt = gimple_build_assign (build_simple_mem_ref (unshare_expr (addr)),
@@ -7175,7 +7182,7 @@ expand_omp_target (struct omp_region *region)
/* Split ENTRY_BB at GIMPLE_*,
so that it can be moved to the child function. */
- gsi = gsi_last_bb (entry_bb);
+ gsi = gsi_last_nondebug_bb (entry_bb);
stmt = gsi_stmt (gsi);
gcc_assert (stmt
&& gimple_code (stmt) == gimple_code (entry_stmt));
@@ -7187,7 +7194,7 @@ expand_omp_target (struct omp_region *region)
/* Convert GIMPLE_OMP_RETURN into a RETURN_EXPR. */
if (exit_bb)
{
- gsi = gsi_last_bb (exit_bb);
+ gsi = gsi_last_nondebug_bb (exit_bb);
gcc_assert (!gsi_end_p (gsi)
&& gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN);
stmt = gimple_build_return (NULL);
@@ -7369,7 +7376,7 @@ expand_omp_target (struct omp_region *region)
e = split_block_after_labels (new_bb);
else
{
- gsi = gsi_last_bb (new_bb);
+ gsi = gsi_last_nondebug_bb (new_bb);
gsi_prev (&gsi);
e = split_block (new_bb, gsi_stmt (gsi));
}
@@ -7404,11 +7411,11 @@ expand_omp_target (struct omp_region *region)
make_edge (else_bb, new_bb, EDGE_FALLTHRU);
device = tmp_var;
- gsi = gsi_last_bb (new_bb);
+ gsi = gsi_last_nondebug_bb (new_bb);
}
else
{
- gsi = gsi_last_bb (new_bb);
+ gsi = gsi_last_nondebug_bb (new_bb);
device = force_gimple_operand_gsi (&gsi, device, true, NULL_TREE,
true, GSI_SAME_STMT);
}
@@ -7552,7 +7559,7 @@ expand_omp_target (struct omp_region *region)
}
if (data_region && region->exit)
{
- gsi = gsi_last_bb (region->exit);
+ gsi = gsi_last_nondebug_bb (region->exit);
g = gsi_stmt (gsi);
gcc_assert (g && gimple_code (g) == GIMPLE_OMP_RETURN);
gsi_remove (&gsi, true);
@@ -7633,17 +7640,17 @@ grid_expand_omp_for_loop (struct omp_region *kfor, bool intra_group)
gsi_insert_before (&gsi, assign_stmt, GSI_SAME_STMT);
}
/* Remove the omp for statement. */
- gsi = gsi_last_bb (kfor->entry);
+ gsi = gsi_last_nondebug_bb (kfor->entry);
gsi_remove (&gsi, true);
/* Remove the GIMPLE_OMP_CONTINUE statement. */
- gsi = gsi_last_bb (kfor->cont);
+ gsi = gsi_last_nondebug_bb (kfor->cont);
gcc_assert (!gsi_end_p (gsi)
&& gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_CONTINUE);
gsi_remove (&gsi, true);
/* Replace the GIMPLE_OMP_RETURN with a barrier, if necessary. */
- gsi = gsi_last_bb (kfor->exit);
+ gsi = gsi_last_nondebug_bb (kfor->exit);
gcc_assert (!gsi_end_p (gsi)
&& gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN);
if (intra_group)
@@ -7787,11 +7794,11 @@ grid_expand_target_grid_body (struct omp_region *target)
grid_expand_omp_for_loop (kfor, false);
/* Remove the omp for statement. */
- gimple_stmt_iterator gsi = gsi_last_bb (gpukernel->entry);
+ gimple_stmt_iterator gsi = gsi_last_nondebug_bb (gpukernel->entry);
gsi_remove (&gsi, true);
/* Replace the GIMPLE_OMP_RETURN at the end of the kernel region with a real
return. */
- gsi = gsi_last_bb (gpukernel->exit);
+ gsi = gsi_last_nondebug_bb (gpukernel->exit);
gcc_assert (!gsi_end_p (gsi)
&& gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN);
gimple *ret_stmt = gimple_build_return (NULL);
@@ -7975,7 +7982,7 @@ build_omp_regions_1 (basic_block bb, struct omp_region *parent,
gimple *stmt;
basic_block son;
- gsi = gsi_last_bb (bb);
+ gsi = gsi_last_nondebug_bb (bb);
if (!gsi_end_p (gsi) && is_gimple_omp (gsi_stmt (gsi)))
{
struct omp_region *region;
@@ -7015,6 +7015,8 @@ check_combined_parallel (gimple_stmt_iterator *gsi_p,
{
WALK_SUBSTMTS;
+ case GIMPLE_DEBUG:
+ break;
case GIMPLE_OMP_FOR:
case GIMPLE_OMP_SECTIONS:
*info = *info == 0 ? 1 : -1;
@@ -2293,7 +2293,7 @@ common_handle_option (struct gcc_options *opts,
/* FALLTHRU */
case OPT_gdwarf_:
- if (value < 2 || value > 5)
+ if (value < 2 || value > 6)
error_at (loc, "dwarf version %d is not supported", value);
else
opts->x_dwarf_version = value;
@@ -59,7 +59,7 @@ const char *get_some_local_dynamic_name ();
for the new function. The label for the function and associated
assembler pseudo-ops have already been output in
`assemble_start_function'. */
-extern void final_start_function (rtx_insn *, FILE *, int);
+extern void final_start_function (rtx_insn **, FILE *, int);
/* Output assembler code for the end of a function.
For clarity, args are same as those of `final_start_function'
@@ -960,6 +960,15 @@ DEFPARAM (PARAM_MAX_VARTRACK_REVERSE_OP_SIZE,
"Max. size of loc list for which reverse ops should be added.",
50, 0, 0)
+/* Set a threshold to discard debug markers (e.g. debug begin stmt
+ markers) when expanding a function to RTL, or inlining it into
+ another function. */
+
+DEFPARAM (PARAM_MAX_DEBUG_MARKER_COUNT,
+ "max-debug-marker-count",
+ "Max. count of debug markers to expand or inline.",
+ 100000, 0, 0)
+
/* Set minimum insn uid for non-debug insns. */
DEFPARAM (PARAM_MIN_NONDEBUG_INSN_UID,
@@ -258,6 +258,16 @@ rtx_writer::print_rtx_operand_code_0 (const_rtx in_rtx ATTRIBUTE_UNUSED,
fputc ('\t', m_outfile);
break;
+ case NOTE_INSN_BEGIN_STMT:
+#ifndef GENERATOR_FILE
+ {
+ expanded_location xloc
+ = expand_location (NOTE_BEGIN_STMT_LOCATION (in_rtx));
+ fprintf (m_outfile, " %s:%i", xloc.file, xloc.line);
+ }
+#endif
+ break;
+
default:
break;
}
@@ -806,7 +816,9 @@ rtx_writer::print_rtx (const_rtx in_rtx)
#ifndef GENERATOR_FILE
if (GET_CODE (in_rtx) == VAR_LOCATION)
{
- if (TREE_CODE (PAT_VAR_LOCATION_DECL (in_rtx)) == STRING_CST)
+ if (!PAT_VAR_LOCATION_DECL (in_rtx))
+ fputs (" <begin stmt marker>", m_outfile);
+ else if (TREE_CODE (PAT_VAR_LOCATION_DECL (in_rtx)) == STRING_CST)
fputs (" <debug string placeholder>", m_outfile);
else
print_mem_expr (m_outfile, PAT_VAR_LOCATION_DECL (in_rtx));
@@ -1791,6 +1803,12 @@ print_insn (pretty_printer *pp, const rtx_insn *x, int verbose)
case DEBUG_INSN:
{
+ if (!INSN_VAR_LOCATION_DECL (x))
+ {
+ pp_string (pp, "debug begin stmt marker");
+ break;
+ }
+
const char *name = "?";
if (DECL_P (INSN_VAR_LOCATION_DECL (x)))
@@ -436,6 +436,8 @@ find_oldest_value_reg (enum reg_class cl, rtx reg, struct value_data *vd)
machine_mode mode = GET_MODE (reg);
unsigned int i;
+ gcc_assert (regno < FIRST_PSEUDO_REGISTER);
+
/* If we are accessing REG in some mode other that what we set it in,
make sure that the replacement is valid. In particular, consider
(set (reg:DI r11) (...))
@@ -815,7 +815,8 @@ struct GTY(()) rtvec_def {
#define NONDEBUG_INSN_P(X) (INSN_P (X) && !DEBUG_INSN_P (X))
/* Nonzero if DEBUG_INSN_P may possibly hold. */
-#define MAY_HAVE_DEBUG_INSNS (flag_var_tracking_assignments)
+#define MAY_HAVE_DEBUG_INSNS \
+ (flag_var_tracking_assignments || debug_statement_frontiers)
/* Predicate yielding nonzero iff X is a real insn. */
#define INSN_P(X) \
@@ -1585,6 +1586,7 @@ extern const char * const reg_note_name[];
#define NOTE_EH_HANDLER(INSN) XCINT (INSN, 3, NOTE)
#define NOTE_BASIC_BLOCK(INSN) XCBBDEF (INSN, 3, NOTE)
#define NOTE_VAR_LOCATION(INSN) XCEXP (INSN, 3, NOTE)
+#define NOTE_BEGIN_STMT_LOCATION(INSN) XCINT (INSN, 3, NOTE)
#define NOTE_CFI(INSN) XCCFI (INSN, 3, NOTE)
#define NOTE_LABEL_NUMBER(INSN) XCINT (INSN, 3, NOTE)
@@ -2900,13 +2902,13 @@ extern rtx_call_insn *last_call_insn (void);
extern rtx_insn *previous_insn (rtx_insn *);
extern rtx_insn *next_insn (rtx_insn *);
extern rtx_insn *prev_nonnote_insn (rtx_insn *);
-extern rtx_insn *prev_nonnote_insn_bb (rtx_insn *);
extern rtx_insn *next_nonnote_insn (rtx_insn *);
-extern rtx_insn *next_nonnote_insn_bb (rtx_insn *);
extern rtx_insn *prev_nondebug_insn (rtx_insn *);
extern rtx_insn *next_nondebug_insn (rtx_insn *);
extern rtx_insn *prev_nonnote_nondebug_insn (rtx_insn *);
+extern rtx_insn *prev_nonnote_nondebug_insn_bb (rtx_insn *);
extern rtx_insn *next_nonnote_nondebug_insn (rtx_insn *);
+extern rtx_insn *next_nonnote_nondebug_insn_bb (rtx_insn *);
extern rtx_insn *prev_real_insn (rtx_insn *);
extern rtx_insn *next_real_insn (rtx);
extern rtx_insn *prev_active_insn (rtx_insn *);
@@ -1520,6 +1520,18 @@ process_options (void)
warning_at (UNKNOWN_LOCATION, 0,
"var-tracking-assignments changes selective scheduling");
+ if (debug_statement_frontiers == AUTODETECT_VALUE)
+ debug_statement_frontiers = optimize && debug_info_level >= DINFO_LEVEL_NORMAL
+ && (write_symbols == DWARF2_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG);
+
+ if (debug_variable_location_views == AUTODETECT_VALUE)
+ {
+ debug_variable_location_views = flag_var_tracking
+ && debug_info_level >= DINFO_LEVEL_NORMAL
+ && (write_symbols == DWARF2_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG)
+ && !dwarf_strict;
+ }
+
if (flag_tree_cselim == AUTODETECT_VALUE)
{
if (HAVE_conditional_move)
@@ -545,14 +545,22 @@ make_blocks_1 (gimple_seq seq, basic_block bb)
{
gimple_stmt_iterator i = gsi_start (seq);
gimple *stmt = NULL;
+ gimple *prev_stmt = NULL;
bool start_new_block = true;
bool first_stmt_of_seq = true;
while (!gsi_end_p (i))
{
- gimple *prev_stmt;
-
- prev_stmt = stmt;
+ /* PREV_STMT should only be set to a debug stmt if the debug
+ stmt is before nondebug stmts. Once stmt reaches a nondebug
+ nonlabel, prev_stmt will be set to it, so that
+ stmt_starts_bb_p will know to start a new block if a label is
+ found. However, if stmt was a label after debug stmts only,
+ keep the label in prev_stmt even if we find further debug
+ stmts, for there may be other labels after them, and they
+ should land in the same block. */
+ if (!prev_stmt || !stmt || !is_gimple_debug (stmt))
+ prev_stmt = stmt;
stmt = gsi_stmt (i);
if (stmt && is_gimple_call (stmt))
@@ -567,6 +575,7 @@ make_blocks_1 (gimple_seq seq, basic_block bb)
gsi_split_seq_before (&i, &seq);
bb = create_basic_block (seq, bb);
start_new_block = false;
+ prev_stmt = NULL;
}
/* Now add STMT to BB and create the subgraphs for special statement
@@ -980,7 +989,11 @@ make_edges (void)
tree target;
if (!label_stmt)
- break;
+ {
+ if (is_gimple_debug (gsi_stmt (gsi)))
+ continue;
+ break;
+ }
target = gimple_label_label (label_stmt);
@@ -1495,6 +1508,9 @@ cleanup_dead_labels (void)
for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
{
+ if (is_gimple_debug (gsi_stmt (i)))
+ continue;
+
tree label;
glabel *label_stmt = dyn_cast <glabel *> (gsi_stmt (i));
@@ -1655,6 +1671,12 @@ cleanup_dead_labels (void)
for (i = gsi_start_bb (bb); !gsi_end_p (i); )
{
+ if (is_gimple_debug (gsi_stmt (i)))
+ {
+ gsi_next (&i);
+ continue;
+ }
+
tree label;
glabel *label_stmt = dyn_cast <glabel *> (gsi_stmt (i));
@@ -1822,6 +1844,8 @@ gimple_can_merge_blocks_p (basic_block a, basic_block b)
gsi_next (&gsi))
{
tree lab;
+ if (is_gimple_debug (gsi_stmt (gsi)))
+ continue;
glabel *label_stmt = dyn_cast <glabel *> (gsi_stmt (gsi));
if (!label_stmt)
break;
@@ -2624,6 +2648,13 @@ stmt_starts_bb_p (gimple *stmt, gimple *prev_stmt)
if (stmt == NULL)
return false;
+ /* PREV_STMT is only set to a debug stmt if the debug stmt is before
+ any nondebug stmts in the block. We don't want to start another
+ block in this case: the debug stmt will already have started the
+ one STMT would start if we weren't outputting debug stmts. */
+ if (prev_stmt && is_gimple_debug (prev_stmt))
+ return false;
+
/* Labels start a new basic block only if the preceding statement
wasn't a label of the same type. This prevents the creation of
consecutive blocks that have nothing but a single label. */
@@ -5355,6 +5386,10 @@ gimple_verify_flow_info (void)
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
tree label;
+
+ if (is_gimple_debug (gsi_stmt (gsi)))
+ continue;
+
gimple *prev_stmt = stmt;
stmt = gsi_stmt (gsi);
@@ -5424,7 +5459,7 @@ gimple_verify_flow_info (void)
}
}
- gsi = gsi_last_bb (bb);
+ gsi = gsi_last_nondebug_bb (bb);
if (gsi_end_p (gsi))
continue;
@@ -5679,8 +5714,10 @@ gimple_block_label (basic_block bb)
tree label;
glabel *stmt;
- for (i = s; !gsi_end_p (i); first = false, gsi_next (&i))
+ for (i = s; !gsi_end_p (i); gsi_next (&i))
{
+ if (is_gimple_debug (gsi_stmt (i)))
+ continue;
stmt = dyn_cast <glabel *> (gsi_stmt (i));
if (!stmt)
break;
@@ -5691,6 +5728,7 @@ gimple_block_label (basic_block bb)
gsi_move_before (&i, &s);
return label;
}
+ first = false;
}
label = create_artificial_label (UNKNOWN_LOCATION);
@@ -5766,7 +5804,7 @@ gimple_redirect_edge_and_branch (edge e, basic_block dest)
return ret;
}
- gsi = gsi_last_bb (bb);
+ gsi = gsi_last_nondebug_bb (bb);
stmt = gsi_end_p (gsi) ? NULL : gsi_stmt (gsi);
switch (stmt ? gimple_code (stmt) : GIMPLE_ERROR_MARK)
@@ -506,13 +506,13 @@ remove_forwarder_block (basic_block bb)
{
tree decl;
label = gsi_stmt (gsi);
- if (is_gimple_debug (label))
- break;
- decl = gimple_label_label (as_a <glabel *> (label));
- if (EH_LANDING_PAD_NR (decl) != 0
- || DECL_NONLOCAL (decl)
- || FORCED_LABEL (decl)
- || !DECL_ARTIFICIAL (decl))
+ if (is_gimple_debug (label)
+ ? can_move_debug_stmts
+ : ((decl = gimple_label_label (as_a <glabel *> (label))),
+ EH_LANDING_PAD_NR (decl) != 0
+ || DECL_NONLOCAL (decl)
+ || FORCED_LABEL (decl)
+ || !DECL_ARTIFICIAL (decl)))
{
gsi_remove (&gsi, false);
gsi_insert_before (&gsi_to, label, GSI_SAME_STMT);
@@ -521,20 +521,6 @@ remove_forwarder_block (basic_block bb)
gsi_next (&gsi);
}
- /* Move debug statements if the destination has a single predecessor. */
- if (can_move_debug_stmts)
- {
- gsi_to = gsi_after_labels (dest);
- for (gsi = gsi_after_labels (bb); !gsi_end_p (gsi); )
- {
- gimple *debug = gsi_stmt (gsi);
- if (!is_gimple_debug (debug))
- break;
- gsi_remove (&gsi, false);
- gsi_insert_before (&gsi_to, debug, GSI_SAME_STMT);
- }
- }
-
bitmap_set_bit (cfgcleanup_altered_bbs, dest->index);
/* Update the dominators. */
@@ -1236,7 +1222,8 @@ execute_cleanup_cfg_post_optimizing (void)
flag_dump_noaddr = flag_dump_unnumbered = 1;
fprintf (final_output, "\n");
- dump_enumerated_decls (final_output, dump_flags | TDF_NOUID);
+ dump_enumerated_decls (final_output,
+ dump_flags | TDF_SLIM | TDF_NOUID);
flag_dump_noaddr = save_noaddr;
flag_dump_unnumbered = save_unnumbered;
if (fclose (final_output))
@@ -53,6 +53,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-ssa.h"
#include "except.h"
#include "debug.h"
+#include "params.h"
#include "value-prof.h"
#include "cfgloop.h"
#include "builtins.h"
@@ -1346,7 +1347,9 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
gimple_seq stmts = NULL;
if (is_gimple_debug (stmt)
- && !opt_for_fn (id->dst_fn, flag_var_tracking_assignments))
+ && (gimple_debug_begin_stmt_p (stmt)
+ ? !cfun->begin_stmt_markers
+ : !opt_for_fn (id->dst_fn, flag_var_tracking_assignments)))
return stmts;
/* Begin by recognizing trees that we'll completely rewrite for the
@@ -1629,6 +1632,22 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
gimple_seq_add_stmt (&stmts, copy);
return stmts;
}
+ if (gimple_debug_begin_stmt_p (stmt))
+ {
+ /* If the inlined function is has too many debug markers,
+ don't copy them. */
+ if (id->src_cfun->debug_marker_count
+ > PARAM_VALUE (PARAM_MAX_DEBUG_MARKER_COUNT))
+ return stmts;
+
+ gdebug *copy
+ = gimple_build_debug_begin_stmt (gimple_block (stmt),
+ gimple_location (stmt));
+ id->debug_stmts.safe_push (copy);
+ gimple_seq_add_stmt (&stmts, copy);
+ return stmts;
+ }
+ gcc_checking_assert (!is_gimple_debug (stmt));
/* Create a new deep copy of the statement. */
copy = gimple_copy (stmt);
@@ -1724,7 +1743,8 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
gimple_set_block (copy, *n);
}
- if (gimple_debug_bind_p (copy) || gimple_debug_source_bind_p (copy))
+ if (gimple_debug_bind_p (copy) || gimple_debug_source_bind_p (copy)
+ || gimple_debug_begin_stmt_p (copy))
{
gimple_seq_add_stmt (&stmts, copy);
return stmts;
@@ -2598,6 +2618,11 @@ maybe_move_debug_stmts_to_successors (copy_body_data *id, basic_block new_bb)
value = gimple_debug_source_bind_get_value (stmt);
new_stmt = gimple_build_debug_source_bind (var, value, stmt);
}
+ else if (gimple_debug_begin_stmt_p (stmt))
+ {
+ new_stmt = gimple_build_debug_begin_stmt (gimple_block (stmt),
+ gimple_location (stmt));
+ }
else
gcc_unreachable ();
gsi_insert_before (&dsi, new_stmt, GSI_SAME_STMT);
@@ -2914,6 +2939,9 @@ copy_debug_stmt (gdebug *stmt, copy_body_data *id)
gimple_set_block (stmt, n ? *n : id->block);
}
+ if (gimple_debug_begin_stmt_p (stmt))
+ return;
+
/* Remap all the operands in COPY. */
memset (&wi, 0, sizeof (wi));
wi.info = id;
@@ -2922,8 +2950,10 @@ copy_debug_stmt (gdebug *stmt, copy_body_data *id)
if (gimple_debug_source_bind_p (stmt))
t = gimple_debug_source_bind_get_var (stmt);
- else
+ else if (gimple_debug_bind_p (stmt))
t = gimple_debug_bind_get_var (stmt);
+ else
+ gcc_unreachable ();
if (TREE_CODE (t) == PARM_DECL && id->debug_map
&& (n = id->debug_map->get (t)))
@@ -89,7 +89,7 @@ append_to_statement_list_1 (tree t, tree *list_p)
void
append_to_statement_list (tree t, tree *list_p)
{
- if (t && TREE_SIDE_EFFECTS (t))
+ if (t && (TREE_SIDE_EFFECTS (t) || TREE_CODE (t) == DEBUG_BEGIN_STMT))
append_to_statement_list_1 (t, list_p);
}
@@ -137,7 +137,8 @@ tsi_link_before (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)
tail = head;
}
- TREE_SIDE_EFFECTS (i->container) = 1;
+ if (TREE_CODE (t) != DEBUG_BEGIN_STMT)
+ TREE_SIDE_EFFECTS (i->container) = 1;
cur = i->ptr;
@@ -213,7 +214,8 @@ tsi_link_after (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)
tail = head;
}
- TREE_SIDE_EFFECTS (i->container) = 1;
+ if (TREE_CODE (t) != DEBUG_BEGIN_STMT)
+ TREE_SIDE_EFFECTS (i->container) = 1;
cur = i->ptr;
@@ -279,8 +281,9 @@ tsi_delink (tree_stmt_iterator *i)
i->ptr = next;
}
-/* Return the first expression in a sequence of COMPOUND_EXPRs,
- or in a STATEMENT_LIST. */
+/* Return the first expression in a sequence of COMPOUND_EXPRs, or in
+ a STATEMENT_LIST, disregarding DEBUG_BEGIN_STMTs, recursing into a
+ STATEMENT_LIST if that's the first non-DEBUG_BEGIN_STMT. */
tree
expr_first (tree expr)
@@ -291,7 +294,20 @@ expr_first (tree expr)
if (TREE_CODE (expr) == STATEMENT_LIST)
{
struct tree_statement_list_node *n = STATEMENT_LIST_HEAD (expr);
- return n ? n->stmt : NULL_TREE;
+ if (!n)
+ return NULL_TREE;
+ while (TREE_CODE (n->stmt) == DEBUG_BEGIN_STMT)
+ {
+ n = n->next;
+ if (!n)
+ return NULL_TREE;
+ }
+ /* If the first non-debug stmt is not a statement list, we
+ already know it's what we're looking for. */
+ if (TREE_CODE (n->stmt) != STATEMENT_LIST)
+ return n->stmt;
+
+ return expr_first (n->stmt);
}
while (TREE_CODE (expr) == COMPOUND_EXPR)
@@ -300,8 +316,9 @@ expr_first (tree expr)
return expr;
}
-/* Return the last expression in a sequence of COMPOUND_EXPRs,
- or in a STATEMENT_LIST. */
+/* Return the last expression in a sequence of COMPOUND_EXPRs, or in a
+ STATEMENT_LIST, disregarding DEBUG_BEGIN_STMTs, recursing into a
+ STATEMENT_LIST if that's the last non-DEBUG_BEGIN_STMT. */
tree
expr_last (tree expr)
@@ -312,7 +329,20 @@ expr_last (tree expr)
if (TREE_CODE (expr) == STATEMENT_LIST)
{
struct tree_statement_list_node *n = STATEMENT_LIST_TAIL (expr);
- return n ? n->stmt : NULL_TREE;
+ if (!n)
+ return NULL_TREE;
+ while (TREE_CODE (n->stmt) == DEBUG_BEGIN_STMT)
+ {
+ n = n->prev;
+ if (!n)
+ return NULL_TREE;
+ }
+ /* If the last non-debug stmt is not a statement list, we
+ already know it's what we're looking for. */
+ if (TREE_CODE (n->stmt) != STATEMENT_LIST)
+ return n->stmt;
+
+ return expr_last (n->stmt);
}
while (TREE_CODE (expr) == COMPOUND_EXPR)
@@ -3303,6 +3303,10 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags,
pp_string (pp, "_Cilk_sync");
break;
+ case DEBUG_BEGIN_STMT:
+ pp_string (pp, "# DEBUG BEGIN STMT");
+ break;
+
default:
NIY;
}
@@ -3398,7 +3402,10 @@ print_declaration (pretty_printer *pp, tree t, int spc, dump_flags_t flags)
pp_space (pp);
pp_equal (pp);
pp_space (pp);
- dump_generic_node (pp, DECL_INITIAL (t), spc, flags, false);
+ if (!(flags & TDF_SLIM))
+ dump_generic_node (pp, DECL_INITIAL (t), spc, flags, false);
+ else
+ pp_string (pp, "<<< omitted >>>");
}
}
@@ -257,7 +257,8 @@ mark_stmt_if_obviously_necessary (gimple *stmt, bool aggressive)
easily locate the debug temp bind stmt for a use thereof,
would could refrain from marking all debug temps here, and
mark them only if they're used. */
- if (!gimple_debug_bind_p (stmt)
+ if (gimple_debug_begin_stmt_p (stmt)
+ || !gimple_debug_bind_p (stmt)
|| gimple_debug_bind_has_value_p (stmt)
|| TREE_CODE (gimple_debug_bind_get_var (stmt)) != DEBUG_EXPR_DECL)
mark_stmt_necessary (stmt, false);
@@ -1448,8 +1449,7 @@ eliminate_unnecessary_stmts (void)
dominate others. Walking backwards, this should
be the common case. ??? Do we need to recompute
dominators because of cfg_altered? */
- if (!MAY_HAVE_DEBUG_STMTS
- || !first_dom_son (CDI_DOMINATORS, bb))
+ if (!first_dom_son (CDI_DOMINATORS, bb))
delete_basic_block (bb);
else
{
@@ -1294,14 +1294,14 @@ find_duplicate (same_succ *same_succ, basic_block bb1, basic_block bb2)
tree label = gimple_label_label (as_a <glabel *> (gsi_stmt (gsi1)));
if (DECL_NONLOCAL (label) || FORCED_LABEL (label))
return;
- gsi_prev (&gsi1);
+ gsi_prev_nondebug (&gsi1);
}
while (!gsi_end_p (gsi2) && gimple_code (gsi_stmt (gsi2)) == GIMPLE_LABEL)
{
tree label = gimple_label_label (as_a <glabel *> (gsi_stmt (gsi2)));
if (DECL_NONLOCAL (label) || FORCED_LABEL (label))
return;
- gsi_prev (&gsi2);
+ gsi_prev_nondebug (&gsi2);
}
if (!(gsi_end_p (gsi1) && gsi_end_p (gsi2)))
return;
@@ -739,6 +739,8 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)
var = gimple_debug_bind_get_var (stmt);
else if (gimple_debug_source_bind_p (stmt))
var = gimple_debug_source_bind_get_var (stmt);
+ else if (gimple_debug_begin_stmt_p (stmt))
+ continue;
else
gcc_unreachable ();
@@ -766,6 +768,8 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)
var = gimple_debug_bind_get_var (stmt);
else if (gimple_debug_source_bind_p (stmt))
var = gimple_debug_source_bind_get_var (stmt);
+ else if (gimple_debug_begin_stmt_p (stmt))
+ var = NULL;
else
gcc_unreachable ();
@@ -777,7 +781,9 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src)
or somesuch. Adding `&& bb == src' to the condition
below will preserve all potentially relevant debug
notes. */
- if (vars && vars->add (var))
+ if (!var)
+ /* Just copy the stmt. */;
+ else if (vars && vars->add (var))
continue;
else if (!vars)
{
@@ -1011,7 +1011,8 @@ make_node_stat (enum tree_code code MEM_STAT_DECL)
switch (type)
{
case tcc_statement:
- TREE_SIDE_EFFECTS (t) = 1;
+ if (code != DEBUG_BEGIN_STMT)
+ TREE_SIDE_EFFECTS (t) = 1;
break;
case tcc_declaration:
@@ -4403,7 +4404,10 @@ build1_stat (enum tree_code code, tree type, tree node MEM_STAT_DECL)
}
if (TREE_CODE_CLASS (code) == tcc_statement)
- TREE_SIDE_EFFECTS (t) = 1;
+ {
+ if (code != DEBUG_BEGIN_STMT)
+ TREE_SIDE_EFFECTS (t) = 1;
+ }
else switch (code)
{
case VA_ARG_EXPR:
@@ -384,6 +384,9 @@ DEFTREECODE (RESULT_DECL, "result_decl", tcc_declaration, 0)
DEBUG stmts. */
DEFTREECODE (DEBUG_EXPR_DECL, "debug_expr_decl", tcc_declaration, 0)
+/* A stmt that marks the beginning of a source statement. */
+DEFTREECODE (DEBUG_BEGIN_STMT, "debug_begin_stmt", tcc_statement, 0)
+
/* A namespace declaration. Namespaces appear in DECL_CONTEXT of other
_DECLs, providing a hierarchy of names. */
DEFTREECODE (NAMESPACE_DECL, "namespace_decl", tcc_declaration, 0)
@@ -1130,7 +1130,8 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int,
((int)TREE_INT_CST_LOW (VL_EXP_CHECK (NODE)->exp.operands[0]))
/* Nonzero if is_gimple_debug() may possibly hold. */
-#define MAY_HAVE_DEBUG_STMTS (flag_var_tracking_assignments)
+#define MAY_HAVE_DEBUG_STMTS \
+ (flag_var_tracking_assignments || debug_statement_frontiers)
/* In a LOOP_EXPR node. */
#define LOOP_EXPR_BODY(NODE) TREE_OPERAND_CHECK_CODE (NODE, LOOP_EXPR, 0)
@@ -1222,7 +1223,7 @@ extern void protected_set_expr_location (tree, location_t);
/* GOTO_EXPR accessor. This gives access to the label associated with
a goto statement. */
-#define GOTO_DESTINATION(NODE) TREE_OPERAND ((NODE), 0)
+#define GOTO_DESTINATION(NODE) TREE_OPERAND (GOTO_EXPR_CHECK (NODE), 0)
/* ASM_EXPR accessors. ASM_STRING returns a STRING_CST for the
instruction (e.g., "mov x, y"). ASM_OUTPUTS, ASM_INPUTS, and
@@ -9471,6 +9471,24 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
}
}
+/* Return BB's head, unless BB is the block that succeeds ENTRY_BLOCK,
+ in which case it searches back from BB's head for the very first
+ insn. Use [get_first_insn (bb), BB_HEAD (bb->next_bb)[ as a range
+ to iterate over all insns of a function while iterating over its
+ BBs. */
+
+static rtx_insn *
+get_first_insn (basic_block bb)
+{
+ rtx_insn *insn = BB_HEAD (bb);
+
+ if (bb->prev_bb == ENTRY_BLOCK_PTR_FOR_FN (cfun))
+ while (rtx_insn *prev = PREV_INSN (insn))
+ insn = prev;
+
+ return insn;
+}
+
/* Emit notes for the whole function. */
static void
@@ -9501,7 +9519,8 @@ vt_emit_notes (void)
{
/* Emit the notes for changes of variable locations between two
subsequent basic blocks. */
- emit_notes_for_differences (BB_HEAD (bb), &cur, &VTI (bb)->in);
+ emit_notes_for_differences (get_first_insn (bb),
+ &cur, &VTI (bb)->in);
if (MAY_HAVE_DEBUG_INSNS)
local_get_addr_cache = new hash_map<rtx, rtx>;
@@ -9901,6 +9920,51 @@ vt_init_cfa_base (void)
cselib_preserve_cfa_base_value (val, REGNO (cfa_base_rtx));
}
+/* Evaluate to TRUE if INSN is a debug insn that denotes a variable
+ location/value tracking annotation. */
+#define VTA_DEBUG_INSN_P(INSN) \
+ (DEBUG_INSN_P (INSN) \
+ && INSN_VAR_LOCATION_DECL (insn))
+/* Evaluate to TRUE if INSN is a debug insn that denotes a program
+ source location marker. */
+#define MARKER_DEBUG_INSN_P(INSN) \
+ (DEBUG_INSN_P (INSN) \
+ && !INSN_VAR_LOCATION_DECL (insn))
+/* Evaluate to the marker kind. Currently the only kind is
+ BEGIN_STMT. */
+#define INSN_DEBUG_MARKER_KIND(insn) 0
+
+/* Reemit INSN, a MARKER_DEBUG_INSN, as a note. */
+
+static rtx_insn *
+reemit_marker_as_note (rtx_insn *insn)
+{
+ gcc_checking_assert (MARKER_DEBUG_INSN_P (insn));
+ /* FIXME: we could use loc and status for other kinds of markers, or
+ for additional information in them. */
+ gcc_checking_assert (VAR_LOC_UNKNOWN_P (INSN_VAR_LOCATION_LOC (insn)));
+ gcc_checking_assert (INSN_VAR_LOCATION_STATUS (insn)
+ == VAR_INIT_STATUS_INITIALIZED);
+
+ switch (INSN_DEBUG_MARKER_KIND (insn))
+ {
+ case 0:
+ {
+ rtx_insn *note = NULL;
+ if (cfun->begin_stmt_markers)
+ {
+ note = emit_note_before (NOTE_INSN_BEGIN_STMT, insn);
+ NOTE_BEGIN_STMT_LOCATION (note) = INSN_LOCATION (insn);
+ }
+ delete_insn (insn);
+ return note;
+ }
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
/* Allocate and initialize the data structures for variable tracking
and parse the RTL to get the micro operations. */
@@ -10097,11 +10161,34 @@ vt_initialize (void)
{
HOST_WIDE_INT offset = VTI (bb)->out.stack_adjust;
VTI (bb)->out.stack_adjust = VTI (bb)->in.stack_adjust;
- for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb));
- insn = NEXT_INSN (insn))
+
+ /* If we are walking the first basic block, walk any HEADER
+ insns that might be before it too. Unfortunately,
+ BB_HEADER and BB_FOOTER are not set while we run this
+ pass. */
+ insn = get_first_insn (bb);
+ for (rtx_insn *next;
+ insn != BB_HEAD (bb->next_bb)
+ ? next = NEXT_INSN (insn), true : false;
+ insn = next)
{
if (INSN_P (insn))
{
+ basic_block save_bb = BLOCK_FOR_INSN (insn);
+ if (!BLOCK_FOR_INSN (insn))
+ {
+ BLOCK_FOR_INSN (insn) = bb;
+ gcc_assert (DEBUG_INSN_P (insn));
+ /* Reset debug insns between basic blocks.
+ Their location is not reliable, because they
+ were probably not maintained up to date. */
+ if (VTA_DEBUG_INSN_P (insn))
+ INSN_VAR_LOCATION_LOC (insn)
+ = gen_rtx_UNKNOWN_VAR_LOC ();
+ }
+ else
+ gcc_assert (BLOCK_FOR_INSN (insn) == bb);
+
if (!frame_pointer_needed)
{
insn_stack_adjust_offset_pre_post (insn, &pre, &post);
@@ -10123,6 +10210,14 @@ vt_initialize (void)
adjust_insn (bb, insn);
if (MAY_HAVE_DEBUG_INSNS)
{
+ if (MARKER_DEBUG_INSN_P (insn))
+ {
+ insn = reemit_marker_as_note (insn);
+ if (insn)
+ BLOCK_FOR_INSN (insn) = save_bb;
+ continue;
+ }
+
if (CALL_P (insn))
prepare_call_arguments (bb, insn);
cselib_process_insn (insn);
@@ -10169,6 +10264,7 @@ vt_initialize (void)
}
}
}
+ BLOCK_FOR_INSN (insn) = save_bb;
}
}
gcc_assert (offset == VTI (bb)->out.stack_adjust);
@@ -10196,10 +10292,11 @@ vt_initialize (void)
static int debug_label_num = 1;
-/* Get rid of all debug insns from the insn stream. */
+/* Remove from the insn stream all debug insns used for variable
+ tracking at assignments. */
static void
-delete_debug_insns (void)
+delete_vta_debug_insns (void)
{
basic_block bb;
rtx_insn *insn, *next;
@@ -10209,9 +10306,18 @@ delete_debug_insns (void)
FOR_EACH_BB_FN (bb, cfun)
{
- FOR_BB_INSNS_SAFE (bb, insn, next)
+ for (insn = get_first_insn (bb);
+ insn != BB_HEAD (bb->next_bb)
+ ? next = NEXT_INSN (insn), true : false;
+ insn = next)
if (DEBUG_INSN_P (insn))
{
+ if (MARKER_DEBUG_INSN_P (insn))
+ {
+ insn = reemit_marker_as_note (insn);
+ continue;
+ }
+
tree decl = INSN_VAR_LOCATION_DECL (insn);
if (TREE_CODE (decl) == LABEL_DECL
&& DECL_NAME (decl)
@@ -10237,10 +10343,13 @@ delete_debug_insns (void)
handled as well.. */
static void
-vt_debug_insns_local (bool skipped ATTRIBUTE_UNUSED)
+vt_debug_insns_local (bool skipped)
{
- /* ??? Just skip it all for now. */
- delete_debug_insns ();
+ /* ??? Just skip it all for now. If we skipped the global pass,
+ arrange for stmt markers to be dropped as well. */
+ if (skipped)
+ cfun->begin_stmt_markers = 0;
+ delete_vta_debug_insns ();
}
/* Free the data structures needed for variable tracking. */
@@ -10305,15 +10414,21 @@ variable_tracking_main_1 (void)
{
bool success;
- if (flag_var_tracking_assignments < 0
+ /* We won't be called as a separate pass if flag_var_tracking is not
+ set, but final may call us to turn debug markers into notes. */
+ if ((!flag_var_tracking && MAY_HAVE_DEBUG_INSNS)
+ || flag_var_tracking_assignments < 0
/* Var-tracking right now assumes the IR doesn't contain
any pseudos at this point. */
|| targetm.no_register_allocation)
{
- delete_debug_insns ();
+ delete_vta_debug_insns ();
return 0;
}
+ if (!flag_var_tracking)
+ return 0;
+
if (n_basic_blocks_for_fn (cfun) > 500 &&
n_edges_for_fn (cfun) / n_basic_blocks_for_fn (cfun) >= 20)
{
@@ -10335,7 +10450,9 @@ variable_tracking_main_1 (void)
{
vt_finalize ();
- delete_debug_insns ();
+ cfun->begin_stmt_markers = 0;
+
+ delete_vta_debug_insns ();
/* This is later restored by our caller. */
flag_var_tracking_assignments = 0;
@@ -443,6 +443,7 @@ DW_AT (DW_AT_GNU_pubtypes, 0x2135)
/* Attribute for discriminator.
See http://gcc.gnu.org/wiki/Discriminator */
DW_AT (DW_AT_GNU_discriminator, 0x2136)
+DW_AT (DW_AT_GNU_locviews, 0x2137)
/* VMS extensions. */
DW_AT (DW_AT_VMS_rtnbeg_pd_address, 0x2201)
/* GNAT extensions. */
@@ -296,6 +296,14 @@ enum dwarf_location_list_entry_type
DW_LLE_start_end = 0x07,
DW_LLE_start_length = 0x08,
+ /* <http://lists.dwarfstd.org/private.cgi/dwarf-discuss-dwarfstd.org/2017-April/004347.html>
+ has the proposal for now; only available to list members.
+
+ A (possibly updated) copy of the proposal is available at
+ <http://people.redhat.com/aoliva/papers/sfn/dwarf6-sfn-lvu.txt>. */
+ DW_LLE_GNU_view_pair = 0x09,
+#define DW_LLE_view_pair DW_LLE_GNU_view_pair
+
/* Former extension for Fission.
See http://gcc.gnu.org/wiki/DebugFission. */
DW_LLE_GNU_end_of_list_entry = 0x00,