Branch data Line data Source code
1 : : /* Support for plugin-supplied behaviors of known functions.
2 : : Copyright (C) 2022-2024 Free Software Foundation, Inc.
3 : : Contributed by David Malcolm <dmalcolm@redhat.com>.
4 : :
5 : : This file is part of GCC.
6 : :
7 : : GCC is free software; you can redistribute it and/or modify it
8 : : under the terms of the GNU General Public License as published by
9 : : the Free Software Foundation; either version 3, or (at your option)
10 : : any later version.
11 : :
12 : : GCC is distributed in the hope that it will be useful, but
13 : : WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : General Public License for more details.
16 : :
17 : : You should have received a copy of the GNU General Public License
18 : : along with GCC; see the file COPYING3. If not see
19 : : <http://www.gnu.org/licenses/>. */
20 : :
21 : : #include "config.h"
22 : : #define INCLUDE_VECTOR
23 : : #include "system.h"
24 : : #include "coretypes.h"
25 : : #include "tree.h"
26 : : #include "analyzer/analyzer.h"
27 : : #include "diagnostic-core.h"
28 : : #include "analyzer/analyzer-logging.h"
29 : : #include "stringpool.h"
30 : : #include "basic-block.h"
31 : : #include "gimple.h"
32 : : #include "analyzer/known-function-manager.h"
33 : : #include "analyzer/region-model.h"
34 : : #include "analyzer/call-details.h"
35 : :
36 : : #if ENABLE_ANALYZER
37 : :
38 : : namespace ana {
39 : :
40 : : /* class known_function_manager : public log_user. */
41 : :
42 : 3769 : known_function_manager::known_function_manager (logger *logger)
43 : 3769 : : log_user (logger)
44 : : {
45 : 3769 : memset (m_combined_fns_arr, 0, sizeof (m_combined_fns_arr));
46 : 3769 : }
47 : :
48 : 3769 : known_function_manager::~known_function_manager ()
49 : : {
50 : : /* Delete all owned kfs. */
51 : 553867 : for (auto iter : m_map_id_to_kf)
52 : 275049 : delete iter.second;
53 : 112467 : for (auto iter : m_std_ns_map_id_to_kf)
54 : 54349 : delete iter.second;
55 : 8374718 : for (auto iter : m_combined_fns_arr)
56 : 8370949 : delete iter;
57 : 3769 : }
58 : :
59 : : void
60 : 275049 : known_function_manager::add (const char *name,
61 : : std::unique_ptr<known_function> kf)
62 : : {
63 : 275049 : LOG_FUNC_1 (get_logger (), "registering %s", name);
64 : 275049 : tree id = get_identifier (name);
65 : 275049 : m_map_id_to_kf.put (id, kf.release ());
66 : 275049 : }
67 : :
68 : : void
69 : 54349 : known_function_manager::add_std_ns (const char *name,
70 : : std::unique_ptr<known_function> kf)
71 : : {
72 : 54349 : LOG_FUNC_1 (get_logger (), "registering std::%s", name);
73 : 54349 : tree id = get_identifier (name);
74 : 54349 : m_std_ns_map_id_to_kf.put (id, kf.release ());
75 : 54349 : }
76 : :
77 : : void
78 : 549884 : known_function_manager::add (enum built_in_function name,
79 : : std::unique_ptr<known_function> kf)
80 : : {
81 : 549884 : gcc_assert (name < END_BUILTINS);
82 : 549884 : delete m_combined_fns_arr[name];
83 : 549884 : m_combined_fns_arr[name] = kf.release ();
84 : 549884 : }
85 : :
86 : : void
87 : 12788 : known_function_manager::add (enum internal_fn ifn,
88 : : std::unique_ptr<known_function> kf)
89 : : {
90 : 12788 : gcc_assert (ifn < IFN_LAST);
91 : 12788 : delete m_combined_fns_arr[ifn + END_BUILTINS];
92 : 12788 : m_combined_fns_arr[ifn + END_BUILTINS] = kf.release ();
93 : 12788 : }
94 : :
95 : : /* Get any known_function for FNDECL for call CD.
96 : :
97 : : The call must match all assumptions made by the known_function (such as
98 : : e.g. "argument 1's type must be a pointer type").
99 : :
100 : : Return NULL if no known_function is found, or it does not match the
101 : : assumption(s). */
102 : :
103 : : const known_function *
104 : 354590 : known_function_manager::get_match (tree fndecl, const call_details &cd) const
105 : : {
106 : : /* Look for a matching built-in. */
107 : 354590 : if (fndecl_built_in_p (fndecl, BUILT_IN_NORMAL))
108 : : {
109 : 292564 : if (const known_function *candidate
110 : 146282 : = get_normal_builtin (DECL_FUNCTION_CODE (fndecl)))
111 : 19019 : if (gimple_builtin_call_types_compatible_p (cd.get_call_stmt (),
112 : : fndecl))
113 : : return candidate;
114 : : }
115 : :
116 : : /* Look for a match by name. */
117 : :
118 : 335571 : if (is_std_function_p (fndecl))
119 : : {
120 : 108 : if (tree identifier = DECL_NAME (fndecl))
121 : 216 : if (const known_function *candidate
122 : 108 : = get_by_identifier_in_std_ns (identifier))
123 : 90 : if (candidate->matches_call_types_p (cd))
124 : : return candidate;
125 : 18 : return nullptr;
126 : : }
127 : :
128 : 335463 : if (DECL_CONTEXT (fndecl)
129 : 335463 : && TREE_CODE (DECL_CONTEXT (fndecl)) != TRANSLATION_UNIT_DECL)
130 : : return NULL;
131 : 329779 : if (tree identifier = DECL_NAME (fndecl))
132 : 329779 : if (const known_function *candidate = get_by_identifier (identifier))
133 : 192709 : if (candidate->matches_call_types_p (cd))
134 : : return candidate;
135 : :
136 : : return NULL;
137 : : }
138 : :
139 : : /* Get any known_function for IFN, or NULL. */
140 : :
141 : : const known_function *
142 : 1327 : known_function_manager::get_internal_fn (enum internal_fn ifn) const
143 : : {
144 : 1327 : gcc_assert (ifn < IFN_LAST);
145 : 1327 : return m_combined_fns_arr[ifn + END_BUILTINS];
146 : : }
147 : :
148 : : /* Get any known_function for NAME, without type-checking.
149 : : Return NULL if there isn't one. */
150 : :
151 : : const known_function *
152 : 146282 : known_function_manager::get_normal_builtin (enum built_in_function name) const
153 : : {
154 : : /* The numbers for built-in functions in enum combined_fn are the same as
155 : : for the built_in_function enum. */
156 : 146282 : gcc_assert (name < END_BUILTINS);
157 : 146282 : return m_combined_fns_arr[name];
158 : : }
159 : :
160 : : const known_function *
161 : 0 : known_function_manager::
162 : : get_normal_builtin (const builtin_known_function *builtin_kf) const
163 : : {
164 : 0 : return get_normal_builtin (builtin_kf->builtin_code ());
165 : : }
166 : :
167 : : /* Get any known_function matching IDENTIFIER, without type-checking.
168 : : Return NULL if there isn't one. */
169 : :
170 : : const known_function *
171 : 329779 : known_function_manager::get_by_identifier (tree identifier) const
172 : : {
173 : 329779 : known_function_manager *mut_this = const_cast<known_function_manager *>(this);
174 : 329779 : known_function **slot = mut_this->m_map_id_to_kf.get (identifier);
175 : 329779 : if (slot)
176 : 192709 : return *slot;
177 : : else
178 : : return NULL;
179 : : }
180 : :
181 : : /* Get any known_function in C++ std:: namespace matching IDENTIFIER, without
182 : : type-checking.
183 : : Return nullptr if there isn't one. */
184 : :
185 : : const known_function *
186 : 108 : known_function_manager::get_by_identifier_in_std_ns (tree identifier) const
187 : : {
188 : 108 : known_function_manager *mut_this = const_cast<known_function_manager *>(this);
189 : 108 : known_function **slot = mut_this->m_std_ns_map_id_to_kf.get (identifier);
190 : 108 : if (slot)
191 : 90 : return *slot;
192 : : else
193 : : return nullptr;
194 : : }
195 : :
196 : :
197 : : } // namespace ana
198 : :
199 : : #endif /* #if ENABLE_ANALYZER */
|