1 |
12 |
jlechner |
/* Interprocedural constant propagation
|
2 |
|
|
Copyright (C) 2005 Free Software Foundation, Inc.
|
3 |
|
|
Contributed by Razya Ladelsky <RAZYA@il.ibm.com>
|
4 |
|
|
|
5 |
|
|
This file is part of GCC.
|
6 |
|
|
|
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 2, or (at your option) any later
|
10 |
|
|
version.
|
11 |
|
|
|
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
|
15 |
|
|
for more details.
|
16 |
|
|
|
17 |
|
|
You should have received a copy of the GNU General Public License
|
18 |
|
|
along with GCC; see the file COPYING. If not, write to the Free
|
19 |
|
|
Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
|
20 |
|
|
02110-1301, USA. */
|
21 |
|
|
|
22 |
|
|
/* Interprocedural constant propagation.
|
23 |
|
|
The aim of interprocedural constant propagation (IPCP) is to find which
|
24 |
|
|
function's argument has the same constant value in each invocation throughout
|
25 |
|
|
the whole program. For example, for an application consisting of two files,
|
26 |
|
|
foo1.c, foo2.c:
|
27 |
|
|
|
28 |
|
|
foo1.c contains :
|
29 |
|
|
|
30 |
|
|
int f (int x)
|
31 |
|
|
{
|
32 |
|
|
g (x);
|
33 |
|
|
}
|
34 |
|
|
void main (void)
|
35 |
|
|
{
|
36 |
|
|
f (3);
|
37 |
|
|
h (3);
|
38 |
|
|
}
|
39 |
|
|
|
40 |
|
|
foo2.c contains :
|
41 |
|
|
|
42 |
|
|
int h (int y)
|
43 |
|
|
{
|
44 |
|
|
g (y);
|
45 |
|
|
}
|
46 |
|
|
int g (int y)
|
47 |
|
|
{
|
48 |
|
|
printf ("value is %d",y);
|
49 |
|
|
}
|
50 |
|
|
|
51 |
|
|
The IPCP algorithm will find that g's formal argument y
|
52 |
|
|
is always called with the value 3.
|
53 |
|
|
|
54 |
|
|
The algorithm used is based on "Interprocedural Constant Propagation",
|
55 |
|
|
by Challahan David, Keith D Cooper, Ken Kennedy, Linda Torczon, Comp86,
|
56 |
|
|
pg 152-161
|
57 |
|
|
|
58 |
|
|
The optimization is divided into three stages:
|
59 |
|
|
|
60 |
|
|
First stage - intraprocedural analysis
|
61 |
|
|
=======================================
|
62 |
|
|
This phase computes jump_function and modify information.
|
63 |
|
|
|
64 |
|
|
A jump function for a callsite represents the values passed as actual
|
65 |
|
|
arguments
|
66 |
|
|
of the callsite. There are three types of values :
|
67 |
|
|
Formal - the caller's formal parameter is passed as an actual argument.
|
68 |
|
|
Constant - a constant is passed as a an actual argument.
|
69 |
|
|
Unknown - neither of the above.
|
70 |
|
|
|
71 |
|
|
In order to compute the jump functions, we need the modify information for
|
72 |
|
|
the formal parameters of methods.
|
73 |
|
|
|
74 |
|
|
The jump function info, ipa_jump_func, is defined in ipa_edge
|
75 |
|
|
structure (defined in ipa_prop.h and pointed to by cgraph_node->aux)
|
76 |
|
|
The modify info, ipa_modify, is defined in ipa_node structure
|
77 |
|
|
(defined in ipa_prop.h and pointed to by cgraph_edge->aux).
|
78 |
|
|
|
79 |
|
|
-ipcp_init_stage() is the first stage driver.
|
80 |
|
|
|
81 |
|
|
Second stage - interprocedural analysis
|
82 |
|
|
========================================
|
83 |
|
|
This phase does the interprocedural constant propagation.
|
84 |
|
|
It computes for all formal parameters in the program
|
85 |
|
|
their cval value that may be:
|
86 |
|
|
TOP - unknown.
|
87 |
|
|
BOTTOM - non constant.
|
88 |
|
|
CONSTANT_TYPE - constant value.
|
89 |
|
|
|
90 |
|
|
Cval of formal f will have a constant value if all callsites to this
|
91 |
|
|
function have the same constant value passed to f.
|
92 |
|
|
|
93 |
|
|
The cval info, ipcp_formal, is defined in ipa_node structure
|
94 |
|
|
(defined in ipa_prop.h and pointed to by cgraph_edge->aux).
|
95 |
|
|
|
96 |
|
|
-ipcp_iterate_stage() is the second stage driver.
|
97 |
|
|
|
98 |
|
|
Third phase - transformation of methods code
|
99 |
|
|
============================================
|
100 |
|
|
Propagates the constant-valued formals into the function.
|
101 |
|
|
For each method mt, whose parameters are consts, we create a clone/version.
|
102 |
|
|
|
103 |
|
|
We use two ways to annotate the versioned function with the constant
|
104 |
|
|
formal information:
|
105 |
|
|
1. We insert an assignment statement 'parameter = const' at the beginning
|
106 |
|
|
of the cloned method.
|
107 |
|
|
2. For read-only formals whose address is not taken, we replace all uses
|
108 |
|
|
of the formal with the constant (we provide versioning with an
|
109 |
|
|
ipa_replace_map struct representing the trees we want to replace).
|
110 |
|
|
|
111 |
|
|
We also need to modify some callsites to call to the cloned methods instead
|
112 |
|
|
of the original ones. For a callsite passing an argument found to be a
|
113 |
|
|
constant by IPCP, there are two different cases to handle:
|
114 |
|
|
1. A constant is passed as an argument.
|
115 |
|
|
2. A parameter (of the caller) passed as an argument (pass through argument).
|
116 |
|
|
|
117 |
|
|
In the first case, the callsite in the original caller should be redirected
|
118 |
|
|
to call the cloned callee.
|
119 |
|
|
In the second case, both the caller and the callee have clones
|
120 |
|
|
and the callsite of the cloned caller would be redirected to call to
|
121 |
|
|
the cloned callee.
|
122 |
|
|
|
123 |
|
|
The callgraph is updated accordingly.
|
124 |
|
|
|
125 |
|
|
This update is done in two stages:
|
126 |
|
|
First all cloned methods are created during a traversal of the callgraph,
|
127 |
|
|
during which all callsites are redirected to call the cloned method.
|
128 |
|
|
Then the callsites are traversed and updated as described above.
|
129 |
|
|
|
130 |
|
|
-ipcp_insert_stage() is the third phase driver.
|
131 |
|
|
|
132 |
|
|
*/
|
133 |
|
|
|
134 |
|
|
#include "config.h"
|
135 |
|
|
#include "system.h"
|
136 |
|
|
#include "coretypes.h"
|
137 |
|
|
#include "tree.h"
|
138 |
|
|
#include "target.h"
|
139 |
|
|
#include "cgraph.h"
|
140 |
|
|
#include "ipa-prop.h"
|
141 |
|
|
#include "tree-flow.h"
|
142 |
|
|
#include "tree-pass.h"
|
143 |
|
|
#include "flags.h"
|
144 |
|
|
#include "timevar.h"
|
145 |
|
|
#include "diagnostic.h"
|
146 |
|
|
|
147 |
|
|
/* Get orig node field of ipa_node associated with method MT. */
|
148 |
|
|
static inline struct cgraph_node *
|
149 |
|
|
ipcp_method_orig_node (struct cgraph_node *mt)
|
150 |
|
|
{
|
151 |
|
|
return IPA_NODE_REF (mt)->ipcp_orig_node;
|
152 |
|
|
}
|
153 |
|
|
|
154 |
|
|
/* Return true if NODE is a cloned/versioned method. */
|
155 |
|
|
static inline bool
|
156 |
|
|
ipcp_method_is_cloned (struct cgraph_node *node)
|
157 |
|
|
{
|
158 |
|
|
return (ipcp_method_orig_node (node) != NULL);
|
159 |
|
|
}
|
160 |
|
|
|
161 |
|
|
/* Set ORIG_NODE in ipa_node associated with method NODE. */
|
162 |
|
|
static inline void
|
163 |
|
|
ipcp_method_set_orig_node (struct cgraph_node *node,
|
164 |
|
|
struct cgraph_node *orig_node)
|
165 |
|
|
{
|
166 |
|
|
IPA_NODE_REF (node)->ipcp_orig_node = orig_node;
|
167 |
|
|
}
|
168 |
|
|
|
169 |
|
|
/* Create ipa_node and its data structures for NEW_NODE.
|
170 |
|
|
Set ORIG_NODE as the orig_node field in ipa_node. */
|
171 |
|
|
static void
|
172 |
|
|
ipcp_cloned_create (struct cgraph_node *orig_node,
|
173 |
|
|
struct cgraph_node *new_node)
|
174 |
|
|
{
|
175 |
|
|
ipa_node_create (new_node);
|
176 |
|
|
ipcp_method_set_orig_node (new_node, orig_node);
|
177 |
|
|
ipa_method_formal_compute_count (new_node);
|
178 |
|
|
ipa_method_compute_tree_map (new_node);
|
179 |
|
|
}
|
180 |
|
|
|
181 |
|
|
/* Return cval_type field of CVAL. */
|
182 |
|
|
static inline enum cvalue_type
|
183 |
|
|
ipcp_cval_get_cvalue_type (struct ipcp_formal *cval)
|
184 |
|
|
{
|
185 |
|
|
return cval->cval_type;
|
186 |
|
|
}
|
187 |
|
|
|
188 |
|
|
/* Return scale for MT. */
|
189 |
|
|
static inline gcov_type
|
190 |
|
|
ipcp_method_get_scale (struct cgraph_node *mt)
|
191 |
|
|
{
|
192 |
|
|
return IPA_NODE_REF (mt)->count_scale;
|
193 |
|
|
}
|
194 |
|
|
|
195 |
|
|
/* Set COUNT as scale for MT. */
|
196 |
|
|
static inline void
|
197 |
|
|
ipcp_method_set_scale (struct cgraph_node *node, gcov_type count)
|
198 |
|
|
{
|
199 |
|
|
IPA_NODE_REF (node)->count_scale = count;
|
200 |
|
|
}
|
201 |
|
|
|
202 |
|
|
/* Set TYPE as cval_type field of CVAL. */
|
203 |
|
|
static inline void
|
204 |
|
|
ipcp_cval_set_cvalue_type (struct ipcp_formal *cval, enum cvalue_type type)
|
205 |
|
|
{
|
206 |
|
|
cval->cval_type = type;
|
207 |
|
|
}
|
208 |
|
|
|
209 |
|
|
/* Return cvalue field of CVAL. */
|
210 |
|
|
static inline union parameter_info *
|
211 |
|
|
ipcp_cval_get_cvalue (struct ipcp_formal *cval)
|
212 |
|
|
{
|
213 |
|
|
return &(cval->cvalue);
|
214 |
|
|
}
|
215 |
|
|
|
216 |
|
|
/* Set VALUE as cvalue field CVAL. */
|
217 |
|
|
static inline void
|
218 |
|
|
ipcp_cval_set_cvalue (struct ipcp_formal *cval, union parameter_info *value,
|
219 |
|
|
enum cvalue_type type)
|
220 |
|
|
{
|
221 |
|
|
if (type == CONST_VALUE || type == CONST_VALUE_REF)
|
222 |
|
|
cval->cvalue.value = value->value;
|
223 |
|
|
}
|
224 |
|
|
|
225 |
|
|
/* Return whether TYPE is a constant type. */
|
226 |
|
|
static bool
|
227 |
|
|
ipcp_type_is_const (enum cvalue_type type)
|
228 |
|
|
{
|
229 |
|
|
if (type == CONST_VALUE || type == CONST_VALUE_REF)
|
230 |
|
|
return true;
|
231 |
|
|
else
|
232 |
|
|
return false;
|
233 |
|
|
}
|
234 |
|
|
|
235 |
|
|
/* Return true if CONST_VAL1 and CONST_VAL2 are equal. */
|
236 |
|
|
static inline bool
|
237 |
|
|
ipcp_cval_equal_cvalues (union parameter_info *const_val1,
|
238 |
|
|
union parameter_info *const_val2,
|
239 |
|
|
enum cvalue_type type1, enum cvalue_type type2)
|
240 |
|
|
{
|
241 |
|
|
gcc_assert (ipcp_type_is_const (type1) && ipcp_type_is_const (type2));
|
242 |
|
|
if (type1 != type2)
|
243 |
|
|
return false;
|
244 |
|
|
|
245 |
|
|
if (operand_equal_p (const_val1->value, const_val2->value, 0))
|
246 |
|
|
return true;
|
247 |
|
|
|
248 |
|
|
return false;
|
249 |
|
|
}
|
250 |
|
|
|
251 |
|
|
/* Compute Meet arithmetics:
|
252 |
|
|
Meet (BOTTOM, x) = BOTTOM
|
253 |
|
|
Meet (TOP,x) = x
|
254 |
|
|
Meet (const_a,const_b) = BOTTOM, if const_a != const_b.
|
255 |
|
|
MEET (const_a,const_b) = const_a, if const_a == const_b.*/
|
256 |
|
|
static void
|
257 |
|
|
ipcp_cval_meet (struct ipcp_formal *cval, struct ipcp_formal *cval1,
|
258 |
|
|
struct ipcp_formal *cval2)
|
259 |
|
|
{
|
260 |
|
|
if (ipcp_cval_get_cvalue_type (cval1) == BOTTOM
|
261 |
|
|
|| ipcp_cval_get_cvalue_type (cval2) == BOTTOM)
|
262 |
|
|
{
|
263 |
|
|
ipcp_cval_set_cvalue_type (cval, BOTTOM);
|
264 |
|
|
return;
|
265 |
|
|
}
|
266 |
|
|
if (ipcp_cval_get_cvalue_type (cval1) == TOP)
|
267 |
|
|
{
|
268 |
|
|
ipcp_cval_set_cvalue_type (cval, ipcp_cval_get_cvalue_type (cval2));
|
269 |
|
|
ipcp_cval_set_cvalue (cval, ipcp_cval_get_cvalue (cval2),
|
270 |
|
|
ipcp_cval_get_cvalue_type (cval2));
|
271 |
|
|
return;
|
272 |
|
|
}
|
273 |
|
|
if (ipcp_cval_get_cvalue_type (cval2) == TOP)
|
274 |
|
|
{
|
275 |
|
|
ipcp_cval_set_cvalue_type (cval, ipcp_cval_get_cvalue_type (cval1));
|
276 |
|
|
ipcp_cval_set_cvalue (cval, ipcp_cval_get_cvalue (cval1),
|
277 |
|
|
ipcp_cval_get_cvalue_type (cval1));
|
278 |
|
|
return;
|
279 |
|
|
}
|
280 |
|
|
if (!ipcp_cval_equal_cvalues (ipcp_cval_get_cvalue (cval1),
|
281 |
|
|
ipcp_cval_get_cvalue (cval2),
|
282 |
|
|
ipcp_cval_get_cvalue_type (cval1),
|
283 |
|
|
ipcp_cval_get_cvalue_type (cval2)))
|
284 |
|
|
{
|
285 |
|
|
ipcp_cval_set_cvalue_type (cval, BOTTOM);
|
286 |
|
|
return;
|
287 |
|
|
}
|
288 |
|
|
ipcp_cval_set_cvalue_type (cval, ipcp_cval_get_cvalue_type (cval1));
|
289 |
|
|
ipcp_cval_set_cvalue (cval, ipcp_cval_get_cvalue (cval1),
|
290 |
|
|
ipcp_cval_get_cvalue_type (cval1));
|
291 |
|
|
}
|
292 |
|
|
|
293 |
|
|
/* Return cval structure for the formal at index INFO_TYPE in MT. */
|
294 |
|
|
static inline struct ipcp_formal *
|
295 |
|
|
ipcp_method_cval (struct cgraph_node *mt, int info_type)
|
296 |
|
|
{
|
297 |
|
|
return &(IPA_NODE_REF (mt)->ipcp_cval[info_type]);
|
298 |
|
|
}
|
299 |
|
|
|
300 |
|
|
/* Given the jump function (TYPE, INFO_TYPE), compute a new value of CVAL.
|
301 |
|
|
If TYPE is FORMAL_IPA_TYPE, the cval of the corresponding formal is
|
302 |
|
|
drawn from MT. */
|
303 |
|
|
static void
|
304 |
|
|
ipcp_cval_compute (struct ipcp_formal *cval, struct cgraph_node *mt,
|
305 |
|
|
enum jump_func_type type, union parameter_info *info_type)
|
306 |
|
|
{
|
307 |
|
|
if (type == UNKNOWN_IPATYPE)
|
308 |
|
|
ipcp_cval_set_cvalue_type (cval, BOTTOM);
|
309 |
|
|
else if (type == CONST_IPATYPE)
|
310 |
|
|
{
|
311 |
|
|
ipcp_cval_set_cvalue_type (cval, CONST_VALUE);
|
312 |
|
|
ipcp_cval_set_cvalue (cval, info_type, CONST_VALUE);
|
313 |
|
|
}
|
314 |
|
|
else if (type == CONST_IPATYPE_REF)
|
315 |
|
|
{
|
316 |
|
|
ipcp_cval_set_cvalue_type (cval, CONST_VALUE_REF);
|
317 |
|
|
ipcp_cval_set_cvalue (cval, info_type, CONST_VALUE_REF);
|
318 |
|
|
}
|
319 |
|
|
else if (type == FORMAL_IPATYPE)
|
320 |
|
|
{
|
321 |
|
|
enum cvalue_type type =
|
322 |
|
|
ipcp_cval_get_cvalue_type (ipcp_method_cval
|
323 |
|
|
(mt, info_type->formal_id));
|
324 |
|
|
ipcp_cval_set_cvalue_type (cval, type);
|
325 |
|
|
ipcp_cval_set_cvalue (cval,
|
326 |
|
|
ipcp_cval_get_cvalue (ipcp_method_cval
|
327 |
|
|
(mt, info_type->formal_id)),
|
328 |
|
|
type);
|
329 |
|
|
}
|
330 |
|
|
}
|
331 |
|
|
|
332 |
|
|
/* True when CVAL1 and CVAL2 values are not the same. */
|
333 |
|
|
static bool
|
334 |
|
|
ipcp_cval_changed (struct ipcp_formal *cval1, struct ipcp_formal *cval2)
|
335 |
|
|
{
|
336 |
|
|
if (ipcp_cval_get_cvalue_type (cval1) == ipcp_cval_get_cvalue_type (cval2))
|
337 |
|
|
{
|
338 |
|
|
if (ipcp_cval_get_cvalue_type (cval1) != CONST_VALUE &&
|
339 |
|
|
ipcp_cval_get_cvalue_type (cval1) != CONST_VALUE_REF)
|
340 |
|
|
return false;
|
341 |
|
|
if (ipcp_cval_equal_cvalues (ipcp_cval_get_cvalue (cval1),
|
342 |
|
|
ipcp_cval_get_cvalue (cval2),
|
343 |
|
|
ipcp_cval_get_cvalue_type (cval1),
|
344 |
|
|
ipcp_cval_get_cvalue_type (cval2)))
|
345 |
|
|
return false;
|
346 |
|
|
}
|
347 |
|
|
return true;
|
348 |
|
|
}
|
349 |
|
|
|
350 |
|
|
/* Create cval structure for method MT. */
|
351 |
|
|
static inline void
|
352 |
|
|
ipcp_formal_create (struct cgraph_node *mt)
|
353 |
|
|
{
|
354 |
|
|
IPA_NODE_REF (mt)->ipcp_cval =
|
355 |
|
|
xcalloc (ipa_method_formal_count (mt), sizeof (struct ipcp_formal));
|
356 |
|
|
}
|
357 |
|
|
|
358 |
|
|
/* Set cval structure of I-th formal of MT to CVAL. */
|
359 |
|
|
static inline void
|
360 |
|
|
ipcp_method_cval_set (struct cgraph_node *mt, int i, struct ipcp_formal *cval)
|
361 |
|
|
{
|
362 |
|
|
IPA_NODE_REF (mt)->ipcp_cval[i].cval_type = cval->cval_type;
|
363 |
|
|
ipcp_cval_set_cvalue (ipcp_method_cval (mt, i),
|
364 |
|
|
ipcp_cval_get_cvalue (cval), cval->cval_type);
|
365 |
|
|
}
|
366 |
|
|
|
367 |
|
|
/* Set type of cval structure of formal I of MT to CVAL_TYPE1. */
|
368 |
|
|
static inline void
|
369 |
|
|
ipcp_method_cval_set_cvalue_type (struct cgraph_node *mt, int i,
|
370 |
|
|
enum cvalue_type cval_type1)
|
371 |
|
|
{
|
372 |
|
|
IPA_NODE_REF (mt)->ipcp_cval[i].cval_type = cval_type1;
|
373 |
|
|
}
|
374 |
|
|
|
375 |
|
|
/* Print ipcp_cval data structures to F. */
|
376 |
|
|
static void
|
377 |
|
|
ipcp_method_cval_print (FILE * f)
|
378 |
|
|
{
|
379 |
|
|
struct cgraph_node *node;
|
380 |
|
|
int i, count;
|
381 |
|
|
tree cvalue;
|
382 |
|
|
|
383 |
|
|
fprintf (f, "\nCVAL PRINT\n");
|
384 |
|
|
for (node = cgraph_nodes; node; node = node->next)
|
385 |
|
|
{
|
386 |
|
|
fprintf (f, "Printing cvals %s:\n", cgraph_node_name (node));
|
387 |
|
|
count = ipa_method_formal_count (node);
|
388 |
|
|
for (i = 0; i < count; i++)
|
389 |
|
|
{
|
390 |
|
|
if (ipcp_cval_get_cvalue_type (ipcp_method_cval (node, i))
|
391 |
|
|
== CONST_VALUE
|
392 |
|
|
|| ipcp_cval_get_cvalue_type (ipcp_method_cval (node, i)) ==
|
393 |
|
|
CONST_VALUE_REF)
|
394 |
|
|
{
|
395 |
|
|
fprintf (f, " param [%d]: ", i);
|
396 |
|
|
fprintf (f, "type is CONST ");
|
397 |
|
|
cvalue =
|
398 |
|
|
ipcp_cval_get_cvalue (ipcp_method_cval (node, i))->
|
399 |
|
|
value;
|
400 |
|
|
print_generic_expr (f, cvalue, 0);
|
401 |
|
|
fprintf (f, "\n");
|
402 |
|
|
}
|
403 |
|
|
else if (ipcp_method_cval (node, i)->cval_type == TOP)
|
404 |
|
|
fprintf (f, "param [%d]: type is TOP \n", i);
|
405 |
|
|
else
|
406 |
|
|
fprintf (f, "param [%d]: type is BOTTOM \n", i);
|
407 |
|
|
}
|
408 |
|
|
}
|
409 |
|
|
}
|
410 |
|
|
|
411 |
|
|
/* Initialize ipcp_cval array of MT with TOP values.
|
412 |
|
|
All cvals for a method's formal parameters are initialized to BOTTOM
|
413 |
|
|
The currently supported types are integer types, real types and
|
414 |
|
|
Fortran constants (i.e. references to constants defined as
|
415 |
|
|
const_decls). All other types are not analyzed and therefore are
|
416 |
|
|
assigned with BOTTOM. */
|
417 |
|
|
static void
|
418 |
|
|
ipcp_method_cval_init (struct cgraph_node *mt)
|
419 |
|
|
{
|
420 |
|
|
int i;
|
421 |
|
|
tree parm_tree;
|
422 |
|
|
|
423 |
|
|
ipcp_formal_create (mt);
|
424 |
|
|
for (i = 0; i < ipa_method_formal_count (mt); i++)
|
425 |
|
|
{
|
426 |
|
|
parm_tree = ipa_method_get_tree (mt, i);
|
427 |
|
|
if (INTEGRAL_TYPE_P (TREE_TYPE (parm_tree))
|
428 |
|
|
|| SCALAR_FLOAT_TYPE_P (TREE_TYPE (parm_tree))
|
429 |
|
|
|| POINTER_TYPE_P (TREE_TYPE (parm_tree)))
|
430 |
|
|
ipcp_method_cval_set_cvalue_type (mt, i, TOP);
|
431 |
|
|
else
|
432 |
|
|
ipcp_method_cval_set_cvalue_type (mt, i, BOTTOM);
|
433 |
|
|
}
|
434 |
|
|
}
|
435 |
|
|
|
436 |
|
|
/* Create a new assignment statment and make
|
437 |
|
|
it the first statement in the function FN
|
438 |
|
|
tree.
|
439 |
|
|
PARM1 is the lhs of the assignment and
|
440 |
|
|
VAL is the rhs. */
|
441 |
|
|
static void
|
442 |
|
|
constant_val_insert (tree fn, tree parm1, tree val)
|
443 |
|
|
{
|
444 |
|
|
struct function *func;
|
445 |
|
|
tree init_stmt;
|
446 |
|
|
edge e_step;
|
447 |
|
|
edge_iterator ei;
|
448 |
|
|
|
449 |
|
|
init_stmt = build2 (MODIFY_EXPR, void_type_node, parm1, val);
|
450 |
|
|
func = DECL_STRUCT_FUNCTION (fn);
|
451 |
|
|
cfun = func;
|
452 |
|
|
current_function_decl = fn;
|
453 |
|
|
if (ENTRY_BLOCK_PTR_FOR_FUNCTION (func)->succs)
|
454 |
|
|
FOR_EACH_EDGE (e_step, ei, ENTRY_BLOCK_PTR_FOR_FUNCTION (func)->succs)
|
455 |
|
|
bsi_insert_on_edge_immediate (e_step, init_stmt);
|
456 |
|
|
}
|
457 |
|
|
|
458 |
|
|
/* build INTEGER_CST tree with type TREE_TYPE and
|
459 |
|
|
value according to CVALUE. Return the tree. */
|
460 |
|
|
static tree
|
461 |
|
|
build_const_val (union parameter_info *cvalue, enum cvalue_type type,
|
462 |
|
|
tree tree_type)
|
463 |
|
|
{
|
464 |
|
|
tree const_val = NULL;
|
465 |
|
|
|
466 |
|
|
gcc_assert (ipcp_type_is_const (type));
|
467 |
|
|
const_val = fold_convert (tree_type, cvalue->value);
|
468 |
|
|
return const_val;
|
469 |
|
|
}
|
470 |
|
|
|
471 |
|
|
/* Build the tree representing the constant and call
|
472 |
|
|
constant_val_insert(). */
|
473 |
|
|
static void
|
474 |
|
|
ipcp_propagate_const (struct cgraph_node *mt, int param,
|
475 |
|
|
union parameter_info *cvalue ,enum cvalue_type type)
|
476 |
|
|
{
|
477 |
|
|
tree fndecl;
|
478 |
|
|
tree const_val;
|
479 |
|
|
tree parm_tree;
|
480 |
|
|
|
481 |
|
|
if (dump_file)
|
482 |
|
|
fprintf (dump_file, "propagating const to %s\n", cgraph_node_name (mt));
|
483 |
|
|
fndecl = mt->decl;
|
484 |
|
|
parm_tree = ipa_method_get_tree (mt, param);
|
485 |
|
|
const_val = build_const_val (cvalue, type, TREE_TYPE (parm_tree));
|
486 |
|
|
constant_val_insert (fndecl, parm_tree, const_val);
|
487 |
|
|
}
|
488 |
|
|
|
489 |
|
|
/* Compute the proper scale for NODE. It is the ratio between
|
490 |
|
|
the number of direct calls (represented on the incoming
|
491 |
|
|
cgraph_edges) and sum of all invocations of NODE (represented
|
492 |
|
|
as count in cgraph_node). */
|
493 |
|
|
static void
|
494 |
|
|
ipcp_method_compute_scale (struct cgraph_node *node)
|
495 |
|
|
{
|
496 |
|
|
gcov_type sum;
|
497 |
|
|
struct cgraph_edge *cs;
|
498 |
|
|
|
499 |
|
|
sum = 0;
|
500 |
|
|
/* Compute sum of all counts of callers. */
|
501 |
|
|
for (cs = node->callers; cs != NULL; cs = cs->next_caller)
|
502 |
|
|
sum += cs->count;
|
503 |
|
|
if (node->count == 0)
|
504 |
|
|
ipcp_method_set_scale (node, 0);
|
505 |
|
|
else
|
506 |
|
|
ipcp_method_set_scale (node, sum * REG_BR_PROB_BASE / node->count);
|
507 |
|
|
}
|
508 |
|
|
|
509 |
|
|
/* Initialization and computation of IPCP data structures.
|
510 |
|
|
It is an intraprocedural
|
511 |
|
|
analysis of methods, which gathers information to be propagated
|
512 |
|
|
later on. */
|
513 |
|
|
static void
|
514 |
|
|
ipcp_init_stage (void)
|
515 |
|
|
{
|
516 |
|
|
struct cgraph_node *node;
|
517 |
|
|
struct cgraph_edge *cs;
|
518 |
|
|
|
519 |
|
|
for (node = cgraph_nodes; node; node = node->next)
|
520 |
|
|
{
|
521 |
|
|
ipa_method_formal_compute_count (node);
|
522 |
|
|
ipa_method_compute_tree_map (node);
|
523 |
|
|
ipcp_method_cval_init (node);
|
524 |
|
|
ipa_method_compute_modify (node);
|
525 |
|
|
ipcp_method_compute_scale (node);
|
526 |
|
|
}
|
527 |
|
|
for (node = cgraph_nodes; node; node = node->next)
|
528 |
|
|
{
|
529 |
|
|
/* building jump functions */
|
530 |
|
|
for (cs = node->callees; cs; cs = cs->next_callee)
|
531 |
|
|
{
|
532 |
|
|
ipa_callsite_compute_count (cs);
|
533 |
|
|
if (ipa_callsite_param_count (cs)
|
534 |
|
|
!= ipa_method_formal_count (cs->callee))
|
535 |
|
|
{
|
536 |
|
|
/* Handle cases of functions with
|
537 |
|
|
a variable number of parameters. */
|
538 |
|
|
ipa_callsite_param_count_set (cs, 0);
|
539 |
|
|
ipa_method_formal_count_set (cs->callee, 0);
|
540 |
|
|
}
|
541 |
|
|
else
|
542 |
|
|
ipa_callsite_compute_param (cs);
|
543 |
|
|
}
|
544 |
|
|
}
|
545 |
|
|
}
|
546 |
|
|
|
547 |
|
|
/* Return true if there are some formal parameters whose value is TOP.
|
548 |
|
|
Change their values to BOTTOM, since they weren't determined. */
|
549 |
|
|
static bool
|
550 |
|
|
ipcp_after_propagate (void)
|
551 |
|
|
{
|
552 |
|
|
int i, count;
|
553 |
|
|
struct cgraph_node *node;
|
554 |
|
|
bool prop_again;
|
555 |
|
|
|
556 |
|
|
prop_again = false;
|
557 |
|
|
for (node = cgraph_nodes; node; node = node->next)
|
558 |
|
|
{
|
559 |
|
|
count = ipa_method_formal_count (node);
|
560 |
|
|
for (i = 0; i < count; i++)
|
561 |
|
|
if (ipcp_cval_get_cvalue_type (ipcp_method_cval (node, i)) == TOP)
|
562 |
|
|
{
|
563 |
|
|
prop_again = true;
|
564 |
|
|
ipcp_method_cval_set_cvalue_type (node, i, BOTTOM);
|
565 |
|
|
}
|
566 |
|
|
}
|
567 |
|
|
return prop_again;
|
568 |
|
|
}
|
569 |
|
|
|
570 |
|
|
/* Interprocedural analysis. The algorithm propagates constants from
|
571 |
|
|
the caller's parameters to the callee's arguments. */
|
572 |
|
|
static void
|
573 |
|
|
ipcp_propagate_stage (void)
|
574 |
|
|
{
|
575 |
|
|
int i;
|
576 |
|
|
struct ipcp_formal cval1 = { 0, {0} }, cval = { 0,{0} };
|
577 |
|
|
struct ipcp_formal *cval2;
|
578 |
|
|
struct cgraph_node *mt, *callee;
|
579 |
|
|
struct cgraph_edge *cs;
|
580 |
|
|
struct ipa_jump_func *jump_func;
|
581 |
|
|
enum jump_func_type type;
|
582 |
|
|
union parameter_info *info_type;
|
583 |
|
|
ipa_methodlist_p wl;
|
584 |
|
|
int count;
|
585 |
|
|
|
586 |
|
|
/* Initialize worklist to contain all methods. */
|
587 |
|
|
wl = ipa_methodlist_init ();
|
588 |
|
|
while (ipa_methodlist_not_empty (wl))
|
589 |
|
|
{
|
590 |
|
|
mt = ipa_remove_method (&wl);
|
591 |
|
|
for (cs = mt->callees; cs; cs = cs->next_callee)
|
592 |
|
|
{
|
593 |
|
|
callee = ipa_callsite_callee (cs);
|
594 |
|
|
count = ipa_callsite_param_count (cs);
|
595 |
|
|
for (i = 0; i < count; i++)
|
596 |
|
|
{
|
597 |
|
|
jump_func = ipa_callsite_param (cs, i);
|
598 |
|
|
type = get_type (jump_func);
|
599 |
|
|
info_type = ipa_jf_get_info_type (jump_func);
|
600 |
|
|
ipcp_cval_compute (&cval1, mt, type, info_type);
|
601 |
|
|
cval2 = ipcp_method_cval (callee, i);
|
602 |
|
|
ipcp_cval_meet (&cval, &cval1, cval2);
|
603 |
|
|
if (ipcp_cval_changed (&cval, cval2))
|
604 |
|
|
{
|
605 |
|
|
ipcp_method_cval_set (callee, i, &cval);
|
606 |
|
|
ipa_add_method (&wl, callee);
|
607 |
|
|
}
|
608 |
|
|
}
|
609 |
|
|
}
|
610 |
|
|
}
|
611 |
|
|
}
|
612 |
|
|
|
613 |
|
|
/* Call the constant propagation algorithm and re-call it if necessary
|
614 |
|
|
(if there are undetermined values left). */
|
615 |
|
|
static void
|
616 |
|
|
ipcp_iterate_stage (void)
|
617 |
|
|
{
|
618 |
|
|
ipcp_propagate_stage ();
|
619 |
|
|
if (ipcp_after_propagate ())
|
620 |
|
|
/* Some cvals have changed from TOP to BOTTOM.
|
621 |
|
|
This change should be propagated. */
|
622 |
|
|
ipcp_propagate_stage ();
|
623 |
|
|
}
|
624 |
|
|
|
625 |
|
|
/* Check conditions to forbid constant insertion to MT. */
|
626 |
|
|
static bool
|
627 |
|
|
ipcp_method_dont_insert_const (struct cgraph_node *mt)
|
628 |
|
|
{
|
629 |
|
|
/* ??? Handle pending sizes case. */
|
630 |
|
|
if (DECL_UNINLINABLE (mt->decl))
|
631 |
|
|
return true;
|
632 |
|
|
return false;
|
633 |
|
|
}
|
634 |
|
|
|
635 |
|
|
/* Print ipa_jump_func data structures to F. */
|
636 |
|
|
static void
|
637 |
|
|
ipcp_callsite_param_print (FILE * f)
|
638 |
|
|
{
|
639 |
|
|
struct cgraph_node *node;
|
640 |
|
|
int i, count;
|
641 |
|
|
struct cgraph_edge *cs;
|
642 |
|
|
struct ipa_jump_func *jump_func;
|
643 |
|
|
enum jump_func_type type;
|
644 |
|
|
tree info_type;
|
645 |
|
|
|
646 |
|
|
fprintf (f, "\nCALLSITE PARAM PRINT\n");
|
647 |
|
|
for (node = cgraph_nodes; node; node = node->next)
|
648 |
|
|
{
|
649 |
|
|
for (cs = node->callees; cs; cs = cs->next_callee)
|
650 |
|
|
{
|
651 |
|
|
fprintf (f, "callsite %s ", cgraph_node_name (node));
|
652 |
|
|
fprintf (f, "-> %s :: \n", cgraph_node_name (cs->callee));
|
653 |
|
|
count = ipa_callsite_param_count (cs);
|
654 |
|
|
for (i = 0; i < count; i++)
|
655 |
|
|
{
|
656 |
|
|
jump_func = ipa_callsite_param (cs, i);
|
657 |
|
|
type = get_type (jump_func);
|
658 |
|
|
|
659 |
|
|
fprintf (f, " param %d: ", i);
|
660 |
|
|
if (type == UNKNOWN_IPATYPE)
|
661 |
|
|
fprintf (f, "UNKNOWN\n");
|
662 |
|
|
else if (type == CONST_IPATYPE || type == CONST_IPATYPE_REF)
|
663 |
|
|
{
|
664 |
|
|
info_type =
|
665 |
|
|
ipa_jf_get_info_type (jump_func)->value;
|
666 |
|
|
fprintf (f, "CONST : ");
|
667 |
|
|
print_generic_expr (f, info_type, 0);
|
668 |
|
|
fprintf (f, "\n");
|
669 |
|
|
}
|
670 |
|
|
else if (type == FORMAL_IPATYPE)
|
671 |
|
|
{
|
672 |
|
|
fprintf (f, "FORMAL : ");
|
673 |
|
|
fprintf (f, "%d\n",
|
674 |
|
|
ipa_jf_get_info_type (jump_func)->formal_id);
|
675 |
|
|
}
|
676 |
|
|
}
|
677 |
|
|
}
|
678 |
|
|
}
|
679 |
|
|
}
|
680 |
|
|
|
681 |
|
|
/* Print count scale data structures. */
|
682 |
|
|
static void
|
683 |
|
|
ipcp_method_scale_print (FILE * f)
|
684 |
|
|
{
|
685 |
|
|
struct cgraph_node *node;
|
686 |
|
|
|
687 |
|
|
for (node = cgraph_nodes; node; node = node->next)
|
688 |
|
|
{
|
689 |
|
|
fprintf (f, "printing scale for %s: ", cgraph_node_name (node));
|
690 |
|
|
fprintf (f, "value is " HOST_WIDE_INT_PRINT_DEC
|
691 |
|
|
" \n", (HOST_WIDE_INT) ipcp_method_get_scale (node));
|
692 |
|
|
}
|
693 |
|
|
}
|
694 |
|
|
|
695 |
|
|
/* Print counts of all cgraph nodes. */
|
696 |
|
|
static void
|
697 |
|
|
ipcp_profile_mt_count_print (FILE * f)
|
698 |
|
|
{
|
699 |
|
|
struct cgraph_node *node;
|
700 |
|
|
|
701 |
|
|
for (node = cgraph_nodes; node; node = node->next)
|
702 |
|
|
{
|
703 |
|
|
fprintf (f, "method %s: ", cgraph_node_name (node));
|
704 |
|
|
fprintf (f, "count is " HOST_WIDE_INT_PRINT_DEC
|
705 |
|
|
" \n", (HOST_WIDE_INT) node->count);
|
706 |
|
|
}
|
707 |
|
|
}
|
708 |
|
|
|
709 |
|
|
/* Print counts of all cgraph edges. */
|
710 |
|
|
static void
|
711 |
|
|
ipcp_profile_cs_count_print (FILE * f)
|
712 |
|
|
{
|
713 |
|
|
struct cgraph_node *node;
|
714 |
|
|
struct cgraph_edge *cs;
|
715 |
|
|
|
716 |
|
|
for (node = cgraph_nodes; node; node = node->next)
|
717 |
|
|
{
|
718 |
|
|
for (cs = node->callees; cs; cs = cs->next_callee)
|
719 |
|
|
{
|
720 |
|
|
fprintf (f, "%s -> %s ", cgraph_node_name (cs->caller),
|
721 |
|
|
cgraph_node_name (cs->callee));
|
722 |
|
|
fprintf (f, "count is " HOST_WIDE_INT_PRINT_DEC " \n",
|
723 |
|
|
(HOST_WIDE_INT) cs->count);
|
724 |
|
|
}
|
725 |
|
|
}
|
726 |
|
|
}
|
727 |
|
|
|
728 |
|
|
/* Print all counts and probabilities of cfg edges of all methods. */
|
729 |
|
|
static void
|
730 |
|
|
ipcp_profile_edge_print (FILE * f)
|
731 |
|
|
{
|
732 |
|
|
struct cgraph_node *node;
|
733 |
|
|
basic_block bb;
|
734 |
|
|
edge_iterator ei;
|
735 |
|
|
edge e;
|
736 |
|
|
|
737 |
|
|
for (node = cgraph_nodes; node; node = node->next)
|
738 |
|
|
{
|
739 |
|
|
fprintf (f, "method %s: \n", cgraph_node_name (node));
|
740 |
|
|
if (DECL_SAVED_TREE (node->decl))
|
741 |
|
|
{
|
742 |
|
|
bb =
|
743 |
|
|
ENTRY_BLOCK_PTR_FOR_FUNCTION (DECL_STRUCT_FUNCTION (node->decl));
|
744 |
|
|
fprintf (f, "ENTRY: ");
|
745 |
|
|
fprintf (f, " " HOST_WIDE_INT_PRINT_DEC
|
746 |
|
|
" %d\n", (HOST_WIDE_INT) bb->count, bb->frequency);
|
747 |
|
|
|
748 |
|
|
if (bb->succs)
|
749 |
|
|
FOR_EACH_EDGE (e, ei, bb->succs)
|
750 |
|
|
{
|
751 |
|
|
if (e->dest ==
|
752 |
|
|
EXIT_BLOCK_PTR_FOR_FUNCTION (DECL_STRUCT_FUNCTION
|
753 |
|
|
(node->decl)))
|
754 |
|
|
fprintf (f, "edge ENTRY -> EXIT, Count");
|
755 |
|
|
else
|
756 |
|
|
fprintf (f, "edge ENTRY -> %d, Count", e->dest->index);
|
757 |
|
|
fprintf (f, " " HOST_WIDE_INT_PRINT_DEC
|
758 |
|
|
" Prob %d\n", (HOST_WIDE_INT) e->count,
|
759 |
|
|
e->probability);
|
760 |
|
|
}
|
761 |
|
|
FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
|
762 |
|
|
{
|
763 |
|
|
fprintf (f, "bb[%d]: ", bb->index);
|
764 |
|
|
fprintf (f, " " HOST_WIDE_INT_PRINT_DEC
|
765 |
|
|
" %d\n", (HOST_WIDE_INT) bb->count, bb->frequency);
|
766 |
|
|
FOR_EACH_EDGE (e, ei, bb->succs)
|
767 |
|
|
{
|
768 |
|
|
if (e->dest ==
|
769 |
|
|
EXIT_BLOCK_PTR_FOR_FUNCTION (DECL_STRUCT_FUNCTION
|
770 |
|
|
(node->decl)))
|
771 |
|
|
fprintf (f, "edge %d -> EXIT, Count", e->src->index);
|
772 |
|
|
else
|
773 |
|
|
fprintf (f, "edge %d -> %d, Count", e->src->index,
|
774 |
|
|
e->dest->index);
|
775 |
|
|
fprintf (f, " " HOST_WIDE_INT_PRINT_DEC " Prob %d\n",
|
776 |
|
|
(HOST_WIDE_INT) e->count, e->probability);
|
777 |
|
|
}
|
778 |
|
|
}
|
779 |
|
|
}
|
780 |
|
|
}
|
781 |
|
|
}
|
782 |
|
|
|
783 |
|
|
/* Print counts and frequencies for all basic blocks of all methods. */
|
784 |
|
|
static void
|
785 |
|
|
ipcp_profile_bb_print (FILE * f)
|
786 |
|
|
{
|
787 |
|
|
basic_block bb;
|
788 |
|
|
struct cgraph_node *node;
|
789 |
|
|
|
790 |
|
|
for (node = cgraph_nodes; node; node = node->next)
|
791 |
|
|
{
|
792 |
|
|
fprintf (f, "method %s: \n", cgraph_node_name (node));
|
793 |
|
|
if (DECL_SAVED_TREE (node->decl))
|
794 |
|
|
{
|
795 |
|
|
bb =
|
796 |
|
|
ENTRY_BLOCK_PTR_FOR_FUNCTION (DECL_STRUCT_FUNCTION (node->decl));
|
797 |
|
|
fprintf (f, "ENTRY: Count");
|
798 |
|
|
fprintf (f, " " HOST_WIDE_INT_PRINT_DEC
|
799 |
|
|
" Frquency %d\n", (HOST_WIDE_INT) bb->count,
|
800 |
|
|
bb->frequency);
|
801 |
|
|
|
802 |
|
|
FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
|
803 |
|
|
{
|
804 |
|
|
fprintf (f, "bb[%d]: Count", bb->index);
|
805 |
|
|
fprintf (f, " " HOST_WIDE_INT_PRINT_DEC
|
806 |
|
|
" Frequency %d\n", (HOST_WIDE_INT) bb->count,
|
807 |
|
|
bb->frequency);
|
808 |
|
|
}
|
809 |
|
|
bb =
|
810 |
|
|
EXIT_BLOCK_PTR_FOR_FUNCTION (DECL_STRUCT_FUNCTION (node->decl));
|
811 |
|
|
fprintf (f, "EXIT: Count");
|
812 |
|
|
fprintf (f, " " HOST_WIDE_INT_PRINT_DEC
|
813 |
|
|
" Frequency %d\n", (HOST_WIDE_INT) bb->count,
|
814 |
|
|
bb->frequency);
|
815 |
|
|
|
816 |
|
|
}
|
817 |
|
|
}
|
818 |
|
|
}
|
819 |
|
|
|
820 |
|
|
/* Print all IPCP data structures to F. */
|
821 |
|
|
static void
|
822 |
|
|
ipcp_structures_print (FILE * f)
|
823 |
|
|
{
|
824 |
|
|
ipcp_method_cval_print (f);
|
825 |
|
|
ipcp_method_scale_print (f);
|
826 |
|
|
ipa_method_tree_print (f);
|
827 |
|
|
ipa_method_modify_print (f);
|
828 |
|
|
ipcp_callsite_param_print (f);
|
829 |
|
|
}
|
830 |
|
|
|
831 |
|
|
/* Print profile info for all methods. */
|
832 |
|
|
static void
|
833 |
|
|
ipcp_profile_print (FILE * f)
|
834 |
|
|
{
|
835 |
|
|
fprintf (f, "\nNODE COUNTS :\n");
|
836 |
|
|
ipcp_profile_mt_count_print (f);
|
837 |
|
|
fprintf (f, "\nCS COUNTS stage:\n");
|
838 |
|
|
ipcp_profile_cs_count_print (f);
|
839 |
|
|
fprintf (f, "\nBB COUNTS and FREQUENCIES :\n");
|
840 |
|
|
ipcp_profile_bb_print (f);
|
841 |
|
|
fprintf (f, "\nCFG EDGES COUNTS and PROBABILITIES :\n");
|
842 |
|
|
ipcp_profile_edge_print (f);
|
843 |
|
|
}
|
844 |
|
|
|
845 |
|
|
/* Build and initialize ipa_replace_map struct
|
846 |
|
|
according to TYPE. This struct is read by versioning, which
|
847 |
|
|
operates according to the flags sent. PARM_TREE is the
|
848 |
|
|
formal's tree found to be constant. CVALUE represents the constant. */
|
849 |
|
|
static struct ipa_replace_map *
|
850 |
|
|
ipcp_replace_map_create (enum cvalue_type type, tree parm_tree,
|
851 |
|
|
union parameter_info *cvalue)
|
852 |
|
|
{
|
853 |
|
|
struct ipa_replace_map *replace_map;
|
854 |
|
|
tree const_val;
|
855 |
|
|
|
856 |
|
|
replace_map = xcalloc (1, sizeof (struct ipa_replace_map));
|
857 |
|
|
gcc_assert (ipcp_type_is_const (type));
|
858 |
|
|
if (type == CONST_VALUE_REF )
|
859 |
|
|
{
|
860 |
|
|
const_val =
|
861 |
|
|
build_const_val (cvalue, type, TREE_TYPE (TREE_TYPE (parm_tree)));
|
862 |
|
|
replace_map->old_tree = parm_tree;
|
863 |
|
|
replace_map->new_tree = const_val;
|
864 |
|
|
replace_map->replace_p = true;
|
865 |
|
|
replace_map->ref_p = true;
|
866 |
|
|
}
|
867 |
|
|
else if (TREE_READONLY (parm_tree) && !TREE_ADDRESSABLE (parm_tree))
|
868 |
|
|
{
|
869 |
|
|
const_val = build_const_val (cvalue, type, TREE_TYPE (parm_tree));
|
870 |
|
|
replace_map->old_tree = parm_tree;
|
871 |
|
|
replace_map->new_tree = const_val;
|
872 |
|
|
replace_map->replace_p = true;
|
873 |
|
|
replace_map->ref_p = false;
|
874 |
|
|
}
|
875 |
|
|
else
|
876 |
|
|
{
|
877 |
|
|
replace_map->old_tree = NULL;
|
878 |
|
|
replace_map->new_tree = NULL;
|
879 |
|
|
replace_map->replace_p = false;
|
880 |
|
|
replace_map->ref_p = false;
|
881 |
|
|
}
|
882 |
|
|
|
883 |
|
|
return replace_map;
|
884 |
|
|
}
|
885 |
|
|
|
886 |
|
|
/* Return true if this callsite should be redirected to
|
887 |
|
|
the orig callee (instead of the cloned one). */
|
888 |
|
|
static bool
|
889 |
|
|
ipcp_redirect (struct cgraph_edge *cs)
|
890 |
|
|
{
|
891 |
|
|
struct cgraph_node *caller, *callee, *orig_callee;
|
892 |
|
|
int i, count;
|
893 |
|
|
struct ipa_jump_func *jump_func;
|
894 |
|
|
enum jump_func_type type;
|
895 |
|
|
enum cvalue_type cval_type;
|
896 |
|
|
|
897 |
|
|
caller = cs->caller;
|
898 |
|
|
callee = cs->callee;
|
899 |
|
|
orig_callee = ipcp_method_orig_node (callee);
|
900 |
|
|
count = ipa_method_formal_count (orig_callee);
|
901 |
|
|
for (i = 0; i < count; i++)
|
902 |
|
|
{
|
903 |
|
|
cval_type =
|
904 |
|
|
ipcp_cval_get_cvalue_type (ipcp_method_cval (orig_callee, i));
|
905 |
|
|
if (ipcp_type_is_const (cval_type))
|
906 |
|
|
{
|
907 |
|
|
jump_func = ipa_callsite_param (cs, i);
|
908 |
|
|
type = get_type (jump_func);
|
909 |
|
|
if (type != CONST_IPATYPE
|
910 |
|
|
&& type != CONST_IPATYPE_REF)
|
911 |
|
|
return true;
|
912 |
|
|
}
|
913 |
|
|
}
|
914 |
|
|
|
915 |
|
|
return false;
|
916 |
|
|
}
|
917 |
|
|
|
918 |
|
|
/* Fix the callsites and the callgraph after function cloning was done. */
|
919 |
|
|
static void
|
920 |
|
|
ipcp_update_callgraph (void)
|
921 |
|
|
{
|
922 |
|
|
struct cgraph_node *node, *orig_callee;
|
923 |
|
|
struct cgraph_edge *cs;
|
924 |
|
|
|
925 |
|
|
for (node = cgraph_nodes; node; node = node->next)
|
926 |
|
|
{
|
927 |
|
|
/* want to fix only original nodes */
|
928 |
|
|
if (ipcp_method_is_cloned (node))
|
929 |
|
|
continue;
|
930 |
|
|
for (cs = node->callees; cs; cs = cs->next_callee)
|
931 |
|
|
if (ipcp_method_is_cloned (cs->callee))
|
932 |
|
|
{
|
933 |
|
|
/* Callee is a cloned node */
|
934 |
|
|
orig_callee = ipcp_method_orig_node (cs->callee);
|
935 |
|
|
if (ipcp_redirect (cs))
|
936 |
|
|
{
|
937 |
|
|
cgraph_redirect_edge_callee (cs, orig_callee);
|
938 |
|
|
TREE_OPERAND (TREE_OPERAND
|
939 |
|
|
(get_call_expr_in (cs->call_stmt), 0), 0) =
|
940 |
|
|
orig_callee->decl;
|
941 |
|
|
}
|
942 |
|
|
}
|
943 |
|
|
}
|
944 |
|
|
}
|
945 |
|
|
|
946 |
|
|
/* Update all cfg basic blocks in NODE according to SCALE. */
|
947 |
|
|
static void
|
948 |
|
|
ipcp_update_bb_counts (struct cgraph_node *node, gcov_type scale)
|
949 |
|
|
{
|
950 |
|
|
basic_block bb;
|
951 |
|
|
|
952 |
|
|
FOR_ALL_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
|
953 |
|
|
bb->count = bb->count * scale / REG_BR_PROB_BASE;
|
954 |
|
|
}
|
955 |
|
|
|
956 |
|
|
/* Update all cfg edges in NODE according to SCALE. */
|
957 |
|
|
static void
|
958 |
|
|
ipcp_update_edges_counts (struct cgraph_node *node, gcov_type scale)
|
959 |
|
|
{
|
960 |
|
|
basic_block bb;
|
961 |
|
|
edge_iterator ei;
|
962 |
|
|
edge e;
|
963 |
|
|
|
964 |
|
|
FOR_ALL_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
|
965 |
|
|
FOR_EACH_EDGE (e, ei, bb->succs)
|
966 |
|
|
e->count = e->count * scale / REG_BR_PROB_BASE;
|
967 |
|
|
}
|
968 |
|
|
|
969 |
|
|
/* Update profiling info for versioned methods and the
|
970 |
|
|
methods they were versioned from. */
|
971 |
|
|
static void
|
972 |
|
|
ipcp_update_profiling (void)
|
973 |
|
|
{
|
974 |
|
|
struct cgraph_node *node, *orig_node;
|
975 |
|
|
gcov_type scale, scale_complement;
|
976 |
|
|
struct cgraph_edge *cs;
|
977 |
|
|
|
978 |
|
|
for (node = cgraph_nodes; node; node = node->next)
|
979 |
|
|
{
|
980 |
|
|
if (ipcp_method_is_cloned (node))
|
981 |
|
|
{
|
982 |
|
|
orig_node = ipcp_method_orig_node (node);
|
983 |
|
|
scale = ipcp_method_get_scale (orig_node);
|
984 |
|
|
node->count = orig_node->count * scale / REG_BR_PROB_BASE;
|
985 |
|
|
scale_complement = REG_BR_PROB_BASE - scale;
|
986 |
|
|
orig_node->count =
|
987 |
|
|
orig_node->count * scale_complement / REG_BR_PROB_BASE;
|
988 |
|
|
for (cs = node->callees; cs; cs = cs->next_callee)
|
989 |
|
|
cs->count = cs->count * scale / REG_BR_PROB_BASE;
|
990 |
|
|
for (cs = orig_node->callees; cs; cs = cs->next_callee)
|
991 |
|
|
cs->count = cs->count * scale_complement / REG_BR_PROB_BASE;
|
992 |
|
|
ipcp_update_bb_counts (node, scale);
|
993 |
|
|
ipcp_update_bb_counts (orig_node, scale_complement);
|
994 |
|
|
ipcp_update_edges_counts (node, scale);
|
995 |
|
|
ipcp_update_edges_counts (orig_node, scale_complement);
|
996 |
|
|
}
|
997 |
|
|
}
|
998 |
|
|
}
|
999 |
|
|
|
1000 |
|
|
/* Propagate the constant parameters found by ipcp_iterate_stage()
|
1001 |
|
|
to the function's code. */
|
1002 |
|
|
static void
|
1003 |
|
|
ipcp_insert_stage (void)
|
1004 |
|
|
{
|
1005 |
|
|
struct cgraph_node *node, *node1 = NULL;
|
1006 |
|
|
int i, const_param;
|
1007 |
|
|
union parameter_info *cvalue;
|
1008 |
|
|
varray_type redirect_callers, replace_trees;
|
1009 |
|
|
struct cgraph_edge *cs;
|
1010 |
|
|
int node_callers, count;
|
1011 |
|
|
tree parm_tree;
|
1012 |
|
|
enum cvalue_type type;
|
1013 |
|
|
struct ipa_replace_map *replace_param;
|
1014 |
|
|
|
1015 |
|
|
for (node = cgraph_nodes; node; node = node->next)
|
1016 |
|
|
{
|
1017 |
|
|
/* Propagation of the constant is forbidden in
|
1018 |
|
|
certain conditions. */
|
1019 |
|
|
if (ipcp_method_dont_insert_const (node))
|
1020 |
|
|
continue;
|
1021 |
|
|
const_param = 0;
|
1022 |
|
|
count = ipa_method_formal_count (node);
|
1023 |
|
|
for (i = 0; i < count; i++)
|
1024 |
|
|
{
|
1025 |
|
|
type = ipcp_cval_get_cvalue_type (ipcp_method_cval (node, i));
|
1026 |
|
|
if (ipcp_type_is_const (type))
|
1027 |
|
|
const_param++;
|
1028 |
|
|
}
|
1029 |
|
|
if (const_param == 0)
|
1030 |
|
|
continue;
|
1031 |
|
|
VARRAY_GENERIC_PTR_INIT (replace_trees, const_param, "replace_trees");
|
1032 |
|
|
for (i = 0; i < count; i++)
|
1033 |
|
|
{
|
1034 |
|
|
type = ipcp_cval_get_cvalue_type (ipcp_method_cval (node, i));
|
1035 |
|
|
if (ipcp_type_is_const (type))
|
1036 |
|
|
{
|
1037 |
|
|
cvalue = ipcp_cval_get_cvalue (ipcp_method_cval (node, i));
|
1038 |
|
|
parm_tree = ipa_method_get_tree (node, i);
|
1039 |
|
|
replace_param =
|
1040 |
|
|
ipcp_replace_map_create (type, parm_tree, cvalue);
|
1041 |
|
|
VARRAY_PUSH_GENERIC_PTR (replace_trees, replace_param);
|
1042 |
|
|
}
|
1043 |
|
|
}
|
1044 |
|
|
/* Compute how many callers node has. */
|
1045 |
|
|
node_callers = 0;
|
1046 |
|
|
for (cs = node->callers; cs != NULL; cs = cs->next_caller)
|
1047 |
|
|
node_callers++;
|
1048 |
|
|
VARRAY_GENERIC_PTR_INIT (redirect_callers, node_callers,
|
1049 |
|
|
"redirect_callers");
|
1050 |
|
|
for (cs = node->callers; cs != NULL; cs = cs->next_caller)
|
1051 |
|
|
VARRAY_PUSH_GENERIC_PTR (redirect_callers, cs);
|
1052 |
|
|
/* Redirecting all the callers of the node to the
|
1053 |
|
|
new versioned node. */
|
1054 |
|
|
node1 =
|
1055 |
|
|
cgraph_function_versioning (node, redirect_callers, replace_trees);
|
1056 |
|
|
VARRAY_CLEAR (redirect_callers);
|
1057 |
|
|
VARRAY_CLEAR (replace_trees);
|
1058 |
|
|
if (node1 == NULL)
|
1059 |
|
|
continue;
|
1060 |
|
|
if (dump_file)
|
1061 |
|
|
fprintf (dump_file, "versioned function %s\n",
|
1062 |
|
|
cgraph_node_name (node));
|
1063 |
|
|
ipcp_cloned_create (node, node1);
|
1064 |
|
|
for (i = 0; i < count; i++)
|
1065 |
|
|
{
|
1066 |
|
|
type = ipcp_cval_get_cvalue_type (ipcp_method_cval (node, i));
|
1067 |
|
|
if (ipcp_type_is_const (type))
|
1068 |
|
|
{
|
1069 |
|
|
cvalue = ipcp_cval_get_cvalue (ipcp_method_cval (node, i));
|
1070 |
|
|
parm_tree = ipa_method_get_tree (node, i);
|
1071 |
|
|
if (type != CONST_VALUE_REF
|
1072 |
|
|
&& !TREE_READONLY (parm_tree))
|
1073 |
|
|
ipcp_propagate_const (node1, i, cvalue, type);
|
1074 |
|
|
}
|
1075 |
|
|
}
|
1076 |
|
|
}
|
1077 |
|
|
ipcp_update_callgraph ();
|
1078 |
|
|
ipcp_update_profiling ();
|
1079 |
|
|
}
|
1080 |
|
|
|
1081 |
|
|
/* The IPCP driver. */
|
1082 |
|
|
void
|
1083 |
|
|
ipcp_driver (void)
|
1084 |
|
|
{
|
1085 |
|
|
if (dump_file)
|
1086 |
|
|
fprintf (dump_file, "\nIPA constant propagation start:\n");
|
1087 |
|
|
ipa_nodes_create ();
|
1088 |
|
|
ipa_edges_create ();
|
1089 |
|
|
/* 1. Call the init stage to initialize
|
1090 |
|
|
the ipa_node and ipa_edge structures. */
|
1091 |
|
|
ipcp_init_stage ();
|
1092 |
|
|
if (dump_file)
|
1093 |
|
|
{
|
1094 |
|
|
fprintf (dump_file, "\nIPA structures before propagation:\n");
|
1095 |
|
|
ipcp_structures_print (dump_file);
|
1096 |
|
|
}
|
1097 |
|
|
/* 2. Do the interprocedural propagation. */
|
1098 |
|
|
ipcp_iterate_stage ();
|
1099 |
|
|
if (dump_file)
|
1100 |
|
|
{
|
1101 |
|
|
fprintf (dump_file, "\nIPA structures after propagation:\n");
|
1102 |
|
|
ipcp_structures_print (dump_file);
|
1103 |
|
|
fprintf (dump_file, "\nProfiling info before insert stage:\n");
|
1104 |
|
|
ipcp_profile_print (dump_file);
|
1105 |
|
|
}
|
1106 |
|
|
/* 3. Insert the constants found to the functions. */
|
1107 |
|
|
ipcp_insert_stage ();
|
1108 |
|
|
if (dump_file)
|
1109 |
|
|
{
|
1110 |
|
|
fprintf (dump_file, "\nProfiling info after insert stage:\n");
|
1111 |
|
|
ipcp_profile_print (dump_file);
|
1112 |
|
|
}
|
1113 |
|
|
/* Free all IPCP structures. */
|
1114 |
|
|
ipa_free ();
|
1115 |
|
|
ipa_nodes_free ();
|
1116 |
|
|
ipa_edges_free ();
|
1117 |
|
|
if (dump_file)
|
1118 |
|
|
fprintf (dump_file, "\nIPA constant propagation end\n");
|
1119 |
|
|
cgraph_remove_unreachable_nodes (true, NULL);
|
1120 |
|
|
}
|
1121 |
|
|
|
1122 |
|
|
/* Gate for IPCP optimization. */
|
1123 |
|
|
static bool
|
1124 |
|
|
cgraph_gate_cp (void)
|
1125 |
|
|
{
|
1126 |
|
|
return flag_ipa_cp;
|
1127 |
|
|
}
|
1128 |
|
|
|
1129 |
|
|
struct tree_opt_pass pass_ipa_cp = {
|
1130 |
|
|
"cp", /* name */
|
1131 |
|
|
cgraph_gate_cp, /* gate */
|
1132 |
|
|
ipcp_driver, /* execute */
|
1133 |
|
|
NULL, /* sub */
|
1134 |
|
|
NULL, /* next */
|
1135 |
|
|
0, /* static_pass_number */
|
1136 |
|
|
TV_IPA_CONSTANT_PROP, /* tv_id */
|
1137 |
|
|
0, /* properties_required */
|
1138 |
|
|
PROP_trees, /* properties_provided */
|
1139 |
|
|
0, /* properties_destroyed */
|
1140 |
|
|
0, /* todo_flags_start */
|
1141 |
|
|
TODO_dump_cgraph | TODO_dump_func, /* todo_flags_finish */
|
1142 |
|
|
|
1143 |
|
|
};
|