/* Control flow graph manipulation code for GNU compiler.
- Copyright (C) 1987-2019 Free Software Foundation, Inc.
+ Copyright (C) 1987-2020 Free Software Foundation, Inc.
This file is part of GCC.
#include "tree-pass.h"
#include "print-rtl.h"
+/* Disable warnings about missing quoting in GCC diagnostics. */
+#if __GNUC__ >= 10
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wformat-diag"
+#endif
+
/* Holds the interesting leading and trailing notes for the function.
Only applicable if the CFG is in cfglayout mode. */
static GTY(()) rtx_insn *cfg_layout_function_footer;
{
bool purge = false;
- if (INSN_P (insn)
- && BLOCK_FOR_INSN (insn)
- && BB_END (BLOCK_FOR_INSN (insn)) == insn)
- purge = true;
+ if (INSN_P (insn) && BLOCK_FOR_INSN (insn))
+ {
+ basic_block bb = BLOCK_FOR_INSN (insn);
+ if (BB_END (bb) == insn)
+ purge = true;
+ else if (DEBUG_INSN_P (BB_END (bb)))
+ for (rtx_insn *dinsn = NEXT_INSN (insn);
+ DEBUG_INSN_P (dinsn); dinsn = NEXT_INSN (dinsn))
+ if (BB_END (bb) == dinsn)
+ {
+ purge = true;
+ break;
+ }
+ }
delete_insn (insn);
if (purge)
return purge_dead_edges (BLOCK_FOR_INSN (insn));
}
\f
-/* Like active_insn_p, except keep the return value clobber around
+/* Like active_insn_p, except keep the return value use or clobber around
even after reload. */
static bool
programs that fail to return a value. Its effect is to
keep the return value from being live across the entire
function. If we allow it to be skipped, we introduce the
- possibility for register lifetime confusion. */
- if (GET_CODE (PATTERN (insn)) == CLOBBER
+ possibility for register lifetime confusion.
+ Similarly, keep a USE of the function return value, otherwise
+ the USE is dropped and we could fail to thread jump if USE
+ appears on some paths and not on others, see PR90257. */
+ if ((GET_CODE (PATTERN (insn)) == CLOBBER
+ || GET_CODE (PATTERN (insn)) == USE)
&& REG_P (XEXP (PATTERN (insn), 0))
&& REG_FUNCTION_VALUE_P (XEXP (PATTERN (insn), 0)))
return true;
}
/* Handle casesi dispatch insns. */
- if ((tmp = single_set (insn)) != NULL
- && SET_DEST (tmp) == pc_rtx
- && GET_CODE (SET_SRC (tmp)) == IF_THEN_ELSE
- && GET_CODE (XEXP (SET_SRC (tmp), 2)) == LABEL_REF
+ if ((tmp = tablejump_casesi_pattern (insn)) != NULL_RTX
&& label_ref_label (XEXP (SET_SRC (tmp), 2)) == old_label)
{
XEXP (SET_SRC (tmp), 2) = gen_rtx_LABEL_REF (Pmode,
which will be done by fixup_partitions. */
fixup_partitions ();
- checking_verify_flow_info ();
+ if (!currently_expanding_to_rtl)
+ checking_verify_flow_info ();
FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun),
EXIT_BLOCK_PTR_FOR_FN (cfun), next_bb)
FOR_EACH_EDGE (e, ei, bb->succs)
if (e->insns.r)
- commit_one_edge_insertion (e);
+ {
+ if (currently_expanding_to_rtl)
+ rebuild_jump_labels_chain (e->insns.r);
+ commit_one_edge_insertion (e);
+ }
}
}
\f
if (df)
df_dump_start (outf);
- if (flags & TDF_BLOCKS)
+ if (cfun->curr_properties & PROP_cfg)
{
FOR_EACH_BB_REVERSE_FN (bb, cfun)
{
start[INSN_UID (BB_HEAD (bb))] = bb;
end[INSN_UID (BB_END (bb))] = bb;
- for (x = BB_HEAD (bb); x != NULL_RTX; x = NEXT_INSN (x))
+ if (flags & TDF_BLOCKS)
{
- enum bb_state state = IN_MULTIPLE_BB;
+ for (x = BB_HEAD (bb); x != NULL_RTX; x = NEXT_INSN (x))
+ {
+ enum bb_state state = IN_MULTIPLE_BB;
- if (in_bb_p[INSN_UID (x)] == NOT_IN_BB)
- state = IN_ONE_BB;
- in_bb_p[INSN_UID (x)] = state;
+ if (in_bb_p[INSN_UID (x)] == NOT_IN_BB)
+ state = IN_ONE_BB;
+ in_bb_p[INSN_UID (x)] = state;
- if (x == BB_END (bb))
- break;
+ if (x == BB_END (bb))
+ break;
+ }
}
}
}
if (flags & TDF_DETAILS)
df_dump_insn_bottom (tmp_rtx, outf);
- if (flags & TDF_BLOCKS)
+ bb = end[INSN_UID (tmp_rtx)];
+ if (bb != NULL)
{
- bb = end[INSN_UID (tmp_rtx)];
- if (bb != NULL)
+ if (flags & TDF_BLOCKS)
{
dump_bb_info (outf, bb, 0, dump_flags, false, true);
if (df && (flags & TDF_DETAILS))
df_dump_bottom (bb, outf);
putc ('\n', outf);
}
+ /* Emit a hint if the fallthrough target of current basic block
+ isn't the one placed right next. */
+ else if (EDGE_COUNT (bb->succs) > 0)
+ {
+ gcc_assert (BB_END (bb) == tmp_rtx);
+ const rtx_insn *ninsn = NEXT_INSN (tmp_rtx);
+ /* Bypass intervening deleted-insn notes and debug insns. */
+ while (ninsn
+ && !NONDEBUG_INSN_P (ninsn)
+ && !start[INSN_UID (ninsn)])
+ ninsn = NEXT_INSN (ninsn);
+ edge e = find_fallthru_edge (bb->succs);
+ if (e && ninsn)
+ {
+ basic_block dest = e->dest;
+ if (start[INSN_UID (ninsn)] != dest)
+ fprintf (outf, "%s ; pc falls through to BB %d\n",
+ print_rtx_head, dest->index);
+ }
+ }
}
}
find_partition_fixes (bool flag_only)
{
basic_block bb;
- vec<basic_block> bbs_in_cold_partition = vNULL;
vec<basic_block> bbs_to_fix = vNULL;
hash_set<basic_block> set;
else
BB_SET_PARTITION (bb, BB_COLD_PARTITION);
bbs_to_fix.safe_push (bb);
- bbs_in_cold_partition.safe_push (bb);
}
return bbs_to_fix;
basic_block last_bb_seen = ENTRY_BLOCK_PTR_FOR_FN (cfun), curr_bb = NULL;
num_bb_notes = 0;
- last_bb_seen = ENTRY_BLOCK_PTR_FOR_FN (cfun);
for (x = rtx_first; x; x = NEXT_INSN (x))
{
bool found;
edge_iterator ei;
- if (DEBUG_INSN_P (insn) && insn != BB_HEAD (bb))
+ if ((DEBUG_INSN_P (insn) || NOTE_P (insn)) && insn != BB_HEAD (bb))
do
insn = PREV_INSN (insn);
while ((DEBUG_INSN_P (insn) || NOTE_P (insn)) && insn != BB_HEAD (bb));
{
fprintf (dump_file, " %i ", index);
if (get_bb_original (bb))
- fprintf (dump_file, "duplicate of %i ",
+ fprintf (dump_file, "duplicate of %i\n",
get_bb_original (bb)->index);
else if (forwarder_block_p (bb)
&& !LABEL_P (BB_HEAD (bb)))
- fprintf (dump_file, "compensation ");
+ fprintf (dump_file, "compensation\n");
else
- fprintf (dump_file, "bb %i ", bb->index);
+ fprintf (dump_file, "bb %i\n", bb->index);
}
}
};
#include "gt-cfgrtl.h"
+
+#if __GNUC__ >= 10
+# pragma GCC diagnostic pop
+#endif