1 | /* Search for references that a functions loads or stores. |
2 | Copyright (C) 2019-2023 Free Software Foundation, Inc. |
3 | |
4 | This file is part of GCC. |
5 | |
6 | GCC is free software; you can redistribute it and/or modify it under |
7 | the terms of the GNU General Public License as published by the Free |
8 | Software Foundation; either version 3, or (at your option) any later |
9 | version. |
10 | |
11 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or |
13 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
14 | for more details. |
15 | |
16 | You should have received a copy of the GNU General Public License |
17 | along with GCC; see the file COPYING3. If not see |
18 | <http://www.gnu.org/licenses/>. */ |
19 | |
20 | #ifndef IPA_MODREF_H |
21 | #define IPA_MODREF_H |
22 | |
23 | typedef modref_tree <alias_set_type> modref_records; |
24 | typedef unsigned short eaf_flags_t; |
25 | |
26 | /* Single function summary. */ |
27 | |
28 | struct GTY(()) modref_summary |
29 | { |
30 | /* Load and stores in function (transitively closed to all callees) */ |
31 | modref_records *loads; |
32 | modref_records *stores; |
33 | auto_vec<modref_access_node> GTY((skip)) kills; |
34 | auto_vec<eaf_flags_t> GTY((skip)) arg_flags; |
35 | |
36 | eaf_flags_t retslot_flags; |
37 | eaf_flags_t static_chain_flags; |
38 | |
39 | unsigned writes_errno : 1; |
40 | /* Side effects does not include memory loads and stores which are |
41 | expressed using loads, stores and calls_interposable fields. */ |
42 | unsigned side_effects : 1; |
43 | /* If true function can not be CSE optimized because it may behave |
44 | differently even if invoked with same inputs. */ |
45 | unsigned nondeterministic : 1; |
46 | /* IF true the function may read any reachable memory but not use |
47 | it for anything useful. This may happen i.e. when interposing |
48 | function with optimized out conditional with unoptimized one. |
49 | |
50 | In this situation the loads summary is not useful for DSE but |
51 | it is still useful for CSE. */ |
52 | unsigned calls_interposable : 1; |
53 | |
54 | /* Flags computed by finalize method. */ |
55 | |
56 | /* Total number of accesses in loads tree. */ |
57 | unsigned int load_accesses; |
58 | /* global_memory_read is not set for functions calling functions |
59 | with !binds_to_current_def which, after interposition, may read global |
60 | memory but do nothing useful with it (except for crashing if some |
61 | stores are optimized out. */ |
62 | unsigned global_memory_read : 1; |
63 | unsigned global_memory_written : 1; |
64 | unsigned try_dse : 1; |
65 | |
66 | |
67 | modref_summary (); |
68 | ~modref_summary (); |
69 | void dump (FILE *) const; |
70 | bool useful_p (int ecf_flags, bool check_flags = true); |
71 | void finalize (tree); |
72 | }; |
73 | |
74 | modref_summary *get_modref_function_summary (cgraph_node *func); |
75 | modref_summary *get_modref_function_summary (gcall *call, bool *interposed); |
76 | void ipa_modref_cc_finalize (); |
77 | void ipa_merge_modref_summary_after_inlining (cgraph_edge *e); |
78 | |
79 | /* All flags that are implied by the ECF_CONST functions. */ |
80 | static const int implicit_const_eaf_flags |
81 | = EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER |
82 | | EAF_NO_DIRECT_ESCAPE | EAF_NO_INDIRECT_ESCAPE |
83 | | EAF_NO_DIRECT_READ | EAF_NO_INDIRECT_READ |
84 | | EAF_NOT_RETURNED_INDIRECTLY; |
85 | |
86 | /* All flags that are implied by the ECF_PURE function. */ |
87 | static const int implicit_pure_eaf_flags |
88 | = EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER |
89 | | EAF_NO_DIRECT_ESCAPE | EAF_NO_INDIRECT_ESCAPE; |
90 | |
91 | /* All flags implied when we know we can ignore stores (i.e. when handling |
92 | call to noreturn). */ |
93 | static const int ignore_stores_eaf_flags |
94 | = EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER |
95 | | EAF_NO_DIRECT_ESCAPE | EAF_NO_INDIRECT_ESCAPE; |
96 | |
97 | /* Return slot is write-only. */ |
98 | static const int implicit_retslot_eaf_flags |
99 | = EAF_NO_DIRECT_READ | EAF_NO_INDIRECT_READ |
100 | | EAF_NO_INDIRECT_ESCAPE | EAF_NO_INDIRECT_CLOBBER |
101 | | EAF_NOT_RETURNED_INDIRECTLY; |
102 | |
103 | /* If function does not bind to current def (i.e. it is inline in comdat |
104 | section), the modref analysis may not match the behavior of function |
105 | which will be later symbol interposed to. All side effects must match |
106 | however it is possible that the other function body contains more loads |
107 | which may trap. |
108 | MODREF_FLAGS are flags determined by analysis of function body while |
109 | FLAGS are flags known otherwise (i.e. by fnspec, pure/const attributes |
110 | etc.) */ |
111 | inline int |
112 | interposable_eaf_flags (int modref_flags, int flags) |
113 | { |
114 | /* If parameter was previously unused, we know it is only read |
115 | and its value is not used. */ |
116 | if ((modref_flags & EAF_UNUSED) && !(flags & EAF_UNUSED)) |
117 | { |
118 | modref_flags &= ~EAF_UNUSED; |
119 | modref_flags |= EAF_NO_DIRECT_ESCAPE | EAF_NO_INDIRECT_ESCAPE |
120 | | EAF_NOT_RETURNED_DIRECTLY | EAF_NOT_RETURNED_INDIRECTLY |
121 | | EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER; |
122 | } |
123 | /* We can not determine that value is not read at all. */ |
124 | if ((modref_flags & EAF_NO_DIRECT_READ) && !(flags & EAF_NO_DIRECT_READ)) |
125 | modref_flags &= ~EAF_NO_DIRECT_READ; |
126 | if ((modref_flags & EAF_NO_INDIRECT_READ) && !(flags & EAF_NO_INDIRECT_READ)) |
127 | modref_flags &= ~EAF_NO_INDIRECT_READ; |
128 | return modref_flags; |
129 | } |
130 | |
131 | #endif |
132 | |