Line data Source code
1 : /* Callback attribute handling
2 : Copyright (C) 2025-2026 Free Software Foundation, Inc.
3 : Contributed by Josef Melcr <jmelcr@gcc.gnu.org>
4 :
5 : This file is part of GCC.
6 :
7 : GCC is free software; you can redistribute it and/or modify
8 : under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : GCC is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU 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 : #include "system.h"
23 : #include "coretypes.h"
24 : #include "backend.h"
25 : #include "tree.h"
26 : #include "gimple.h"
27 : #include "alloc-pool.h"
28 : #include "cgraph.h"
29 : #include "diagnostic.h"
30 : #include "builtins.h"
31 : #include "options.h"
32 : #include "gimple-range.h"
33 : #include "attribs.h"
34 : #include "symbol-summary.h"
35 : #include "lto-streamer.h"
36 : #include "attr-callback.h"
37 : #include "callback-info.h"
38 :
39 : /* Returns a callback attribute with callback index FN_IDX, and ARG_COUNT
40 : arguments specified by VA_ARGS. */
41 : tree
42 388488 : callback_build_attr (unsigned fn_idx, unsigned arg_count...)
43 : {
44 388488 : va_list args;
45 388488 : va_start (args, arg_count);
46 :
47 388488 : tree cblist = NULL_TREE;
48 388488 : tree *pp = &cblist;
49 388488 : unsigned i;
50 776976 : for (i = 0; i < arg_count; i++)
51 : {
52 388488 : int num = va_arg (args, int);
53 388488 : tree tnum = build_int_cst (integer_type_node, num);
54 388488 : *pp = build_tree_list (NULL, tnum);
55 388488 : pp = &TREE_CHAIN (*pp);
56 : }
57 388488 : cblist
58 388488 : = tree_cons (NULL_TREE, build_int_cst (integer_type_node, fn_idx), cblist);
59 388488 : tree attr
60 388488 : = tree_cons (get_identifier ("callback_only"), cblist, NULL_TREE);
61 388488 : return attr;
62 : }
63 :
64 : /* Returns TRUE if a function should be treated as if it had a callback
65 : attribute despite the DECL not having it. STMT can be passed NULL
66 : if the call statement is not available at the time, for example WPA, but it
67 : should be called with the statement itself whenever possible. */
68 : bool
69 2774983 : callback_is_special_cased (tree decl, gcall *stmt)
70 : {
71 2774983 : if (fndecl_built_in_p (decl, BUILT_IN_GOMP_TASK))
72 : {
73 18345 : if (stmt)
74 18345 : return gimple_call_arg (stmt, 2) == null_pointer_node;
75 : return true;
76 : }
77 : return false;
78 : }
79 :
80 : /* Returns an attribute for a special cased function. */
81 : tree
82 3540 : callback_special_case_attr (tree decl)
83 : {
84 3540 : if (fndecl_built_in_p (decl, BUILT_IN_GOMP_TASK))
85 3540 : return callback_build_attr (1, 1, 2);
86 0 : gcc_unreachable ();
87 : }
88 :
89 : /* Returns TRUE if the callee of E has a callback attribute. */
90 : bool
91 2641931 : callback_edge_callee_has_attr (cgraph_edge *e)
92 : {
93 2641931 : return lookup_attribute ("callback_only",
94 2641931 : DECL_ATTRIBUTES (e->callee->decl))
95 2641931 : || callback_is_special_cased (e->callee->decl, e->call_stmt);
96 : }
97 :
98 : /* Given an instance of callback attribute, return the 0-based
99 : index of the called function in question. */
100 : int
101 28489 : callback_get_fn_index (tree cb_attr)
102 : {
103 28489 : tree args = TREE_VALUE (cb_attr);
104 28489 : int idx = TREE_INT_CST_LOW (TREE_VALUE (args)) - 1;
105 28489 : return idx;
106 : }
107 :
108 : /* For a given callback pair, retrieves the callback attribute used
109 : to create E from the callee of CARRYING. */
110 : tree
111 15127 : callback_fetch_attr_by_edge (cgraph_edge *e, cgraph_edge *carrying)
112 : {
113 15127 : gcc_checking_assert (e->call_stmt == carrying->call_stmt
114 : && e->lto_stmt_uid == carrying->lto_stmt_uid);
115 :
116 15127 : if (callback_is_special_cased (carrying->callee->decl, e->call_stmt))
117 1770 : return callback_special_case_attr (carrying->callee->decl);
118 :
119 13357 : tree cb_attr = lookup_attribute ("callback_only",
120 13357 : DECL_ATTRIBUTES (carrying->callee->decl));
121 13357 : gcc_checking_assert (cb_attr);
122 13357 : callback_info *ci = callback_info_sum->get (e);
123 13357 : tree res = NULL_TREE;
124 13358 : for (; cb_attr;
125 1 : cb_attr = lookup_attribute ("callback_only", TREE_CHAIN (cb_attr)))
126 : {
127 13358 : unsigned fn_idx = callback_get_fn_index (cb_attr);
128 13358 : if (fn_idx == ci->get_id ())
129 : {
130 : res = cb_attr;
131 : break;
132 : }
133 : }
134 13357 : gcc_checking_assert (res != NULL_TREE);
135 : return res;
136 : }
137 :
138 : /* Returns the argument mapping from the dispatching function to the callback
139 : function parsed from the attribute. */
140 : auto_vec<int>
141 15127 : callback_get_arg_mapping_from_attr (tree attr)
142 : {
143 15127 : tree args = TREE_VALUE (attr);
144 15127 : auto_vec<int> res;
145 15127 : tree it;
146 :
147 : /* Skip over the first argument, which denotes
148 : which argument is the called function. */
149 30255 : for (it = TREE_CHAIN (args); it != NULL_TREE; it = TREE_CHAIN (it))
150 : {
151 15128 : int idx = TREE_INT_CST_LOW (TREE_VALUE (it));
152 : /* Subtract 1 to account for 1-based indexing. If the value is unknown,
153 : use ARG_MAPPING_UNKNOWN_IDX instead. */
154 15128 : idx = idx == CB_UNKNOWN_POS ? ARG_MAPPING_UNKNOWN_IDX : idx - 1;
155 15128 : res.safe_push (idx);
156 : }
157 :
158 15127 : return res;
159 : }
160 :
161 : /* Returns TRUE if E is considered useful in the callgraph, FALSE otherwise. If
162 : this predicate returns FALSE, then E wasn't used to optimize its callee and
163 : can be safely removed from the callgraph. */
164 : bool
165 13672 : callback_edge_useful_p (cgraph_edge *e)
166 : {
167 13672 : gcc_checking_assert (e->callback);
168 13672 : callback_info *ci = callback_info_sum->get (e);
169 13672 : return ci->redirected;
170 : }
171 :
172 : /* Returns the number of arguments the callback function described by ATTR
173 : takes. */
174 :
175 : size_t
176 15127 : callback_num_args (tree attr)
177 : {
178 15127 : tree args = TREE_VALUE (attr);
179 15127 : size_t res = 0;
180 15127 : tree it;
181 :
182 30255 : for (it = TREE_CHAIN (args); it != NULL_TREE; it = TREE_CHAIN (it), ++res)
183 : ;
184 15127 : return res;
185 : }
|