1 /* Data structure for the modref pass.
2 Copyright (C) 2020 Free Software Foundation, Inc.
3 Contributed by David Cepelik and Jan Hubicka
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
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/>. */
21 /* modref_tree represent a decision tree that can be used by alias analysis
22 oracle to determine whether given memory access can be affected by a function
23 call. For every function we collect two trees, one for loads and other
24 for stores. Tree consist of following levels:
26 1) Base: this level represent base alias set of the acecess and refers
27 to sons (ref nodes). Flag all_refs means that all possible references
30 Because for LTO streaming we need to stream types rahter than alias sets
31 modref_base_node is implemented as a template.
32 2) Ref: this level represent ref alias set and links to acesses unless
34 Again ref is an template to allow LTO streaming.
35 3) Access: this level represent info about individual accesses. Presently
36 we record whether access is trhough a dereference of a function parameter
39 #ifndef GCC_MODREF_TREE_H
40 #define GCC_MODREF_TREE_H
42 struct ipa_modref_summary
;
45 struct GTY(()) modref_access_node
47 /* Index of parameter which specifies the base of access. -1 if base is not
48 a function parameter. */
51 /* Return true if access node holds no useful info. */
54 return parm_index
!= -1;
59 struct GTY((user
)) modref_ref_node
63 vec
<modref_access_node
, va_gc
> *accesses
;
65 modref_ref_node (T ref
):
71 /* Search REF; return NULL if failed. */
72 modref_access_node
*search (modref_access_node access
)
75 modref_access_node
*a
;
76 FOR_EACH_VEC_SAFE_ELT (accesses
, i
, a
)
77 if (a
->parm_index
== access
.parm_index
)
82 /* Collapse the tree. */
90 /* Insert access with OFFSET and SIZE.
91 Collapse tree if it has more than MAX_ACCESSES entries. */
92 void insert_access (modref_access_node a
, size_t max_accesses
)
94 /* If this base->ref pair has no access information, bail out. */
98 /* Otherwise, insert a node for the ref of the access under the base. */
99 modref_access_node
*access_node
= search (a
);
103 /* If this base->ref pair has too many accesses stored, we will clear
104 all accesses and bail out. */
105 if ((accesses
&& accesses
->length () >= max_accesses
)
108 if (dump_file
&& a
.useful_p ())
110 "--param param=modref-max-accesses limit reached\n");
114 vec_safe_push (accesses
, a
);
118 /* Base of an access. */
119 template <typename T
>
120 struct GTY((user
)) modref_base_node
123 vec
<modref_ref_node
<T
> *, va_gc
> *refs
;
126 modref_base_node (T base
):
131 /* Search REF; return NULL if failed. */
132 modref_ref_node
<T
> *search (T ref
)
135 modref_ref_node
<T
> *n
;
136 FOR_EACH_VEC_SAFE_ELT (refs
, i
, n
)
142 /* Insert REF; collapse tree if there are more than MAX_REFS. */
143 modref_ref_node
<T
> *insert_ref (T ref
, size_t max_refs
)
145 modref_ref_node
<T
> *ref_node
;
147 /* If the node is collapsed, don't do anything. */
151 /* Otherwise, insert a node for the ref of the access under the base. */
152 ref_node
= search (ref
);
156 /* Collapse the node if too full already. */
157 if (refs
&& refs
->length () >= max_refs
)
160 fprintf (dump_file
, "--param param=modref-max-refs limit reached\n");
165 ref_node
= new (ggc_alloc
<modref_ref_node
<T
> > ())modref_ref_node
<T
>
167 vec_safe_push (refs
, ref_node
);
174 modref_ref_node
<T
> *r
;
178 FOR_EACH_VEC_SAFE_ELT (refs
, i
, r
)
190 /* Access tree for a single function. */
191 template <typename T
>
192 struct GTY((user
)) modref_tree
194 vec
<modref_base_node
<T
> *, va_gc
> *bases
;
200 modref_tree (size_t max_bases
, size_t max_refs
, size_t max_accesses
):
202 max_bases (max_bases
),
204 max_accesses (max_accesses
),
205 every_base (false) {}
207 modref_base_node
<T
> *insert_base (T base
)
209 modref_base_node
<T
> *base_node
;
211 /* If the node is collapsed, don't do anything. */
215 /* Otherwise, insert a node for the base of the access into the tree. */
216 base_node
= search (base
);
220 /* Collapse the node if too full already. */
221 if (bases
&& bases
->length () >= max_bases
)
224 fprintf (dump_file
, "--param param=modref-max-bases limit reached\n");
229 base_node
= new (ggc_alloc
<modref_base_node
<T
> > ())
230 modref_base_node
<T
> (base
);
231 vec_safe_push (bases
, base_node
);
235 /* Insert memory access to the tree. */
236 void insert (T base
, T ref
, modref_access_node a
)
238 /* No useful information tracked; collapse everything. */
239 if (!base
&& !ref
&& !a
.useful_p ())
245 modref_base_node
<T
> *base_node
= insert_base (base
);
248 gcc_assert (search (base
) != NULL
);
250 modref_ref_node
<T
> *ref_node
= base_node
->insert_ref (ref
, max_refs
);
252 /* No useful ref information and no useful base; collapse everyting. */
253 if (!base
&& base_node
->every_ref
)
260 /* No useful ref and access; collapse ref. */
261 if (!ref
&& !a
.useful_p ())
262 ref_node
->collapse ();
265 ref_node
->insert_access (a
, max_accesses
);
266 /* If ref has collapses and there is no useful base; collapse
268 if (!base
&& !ref
&& ref_node
->every_access
)
274 /* Remove tree branches that are not useful (i.e. they will allways pass). */
279 modref_base_node
<T
> *base_node
;
280 modref_ref_node
<T
> *ref_node
;
285 for (i
= 0; vec_safe_iterate (bases
, i
, &base_node
);)
288 for (j
= 0; vec_safe_iterate (base_node
->refs
, j
, &ref_node
);)
290 if (!ref_node
->every_access
291 && (!ref_node
->accesses
292 || !ref_node
->accesses
->length ()))
294 base_node
->refs
->unordered_remove (j
);
295 vec_free (ref_node
->accesses
);
296 ggc_delete (ref_node
);
301 if (!base_node
->every_ref
302 && (!base_node
->refs
|| !base_node
->refs
->length ()))
304 bases
->unordered_remove (i
);
305 vec_free (base_node
->refs
);
306 ggc_delete (base_node
);
311 if (bases
&& !bases
->length ())
318 /* Merge OTHER into the tree.
319 PARM_MAP, if non-NULL, maps parm indexes of callee to caller. -2 is used
320 to signalize that parameter is local and does not need to be tracked. */
321 void merge (modref_tree
<T
> *other
, vec
<int> *parm_map
)
325 if (other
->every_base
)
332 modref_base_node
<T
> *base_node
, *my_base_node
;
333 modref_ref_node
<T
> *ref_node
, *my_ref_node
;
334 modref_access_node
*access_node
;
335 FOR_EACH_VEC_SAFE_ELT (other
->bases
, i
, base_node
)
337 my_base_node
= insert_base (base_node
->base
);
341 if (base_node
->every_ref
)
343 my_base_node
->collapse ();
347 FOR_EACH_VEC_SAFE_ELT (base_node
->refs
, j
, ref_node
)
349 my_ref_node
= my_base_node
->insert_ref (ref_node
->ref
, max_refs
);
353 if (ref_node
->every_access
)
355 my_ref_node
->collapse ();
358 FOR_EACH_VEC_SAFE_ELT (ref_node
->accesses
, k
, access_node
)
360 modref_access_node a
= *access_node
;
361 if (a
.parm_index
!= -1 && parm_map
)
363 if (a
.parm_index
>= (int)parm_map
->length ())
365 else if ((*parm_map
) [a
.parm_index
] == -2)
368 a
.parm_index
= (*parm_map
) [a
.parm_index
];
370 my_ref_node
->insert_access (a
, max_accesses
);
378 /* Copy OTHER to THIS. */
379 void copy_from (modref_tree
<T
> *other
)
384 /* Search BASE in tree; return NULL if failed. */
385 modref_base_node
<T
> *search (T base
)
388 modref_base_node
<T
> *n
;
389 FOR_EACH_VEC_SAFE_ELT (bases
, i
, n
)
395 /* Return ggc allocated instance. We explicitly call destructors via
396 ggc_delete and do not want finalizers to be registered and
397 called at the garbage collection time. */
398 static modref_tree
<T
> *create_ggc (size_t max_bases
, size_t max_refs
,
401 return new (ggc_alloc_no_dtor
<modref_tree
<T
>> ())
402 modref_tree
<T
> (max_bases
, max_refs
, max_accesses
);
405 /* Remove all records and mark tree to alias with everything. */
409 modref_base_node
<T
> *n
;
413 FOR_EACH_VEC_SAFE_ELT (bases
, i
, n
)
424 /* Release memory. */
431 void modref_c_tests ();
433 void gt_ggc_mx (modref_tree
<int>* const&);
434 void gt_ggc_mx (modref_tree
<tree_node
*>* const&);
435 void gt_pch_nx (modref_tree
<int>* const&);
436 void gt_pch_nx (modref_tree
<tree_node
*>* const&);
437 void gt_pch_nx (modref_tree
<int>* const&, gt_pointer_operator op
, void *cookie
);
438 void gt_pch_nx (modref_tree
<tree_node
*>* const&, gt_pointer_operator op
,
441 void gt_ggc_mx (modref_base_node
<int>*);
442 void gt_ggc_mx (modref_base_node
<tree_node
*>* &);
443 void gt_pch_nx (modref_base_node
<int>* const&);
444 void gt_pch_nx (modref_base_node
<tree_node
*>* const&);
445 void gt_pch_nx (modref_base_node
<int>* const&, gt_pointer_operator op
,
447 void gt_pch_nx (modref_base_node
<tree_node
*>* const&, gt_pointer_operator op
,
450 void gt_ggc_mx (modref_ref_node
<int>*);
451 void gt_ggc_mx (modref_ref_node
<tree_node
*>* &);
452 void gt_pch_nx (modref_ref_node
<int>* const&);
453 void gt_pch_nx (modref_ref_node
<tree_node
*>* const&);
454 void gt_pch_nx (modref_ref_node
<int>* const&, gt_pointer_operator op
,
456 void gt_pch_nx (modref_ref_node
<tree_node
*>* const&, gt_pointer_operator op
,