> On Oct 30, 2024, at 13:48, Sam James <s...@gentoo.org> wrote:
> 
> Qing Zhao <qing.z...@oracle.com> writes:
> 
>> 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];};
>>      |                  ^~~~
>> 
>> PR tree-optimization/109071
>> 
>> gcc/ChangeLog:
>> 
>> * Makefile.in (OBJS): Add diagnostic-move-history.o
>> and move-history-diagnostic-path.o.
>> * gcc/common.opt (fdiagnostics-details): New option.
>> * gcc/doc/invoke.texi (fdiagnostics-details): Add
>> documentation for the new option.
>> * gimple-array-bounds.cc (build_rich_location_with_diagnostic_path):
>> New function.
>> (check_out_of_bounds_and_warn): Add one new parameter. Use rich
>> location with move_history_diagnostic_path for warning_at.
>> (array_bounds_checker::check_array_ref): Use rich location with
>> move_history_diagnostic_path for warning_at.
>> (array_bounds_checker::check_mem_ref): Add one new parameter.
>> Use rich location with move_history_diagnostic_path for warning_at.
>> (array_bounds_checker::check_addr_expr): Use rich location with
>> move_history_diagnostic_path for warning_at.
>> (array_bounds_checker::check_array_bounds): Call check_mem_ref with
>> one more parameter.
>> * gimple-array-bounds.h: Update prototype for check_mem_ref.
>> * 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.
>> * gimple-ssa-warn-restrict.cc (maybe_diag_access_bounds): Use
>> rich location with move_history_diagnostic_path for warning_at.
>>        * gimple-ssa-warn-access.cc (warn_string_no_nul): Likewise.
>>        (maybe_warn_nonstring_arg): Likewise.
>>        (maybe_warn_for_bound): Likewise.
>>        (warn_for_access): Likewise.
>>        (check_access): Likewise.
>>        (pass_waccess::check_strncat): Likewise.
>>        (pass_waccess::maybe_check_access_sizes): Likewise.
>>        * 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.
>> * move-history-diagnostic-path.cc: New file.
>> * move-history-diagnostic-path.h: New file.
>> * diagnostic-move-history.cc: New file.
>> * diagnostic-move-history.h: New file.
>> 
>> gcc/testsuite/ChangeLog:
>> 
>> PR tree-optimization/109071
>> 
>> * gcc.dg/pr109071.c: New test.
>> * gcc.dg/pr109071_1.c: New test.
>> * gcc.dg/pr109071_2.c: New test.
>> * gcc.dg/pr109071_3.c: New test.
>> * gcc.dg/pr109071_4.c: New test.
>>        * gcc.dg/pr109071_5.c: New test.
>>        * gcc.dg/pr109071_6.c: New test.
>> ---
>> gcc/Makefile.in                     |   2 +
>> gcc/common.opt                      |   4 +
>> gcc/diagnostic-move-history.cc      | 264 ++++++++++++++++++++++++++++
>> gcc/diagnostic-move-history.h       |  92 ++++++++++
>> gcc/doc/invoke.texi                 |   7 +
>> gcc/gimple-array-bounds.cc          |  75 ++++++--
>> gcc/gimple-array-bounds.h           |   2 +-
>> gcc/gimple-iterator.cc              |   3 +
>> gcc/gimple-pretty-print.cc          |   4 +
>> gcc/gimple-ssa-isolate-paths.cc     |  11 ++
>> gcc/gimple-ssa-warn-access.cc       | 153 ++++++++++------
>> gcc/gimple-ssa-warn-restrict.cc     |  27 +--
>> gcc/move-history-diagnostic-path.cc | 119 +++++++++++++
>> gcc/move-history-diagnostic-path.h  |  96 ++++++++++
>> gcc/testsuite/gcc.dg/pr109071.c     |  43 +++++
>> gcc/testsuite/gcc.dg/pr109071_1.c   |  36 ++++
>> gcc/testsuite/gcc.dg/pr109071_2.c   |  50 ++++++
>> gcc/testsuite/gcc.dg/pr109071_3.c   |  42 +++++
>> gcc/testsuite/gcc.dg/pr109071_4.c   |  41 +++++
>> gcc/testsuite/gcc.dg/pr109071_5.c   |  33 ++++
>> gcc/testsuite/gcc.dg/pr109071_6.c   |  49 ++++++
>> gcc/toplev.cc                       |   3 +
>> gcc/tree-ssa-sink.cc                |  10 ++
>> gcc/tree-ssa-threadupdate.cc        |  25 +++
>> 24 files changed, 1105 insertions(+), 86 deletions(-)
>> create mode 100644 gcc/diagnostic-move-history.cc
>> create mode 100644 gcc/diagnostic-move-history.h
>> create mode 100644 gcc/move-history-diagnostic-path.cc
>> create mode 100644 gcc/move-history-diagnostic-path.h
>> create mode 100644 gcc/testsuite/gcc.dg/pr109071.c
>> create mode 100644 gcc/testsuite/gcc.dg/pr109071_1.c
>> create mode 100644 gcc/testsuite/gcc.dg/pr109071_2.c
>> create mode 100644 gcc/testsuite/gcc.dg/pr109071_3.c
>> create mode 100644 gcc/testsuite/gcc.dg/pr109071_4.c
>> create mode 100644 gcc/testsuite/gcc.dg/pr109071_5.c
>> create mode 100644 gcc/testsuite/gcc.dg/pr109071_6.c
>> 
>> diff --git a/gcc/Makefile.in b/gcc/Makefile.in
>> index 059cf2e8f79f..0d119ba46e1b 100644
>> --- a/gcc/Makefile.in
>> +++ b/gcc/Makefile.in
>> @@ -1432,6 +1432,8 @@ OBJS = \
>> df-problems.o \
>> df-scan.o \
>> dfp.o \
>> + diagnostic-move-history.o \
>> + move-history-diagnostic-path.o \
>> digraph.o \
>> dojump.o \
>> dominance.o \
>> diff --git a/gcc/common.opt b/gcc/common.opt
>> index 12b25ff486de..84ebef080143 100644
>> --- a/gcc/common.opt
>> +++ b/gcc/common.opt
>> @@ -1566,6 +1566,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 000000000000..b0e8308dbf6b
>> --- /dev/null
>> +++ b/gcc/diagnostic-move-history.cc
>> @@ -0,0 +1,264 @@
>> +/* Functions to handle move history.
>> +   Copyright (C) 2024-2024 Free Software Foundation, Inc.
> 
> Just '2024'.
> 
>> +   Contributed by Qing Zhao <qing.z...@oracle.com>
>> +
>> [...]
>> diff --git a/gcc/diagnostic-move-history.h b/gcc/diagnostic-move-history.h
>> new file mode 100644
>> index 000000000000..cac9cb1e2675
>> --- /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-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_INCLUDED
>> +#define DIAGNOSTIC_MOVE_HISTORY_H_INCLUDED
> 
> I think usually the guards lack _INCLUDED.

Just checked GCC’s source code, yes, only “diagnostic-spec.h”, 
“simple-predicate-analysis.h” use _INCLUDED to guard.
Other header files do not add _INCLUDED.
I can remove it in the next version.
> 
>> +
>> +#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_INCLUDED
>> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
>> index 987b63601520..8bb7568d0e30 100644
>> --- a/gcc/doc/invoke.texi
>> +++ b/gcc/doc/invoke.texi
>> @@ -324,6 +324,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}.
>> @@ -5609,6 +5610,12 @@ 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.
>> +
> 
> Two comments:
> 1) I don't know if we should note here that it might be a bit slower as it
> requires that collection or if it's implied/obvious?
I think that adding such notes should not hurt anything. 
> 
> 2) Should we mention a list of warnings we know are wired up to it?
> (either here, or in the docs for the warnings themselves)

Yes, this is reasonable to clarify on both sides. 
I will update this.

Thanks for the comments and suggestions. 
Qing
> 
>> @opindex fdiagnostics-parseable-fixits
>> @item -fdiagnostics-parseable-fixits
>> Emit fix-it hints in a machine-parseable format, suitable for consumption
>> [...]
> 
> thanks,
> sam

Reply via email to