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_MEMORY |
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 | known_function_manager::known_function_manager (logger *logger) |
43 | : log_user (logger) |
44 | { |
45 | memset (s: m_combined_fns_arr, c: 0, n: sizeof (m_combined_fns_arr)); |
46 | } |
47 | |
48 | known_function_manager::~known_function_manager () |
49 | { |
50 | /* Delete all owned kfs. */ |
51 | for (auto iter : m_map_id_to_kf) |
52 | delete iter.second; |
53 | for (auto iter : m_combined_fns_arr) |
54 | delete iter; |
55 | } |
56 | |
57 | void |
58 | known_function_manager::add (const char *name, |
59 | std::unique_ptr<known_function> kf) |
60 | { |
61 | LOG_FUNC_1 (get_logger (), "registering %s" , name); |
62 | tree id = get_identifier (name); |
63 | m_map_id_to_kf.put (k: id, v: kf.release ()); |
64 | } |
65 | |
66 | void |
67 | known_function_manager::add (enum built_in_function name, |
68 | std::unique_ptr<known_function> kf) |
69 | { |
70 | gcc_assert (name < END_BUILTINS); |
71 | delete m_combined_fns_arr[name]; |
72 | m_combined_fns_arr[name] = kf.release (); |
73 | } |
74 | |
75 | void |
76 | known_function_manager::add (enum internal_fn ifn, |
77 | std::unique_ptr<known_function> kf) |
78 | { |
79 | gcc_assert (ifn < IFN_LAST); |
80 | delete m_combined_fns_arr[ifn + END_BUILTINS]; |
81 | m_combined_fns_arr[ifn + END_BUILTINS] = kf.release (); |
82 | } |
83 | |
84 | /* Get any known_function for FNDECL for call CD. |
85 | |
86 | The call must match all assumptions made by the known_function (such as |
87 | e.g. "argument 1's type must be a pointer type"). |
88 | |
89 | Return NULL if no known_function is found, or it does not match the |
90 | assumption(s). */ |
91 | |
92 | const known_function * |
93 | known_function_manager::get_match (tree fndecl, const call_details &cd) const |
94 | { |
95 | /* Look for a matching built-in. */ |
96 | if (fndecl_built_in_p (node: fndecl, klass: BUILT_IN_NORMAL)) |
97 | { |
98 | if (const known_function *candidate |
99 | = get_normal_builtin (name: DECL_FUNCTION_CODE (decl: fndecl))) |
100 | if (gimple_builtin_call_types_compatible_p (cd.get_call_stmt (), |
101 | fndecl)) |
102 | return candidate; |
103 | } |
104 | |
105 | /* Look for a match by name. */ |
106 | |
107 | /* Reject fndecls that aren't in the root namespace. */ |
108 | if (DECL_CONTEXT (fndecl) |
109 | && TREE_CODE (DECL_CONTEXT (fndecl)) != TRANSLATION_UNIT_DECL) |
110 | return NULL; |
111 | if (tree identifier = DECL_NAME (fndecl)) |
112 | if (const known_function *candidate = get_by_identifier (identifier)) |
113 | if (candidate->matches_call_types_p (cd)) |
114 | return candidate; |
115 | |
116 | return NULL; |
117 | } |
118 | |
119 | /* Get any known_function for IFN, or NULL. */ |
120 | |
121 | const known_function * |
122 | known_function_manager::get_internal_fn (enum internal_fn ifn) const |
123 | { |
124 | gcc_assert (ifn < IFN_LAST); |
125 | return m_combined_fns_arr[ifn + END_BUILTINS]; |
126 | } |
127 | |
128 | /* Get any known_function for NAME, without type-checking. |
129 | Return NULL if there isn't one. */ |
130 | |
131 | const known_function * |
132 | known_function_manager::get_normal_builtin (enum built_in_function name) const |
133 | { |
134 | /* The numbers for built-in functions in enum combined_fn are the same as |
135 | for the built_in_function enum. */ |
136 | gcc_assert (name < END_BUILTINS); |
137 | return m_combined_fns_arr[name]; |
138 | } |
139 | |
140 | const known_function * |
141 | known_function_manager:: |
142 | get_normal_builtin (const builtin_known_function *builtin_kf) const |
143 | { |
144 | return get_normal_builtin (name: builtin_kf->builtin_code ()); |
145 | } |
146 | |
147 | /* Get any known_function matching IDENTIFIER, without type-checking. |
148 | Return NULL if there isn't one. */ |
149 | |
150 | const known_function * |
151 | known_function_manager::get_by_identifier (tree identifier) const |
152 | { |
153 | known_function_manager *mut_this = const_cast<known_function_manager *>(this); |
154 | known_function **slot = mut_this->m_map_id_to_kf.get (k: identifier); |
155 | if (slot) |
156 | return *slot; |
157 | else |
158 | return NULL; |
159 | } |
160 | |
161 | } // namespace ana |
162 | |
163 | #endif /* #if ENABLE_ANALYZER */ |
164 | |