[PR109071,PR85788,PR88771,PR106762,PR108770,PR115274,PR117179] Control this with a new option -fdiagnostics-details.
$ cat t.c extern void warn(void); static inline void assign(int val, int *regs, int *index) { if (*index >= 4) warn(); *regs = val; } struct nums {int vals[4];}; void sparx5_set (int *ptr, struct nums *sg, int index) { int *val = &sg->vals[index]; assign(0, ptr, &index); assign(*val, ptr, &index); } $ gcc -Wall -O2 -c -o t.o t.c t.c: In function ‘sparx5_set’: t.c:12:23: warning: array subscript 4 is above array bounds of ‘int[4]’ [-Warray-bounds=] 12 | int *val = &sg->vals[index]; | ~~~~~~~~^~~~~~~ t.c:8:18: note: while referencing ‘vals’ 8 | struct nums {int vals[4];}; | ^~~~ In the above, Although the warning is correct in theory, the warning message itself is confusing to the end-user since there is information that cannot be connected to the source code directly. It will be a nice improvement to add more information in the warning message to report where such index value come from. In order to achieve this, we add a new data structure "move_history" to record 1. the "condition" that triggers the code movement; 2. whether the code movement is on the true path of the "condition"; 3. the "compiler transformation" that triggers the code movement. Whenever there is a code movement along control flow graph due to some specific transformations, such as jump threading, path isolation, tree sinking, etc., a move_history structure is created and attached to the moved gimple statement. During array out-of-bound checking or -Wstringop-* warning checking, the "move_history" that was attached to the gimple statement is used to form a sequence of diagnostic events that are added to the corresponding rich location to be used to report the warning message. This behavior is controled by the new option -fdiagnostics-details which is off by default. With this change, by adding -fdiagnostics-details, the warning message for the above testing case is now: $ gcc -Wall -O2 -fdiagnostics-details -c -o t.o t.c t.c: In function ‘sparx5_set’: t.c:12:23: warning: array subscript 4 is above array bounds of ‘int[4]’ [-Warray-bounds=] 12 | int *val = &sg->vals[index]; | ~~~~~~~~^~~~~~~ ‘sparx5_set’: events 1-2 4 | if (*index >= 4) | ^ | | | (1) when the condition is evaluated to true ...... 12 | int *val = &sg->vals[index]; | ~~~~~~~~~~~~~~~ | | | (2) out of array bounds here t.c:8:18: note: while referencing ‘vals’ 8 | struct nums {int vals[4];}; | ^~~~ The change was divided into 3 parts: Part 1: Add new data structure move_history, record move_history during transformation; Part 2: In warning analysis, Use the new move_history to form a rich location with a sequence of events, to report more context info of the warnings. Part 3: Add debugging mechanism for move_history. PR tree-optimization/109071 PR tree-optimization/85788 PR tree-optimization/88771 PR tree-optimization/106762 PR tree-optimization/108770 PR tree-optimization/115274 PR tree-optimization/117179 gcc/ChangeLog: * Makefile.in (OBJS): Add diagnostic-move-history.o. * gcc/common.opt (fdiagnostics-details): New option. * gcc/doc/invoke.texi (fdiagnostics-details): Add documentation for the new option. * gimple-iterator.cc (gsi_remove): (gsi_remove): Remove the move history when removing the gimple. * gimple-pretty-print.cc (pp_gimple_stmt_1): Emit MV_H marking if the gimple has a move_history. * gimple-ssa-isolate-paths.cc (isolate_path): Set move history for the gimples of the duplicated blocks. * tree-ssa-sink.cc (sink_code_in_bb): Create move_history for stmt when it is sinked. * toplev.cc (toplev::finalize): Call move_history_finalize. * tree-ssa-threadupdate.cc (ssa_redirect_edges): Create move_history for stmts when they are duplicated. (back_jt_path_registry::duplicate_thread_path): Likewise. * diagnostic-move-history.cc: New file. * diagnostic-move-history.h: New file. gcc/testsuite/ChangeLog: * gcc.dg/pr117375.c: New test. --- gcc/Makefile.in | 1 + gcc/common.opt | 4 + gcc/diagnostic-move-history.cc | 265 ++++++++++++++++++++++++++++++++ gcc/diagnostic-move-history.h | 92 +++++++++++ gcc/doc/invoke.texi | 11 ++ gcc/gimple-iterator.cc | 3 + gcc/gimple-pretty-print.cc | 4 + gcc/gimple-ssa-isolate-paths.cc | 11 ++ gcc/testsuite/gcc.dg/pr117375.c | 13 ++ gcc/toplev.cc | 3 + gcc/tree-ssa-sink.cc | 57 +++++++ gcc/tree-ssa-threadupdate.cc | 25 +++ 12 files changed, 489 insertions(+) create mode 100644 gcc/diagnostic-move-history.cc create mode 100644 gcc/diagnostic-move-history.h create mode 100644 gcc/testsuite/gcc.dg/pr117375.c diff --git a/gcc/Makefile.in b/gcc/Makefile.in index ebfcd8a8a0d..29663be1d48 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1451,6 +1451,7 @@ OBJS = \ df-problems.o \ df-scan.o \ dfp.o \ + diagnostic-move-history.o \ digraph.o \ dojump.o \ dominance.o \ diff --git a/gcc/common.opt b/gcc/common.opt index b9e74cd3ac4..09a77fef277 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -1597,6 +1597,10 @@ fdiagnostics-minimum-margin-width= Common Joined UInteger Var(diagnostics_minimum_margin_width) Init(6) Set minimum width of left margin of source code when showing source. +fdiagnostics-details +Common Var(flag_diagnostics_details) +Collect and print more context information for diagnostics. + fdisable- Common Joined RejectNegative Var(common_deferred_options) Defer -fdisable-[tree|rtl|ipa]-<pass>=range1+range2 Disable an optimization pass. diff --git a/gcc/diagnostic-move-history.cc b/gcc/diagnostic-move-history.cc new file mode 100644 index 00000000000..83d8a42b577 --- /dev/null +++ b/gcc/diagnostic-move-history.cc @@ -0,0 +1,265 @@ +/* Functions to handle move history. + Copyright (C) 2024 Free Software Foundation, Inc. + Contributed by Qing Zhao <qing.z...@oracle.com> + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 3, or (at your option) any later + version. + + GCC is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +#define INCLUDE_MEMORY +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "tree.h" +#include "gimple.h" +#include "gimple-iterator.h" +#include "cfganal.h" +#include "diagnostic-move-history.h" + +/* A mapping from a gimple to a pointer to the move history of it. */ +static move_history_map_t *move_history_map; + +/* Obstack for move history. */ +static struct obstack move_history_obstack; + +/* Create a new move history. */ + +move_history_t +create_move_history (location_t condition, + bool is_true_path, + enum move_reason reason, + move_history_t prev_move) +{ + static bool initialized = false; + + if (!initialized) + { + gcc_obstack_init (&move_history_obstack); + initialized = true; + } + + move_history_t move_history + = (move_history_t) obstack_alloc (&move_history_obstack, + sizeof (struct move_history)); + move_history->condition = condition; + move_history->is_true_path = is_true_path; + move_history->reason = reason; + move_history->prev_move = prev_move; + return move_history; +} + +/* Insert the move history for the gimple STMT assuming the linked list + of MV_HISTORY does not have duplications. It's the caller's + responsibility to make sure that the linked list of MV_HISTORY does + not have duplications. */ + +void +insert_move_history (gimple *stmt, move_history_t mv_history) +{ + if (!move_history_map) + move_history_map = new move_history_map_t; + + move_history_map->put (stmt, mv_history); + return; +} + +/* Get the move history for the gimple STMT, return NULL when there is + no associated move history. */ + +move_history_t +get_move_history (const gimple *stmt) +{ + if (!move_history_map) + return NULL; + + if (const move_history_t *mv_history_p = move_history_map->get (stmt)) + return *mv_history_p; + + return NULL; +} + +/* Remove the move history for STMT. */ + +void +remove_move_history (gimple *stmt) +{ + if (!move_history_map) + return; + move_history_map->remove (stmt); + return; +} + +/* Check whether the cond_location, is_true_path and reason existed + * in the OLD_MOVE_HISTORY. */ + +static bool +is_move_history_existed (location_t cond_location, bool is_true_path, + enum move_reason reason, + move_history_t old_move_history) +{ + for (move_history_t cur_ch = old_move_history; cur_ch; + cur_ch = cur_ch->prev_move) + if ((cur_ch->condition == cond_location) + && (cur_ch->is_true_path == is_true_path) + && (cur_ch->reason == reason)) + return true; + + return false; +} + +/* Set move history for the gimple STMT. Return TRUE when a new move + * history is created and inserted. Otherwise return FALSE. */ + +bool +set_move_history (gimple *stmt, location_t cond_location, + bool is_true_path, enum move_reason reason) +{ + + /* First, get the old move history associated with this STMT. */ + move_history_t old_mv_history = get_move_history (stmt); + + /* If the current move history is not in the STMT's move history linked + list yet, create the new move history, put the old_move_history as the + prev_move of it. */ + move_history_t new_mv_history = NULL; + if (!is_move_history_existed (cond_location, is_true_path, + reason, old_mv_history)) + new_mv_history + = create_move_history (cond_location, is_true_path, + reason, old_mv_history); + + /* Insert the move history into the hash map. */ + if (new_mv_history) + { + insert_move_history (stmt, new_mv_history); + return true; + } + + return false; +} + +/* Reset all state for diagnostic-move-history.cc so that we can rerun the + compiler within the same process. For use by toplev::finalize. */ + +void +move_history_finalize (void) +{ + if (move_history_map) + { + delete move_history_map; + move_history_map = NULL; + } + obstack_free (&move_history_obstack, NULL); + return; +} + +/* Given an edge ENTRY and whether the new code will be moved to the + destination of the edge, IS_DISTINATION, return the condition + statement in the source of the ENTRY if found. Return NULL otherwise. + + When the condition statement is found, setting IS_TRUE_PATH to true + if the destination of the edge is on the true path of the condition. + + IS_TRUE_PATH is only valid when the condition statement is found. + + source + | ENTRY + V + destination + +*/ + +static gimple * +get_cond_stmt (edge entry, bool is_destination, bool *is_true_path) +{ + /* First, get the condition statement in the source of the + edge ENTRY. */ + basic_block cond_block = entry->src; + gimple *cond_stmt = NULL; + gimple_stmt_iterator gsi; + *is_true_path = false; + + /* if the cond_block ends with a conditional statement, get it. */ + while (!cond_stmt && cond_block) + { + gsi = gsi_last_bb (cond_block); + if (!gsi_end_p (gsi) + && gsi_stmt (gsi) + && (gimple_code (gsi_stmt (gsi)) == GIMPLE_COND)) + cond_stmt = gsi_stmt (gsi); + /* If there is no cond_stmt in the cond_block, search the single_pred + of it. */ + if (!cond_stmt && single_pred_p (cond_block)) + { + basic_block prev_cond_block = cond_block; + cond_block = single_pred (cond_block); + entry = find_edge (cond_block, prev_cond_block); + } + else + break; + } + + bool is_branch_taken = (cond_stmt && (BRANCH_EDGE (cond_block) == entry)); + *is_true_path = !(is_branch_taken ^ is_destination); + + return cond_stmt; +} + +/* Set move history to the stmt based on the edge ENTRY and whether this stmt + will be in the destination of the ENTRY. + The REASON indicates what kind of transformation contributing to the + statment movement. Return TRUE when the move history has been set + successfully. */ + +bool +set_move_history_to_stmt (gimple *stmt, edge entry, + bool is_destination, enum move_reason reason) +{ + bool is_true_path = false; + gimple *cond_stmt = get_cond_stmt (entry, is_destination, &is_true_path); + + if (!cond_stmt) + return false; + + set_move_history (stmt, gimple_location (cond_stmt), + is_true_path, reason); + return true; +} + +/* Set move history to all the stmts in the basic block BB based on + the edge ENTRY and whether this basic block will be the destination + of the ENTRY. + The REASON indicates what kind of transformation contributing to the + statement move. Return TRUE when the move history has been set + successfully. */ + +bool +set_move_history_to_stmts_in_bb (basic_block bb, edge entry, + bool is_destination, + enum move_reason reason) +{ + bool is_true_path = false; + gimple_stmt_iterator gsi; + gimple *cond_stmt = get_cond_stmt (entry, is_destination, &is_true_path); + + if (!cond_stmt) + return false; + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + set_move_history (gsi_stmt (gsi), gimple_location (cond_stmt), + is_true_path, reason); + + return true; +} diff --git a/gcc/diagnostic-move-history.h b/gcc/diagnostic-move-history.h new file mode 100644 index 00000000000..9a58766d544 --- /dev/null +++ b/gcc/diagnostic-move-history.h @@ -0,0 +1,92 @@ +/* Move history associated with a gimple statement to record its history + of movement due to different transformations. + The move history will be used to construct events for later diagnostic. + + Copyright (C) 2024 Free Software Foundation, Inc. + Contributed by Qing Zhao <qing.z...@oracle.com> + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 3, or (at your option) any later + version. + + GCC is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +#ifndef DIAGNOSTIC_MOVE_HISTORY_H +#define DIAGNOSTIC_MOVE_HISTORY_H + +#include "hash-map.h" +#include "line-map.h" + +/* An enum for the reason why this move is made. Right now, there are + three reasons, we can add more if needed. */ +enum move_reason { + COPY_BY_THREAD_JUMP, + COPY_BY_ISOLATE_PATH, + MOVE_BY_SINK, + COPY_BY_MAX +}; + +/* This data structure records the information when a statement is + moved along control flow graph during different transformations. + Such information will be used by the later diagnostic messages + to report more contexts of the warnings or errors. */ +struct move_history { + /* The location of the condition statement that triggered the code + movement. */ + location_t condition; + + /* Whether this move is on the TRUE path of the condition. */ + bool is_true_path; + + /* The reason for the code movement. */ + enum move_reason reason; + + /* This statement itself might be a previous code movement. */ + struct move_history *prev_move; +}; + +typedef struct move_history *move_history_t; + +/* Create a new move history. */ +extern move_history_t create_move_history (location_t, bool, + enum move_reason, move_history_t); + +typedef hash_map<const gimple *, move_history_t> move_history_map_t; + +/* Get the move history for the gimple STMT, return NULL when there is + no associated move history. */ +extern move_history_t get_move_history (const gimple *); + +/* Remove the move history for STMT from the move_history_map. */ +extern void remove_move_history (gimple *); + +/* Set move history for the gimple STMT. */ +extern bool set_move_history (gimple *, location_t, + bool, enum move_reason); + +/* Reset all state for diagnostic-move-history.cc so that we can rerun the + compiler within the same process. For use by toplev::finalize. */ +extern void move_history_finalize (void); + +/* Set move history to the stmt based on the edge ENTRY and whether this stmt + will be in the destination of the ENTRY. */ +extern bool set_move_history_to_stmt (gimple *, edge, + bool, enum move_reason); + +/* Set move history to all the stmts in the basic block based on + the entry edge and whether this basic block will be the destination + of the entry edge. */ +extern bool set_move_history_to_stmts_in_bb (basic_block, edge, + bool, enum move_reason); + +#endif // DIAGNOSTIC_MOVE_HISTORY_H diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 4c9af429ab0..c418fd811bb 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -332,6 +332,7 @@ Objective-C and Objective-C++ Dialects}. -fdiagnostics-column-origin=@var{origin} -fdiagnostics-escape-format=@r{[}unicode@r{|}bytes@r{]} -fdiagnostics-text-art-charset=@r{[}none@r{|}ascii@r{|}unicode@r{|}emoji@r{]}} +-fdiagnostics-details @item Warning Options @xref{Warning Options,,Options to Request or Suppress Warnings}. @@ -5670,6 +5671,16 @@ left margin. This option controls the minimum width of the left margin printed by @option{-fdiagnostics-show-line-numbers}. It defaults to 6. +@opindex fdiagnostics-details +@item -fdiagnostics-details +With this option, the compiler collects more context information for +diagnostics and emits them to the users to provide more hints on how +the diagnostics come from, at the cost of a slightly slower compilation. +Currently, The list of the impacted warning options includes: +@option{-Warray-bounds}, @option{-Wstringop-overflow}, +@option{-Wstringop-overread}, and @option{-Wstringop-truncation}. +More warning options might be added to this list in future releases. + @opindex fdiagnostics-parseable-fixits @item -fdiagnostics-parseable-fixits Emit fix-it hints in a machine-parseable format, suitable for consumption diff --git a/gcc/gimple-iterator.cc b/gcc/gimple-iterator.cc index 3af672bf0b9..f1d7ca9c78e 100644 --- a/gcc/gimple-iterator.cc +++ b/gcc/gimple-iterator.cc @@ -33,6 +33,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-ssa.h" #include "value-prof.h" #include "gimplify.h" +#include "diagnostic-move-history.h" /* Mark the statement STMT as modified, and update it. */ @@ -581,6 +582,8 @@ gsi_remove (gimple_stmt_iterator *i, bool remove_permanently) cfun->debug_marker_count--; require_eh_edge_purge = remove_stmt_from_eh_lp (stmt); gimple_remove_stmt_histograms (cfun, stmt); + if (get_move_history (stmt) != NULL) + remove_move_history (stmt); } /* Update the iterator and re-wire the links in I->SEQ. */ diff --git a/gcc/gimple-pretty-print.cc b/gcc/gimple-pretty-print.cc index 4e20b4cc371..811164565bb 100644 --- a/gcc/gimple-pretty-print.cc +++ b/gcc/gimple-pretty-print.cc @@ -44,6 +44,7 @@ along with GCC; see the file COPYING3. If not see #include "asan.h" #include "cfgloop.h" #include "gimple-range.h" +#include "diagnostic-move-history.h" /* Disable warnings about quoting issues in the pp_xxx calls below that (intentionally) don't follow GCC diagnostic conventions. */ @@ -2734,6 +2735,9 @@ pp_gimple_stmt_1 (pretty_printer *pp, const gimple *gs, int spc, && (flags & TDF_ALIAS)) dump_ssaname_info (pp, gimple_get_lhs (gs), spc); + if (get_move_history (gs)) + pp_printf (pp, "[MV_H] "); + switch (gimple_code (gs)) { case GIMPLE_ASM: diff --git a/gcc/gimple-ssa-isolate-paths.cc b/gcc/gimple-ssa-isolate-paths.cc index ca1daf1d168..14c86590b17 100644 --- a/gcc/gimple-ssa-isolate-paths.cc +++ b/gcc/gimple-ssa-isolate-paths.cc @@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-cfg.h" #include "cfganal.h" #include "intl.h" +#include "diagnostic-move-history.h" static bool cfg_altered; @@ -170,6 +171,16 @@ isolate_path (basic_block bb, basic_block duplicate, } bb->count -= count; + /* Set the move history for all the stmts in both original and copied + basic blocks. The duplicated block will be the destination of the + incoming edge. */ + if (flag_diagnostics_details) + { + set_move_history_to_stmts_in_bb (bb, e, false, COPY_BY_ISOLATE_PATH); + set_move_history_to_stmts_in_bb (duplicate, e, + true, COPY_BY_ISOLATE_PATH); + } + /* Complete the isolation step by redirecting E to reach DUPLICATE. */ e2 = redirect_edge_and_branch (e, duplicate); if (e2) diff --git a/gcc/testsuite/gcc.dg/pr117375.c b/gcc/testsuite/gcc.dg/pr117375.c new file mode 100644 index 00000000000..beb685afc3b --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr117375.c @@ -0,0 +1,13 @@ +/* PR middle-end/117375 ICE with -fdiagnostics-details patch in sink pass. */ +/* { dg-do compile } + { dg-options "-O2 -Wall -fdiagnostics-details" } */ + +int st, st_0; +int nbFilledBytes, max; +void ec_enc_shrink(); +void max_allowed() { + int nbAvailableBytes = nbFilledBytes; + if (st && st_0) + if (max < nbAvailableBytes) + ec_enc_shrink(); +} diff --git a/gcc/toplev.cc b/gcc/toplev.cc index 6d8b8852fb8..7605acaf4cf 100644 --- a/gcc/toplev.cc +++ b/gcc/toplev.cc @@ -42,6 +42,7 @@ along with GCC; see the file COPYING3. If not see #include "coverage.h" #include "diagnostic.h" #include "pretty-print-urlifier.h" +#include "diagnostic-move-history.h" #include "varasm.h" #include "tree-inline.h" #include "realmpfr.h" /* For GMP/MPFR/MPC versions, in print_version. */ @@ -2437,6 +2438,8 @@ toplev::finalize (void) reginfo_cc_finalize (); varasm_cc_finalize (); + move_history_finalize (); + /* save_decoded_options uses opts_obstack, so these must be cleaned up together. */ obstack_free (&opts_obstack, NULL); diff --git a/gcc/tree-ssa-sink.cc b/gcc/tree-ssa-sink.cc index 959e0d5c6be..0b3441e894c 100644 --- a/gcc/tree-ssa-sink.cc +++ b/gcc/tree-ssa-sink.cc @@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-eh.h" #include "tree-ssa-live.h" #include "tree-dfa.h" +#include "diagnostic-move-history.h" /* TODO: 1. Sinking store only using scalar promotion (IE without moving the RHS): @@ -655,6 +656,49 @@ sink_common_stores_to_bb (basic_block bb) return todo; } +/* Get the edge chain from FROM_BB to TO_BB, FROM_BB dominates TO_BB. + B2 + / \ + V \ + B3 \ + / \ \ + V \---->V + B4 B7 + + In the above CFG, FROM_BB is B2, TO_BB is B4. This routine + will locate two edges, B2->B3, and B3->B4 and return a vector + with these two edges. + This routine will return an empty vector if the control flow + edge chain from FROM_BB to TO_BB is too complicate. */ + +static auto_vec<edge> +get_edge_chain (basic_block from_bb, basic_block to_bb) +{ + auto_vec<edge> rev_edge_chain, edge_chain; + basic_block imm_dom_bb; + edge e; + unsigned int i; + /* Backtracing from TO_BB to FROM_BB through the dominator tree. */ + do + { + imm_dom_bb = get_immediate_dominator (CDI_DOMINATORS, to_bb); + if (!imm_dom_bb) + return edge_chain; + e = find_edge (imm_dom_bb, to_bb); + if (!e) + return edge_chain; + gcc_assert (e); + rev_edge_chain.safe_push (e); + to_bb = imm_dom_bb; + } + while (imm_dom_bb != from_bb); + + /* The order of the edges need to be reverted. */ + FOR_EACH_VEC_ELT_REVERSE (rev_edge_chain, i, e) + edge_chain.safe_push (e); + return edge_chain; +} + /* Perform code sinking on BB */ static unsigned @@ -712,6 +756,19 @@ sink_code_in_bb (basic_block bb, virtual_operand_live &vop_live) bb->index, (gsi_bb (togsi))->index); } + /* Set the move history for the stmt that is sinked from BB to + gsi_bb (togsi). This stmt is on the path from BB to + gsi_bb (togsi). */ + if (flag_diagnostics_details) + { + /* BB might not be the immediate predecessor of gsi_bb (togsi), + get the edge chain from BB to gsi_bb (togsi). */ + auto_vec<edge> edge_chain = get_edge_chain (bb, gsi_bb (togsi)); + + for (edge entry : edge_chain) + set_move_history_to_stmt (stmt, entry, true, MOVE_BY_SINK); + } + /* Update virtual operands of statements in the path we do not sink to. */ if (gimple_vdef (stmt)) diff --git a/gcc/tree-ssa-threadupdate.cc b/gcc/tree-ssa-threadupdate.cc index 4e5c7566857..789ca1d9422 100644 --- a/gcc/tree-ssa-threadupdate.cc +++ b/gcc/tree-ssa-threadupdate.cc @@ -36,6 +36,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-cfg.h" #include "tree-vectorizer.h" #include "tree-pass.h" +#include "diagnostic-move-history.h" /* Given a block B, update the CFG and SSA graph to reflect redirecting one or more in-edges to B to instead reach the destination of an @@ -1341,6 +1342,17 @@ ssa_redirect_edges (struct redirection_data **slot, { edge e2; + /* Set the move history for all the stmts in both original and copied + basic blocks. The duplicated block will be the destination of the + incoming edge. */ + if (flag_diagnostics_details) + { + set_move_history_to_stmts_in_bb (e->dest, e, false, + COPY_BY_THREAD_JUMP); + set_move_history_to_stmts_in_bb (rd->dup_blocks[0], e, + true, COPY_BY_THREAD_JUMP); + } + if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " Threaded jump %d --> %d to %d\n", e->src->index, e->dest->index, rd->dup_blocks[0]->index); @@ -2419,6 +2431,19 @@ back_jt_path_registry::duplicate_thread_path (edge entry, copy_bbs (region, n_region, region_copy, &exit, 1, &exit_copy, loop, split_edge_bb_loc (entry), false); + /* Set the move history for all the stmts in both original and copied + basic blocks. The copied regions will be the destination of the + entry edge. */ + for (i = 0; i < n_region; i++) + if (flag_diagnostics_details) + { + set_move_history_to_stmts_in_bb (region[i], entry, false, + COPY_BY_THREAD_JUMP); + set_move_history_to_stmts_in_bb (region_copy[i], entry, + true, COPY_BY_THREAD_JUMP); + } + + /* Fix up: copy_bbs redirects all edges pointing to copied blocks. The following code ensures that all the edges exiting the jump-thread path are redirected back to the original code: these edges are exceptions -- 2.43.5