From: Qing Zhao <qing.zhao@oracle.com>
To: Richard Biener <richard.guenther@gmail.com>
Cc: David Malcolm <dmalcolm@redhat.com>,
GCC Patches <gcc-patches@gcc.gnu.org>,
Andrew Pinski <pinskia@gmail.com>,
kees Cook <keescook@chromium.org>
Subject: Re: [RFC][PATCH] PR tree-optimization/109071 - -Warray-bounds false positive warnings due to code duplication from jump threading
Date: Fri, 7 Jun 2024 19:13:25 +0000 [thread overview]
Message-ID: <21CA5119-B440-4DD2-AC69-E9DD6731BCBE@oracle.com> (raw)
In-Reply-To: <A2576432-EE42-4E10-88C2-651E047B00E5@oracle.com>
Hi, Richard,
> On Jun 5, 2024, at 13:58, Qing Zhao <qing.zhao@oracle.com> wrote:
>>
>>>>>>>>> Like this?
>>>>>>>>>
>>>>>>>>> diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h
>>>>>>>>> index e6e2b0897572..ee344f91333b 100644
>>>>>>>>> --- a/libcpp/include/line-map.h
>>>>>>>>> +++ b/libcpp/include/line-map.h
>>>>>>>>> @@ -761,8 +761,9 @@ struct GTY(()) maps_info_macro {
>>>>>>>>> struct GTY(()) location_adhoc_data {
>>>>>>>>> location_t locus;
>>>>>>>>> source_range src_range;
>>>>>>>>> - void * GTY((skip)) data;
>>>>>>>>> unsigned discriminator;
>>>>>>>>> + void * GTY((skip)) data;
>>>>>>>>> + void * GTY((skip)) copy_history;
>>>>>>>>> };
>>>>>>>>> struct htab;
>>>>>>>>
>>>>>>>> Yes.
>>>>>>>>
>>>>>>>>> How about the copy_history? Do we need a new data structure (like
>>>>>>>>> the following, or other suggestion) for this? Where should I add
>>>>>>>>> this new data structure?
>>>>>>>>
>>>>>>>> As it needs to be managed by libcpp it should be in this very same
>>>>>>>> file.
>>>>>>>>
>>>>>>>>> struct copy_history {
>>>>>>>>> location_t condition;
>>>>>>>>> Bool is_true_path;
>>>>>>>>> }
>>>>>>>>
>>>>>>>> I think we want a pointer to the previous copy-of state as well in
>>>>>>>> case a stmt
>>>>>>>> was copied twice. We'll see whether a single (condition) location
>>>>>>>> plus edge flag
>>>>>>>> is sufficient. I'd say we should plan for an enum to indicate the
>>>>>>>> duplication
>>>>>>>> reason at least (jump threading, unswitching, unrolling come to my
>>>>>>>> mind). For
>>>>>>>> jump threading being able to say "when <condition> is true/false" is
>>>>>>>> probably
>>>>>>>> good enough, though it might not always be easy to identify a single
>>>>>>>> condition
>>>>>>>> here given a threading path starts at an incoming edge to a CFG merge
>>>>>>>> and
>>>>>>>> will usually end with the outgoing edge of a condition that we can
>>>>>>>> statically
>>>>>>>> evaluate. The condition controlling the path entry might not be
>>>>>>>> determined
>>>>>>>> fully by a single condition location.
>>>>>>>>
>>>>>>>> Possibly building a full "diagnostic path" object at threading time
>>>>>>>> might be
>>>>>>>> the only way to record all the facts, but that's also going to be
>>>>>>>> more
>>>>>>>> expensive.
>>>>>>>
>>>>>>> Note that a diagnostic_path represents a path through some kind of
>>>>>>> graph, whereas it sounds like you want to be storing the *nodes* in the
>>>>>>> graph, and later generating the diagnostic_path from that graph when we
>>>>>>> need it (which is trivial if the graph is actually just a tree: just
>>>>>>> follow the parent links backwards, then reverse it).
>>>>>>
>>>>>> I think we are mixing two things - one is that a single transform like jump
>>>>>> threading produces a stmt copy and when we emit a diagnostic on that
>>>>>> copied statement we want to tell the user the condition under which the
>>>>>> copy is executed. That "condition" can be actually a sequence of
>>>>>> conditionals. I wanted to point out that a diagnostic_path instance could
>>>>>> be used to describe such complex condition.
>>>>>>
>>>>>> But then the other thing I wanted to address with the link to a previous
>>>>>> copy_history - that's when a statement gets copied twice, for example
>>>>>> by two distinct jump threading optimizations. Like when dumping
>>>>>> the inlining decisions for diagnostics we could dump the logical "and"
>>>>>> of the conditions of the two threadings. Since we have a single
>>>>>> location per GIMPLE stmt we'd have to keep a "stack" of copy events
>>>>>> associated with it. That's the linked list (I think a linked list should
>>>>>> work fine here).
>>>>> Yes, the linked list to keep the “stack” of copy events should be good enough
>>>>> to form the sequence of conditionals event for the diagnostic_path instance.
>>>>>>
>>>>>> I realize things may get a bit "fat", but eventually we are not duplicating
>>>>>> statements that much. I do hope we can share for example a big
>>>>>> diagnostic_path when we duplicate a basic block during threading
>>>>>> and use one instance for all stmts in such block copy (IIRC we never
>>>>>> release locations or their ad-hoc data, we just make sure to never
>>>>>> use locations with ad-hoc data pointing to BLOCKs that we released,
>>>>>> but the linemap data will still have pointers in "dead" location entries,
>>>>>> right?)
>>>>> Are you still suggesting to add two artificial stmts in the beginning and the
>>>>> end of the duplicated block to carry the copy history information for all the
>>>>> stmts in the block to save space?
>>>>>
>>>>> Compared with the approach to carry such information to each duplicated stmts (which I preferred),
>>>>> The major concerns with the approach are:
>>>>> 1. Optimizations might move stmts out of these two artificial stmts, therefore we need add
>>>>> Some memory barrier on these two artificial stmts to prevent such movements.
>>>>> This might prevent good optimization from happening and result in runtime performance loss;
>>>>> 2. Every time when query whether the stmt is copied and get its copy history, we have to search backward or
>>>>> Forward through the stmt chain to get to the artificial stmts that carry the copy history, compilation time will
>>>>> be slower.
>>>>>
>>>>> I still think that carrying the copy history info to each duplicated stmts might be better. We can limit the length of
>>>>> the history to control the space, what do you think?
>>>>
>>>> Copying to each stmt is definitely easier so I think it's better to
>>>> start with that and only resort
>>>> to other things when this fails.
>>> Okay. Will try this approach first.
>>>>
>>>> Note we could, instead of putting a pointer to data into the ad-hoc
>>>> info, put in an index
>>>> and have the actual data be maintained elsewhere. That data could
>>>> even only keep
>>>> the "last" 1000 contexts and simply discard "older" ones. Before IPA
>>>> info can still be
>>>> transfered between functions, but after IPA where most of the
>>>> threadings happen the
>>>> extra info could be discarded once we get a function to the last pass
>>>> emitting diagnostics
>>>> we want to amend. Doing an index lookup makes it possible to not
>>>> worry about "stale"
>>>> entries.
>>>
>>> Are you suggesting to use a global array with upper-bound “1000” to hold the copy-history info?
>>> Then for each copied stmt, put in an index to this array to refer the copy-history linked list for it?
>>> Is “1000” enough for one function? We can do some experiments to decide this number.
>>>
>>> What do you mean by “stale” entries? The entries for the previous function?
>>>
>>> Is a function-level array enough for this purpose? i.e, for each function, we use an array to hold the copy-history info, and free this array after this function is done with compilation?
>>> A little confused here….
>>
>> I was thinking of a hash map and noting when we create an entry after IPA so we can scrap it when done with the function
> Okay. I see.
> then where should this hash map be declared? diagnostic-spec.h?
I studied a little bit on hash_map and some related code. For our case, I came up with the following:
====
/* An enum for the reason why this copy is made. Right now, there are
three reasons, we can add more if needed. */
enum copy_reason {
COPY_BY_THREAD_JUMP,
COPY_BY_LOOP_UNSWITCH,
COPY_BY_LOOP_UNROLL
};
/* This data structure records the information when a statement is duplicated
during different transformations. Such information will be used by the later
diagnostic message to report more context of the warning or error. */
struct copy_history {
/* The location of the condition statement that triggered the code
duplication. */
location_t condition;
/* Whether this copy is on the TRUE path of the condition. */
bool is_true_path;
/* The reason for the code duplication. */
enum copy_reason reason;
/* This statement itself might be a previous code duplication. */
structure copy_history *prev_copy;
};
typedef struct copy_history *copy_history_t;
typedef hash_map<gimple *, copy_history_t> copy_history_map_t;
/* A mapping from a simple to a pointer to the copy history of it. */
GTY(()) copy_history_map_t *copy_history_map;
/* Get the copy history for the gimple STMT, return NULL when there is
no associated copy history. */
copy_history_t
get_copy_history (gimple *stmt)
{
if (!copy_history_map)
return NULL;
if (const copy_history_t cp_history = copy_history_map->get (stmt))
return cp_history;
return NULL;
}
/* Insert the copy history for the gimple STMT. */
void
insert_copy_history (gimple *stmt, copy_history_t cp_history)
{
if (!copy_history_map)
copy_history_map = copy_history_map_t::create_ggc (1000);
copy_history_map->put (stmt, cp_history);
return;
}
=====
Do you have any comment and suggestion on the above?
I have some questions:
1. Should I add a new header file for this purpose, for example, diagnostic-copy-history.h?
Of just add these new data structures into an existing header file? If so, which one is better?
2. Should I explicitly delete and free the hash_map “copy_history_map” when it is not used anymore?
If so, where should I do this?
Or “create_ggc” will guarantee that this hash_map will be automatically deleted and freed.
3. You mentioned that this hash_map “copy_history_map” will be scrapped after the current function is done.
Is there any special places in GCC that I should explicitly create this hash_map for the current function and
then delete it when the current function is done?
Thanks a lot.
Qing
>
> Qing
>
>>
>>> Thanks for clarification.
>>>
>>> Qing
>>>
>>>
>>>>
>>>> Richard.
>>>>
>>>>>
>>>>> Qing
>>>>>
>>>>>>
>>>>>> Richard.
>>>>>>
>>>>>>>
>>>>>>> Dave
>>>>>>>
>>>>>>>> I can think of having a -fdiagnostic-try-to-explain-harder option to
>>>>>>>> clarify confusing
>>>>>>>> diagnostics people could use on-demand?
>>>>>>>>
>>>>>>>> Richard.
>>>>>>>>
>>>>>>>>> Qing
>>>>>>>>>>
>>>>>>>>>> Richard.
>>>>>>>>>>
>>>>>>>>>>> Thanks.
>>>>>>>>>>>
>>>>>>>>>>> Qing
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> Richard.
>>>>>>>>>>>>
>>>>>>>>>>>>> But feel free to ask me any questions about the
>>>>>>>>>>>>> diagnostic_path
>>>>>>>>>>>>> machinery within the diagnostics subsystem.
>>>>>>>>>>>>>
>>>>>>>>>>>>> [...snip...]
>>>>>>>>>>>>>
>>>>>>>>>>>>> Regards
>>>>>>>>>>>>> Dave
next prev parent reply other threads:[~2024-06-07 19:13 UTC|newest]
Thread overview: 40+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-05-13 19:48 Qing Zhao
2024-05-13 20:46 ` Jeff Law
2024-05-13 21:41 ` Kees Cook
2024-05-13 23:38 ` Andrew Pinski
2024-05-14 0:14 ` Kees Cook
2024-05-14 14:57 ` Qing Zhao
2024-05-14 15:08 ` Jeff Law
2024-05-14 16:03 ` Qing Zhao
2024-05-14 13:08 ` Richard Biener
2024-05-14 14:17 ` Qing Zhao
2024-05-14 14:29 ` Richard Biener
2024-05-14 15:19 ` Qing Zhao
2024-05-14 17:14 ` Richard Biener
2024-05-14 17:21 ` Qing Zhao
2024-05-15 6:09 ` Richard Biener
2024-05-15 13:37 ` Qing Zhao
2024-05-14 19:50 ` Kees Cook
2024-05-15 5:50 ` Richard Biener
2024-05-15 14:00 ` David Malcolm
2024-05-21 15:13 ` Qing Zhao
2024-05-21 21:36 ` David Malcolm
2024-05-22 7:38 ` Richard Biener
2024-05-22 18:53 ` Qing Zhao
2024-05-23 11:46 ` Richard Biener
2024-05-23 14:03 ` Qing Zhao
2024-05-23 14:13 ` David Malcolm
2024-05-23 14:23 ` Qing Zhao
2024-05-31 21:22 ` Qing Zhao
2024-06-03 6:29 ` Richard Biener
2024-06-03 14:33 ` Qing Zhao
2024-06-03 14:48 ` David Malcolm
2024-06-04 7:43 ` Richard Biener
2024-06-04 20:30 ` Qing Zhao
2024-06-05 7:26 ` Richard Biener
2024-06-05 16:38 ` Qing Zhao
2024-06-05 17:07 ` Richard Biener
2024-06-05 17:58 ` Qing Zhao
2024-06-07 19:13 ` Qing Zhao [this message]
2024-06-12 18:15 ` Qing Zhao
2024-05-14 16:43 ` Kees Cook
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=21CA5119-B440-4DD2-AC69-E9DD6731BCBE@oracle.com \
--to=qing.zhao@oracle.com \
--cc=dmalcolm@redhat.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=keescook@chromium.org \
--cc=pinskia@gmail.com \
--cc=richard.guenther@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).