annotate gcc/ipa-polymorphic-call.c @ 124:c3a50d7877e8

fix ipa-inline.c
author mir3636
date Sat, 31 Mar 2018 17:18:55 +0900
parents 04ced10e8804
children 84e7813d76e9
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 /* Analysis of polymorphic call context.
kono
parents:
diff changeset
2 Copyright (C) 2013-2017 Free Software Foundation, Inc.
kono
parents:
diff changeset
3 Contributed by Jan Hubicka
kono
parents:
diff changeset
4
kono
parents:
diff changeset
5 This file is part of GCC.
kono
parents:
diff changeset
6
kono
parents:
diff changeset
7 GCC is free software; you can redistribute it and/or modify it under
kono
parents:
diff changeset
8 the terms of the GNU General Public License as published by the Free
kono
parents:
diff changeset
9 Software Foundation; either version 3, or (at your option) any later
kono
parents:
diff changeset
10 version.
kono
parents:
diff changeset
11
kono
parents:
diff changeset
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
kono
parents:
diff changeset
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
kono
parents:
diff changeset
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
kono
parents:
diff changeset
15 for more details.
kono
parents:
diff changeset
16
kono
parents:
diff changeset
17 You should have received a copy of the GNU General Public License
kono
parents:
diff changeset
18 along with GCC; see the file COPYING3. If not see
kono
parents:
diff changeset
19 <http://www.gnu.org/licenses/>. */
kono
parents:
diff changeset
20
kono
parents:
diff changeset
21 #include "config.h"
kono
parents:
diff changeset
22 #include "system.h"
kono
parents:
diff changeset
23 #include "coretypes.h"
kono
parents:
diff changeset
24 #include "backend.h"
kono
parents:
diff changeset
25 #include "rtl.h"
kono
parents:
diff changeset
26 #include "tree.h"
kono
parents:
diff changeset
27 #include "gimple.h"
kono
parents:
diff changeset
28 #include "tree-pass.h"
kono
parents:
diff changeset
29 #include "tree-ssa-operands.h"
kono
parents:
diff changeset
30 #include "streamer-hooks.h"
kono
parents:
diff changeset
31 #include "cgraph.h"
kono
parents:
diff changeset
32 #include "data-streamer.h"
kono
parents:
diff changeset
33 #include "diagnostic.h"
kono
parents:
diff changeset
34 #include "alias.h"
kono
parents:
diff changeset
35 #include "fold-const.h"
kono
parents:
diff changeset
36 #include "calls.h"
kono
parents:
diff changeset
37 #include "ipa-utils.h"
kono
parents:
diff changeset
38 #include "tree-dfa.h"
kono
parents:
diff changeset
39 #include "gimple-pretty-print.h"
kono
parents:
diff changeset
40 #include "tree-into-ssa.h"
kono
parents:
diff changeset
41 #include "params.h"
kono
parents:
diff changeset
42
kono
parents:
diff changeset
43 /* Return true when TYPE contains an polymorphic type and thus is interesting
kono
parents:
diff changeset
44 for devirtualization machinery. */
kono
parents:
diff changeset
45
kono
parents:
diff changeset
46 static bool contains_type_p (tree, HOST_WIDE_INT, tree,
kono
parents:
diff changeset
47 bool consider_placement_new = true,
kono
parents:
diff changeset
48 bool consider_bases = true);
kono
parents:
diff changeset
49
kono
parents:
diff changeset
50 bool
kono
parents:
diff changeset
51 contains_polymorphic_type_p (const_tree type)
kono
parents:
diff changeset
52 {
kono
parents:
diff changeset
53 type = TYPE_MAIN_VARIANT (type);
kono
parents:
diff changeset
54
kono
parents:
diff changeset
55 if (RECORD_OR_UNION_TYPE_P (type))
kono
parents:
diff changeset
56 {
kono
parents:
diff changeset
57 if (TYPE_BINFO (type)
kono
parents:
diff changeset
58 && polymorphic_type_binfo_p (TYPE_BINFO (type)))
kono
parents:
diff changeset
59 return true;
kono
parents:
diff changeset
60 for (tree fld = TYPE_FIELDS (type); fld; fld = DECL_CHAIN (fld))
kono
parents:
diff changeset
61 if (TREE_CODE (fld) == FIELD_DECL
kono
parents:
diff changeset
62 && !DECL_ARTIFICIAL (fld)
kono
parents:
diff changeset
63 && contains_polymorphic_type_p (TREE_TYPE (fld)))
kono
parents:
diff changeset
64 return true;
kono
parents:
diff changeset
65 return false;
kono
parents:
diff changeset
66 }
kono
parents:
diff changeset
67 if (TREE_CODE (type) == ARRAY_TYPE)
kono
parents:
diff changeset
68 return contains_polymorphic_type_p (TREE_TYPE (type));
kono
parents:
diff changeset
69 return false;
kono
parents:
diff changeset
70 }
kono
parents:
diff changeset
71
kono
parents:
diff changeset
72 /* Return true if it seems valid to use placement new to build EXPECTED_TYPE
kono
parents:
diff changeset
73 at possition CUR_OFFSET within TYPE.
kono
parents:
diff changeset
74
kono
parents:
diff changeset
75 POD can be changed to an instance of a polymorphic type by
kono
parents:
diff changeset
76 placement new. Here we play safe and assume that any
kono
parents:
diff changeset
77 non-polymorphic type is POD. */
kono
parents:
diff changeset
78 bool
kono
parents:
diff changeset
79 possible_placement_new (tree type, tree expected_type,
kono
parents:
diff changeset
80 HOST_WIDE_INT cur_offset)
kono
parents:
diff changeset
81 {
kono
parents:
diff changeset
82 if (cur_offset < 0)
kono
parents:
diff changeset
83 return true;
kono
parents:
diff changeset
84 return ((TREE_CODE (type) != RECORD_TYPE
kono
parents:
diff changeset
85 || !TYPE_BINFO (type)
kono
parents:
diff changeset
86 || cur_offset >= POINTER_SIZE
kono
parents:
diff changeset
87 || !polymorphic_type_binfo_p (TYPE_BINFO (type)))
kono
parents:
diff changeset
88 && (!TYPE_SIZE (type)
kono
parents:
diff changeset
89 || !tree_fits_shwi_p (TYPE_SIZE (type))
kono
parents:
diff changeset
90 || (cur_offset
kono
parents:
diff changeset
91 + (expected_type ? tree_to_uhwi (TYPE_SIZE (expected_type))
kono
parents:
diff changeset
92 : POINTER_SIZE)
kono
parents:
diff changeset
93 <= tree_to_uhwi (TYPE_SIZE (type)))));
kono
parents:
diff changeset
94 }
kono
parents:
diff changeset
95
kono
parents:
diff changeset
96 /* THIS->OUTER_TYPE is a type of memory object where object of OTR_TYPE
kono
parents:
diff changeset
97 is contained at THIS->OFFSET. Walk the memory representation of
kono
parents:
diff changeset
98 THIS->OUTER_TYPE and find the outermost class type that match
kono
parents:
diff changeset
99 OTR_TYPE or contain OTR_TYPE as a base. Update THIS
kono
parents:
diff changeset
100 to represent it.
kono
parents:
diff changeset
101
kono
parents:
diff changeset
102 If OTR_TYPE is NULL, just find outermost polymorphic type with
kono
parents:
diff changeset
103 virtual table present at possition OFFSET.
kono
parents:
diff changeset
104
kono
parents:
diff changeset
105 For example when THIS represents type
kono
parents:
diff changeset
106 class A
kono
parents:
diff changeset
107 {
kono
parents:
diff changeset
108 int a;
kono
parents:
diff changeset
109 class B b;
kono
parents:
diff changeset
110 }
kono
parents:
diff changeset
111 and we look for type at offset sizeof(int), we end up with B and offset 0.
kono
parents:
diff changeset
112 If the same is produced by multiple inheritance, we end up with A and offset
kono
parents:
diff changeset
113 sizeof(int).
kono
parents:
diff changeset
114
kono
parents:
diff changeset
115 If we can not find corresponding class, give up by setting
kono
parents:
diff changeset
116 THIS->OUTER_TYPE to OTR_TYPE and THIS->OFFSET to NULL.
kono
parents:
diff changeset
117 Return true when lookup was sucesful.
kono
parents:
diff changeset
118
kono
parents:
diff changeset
119 When CONSIDER_PLACEMENT_NEW is false, reject contexts that may be made
kono
parents:
diff changeset
120 valid only via allocation of new polymorphic type inside by means
kono
parents:
diff changeset
121 of placement new.
kono
parents:
diff changeset
122
kono
parents:
diff changeset
123 When CONSIDER_BASES is false, only look for actual fields, not base types
kono
parents:
diff changeset
124 of TYPE. */
kono
parents:
diff changeset
125
kono
parents:
diff changeset
126 bool
kono
parents:
diff changeset
127 ipa_polymorphic_call_context::restrict_to_inner_class (tree otr_type,
kono
parents:
diff changeset
128 bool consider_placement_new,
kono
parents:
diff changeset
129 bool consider_bases)
kono
parents:
diff changeset
130 {
kono
parents:
diff changeset
131 tree type = outer_type;
kono
parents:
diff changeset
132 HOST_WIDE_INT cur_offset = offset;
kono
parents:
diff changeset
133 bool speculative = false;
kono
parents:
diff changeset
134 bool size_unknown = false;
kono
parents:
diff changeset
135 unsigned HOST_WIDE_INT otr_type_size = POINTER_SIZE;
kono
parents:
diff changeset
136
kono
parents:
diff changeset
137 /* Update OUTER_TYPE to match EXPECTED_TYPE if it is not set. */
kono
parents:
diff changeset
138 if (!outer_type)
kono
parents:
diff changeset
139 {
kono
parents:
diff changeset
140 clear_outer_type (otr_type);
kono
parents:
diff changeset
141 type = otr_type;
kono
parents:
diff changeset
142 cur_offset = 0;
kono
parents:
diff changeset
143 }
kono
parents:
diff changeset
144 /* See if OFFSET points inside OUTER_TYPE. If it does not, we know
kono
parents:
diff changeset
145 that the context is either invalid, or the instance type must be
kono
parents:
diff changeset
146 derived from OUTER_TYPE.
kono
parents:
diff changeset
147
kono
parents:
diff changeset
148 Because the instance type may contain field whose type is of OUTER_TYPE,
kono
parents:
diff changeset
149 we can not derive any effective information about it.
kono
parents:
diff changeset
150
kono
parents:
diff changeset
151 TODO: In the case we know all derrived types, we can definitely do better
kono
parents:
diff changeset
152 here. */
kono
parents:
diff changeset
153 else if (TYPE_SIZE (outer_type)
kono
parents:
diff changeset
154 && tree_fits_shwi_p (TYPE_SIZE (outer_type))
kono
parents:
diff changeset
155 && tree_to_shwi (TYPE_SIZE (outer_type)) >= 0
kono
parents:
diff changeset
156 && tree_to_shwi (TYPE_SIZE (outer_type)) <= offset)
kono
parents:
diff changeset
157 {
kono
parents:
diff changeset
158 bool der = maybe_derived_type; /* clear_outer_type will reset it. */
kono
parents:
diff changeset
159 bool dyn = dynamic;
kono
parents:
diff changeset
160 clear_outer_type (otr_type);
kono
parents:
diff changeset
161 type = otr_type;
kono
parents:
diff changeset
162 cur_offset = 0;
kono
parents:
diff changeset
163
kono
parents:
diff changeset
164 /* If derived type is not allowed, we know that the context is invalid.
kono
parents:
diff changeset
165 For dynamic types, we really do not have information about
kono
parents:
diff changeset
166 size of the memory location. It is possible that completely
kono
parents:
diff changeset
167 different type is stored after outer_type. */
kono
parents:
diff changeset
168 if (!der && !dyn)
kono
parents:
diff changeset
169 {
kono
parents:
diff changeset
170 clear_speculation ();
kono
parents:
diff changeset
171 invalid = true;
kono
parents:
diff changeset
172 return false;
kono
parents:
diff changeset
173 }
kono
parents:
diff changeset
174 }
kono
parents:
diff changeset
175
kono
parents:
diff changeset
176 if (otr_type && TYPE_SIZE (otr_type)
kono
parents:
diff changeset
177 && tree_fits_shwi_p (TYPE_SIZE (otr_type)))
kono
parents:
diff changeset
178 otr_type_size = tree_to_uhwi (TYPE_SIZE (otr_type));
kono
parents:
diff changeset
179
kono
parents:
diff changeset
180 if (!type || offset < 0)
kono
parents:
diff changeset
181 goto no_useful_type_info;
kono
parents:
diff changeset
182
kono
parents:
diff changeset
183 /* Find the sub-object the constant actually refers to and mark whether it is
kono
parents:
diff changeset
184 an artificial one (as opposed to a user-defined one).
kono
parents:
diff changeset
185
kono
parents:
diff changeset
186 This loop is performed twice; first time for outer_type and second time
kono
parents:
diff changeset
187 for speculative_outer_type. The second run has SPECULATIVE set. */
kono
parents:
diff changeset
188 while (true)
kono
parents:
diff changeset
189 {
kono
parents:
diff changeset
190 unsigned HOST_WIDE_INT pos, size;
kono
parents:
diff changeset
191 tree fld;
kono
parents:
diff changeset
192
kono
parents:
diff changeset
193 /* If we do not know size of TYPE, we need to be more conservative
kono
parents:
diff changeset
194 about accepting cases where we can not find EXPECTED_TYPE.
kono
parents:
diff changeset
195 Generally the types that do matter here are of constant size.
kono
parents:
diff changeset
196 Size_unknown case should be very rare. */
kono
parents:
diff changeset
197 if (TYPE_SIZE (type)
kono
parents:
diff changeset
198 && tree_fits_shwi_p (TYPE_SIZE (type))
kono
parents:
diff changeset
199 && tree_to_shwi (TYPE_SIZE (type)) >= 0)
kono
parents:
diff changeset
200 size_unknown = false;
kono
parents:
diff changeset
201 else
kono
parents:
diff changeset
202 size_unknown = true;
kono
parents:
diff changeset
203
kono
parents:
diff changeset
204 /* On a match, just return what we found. */
kono
parents:
diff changeset
205 if ((otr_type
kono
parents:
diff changeset
206 && types_odr_comparable (type, otr_type)
kono
parents:
diff changeset
207 && types_same_for_odr (type, otr_type))
kono
parents:
diff changeset
208 || (!otr_type
kono
parents:
diff changeset
209 && TREE_CODE (type) == RECORD_TYPE
kono
parents:
diff changeset
210 && TYPE_BINFO (type)
kono
parents:
diff changeset
211 && polymorphic_type_binfo_p (TYPE_BINFO (type))))
kono
parents:
diff changeset
212 {
kono
parents:
diff changeset
213 if (speculative)
kono
parents:
diff changeset
214 {
kono
parents:
diff changeset
215 /* If we did not match the offset, just give up on speculation. */
kono
parents:
diff changeset
216 if (cur_offset != 0
kono
parents:
diff changeset
217 /* Also check if speculation did not end up being same as
kono
parents:
diff changeset
218 non-speculation. */
kono
parents:
diff changeset
219 || (types_must_be_same_for_odr (speculative_outer_type,
kono
parents:
diff changeset
220 outer_type)
kono
parents:
diff changeset
221 && (maybe_derived_type
kono
parents:
diff changeset
222 == speculative_maybe_derived_type)))
kono
parents:
diff changeset
223 clear_speculation ();
kono
parents:
diff changeset
224 return true;
kono
parents:
diff changeset
225 }
kono
parents:
diff changeset
226 else
kono
parents:
diff changeset
227 {
kono
parents:
diff changeset
228 /* If type is known to be final, do not worry about derived
kono
parents:
diff changeset
229 types. Testing it here may help us to avoid speculation. */
kono
parents:
diff changeset
230 if (otr_type && TREE_CODE (outer_type) == RECORD_TYPE
kono
parents:
diff changeset
231 && (!in_lto_p || odr_type_p (outer_type))
kono
parents:
diff changeset
232 && type_with_linkage_p (outer_type)
kono
parents:
diff changeset
233 && type_known_to_have_no_derivations_p (outer_type))
kono
parents:
diff changeset
234 maybe_derived_type = false;
kono
parents:
diff changeset
235
kono
parents:
diff changeset
236 /* Type can not contain itself on an non-zero offset. In that case
kono
parents:
diff changeset
237 just give up. Still accept the case where size is now known.
kono
parents:
diff changeset
238 Either the second copy may appear past the end of type or within
kono
parents:
diff changeset
239 the non-POD buffer located inside the variably sized type
kono
parents:
diff changeset
240 itself. */
kono
parents:
diff changeset
241 if (cur_offset != 0)
kono
parents:
diff changeset
242 goto no_useful_type_info;
kono
parents:
diff changeset
243 /* If we determined type precisely or we have no clue on
kono
parents:
diff changeset
244 speuclation, we are done. */
kono
parents:
diff changeset
245 if (!maybe_derived_type || !speculative_outer_type
kono
parents:
diff changeset
246 || !speculation_consistent_p (speculative_outer_type,
kono
parents:
diff changeset
247 speculative_offset,
kono
parents:
diff changeset
248 speculative_maybe_derived_type,
kono
parents:
diff changeset
249 otr_type))
kono
parents:
diff changeset
250 {
kono
parents:
diff changeset
251 clear_speculation ();
kono
parents:
diff changeset
252 return true;
kono
parents:
diff changeset
253 }
kono
parents:
diff changeset
254 /* Otherwise look into speculation now. */
kono
parents:
diff changeset
255 else
kono
parents:
diff changeset
256 {
kono
parents:
diff changeset
257 speculative = true;
kono
parents:
diff changeset
258 type = speculative_outer_type;
kono
parents:
diff changeset
259 cur_offset = speculative_offset;
kono
parents:
diff changeset
260 continue;
kono
parents:
diff changeset
261 }
kono
parents:
diff changeset
262 }
kono
parents:
diff changeset
263 }
kono
parents:
diff changeset
264
kono
parents:
diff changeset
265 /* Walk fields and find corresponding on at OFFSET. */
kono
parents:
diff changeset
266 if (TREE_CODE (type) == RECORD_TYPE)
kono
parents:
diff changeset
267 {
kono
parents:
diff changeset
268 for (fld = TYPE_FIELDS (type); fld; fld = DECL_CHAIN (fld))
kono
parents:
diff changeset
269 {
kono
parents:
diff changeset
270 if (TREE_CODE (fld) != FIELD_DECL
kono
parents:
diff changeset
271 || TREE_TYPE (fld) == error_mark_node)
kono
parents:
diff changeset
272 continue;
kono
parents:
diff changeset
273
kono
parents:
diff changeset
274 pos = int_bit_position (fld);
kono
parents:
diff changeset
275 if (pos > (unsigned HOST_WIDE_INT)cur_offset)
kono
parents:
diff changeset
276 continue;
kono
parents:
diff changeset
277
kono
parents:
diff changeset
278 /* Do not consider vptr itself. Not even for placement new. */
kono
parents:
diff changeset
279 if (!pos && DECL_ARTIFICIAL (fld)
kono
parents:
diff changeset
280 && POINTER_TYPE_P (TREE_TYPE (fld))
kono
parents:
diff changeset
281 && TYPE_BINFO (type)
kono
parents:
diff changeset
282 && polymorphic_type_binfo_p (TYPE_BINFO (type)))
kono
parents:
diff changeset
283 continue;
kono
parents:
diff changeset
284
kono
parents:
diff changeset
285 if (!DECL_SIZE (fld) || !tree_fits_uhwi_p (DECL_SIZE (fld)))
kono
parents:
diff changeset
286 goto no_useful_type_info;
kono
parents:
diff changeset
287 size = tree_to_uhwi (DECL_SIZE (fld));
kono
parents:
diff changeset
288
kono
parents:
diff changeset
289 /* We can always skip types smaller than pointer size:
kono
parents:
diff changeset
290 those can not contain a virtual table pointer.
kono
parents:
diff changeset
291
kono
parents:
diff changeset
292 Disqualifying fields that are too small to fit OTR_TYPE
kono
parents:
diff changeset
293 saves work needed to walk them for no benefit.
kono
parents:
diff changeset
294 Because of the way the bases are packed into a class, the
kono
parents:
diff changeset
295 field's size may be smaller than type size, so it needs
kono
parents:
diff changeset
296 to be done with a care. */
kono
parents:
diff changeset
297
kono
parents:
diff changeset
298 if (pos <= (unsigned HOST_WIDE_INT)cur_offset
kono
parents:
diff changeset
299 && (pos + size) >= (unsigned HOST_WIDE_INT)cur_offset
kono
parents:
diff changeset
300 + POINTER_SIZE
kono
parents:
diff changeset
301 && (!otr_type
kono
parents:
diff changeset
302 || !TYPE_SIZE (TREE_TYPE (fld))
kono
parents:
diff changeset
303 || !tree_fits_shwi_p (TYPE_SIZE (TREE_TYPE (fld)))
kono
parents:
diff changeset
304 || (pos + tree_to_uhwi (TYPE_SIZE (TREE_TYPE (fld))))
kono
parents:
diff changeset
305 >= cur_offset + otr_type_size))
kono
parents:
diff changeset
306 break;
kono
parents:
diff changeset
307 }
kono
parents:
diff changeset
308
kono
parents:
diff changeset
309 if (!fld)
kono
parents:
diff changeset
310 goto no_useful_type_info;
kono
parents:
diff changeset
311
kono
parents:
diff changeset
312 type = TYPE_MAIN_VARIANT (TREE_TYPE (fld));
kono
parents:
diff changeset
313 cur_offset -= pos;
kono
parents:
diff changeset
314 /* DECL_ARTIFICIAL represents a basetype. */
kono
parents:
diff changeset
315 if (!DECL_ARTIFICIAL (fld))
kono
parents:
diff changeset
316 {
kono
parents:
diff changeset
317 if (!speculative)
kono
parents:
diff changeset
318 {
kono
parents:
diff changeset
319 outer_type = type;
kono
parents:
diff changeset
320 offset = cur_offset;
kono
parents:
diff changeset
321 /* As soon as we se an field containing the type,
kono
parents:
diff changeset
322 we know we are not looking for derivations. */
kono
parents:
diff changeset
323 maybe_derived_type = false;
kono
parents:
diff changeset
324 }
kono
parents:
diff changeset
325 else
kono
parents:
diff changeset
326 {
kono
parents:
diff changeset
327 speculative_outer_type = type;
kono
parents:
diff changeset
328 speculative_offset = cur_offset;
kono
parents:
diff changeset
329 speculative_maybe_derived_type = false;
kono
parents:
diff changeset
330 }
kono
parents:
diff changeset
331 }
kono
parents:
diff changeset
332 else if (!consider_bases)
kono
parents:
diff changeset
333 goto no_useful_type_info;
kono
parents:
diff changeset
334 }
kono
parents:
diff changeset
335 else if (TREE_CODE (type) == ARRAY_TYPE)
kono
parents:
diff changeset
336 {
kono
parents:
diff changeset
337 tree subtype = TYPE_MAIN_VARIANT (TREE_TYPE (type));
kono
parents:
diff changeset
338
kono
parents:
diff changeset
339 /* Give up if we don't know array field size.
kono
parents:
diff changeset
340 Also give up on non-polymorphic types as they are used
kono
parents:
diff changeset
341 as buffers for placement new. */
kono
parents:
diff changeset
342 if (!TYPE_SIZE (subtype)
kono
parents:
diff changeset
343 || !tree_fits_shwi_p (TYPE_SIZE (subtype))
kono
parents:
diff changeset
344 || tree_to_shwi (TYPE_SIZE (subtype)) <= 0
kono
parents:
diff changeset
345 || !contains_polymorphic_type_p (subtype))
kono
parents:
diff changeset
346 goto no_useful_type_info;
kono
parents:
diff changeset
347
kono
parents:
diff changeset
348 HOST_WIDE_INT new_offset = cur_offset % tree_to_shwi (TYPE_SIZE (subtype));
kono
parents:
diff changeset
349
kono
parents:
diff changeset
350 /* We may see buffer for placement new. In this case the expected type
kono
parents:
diff changeset
351 can be bigger than the subtype. */
kono
parents:
diff changeset
352 if (TYPE_SIZE (subtype)
kono
parents:
diff changeset
353 && (cur_offset + otr_type_size
kono
parents:
diff changeset
354 > tree_to_uhwi (TYPE_SIZE (subtype))))
kono
parents:
diff changeset
355 goto no_useful_type_info;
kono
parents:
diff changeset
356
kono
parents:
diff changeset
357 cur_offset = new_offset;
kono
parents:
diff changeset
358 type = TYPE_MAIN_VARIANT (subtype);
kono
parents:
diff changeset
359 if (!speculative)
kono
parents:
diff changeset
360 {
kono
parents:
diff changeset
361 outer_type = type;
kono
parents:
diff changeset
362 offset = cur_offset;
kono
parents:
diff changeset
363 maybe_derived_type = false;
kono
parents:
diff changeset
364 }
kono
parents:
diff changeset
365 else
kono
parents:
diff changeset
366 {
kono
parents:
diff changeset
367 speculative_outer_type = type;
kono
parents:
diff changeset
368 speculative_offset = cur_offset;
kono
parents:
diff changeset
369 speculative_maybe_derived_type = false;
kono
parents:
diff changeset
370 }
kono
parents:
diff changeset
371 }
kono
parents:
diff changeset
372 /* Give up on anything else. */
kono
parents:
diff changeset
373 else
kono
parents:
diff changeset
374 {
kono
parents:
diff changeset
375 no_useful_type_info:
kono
parents:
diff changeset
376 if (maybe_derived_type && !speculative
kono
parents:
diff changeset
377 && TREE_CODE (outer_type) == RECORD_TYPE
kono
parents:
diff changeset
378 && TREE_CODE (otr_type) == RECORD_TYPE
kono
parents:
diff changeset
379 && TYPE_BINFO (otr_type)
kono
parents:
diff changeset
380 && !offset
kono
parents:
diff changeset
381 && get_binfo_at_offset (TYPE_BINFO (otr_type), 0, outer_type))
kono
parents:
diff changeset
382 {
kono
parents:
diff changeset
383 clear_outer_type (otr_type);
kono
parents:
diff changeset
384 if (!speculative_outer_type
kono
parents:
diff changeset
385 || !speculation_consistent_p (speculative_outer_type,
kono
parents:
diff changeset
386 speculative_offset,
kono
parents:
diff changeset
387 speculative_maybe_derived_type,
kono
parents:
diff changeset
388 otr_type))
kono
parents:
diff changeset
389 clear_speculation ();
kono
parents:
diff changeset
390 if (speculative_outer_type)
kono
parents:
diff changeset
391 {
kono
parents:
diff changeset
392 speculative = true;
kono
parents:
diff changeset
393 type = speculative_outer_type;
kono
parents:
diff changeset
394 cur_offset = speculative_offset;
kono
parents:
diff changeset
395 }
kono
parents:
diff changeset
396 else
kono
parents:
diff changeset
397 return true;
kono
parents:
diff changeset
398 }
kono
parents:
diff changeset
399 /* We found no way to embedd EXPECTED_TYPE in TYPE.
kono
parents:
diff changeset
400 We still permit two special cases - placement new and
kono
parents:
diff changeset
401 the case of variadic types containing themselves. */
kono
parents:
diff changeset
402 if (!speculative
kono
parents:
diff changeset
403 && consider_placement_new
kono
parents:
diff changeset
404 && (size_unknown || !type || maybe_derived_type
kono
parents:
diff changeset
405 || possible_placement_new (type, otr_type, cur_offset)))
kono
parents:
diff changeset
406 {
kono
parents:
diff changeset
407 /* In these weird cases we want to accept the context.
kono
parents:
diff changeset
408 In non-speculative run we have no useful outer_type info
kono
parents:
diff changeset
409 (TODO: we may eventually want to record upper bound on the
kono
parents:
diff changeset
410 type size that can be used to prune the walk),
kono
parents:
diff changeset
411 but we still want to consider speculation that may
kono
parents:
diff changeset
412 give useful info. */
kono
parents:
diff changeset
413 if (!speculative)
kono
parents:
diff changeset
414 {
kono
parents:
diff changeset
415 clear_outer_type (otr_type);
kono
parents:
diff changeset
416 if (!speculative_outer_type
kono
parents:
diff changeset
417 || !speculation_consistent_p (speculative_outer_type,
kono
parents:
diff changeset
418 speculative_offset,
kono
parents:
diff changeset
419 speculative_maybe_derived_type,
kono
parents:
diff changeset
420 otr_type))
kono
parents:
diff changeset
421 clear_speculation ();
kono
parents:
diff changeset
422 if (speculative_outer_type)
kono
parents:
diff changeset
423 {
kono
parents:
diff changeset
424 speculative = true;
kono
parents:
diff changeset
425 type = speculative_outer_type;
kono
parents:
diff changeset
426 cur_offset = speculative_offset;
kono
parents:
diff changeset
427 }
kono
parents:
diff changeset
428 else
kono
parents:
diff changeset
429 return true;
kono
parents:
diff changeset
430 }
kono
parents:
diff changeset
431 else
kono
parents:
diff changeset
432 {
kono
parents:
diff changeset
433 clear_speculation ();
kono
parents:
diff changeset
434 return true;
kono
parents:
diff changeset
435 }
kono
parents:
diff changeset
436 }
kono
parents:
diff changeset
437 else
kono
parents:
diff changeset
438 {
kono
parents:
diff changeset
439 clear_speculation ();
kono
parents:
diff changeset
440 if (speculative)
kono
parents:
diff changeset
441 return true;
kono
parents:
diff changeset
442 clear_outer_type (otr_type);
kono
parents:
diff changeset
443 invalid = true;
kono
parents:
diff changeset
444 return false;
kono
parents:
diff changeset
445 }
kono
parents:
diff changeset
446 }
kono
parents:
diff changeset
447 }
kono
parents:
diff changeset
448 }
kono
parents:
diff changeset
449
kono
parents:
diff changeset
450 /* Return true if OUTER_TYPE contains OTR_TYPE at OFFSET.
kono
parents:
diff changeset
451 CONSIDER_PLACEMENT_NEW makes function to accept cases where OTR_TYPE can
kono
parents:
diff changeset
452 be built within OUTER_TYPE by means of placement new. CONSIDER_BASES makes
kono
parents:
diff changeset
453 function to accept cases where OTR_TYPE appears as base of OUTER_TYPE or as
kono
parents:
diff changeset
454 base of one of fields of OUTER_TYPE. */
kono
parents:
diff changeset
455
kono
parents:
diff changeset
456 static bool
kono
parents:
diff changeset
457 contains_type_p (tree outer_type, HOST_WIDE_INT offset,
kono
parents:
diff changeset
458 tree otr_type,
kono
parents:
diff changeset
459 bool consider_placement_new,
kono
parents:
diff changeset
460 bool consider_bases)
kono
parents:
diff changeset
461 {
kono
parents:
diff changeset
462 ipa_polymorphic_call_context context;
kono
parents:
diff changeset
463
kono
parents:
diff changeset
464 /* Check that type is within range. */
kono
parents:
diff changeset
465 if (offset < 0)
kono
parents:
diff changeset
466 return false;
kono
parents:
diff changeset
467
kono
parents:
diff changeset
468 /* PR ipa/71207
kono
parents:
diff changeset
469 As OUTER_TYPE can be a type which has a diamond virtual inheritance,
kono
parents:
diff changeset
470 it's not necessary that INNER_TYPE will fit within OUTER_TYPE with
kono
parents:
diff changeset
471 a given offset. It can happen that INNER_TYPE also contains a base object,
kono
parents:
diff changeset
472 however it would point to the same instance in the OUTER_TYPE. */
kono
parents:
diff changeset
473
kono
parents:
diff changeset
474 context.offset = offset;
kono
parents:
diff changeset
475 context.outer_type = TYPE_MAIN_VARIANT (outer_type);
kono
parents:
diff changeset
476 context.maybe_derived_type = false;
kono
parents:
diff changeset
477 context.dynamic = false;
kono
parents:
diff changeset
478 return context.restrict_to_inner_class (otr_type, consider_placement_new,
kono
parents:
diff changeset
479 consider_bases);
kono
parents:
diff changeset
480 }
kono
parents:
diff changeset
481
kono
parents:
diff changeset
482
kono
parents:
diff changeset
483 /* Return a FUNCTION_DECL if FN represent a constructor or destructor.
kono
parents:
diff changeset
484 If CHECK_CLONES is true, also check for clones of ctor/dtors. */
kono
parents:
diff changeset
485
kono
parents:
diff changeset
486 tree
kono
parents:
diff changeset
487 polymorphic_ctor_dtor_p (tree fn, bool check_clones)
kono
parents:
diff changeset
488 {
kono
parents:
diff changeset
489 if (TREE_CODE (TREE_TYPE (fn)) != METHOD_TYPE
kono
parents:
diff changeset
490 || (!DECL_CXX_CONSTRUCTOR_P (fn) && !DECL_CXX_DESTRUCTOR_P (fn)))
kono
parents:
diff changeset
491 {
kono
parents:
diff changeset
492 if (!check_clones)
kono
parents:
diff changeset
493 return NULL_TREE;
kono
parents:
diff changeset
494
kono
parents:
diff changeset
495 /* Watch for clones where we constant propagated the first
kono
parents:
diff changeset
496 argument (pointer to the instance). */
kono
parents:
diff changeset
497 fn = DECL_ABSTRACT_ORIGIN (fn);
kono
parents:
diff changeset
498 if (!fn
kono
parents:
diff changeset
499 || TREE_CODE (TREE_TYPE (fn)) != METHOD_TYPE
kono
parents:
diff changeset
500 || (!DECL_CXX_CONSTRUCTOR_P (fn) && !DECL_CXX_DESTRUCTOR_P (fn)))
kono
parents:
diff changeset
501 return NULL_TREE;
kono
parents:
diff changeset
502 }
kono
parents:
diff changeset
503
kono
parents:
diff changeset
504 if (flags_from_decl_or_type (fn) & (ECF_PURE | ECF_CONST))
kono
parents:
diff changeset
505 return NULL_TREE;
kono
parents:
diff changeset
506
kono
parents:
diff changeset
507 return fn;
kono
parents:
diff changeset
508 }
kono
parents:
diff changeset
509
kono
parents:
diff changeset
510 /* Return a FUNCTION_DECL if BLOCK represents a constructor or destructor.
kono
parents:
diff changeset
511 If CHECK_CLONES is true, also check for clones of ctor/dtors. */
kono
parents:
diff changeset
512
kono
parents:
diff changeset
513 tree
kono
parents:
diff changeset
514 inlined_polymorphic_ctor_dtor_block_p (tree block, bool check_clones)
kono
parents:
diff changeset
515 {
kono
parents:
diff changeset
516 tree fn = block_ultimate_origin (block);
kono
parents:
diff changeset
517 if (fn == NULL || TREE_CODE (fn) != FUNCTION_DECL)
kono
parents:
diff changeset
518 return NULL_TREE;
kono
parents:
diff changeset
519
kono
parents:
diff changeset
520 return polymorphic_ctor_dtor_p (fn, check_clones);
kono
parents:
diff changeset
521 }
kono
parents:
diff changeset
522
kono
parents:
diff changeset
523
kono
parents:
diff changeset
524 /* We know that the instance is stored in variable or parameter
kono
parents:
diff changeset
525 (not dynamically allocated) and we want to disprove the fact
kono
parents:
diff changeset
526 that it may be in construction at invocation of CALL.
kono
parents:
diff changeset
527
kono
parents:
diff changeset
528 BASE represents memory location where instance is stored.
kono
parents:
diff changeset
529 If BASE is NULL, it is assumed to be global memory.
kono
parents:
diff changeset
530 OUTER_TYPE is known type of the instance or NULL if not
kono
parents:
diff changeset
531 known.
kono
parents:
diff changeset
532
kono
parents:
diff changeset
533 For the variable to be in construction we actually need to
kono
parents:
diff changeset
534 be in constructor of corresponding global variable or
kono
parents:
diff changeset
535 the inline stack of CALL must contain the constructor.
kono
parents:
diff changeset
536 Check this condition. This check works safely only before
kono
parents:
diff changeset
537 IPA passes, because inline stacks may become out of date
kono
parents:
diff changeset
538 later. */
kono
parents:
diff changeset
539
kono
parents:
diff changeset
540 bool
kono
parents:
diff changeset
541 decl_maybe_in_construction_p (tree base, tree outer_type,
kono
parents:
diff changeset
542 gimple *call, tree function)
kono
parents:
diff changeset
543 {
kono
parents:
diff changeset
544 if (outer_type)
kono
parents:
diff changeset
545 outer_type = TYPE_MAIN_VARIANT (outer_type);
kono
parents:
diff changeset
546 gcc_assert (!base || DECL_P (base));
kono
parents:
diff changeset
547
kono
parents:
diff changeset
548 /* After inlining the code unification optimizations may invalidate
kono
parents:
diff changeset
549 inline stacks. Also we need to give up on global variables after
kono
parents:
diff changeset
550 IPA, because addresses of these may have been propagated to their
kono
parents:
diff changeset
551 constructors. */
kono
parents:
diff changeset
552 if (DECL_STRUCT_FUNCTION (function)->after_inlining)
kono
parents:
diff changeset
553 return true;
kono
parents:
diff changeset
554
kono
parents:
diff changeset
555 /* Pure functions can not do any changes on the dynamic type;
kono
parents:
diff changeset
556 that require writting to memory. */
kono
parents:
diff changeset
557 if ((!base || !auto_var_in_fn_p (base, function))
kono
parents:
diff changeset
558 && flags_from_decl_or_type (function) & (ECF_PURE | ECF_CONST))
kono
parents:
diff changeset
559 return false;
kono
parents:
diff changeset
560
kono
parents:
diff changeset
561 bool check_clones = !base || is_global_var (base);
kono
parents:
diff changeset
562 for (tree block = gimple_block (call); block && TREE_CODE (block) == BLOCK;
kono
parents:
diff changeset
563 block = BLOCK_SUPERCONTEXT (block))
kono
parents:
diff changeset
564 if (tree fn = inlined_polymorphic_ctor_dtor_block_p (block, check_clones))
kono
parents:
diff changeset
565 {
kono
parents:
diff changeset
566 tree type = TYPE_METHOD_BASETYPE (TREE_TYPE (fn));
kono
parents:
diff changeset
567
kono
parents:
diff changeset
568 if (!outer_type || !types_odr_comparable (type, outer_type))
kono
parents:
diff changeset
569 {
kono
parents:
diff changeset
570 if (TREE_CODE (type) == RECORD_TYPE
kono
parents:
diff changeset
571 && TYPE_BINFO (type)
kono
parents:
diff changeset
572 && polymorphic_type_binfo_p (TYPE_BINFO (type)))
kono
parents:
diff changeset
573 return true;
kono
parents:
diff changeset
574 }
kono
parents:
diff changeset
575 else if (types_same_for_odr (type, outer_type))
kono
parents:
diff changeset
576 return true;
kono
parents:
diff changeset
577 }
kono
parents:
diff changeset
578
kono
parents:
diff changeset
579 if (!base || (VAR_P (base) && is_global_var (base)))
kono
parents:
diff changeset
580 {
kono
parents:
diff changeset
581 if (TREE_CODE (TREE_TYPE (function)) != METHOD_TYPE
kono
parents:
diff changeset
582 || (!DECL_CXX_CONSTRUCTOR_P (function)
kono
parents:
diff changeset
583 && !DECL_CXX_DESTRUCTOR_P (function)))
kono
parents:
diff changeset
584 {
kono
parents:
diff changeset
585 if (!DECL_ABSTRACT_ORIGIN (function))
kono
parents:
diff changeset
586 return false;
kono
parents:
diff changeset
587 /* Watch for clones where we constant propagated the first
kono
parents:
diff changeset
588 argument (pointer to the instance). */
kono
parents:
diff changeset
589 function = DECL_ABSTRACT_ORIGIN (function);
kono
parents:
diff changeset
590 if (!function
kono
parents:
diff changeset
591 || TREE_CODE (TREE_TYPE (function)) != METHOD_TYPE
kono
parents:
diff changeset
592 || (!DECL_CXX_CONSTRUCTOR_P (function)
kono
parents:
diff changeset
593 && !DECL_CXX_DESTRUCTOR_P (function)))
kono
parents:
diff changeset
594 return false;
kono
parents:
diff changeset
595 }
kono
parents:
diff changeset
596 tree type = TYPE_METHOD_BASETYPE (TREE_TYPE (function));
kono
parents:
diff changeset
597 if (!outer_type || !types_odr_comparable (type, outer_type))
kono
parents:
diff changeset
598 {
kono
parents:
diff changeset
599 if (TREE_CODE (type) == RECORD_TYPE
kono
parents:
diff changeset
600 && TYPE_BINFO (type)
kono
parents:
diff changeset
601 && polymorphic_type_binfo_p (TYPE_BINFO (type)))
kono
parents:
diff changeset
602 return true;
kono
parents:
diff changeset
603 }
kono
parents:
diff changeset
604 else if (types_same_for_odr (type, outer_type))
kono
parents:
diff changeset
605 return true;
kono
parents:
diff changeset
606 }
kono
parents:
diff changeset
607 return false;
kono
parents:
diff changeset
608 }
kono
parents:
diff changeset
609
kono
parents:
diff changeset
610 /* Dump human readable context to F. If NEWLINE is true, it will be terminated
kono
parents:
diff changeset
611 by a newline. */
kono
parents:
diff changeset
612
kono
parents:
diff changeset
613 void
kono
parents:
diff changeset
614 ipa_polymorphic_call_context::dump (FILE *f, bool newline) const
kono
parents:
diff changeset
615 {
kono
parents:
diff changeset
616 fprintf (f, " ");
kono
parents:
diff changeset
617 if (invalid)
kono
parents:
diff changeset
618 fprintf (f, "Call is known to be undefined");
kono
parents:
diff changeset
619 else
kono
parents:
diff changeset
620 {
kono
parents:
diff changeset
621 if (useless_p ())
kono
parents:
diff changeset
622 fprintf (f, "nothing known");
kono
parents:
diff changeset
623 if (outer_type || offset)
kono
parents:
diff changeset
624 {
kono
parents:
diff changeset
625 fprintf (f, "Outer type%s:", dynamic ? " (dynamic)":"");
kono
parents:
diff changeset
626 print_generic_expr (f, outer_type, TDF_SLIM);
kono
parents:
diff changeset
627 if (maybe_derived_type)
kono
parents:
diff changeset
628 fprintf (f, " (or a derived type)");
kono
parents:
diff changeset
629 if (maybe_in_construction)
kono
parents:
diff changeset
630 fprintf (f, " (maybe in construction)");
kono
parents:
diff changeset
631 fprintf (f, " offset " HOST_WIDE_INT_PRINT_DEC,
kono
parents:
diff changeset
632 offset);
kono
parents:
diff changeset
633 }
kono
parents:
diff changeset
634 if (speculative_outer_type)
kono
parents:
diff changeset
635 {
kono
parents:
diff changeset
636 if (outer_type || offset)
kono
parents:
diff changeset
637 fprintf (f, " ");
kono
parents:
diff changeset
638 fprintf (f, "Speculative outer type:");
kono
parents:
diff changeset
639 print_generic_expr (f, speculative_outer_type, TDF_SLIM);
kono
parents:
diff changeset
640 if (speculative_maybe_derived_type)
kono
parents:
diff changeset
641 fprintf (f, " (or a derived type)");
kono
parents:
diff changeset
642 fprintf (f, " at offset " HOST_WIDE_INT_PRINT_DEC,
kono
parents:
diff changeset
643 speculative_offset);
kono
parents:
diff changeset
644 }
kono
parents:
diff changeset
645 }
kono
parents:
diff changeset
646 if (newline)
kono
parents:
diff changeset
647 fprintf(f, "\n");
kono
parents:
diff changeset
648 }
kono
parents:
diff changeset
649
kono
parents:
diff changeset
650 /* Print context to stderr. */
kono
parents:
diff changeset
651
kono
parents:
diff changeset
652 void
kono
parents:
diff changeset
653 ipa_polymorphic_call_context::debug () const
kono
parents:
diff changeset
654 {
kono
parents:
diff changeset
655 dump (stderr);
kono
parents:
diff changeset
656 }
kono
parents:
diff changeset
657
kono
parents:
diff changeset
658 /* Stream out the context to OB. */
kono
parents:
diff changeset
659
kono
parents:
diff changeset
660 void
kono
parents:
diff changeset
661 ipa_polymorphic_call_context::stream_out (struct output_block *ob) const
kono
parents:
diff changeset
662 {
kono
parents:
diff changeset
663 struct bitpack_d bp = bitpack_create (ob->main_stream);
kono
parents:
diff changeset
664
kono
parents:
diff changeset
665 bp_pack_value (&bp, invalid, 1);
kono
parents:
diff changeset
666 bp_pack_value (&bp, maybe_in_construction, 1);
kono
parents:
diff changeset
667 bp_pack_value (&bp, maybe_derived_type, 1);
kono
parents:
diff changeset
668 bp_pack_value (&bp, speculative_maybe_derived_type, 1);
kono
parents:
diff changeset
669 bp_pack_value (&bp, dynamic, 1);
kono
parents:
diff changeset
670 bp_pack_value (&bp, outer_type != NULL, 1);
kono
parents:
diff changeset
671 bp_pack_value (&bp, offset != 0, 1);
kono
parents:
diff changeset
672 bp_pack_value (&bp, speculative_outer_type != NULL, 1);
kono
parents:
diff changeset
673 streamer_write_bitpack (&bp);
kono
parents:
diff changeset
674
kono
parents:
diff changeset
675 if (outer_type != NULL)
kono
parents:
diff changeset
676 stream_write_tree (ob, outer_type, true);
kono
parents:
diff changeset
677 if (offset)
kono
parents:
diff changeset
678 streamer_write_hwi (ob, offset);
kono
parents:
diff changeset
679 if (speculative_outer_type != NULL)
kono
parents:
diff changeset
680 {
kono
parents:
diff changeset
681 stream_write_tree (ob, speculative_outer_type, true);
kono
parents:
diff changeset
682 streamer_write_hwi (ob, speculative_offset);
kono
parents:
diff changeset
683 }
kono
parents:
diff changeset
684 else
kono
parents:
diff changeset
685 gcc_assert (!speculative_offset);
kono
parents:
diff changeset
686 }
kono
parents:
diff changeset
687
kono
parents:
diff changeset
688 /* Stream in the context from IB and DATA_IN. */
kono
parents:
diff changeset
689
kono
parents:
diff changeset
690 void
kono
parents:
diff changeset
691 ipa_polymorphic_call_context::stream_in (struct lto_input_block *ib,
kono
parents:
diff changeset
692 struct data_in *data_in)
kono
parents:
diff changeset
693 {
kono
parents:
diff changeset
694 struct bitpack_d bp = streamer_read_bitpack (ib);
kono
parents:
diff changeset
695
kono
parents:
diff changeset
696 invalid = bp_unpack_value (&bp, 1);
kono
parents:
diff changeset
697 maybe_in_construction = bp_unpack_value (&bp, 1);
kono
parents:
diff changeset
698 maybe_derived_type = bp_unpack_value (&bp, 1);
kono
parents:
diff changeset
699 speculative_maybe_derived_type = bp_unpack_value (&bp, 1);
kono
parents:
diff changeset
700 dynamic = bp_unpack_value (&bp, 1);
kono
parents:
diff changeset
701 bool outer_type_p = bp_unpack_value (&bp, 1);
kono
parents:
diff changeset
702 bool offset_p = bp_unpack_value (&bp, 1);
kono
parents:
diff changeset
703 bool speculative_outer_type_p = bp_unpack_value (&bp, 1);
kono
parents:
diff changeset
704
kono
parents:
diff changeset
705 if (outer_type_p)
kono
parents:
diff changeset
706 outer_type = stream_read_tree (ib, data_in);
kono
parents:
diff changeset
707 else
kono
parents:
diff changeset
708 outer_type = NULL;
kono
parents:
diff changeset
709 if (offset_p)
kono
parents:
diff changeset
710 offset = (HOST_WIDE_INT) streamer_read_hwi (ib);
kono
parents:
diff changeset
711 else
kono
parents:
diff changeset
712 offset = 0;
kono
parents:
diff changeset
713 if (speculative_outer_type_p)
kono
parents:
diff changeset
714 {
kono
parents:
diff changeset
715 speculative_outer_type = stream_read_tree (ib, data_in);
kono
parents:
diff changeset
716 speculative_offset = (HOST_WIDE_INT) streamer_read_hwi (ib);
kono
parents:
diff changeset
717 }
kono
parents:
diff changeset
718 else
kono
parents:
diff changeset
719 {
kono
parents:
diff changeset
720 speculative_outer_type = NULL;
kono
parents:
diff changeset
721 speculative_offset = 0;
kono
parents:
diff changeset
722 }
kono
parents:
diff changeset
723 }
kono
parents:
diff changeset
724
kono
parents:
diff changeset
725 /* Proudce polymorphic call context for call method of instance
kono
parents:
diff changeset
726 that is located within BASE (that is assumed to be a decl) at offset OFF. */
kono
parents:
diff changeset
727
kono
parents:
diff changeset
728 void
kono
parents:
diff changeset
729 ipa_polymorphic_call_context::set_by_decl (tree base, HOST_WIDE_INT off)
kono
parents:
diff changeset
730 {
kono
parents:
diff changeset
731 gcc_assert (DECL_P (base));
kono
parents:
diff changeset
732 clear_speculation ();
kono
parents:
diff changeset
733
kono
parents:
diff changeset
734 if (!contains_polymorphic_type_p (TREE_TYPE (base)))
kono
parents:
diff changeset
735 {
kono
parents:
diff changeset
736 clear_outer_type ();
kono
parents:
diff changeset
737 offset = off;
kono
parents:
diff changeset
738 return;
kono
parents:
diff changeset
739 }
kono
parents:
diff changeset
740 outer_type = TYPE_MAIN_VARIANT (TREE_TYPE (base));
kono
parents:
diff changeset
741 offset = off;
kono
parents:
diff changeset
742 /* Make very conservative assumption that all objects
kono
parents:
diff changeset
743 may be in construction.
kono
parents:
diff changeset
744
kono
parents:
diff changeset
745 It is up to caller to revisit this via
kono
parents:
diff changeset
746 get_dynamic_type or decl_maybe_in_construction_p. */
kono
parents:
diff changeset
747 maybe_in_construction = true;
kono
parents:
diff changeset
748 maybe_derived_type = false;
kono
parents:
diff changeset
749 dynamic = false;
kono
parents:
diff changeset
750 }
kono
parents:
diff changeset
751
kono
parents:
diff changeset
752 /* CST is an invariant (address of decl), try to get meaningful
kono
parents:
diff changeset
753 polymorphic call context for polymorphic call of method
kono
parents:
diff changeset
754 if instance of OTR_TYPE that is located at offset OFF of this invariant.
kono
parents:
diff changeset
755 Return FALSE if nothing meaningful can be found. */
kono
parents:
diff changeset
756
kono
parents:
diff changeset
757 bool
kono
parents:
diff changeset
758 ipa_polymorphic_call_context::set_by_invariant (tree cst,
kono
parents:
diff changeset
759 tree otr_type,
kono
parents:
diff changeset
760 HOST_WIDE_INT off)
kono
parents:
diff changeset
761 {
kono
parents:
diff changeset
762 HOST_WIDE_INT offset2, size, max_size;
kono
parents:
diff changeset
763 bool reverse;
kono
parents:
diff changeset
764 tree base;
kono
parents:
diff changeset
765
kono
parents:
diff changeset
766 invalid = false;
kono
parents:
diff changeset
767 off = 0;
kono
parents:
diff changeset
768 clear_outer_type (otr_type);
kono
parents:
diff changeset
769
kono
parents:
diff changeset
770 if (TREE_CODE (cst) != ADDR_EXPR)
kono
parents:
diff changeset
771 return false;
kono
parents:
diff changeset
772
kono
parents:
diff changeset
773 cst = TREE_OPERAND (cst, 0);
kono
parents:
diff changeset
774 base = get_ref_base_and_extent (cst, &offset2, &size, &max_size, &reverse);
kono
parents:
diff changeset
775 if (!DECL_P (base) || max_size == -1 || max_size != size)
kono
parents:
diff changeset
776 return false;
kono
parents:
diff changeset
777
kono
parents:
diff changeset
778 /* Only type inconsistent programs can have otr_type that is
kono
parents:
diff changeset
779 not part of outer type. */
kono
parents:
diff changeset
780 if (otr_type && !contains_type_p (TREE_TYPE (base), off, otr_type))
kono
parents:
diff changeset
781 return false;
kono
parents:
diff changeset
782
kono
parents:
diff changeset
783 set_by_decl (base, off);
kono
parents:
diff changeset
784 return true;
kono
parents:
diff changeset
785 }
kono
parents:
diff changeset
786
kono
parents:
diff changeset
787 /* See if OP is SSA name initialized as a copy or by single assignment.
kono
parents:
diff changeset
788 If so, walk the SSA graph up. Because simple PHI conditional is considered
kono
parents:
diff changeset
789 copy, GLOBAL_VISITED may be used to avoid infinite loop walking the SSA
kono
parents:
diff changeset
790 graph. */
kono
parents:
diff changeset
791
kono
parents:
diff changeset
792 static tree
kono
parents:
diff changeset
793 walk_ssa_copies (tree op, hash_set<tree> **global_visited = NULL)
kono
parents:
diff changeset
794 {
kono
parents:
diff changeset
795 hash_set <tree> *visited = NULL;
kono
parents:
diff changeset
796 STRIP_NOPS (op);
kono
parents:
diff changeset
797 while (TREE_CODE (op) == SSA_NAME
kono
parents:
diff changeset
798 && !SSA_NAME_IS_DEFAULT_DEF (op)
kono
parents:
diff changeset
799 /* We might be called via fold_stmt during cfgcleanup where
kono
parents:
diff changeset
800 SSA form need not be up-to-date. */
kono
parents:
diff changeset
801 && !name_registered_for_update_p (op)
kono
parents:
diff changeset
802 && (gimple_assign_single_p (SSA_NAME_DEF_STMT (op))
kono
parents:
diff changeset
803 || gimple_code (SSA_NAME_DEF_STMT (op)) == GIMPLE_PHI))
kono
parents:
diff changeset
804 {
kono
parents:
diff changeset
805 if (global_visited)
kono
parents:
diff changeset
806 {
kono
parents:
diff changeset
807 if (!*global_visited)
kono
parents:
diff changeset
808 *global_visited = new hash_set<tree>;
kono
parents:
diff changeset
809 if ((*global_visited)->add (op))
kono
parents:
diff changeset
810 goto done;
kono
parents:
diff changeset
811 }
kono
parents:
diff changeset
812 else
kono
parents:
diff changeset
813 {
kono
parents:
diff changeset
814 if (!visited)
kono
parents:
diff changeset
815 visited = new hash_set<tree>;
kono
parents:
diff changeset
816 if (visited->add (op))
kono
parents:
diff changeset
817 goto done;
kono
parents:
diff changeset
818 }
kono
parents:
diff changeset
819 /* Special case
kono
parents:
diff changeset
820 if (ptr == 0)
kono
parents:
diff changeset
821 ptr = 0;
kono
parents:
diff changeset
822 else
kono
parents:
diff changeset
823 ptr = ptr.foo;
kono
parents:
diff changeset
824 This pattern is implicitly produced for casts to non-primary
kono
parents:
diff changeset
825 bases. When doing context analysis, we do not really care
kono
parents:
diff changeset
826 about the case pointer is NULL, because the call will be
kono
parents:
diff changeset
827 undefined anyway. */
kono
parents:
diff changeset
828 if (gimple_code (SSA_NAME_DEF_STMT (op)) == GIMPLE_PHI)
kono
parents:
diff changeset
829 {
kono
parents:
diff changeset
830 gimple *phi = SSA_NAME_DEF_STMT (op);
kono
parents:
diff changeset
831
kono
parents:
diff changeset
832 if (gimple_phi_num_args (phi) > 2)
kono
parents:
diff changeset
833 goto done;
kono
parents:
diff changeset
834 if (gimple_phi_num_args (phi) == 1)
kono
parents:
diff changeset
835 op = gimple_phi_arg_def (phi, 0);
kono
parents:
diff changeset
836 else if (integer_zerop (gimple_phi_arg_def (phi, 0)))
kono
parents:
diff changeset
837 op = gimple_phi_arg_def (phi, 1);
kono
parents:
diff changeset
838 else if (integer_zerop (gimple_phi_arg_def (phi, 1)))
kono
parents:
diff changeset
839 op = gimple_phi_arg_def (phi, 0);
kono
parents:
diff changeset
840 else
kono
parents:
diff changeset
841 goto done;
kono
parents:
diff changeset
842 }
kono
parents:
diff changeset
843 else
kono
parents:
diff changeset
844 {
kono
parents:
diff changeset
845 if (gimple_assign_load_p (SSA_NAME_DEF_STMT (op)))
kono
parents:
diff changeset
846 goto done;
kono
parents:
diff changeset
847 op = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (op));
kono
parents:
diff changeset
848 }
kono
parents:
diff changeset
849 STRIP_NOPS (op);
kono
parents:
diff changeset
850 }
kono
parents:
diff changeset
851 done:
kono
parents:
diff changeset
852 if (visited)
kono
parents:
diff changeset
853 delete (visited);
kono
parents:
diff changeset
854 return op;
kono
parents:
diff changeset
855 }
kono
parents:
diff changeset
856
kono
parents:
diff changeset
857 /* Create polymorphic call context from IP invariant CST.
kono
parents:
diff changeset
858 This is typically &global_var.
kono
parents:
diff changeset
859 OTR_TYPE specify type of polymorphic call or NULL if unknown, OFF
kono
parents:
diff changeset
860 is offset of call. */
kono
parents:
diff changeset
861
kono
parents:
diff changeset
862 ipa_polymorphic_call_context::ipa_polymorphic_call_context (tree cst,
kono
parents:
diff changeset
863 tree otr_type,
kono
parents:
diff changeset
864 HOST_WIDE_INT off)
kono
parents:
diff changeset
865 {
kono
parents:
diff changeset
866 clear_speculation ();
kono
parents:
diff changeset
867 set_by_invariant (cst, otr_type, off);
kono
parents:
diff changeset
868 }
kono
parents:
diff changeset
869
kono
parents:
diff changeset
870 /* Build context for pointer REF contained in FNDECL at statement STMT.
kono
parents:
diff changeset
871 if INSTANCE is non-NULL, return pointer to the object described by
kono
parents:
diff changeset
872 the context or DECL where context is contained in. */
kono
parents:
diff changeset
873
kono
parents:
diff changeset
874 ipa_polymorphic_call_context::ipa_polymorphic_call_context (tree fndecl,
kono
parents:
diff changeset
875 tree ref,
kono
parents:
diff changeset
876 gimple *stmt,
kono
parents:
diff changeset
877 tree *instance)
kono
parents:
diff changeset
878 {
kono
parents:
diff changeset
879 tree otr_type = NULL;
kono
parents:
diff changeset
880 tree base_pointer;
kono
parents:
diff changeset
881 hash_set <tree> *visited = NULL;
kono
parents:
diff changeset
882
kono
parents:
diff changeset
883 if (TREE_CODE (ref) == OBJ_TYPE_REF)
kono
parents:
diff changeset
884 {
kono
parents:
diff changeset
885 otr_type = obj_type_ref_class (ref);
kono
parents:
diff changeset
886 base_pointer = OBJ_TYPE_REF_OBJECT (ref);
kono
parents:
diff changeset
887 }
kono
parents:
diff changeset
888 else
kono
parents:
diff changeset
889 base_pointer = ref;
kono
parents:
diff changeset
890
kono
parents:
diff changeset
891 /* Set up basic info in case we find nothing interesting in the analysis. */
kono
parents:
diff changeset
892 clear_speculation ();
kono
parents:
diff changeset
893 clear_outer_type (otr_type);
kono
parents:
diff changeset
894 invalid = false;
kono
parents:
diff changeset
895
kono
parents:
diff changeset
896 /* Walk SSA for outer object. */
kono
parents:
diff changeset
897 while (true)
kono
parents:
diff changeset
898 {
kono
parents:
diff changeset
899 base_pointer = walk_ssa_copies (base_pointer, &visited);
kono
parents:
diff changeset
900 if (TREE_CODE (base_pointer) == ADDR_EXPR)
kono
parents:
diff changeset
901 {
kono
parents:
diff changeset
902 HOST_WIDE_INT size, max_size;
kono
parents:
diff changeset
903 HOST_WIDE_INT offset2;
kono
parents:
diff changeset
904 bool reverse;
kono
parents:
diff changeset
905 tree base
kono
parents:
diff changeset
906 = get_ref_base_and_extent (TREE_OPERAND (base_pointer, 0),
kono
parents:
diff changeset
907 &offset2, &size, &max_size, &reverse);
kono
parents:
diff changeset
908
kono
parents:
diff changeset
909 if (max_size != -1 && max_size == size)
kono
parents:
diff changeset
910 combine_speculation_with (TYPE_MAIN_VARIANT (TREE_TYPE (base)),
kono
parents:
diff changeset
911 offset + offset2,
kono
parents:
diff changeset
912 true,
kono
parents:
diff changeset
913 NULL /* Do not change outer type. */);
kono
parents:
diff changeset
914
kono
parents:
diff changeset
915 /* If this is a varying address, punt. */
kono
parents:
diff changeset
916 if ((TREE_CODE (base) == MEM_REF || DECL_P (base))
kono
parents:
diff changeset
917 && max_size != -1
kono
parents:
diff changeset
918 && max_size == size)
kono
parents:
diff changeset
919 {
kono
parents:
diff changeset
920 /* We found dereference of a pointer. Type of the pointer
kono
parents:
diff changeset
921 and MEM_REF is meaningless, but we can look futher. */
kono
parents:
diff changeset
922 if (TREE_CODE (base) == MEM_REF)
kono
parents:
diff changeset
923 {
kono
parents:
diff changeset
924 offset_int o = mem_ref_offset (base) * BITS_PER_UNIT;
kono
parents:
diff changeset
925 o += offset;
kono
parents:
diff changeset
926 o += offset2;
kono
parents:
diff changeset
927 if (!wi::fits_shwi_p (o))
kono
parents:
diff changeset
928 break;
kono
parents:
diff changeset
929 base_pointer = TREE_OPERAND (base, 0);
kono
parents:
diff changeset
930 offset = o.to_shwi ();
kono
parents:
diff changeset
931 outer_type = NULL;
kono
parents:
diff changeset
932 }
kono
parents:
diff changeset
933 /* We found base object. In this case the outer_type
kono
parents:
diff changeset
934 is known. */
kono
parents:
diff changeset
935 else if (DECL_P (base))
kono
parents:
diff changeset
936 {
kono
parents:
diff changeset
937 if (visited)
kono
parents:
diff changeset
938 delete (visited);
kono
parents:
diff changeset
939 /* Only type inconsistent programs can have otr_type that is
kono
parents:
diff changeset
940 not part of outer type. */
kono
parents:
diff changeset
941 if (otr_type
kono
parents:
diff changeset
942 && !contains_type_p (TREE_TYPE (base),
kono
parents:
diff changeset
943 offset + offset2, otr_type))
kono
parents:
diff changeset
944 {
kono
parents:
diff changeset
945 invalid = true;
kono
parents:
diff changeset
946 if (instance)
kono
parents:
diff changeset
947 *instance = base_pointer;
kono
parents:
diff changeset
948 return;
kono
parents:
diff changeset
949 }
kono
parents:
diff changeset
950 set_by_decl (base, offset + offset2);
kono
parents:
diff changeset
951 if (outer_type && maybe_in_construction && stmt)
kono
parents:
diff changeset
952 maybe_in_construction
kono
parents:
diff changeset
953 = decl_maybe_in_construction_p (base,
kono
parents:
diff changeset
954 outer_type,
kono
parents:
diff changeset
955 stmt,
kono
parents:
diff changeset
956 fndecl);
kono
parents:
diff changeset
957 if (instance)
kono
parents:
diff changeset
958 *instance = base;
kono
parents:
diff changeset
959 return;
kono
parents:
diff changeset
960 }
kono
parents:
diff changeset
961 else
kono
parents:
diff changeset
962 break;
kono
parents:
diff changeset
963 }
kono
parents:
diff changeset
964 else
kono
parents:
diff changeset
965 break;
kono
parents:
diff changeset
966 }
kono
parents:
diff changeset
967 else if (TREE_CODE (base_pointer) == POINTER_PLUS_EXPR
kono
parents:
diff changeset
968 && TREE_CODE (TREE_OPERAND (base_pointer, 1)) == INTEGER_CST)
kono
parents:
diff changeset
969 {
kono
parents:
diff changeset
970 offset_int o
kono
parents:
diff changeset
971 = offset_int::from (wi::to_wide (TREE_OPERAND (base_pointer, 1)),
kono
parents:
diff changeset
972 SIGNED);
kono
parents:
diff changeset
973 o *= BITS_PER_UNIT;
kono
parents:
diff changeset
974 o += offset;
kono
parents:
diff changeset
975 if (!wi::fits_shwi_p (o))
kono
parents:
diff changeset
976 break;
kono
parents:
diff changeset
977 offset = o.to_shwi ();
kono
parents:
diff changeset
978 base_pointer = TREE_OPERAND (base_pointer, 0);
kono
parents:
diff changeset
979 }
kono
parents:
diff changeset
980 else
kono
parents:
diff changeset
981 break;
kono
parents:
diff changeset
982 }
kono
parents:
diff changeset
983
kono
parents:
diff changeset
984 if (visited)
kono
parents:
diff changeset
985 delete (visited);
kono
parents:
diff changeset
986
kono
parents:
diff changeset
987 /* Try to determine type of the outer object. */
kono
parents:
diff changeset
988 if (TREE_CODE (base_pointer) == SSA_NAME
kono
parents:
diff changeset
989 && SSA_NAME_IS_DEFAULT_DEF (base_pointer)
kono
parents:
diff changeset
990 && TREE_CODE (SSA_NAME_VAR (base_pointer)) == PARM_DECL)
kono
parents:
diff changeset
991 {
kono
parents:
diff changeset
992 /* See if parameter is THIS pointer of a method. */
kono
parents:
diff changeset
993 if (TREE_CODE (TREE_TYPE (fndecl)) == METHOD_TYPE
kono
parents:
diff changeset
994 && SSA_NAME_VAR (base_pointer) == DECL_ARGUMENTS (fndecl))
kono
parents:
diff changeset
995 {
kono
parents:
diff changeset
996 outer_type
kono
parents:
diff changeset
997 = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (base_pointer)));
kono
parents:
diff changeset
998 gcc_assert (TREE_CODE (outer_type) == RECORD_TYPE
kono
parents:
diff changeset
999 || TREE_CODE (outer_type) == UNION_TYPE);
kono
parents:
diff changeset
1000
kono
parents:
diff changeset
1001 /* Dynamic casting has possibly upcasted the type
kono
parents:
diff changeset
1002 in the hiearchy. In this case outer type is less
kono
parents:
diff changeset
1003 informative than inner type and we should forget
kono
parents:
diff changeset
1004 about it. */
kono
parents:
diff changeset
1005 if ((otr_type
kono
parents:
diff changeset
1006 && !contains_type_p (outer_type, offset,
kono
parents:
diff changeset
1007 otr_type))
kono
parents:
diff changeset
1008 || !contains_polymorphic_type_p (outer_type))
kono
parents:
diff changeset
1009 {
kono
parents:
diff changeset
1010 outer_type = NULL;
kono
parents:
diff changeset
1011 if (instance)
kono
parents:
diff changeset
1012 *instance = base_pointer;
kono
parents:
diff changeset
1013 return;
kono
parents:
diff changeset
1014 }
kono
parents:
diff changeset
1015
kono
parents:
diff changeset
1016 dynamic = true;
kono
parents:
diff changeset
1017
kono
parents:
diff changeset
1018 /* If the function is constructor or destructor, then
kono
parents:
diff changeset
1019 the type is possibly in construction, but we know
kono
parents:
diff changeset
1020 it is not derived type. */
kono
parents:
diff changeset
1021 if (DECL_CXX_CONSTRUCTOR_P (fndecl)
kono
parents:
diff changeset
1022 || DECL_CXX_DESTRUCTOR_P (fndecl))
kono
parents:
diff changeset
1023 {
kono
parents:
diff changeset
1024 maybe_in_construction = true;
kono
parents:
diff changeset
1025 maybe_derived_type = false;
kono
parents:
diff changeset
1026 }
kono
parents:
diff changeset
1027 else
kono
parents:
diff changeset
1028 {
kono
parents:
diff changeset
1029 maybe_derived_type = true;
kono
parents:
diff changeset
1030 maybe_in_construction = false;
kono
parents:
diff changeset
1031 }
kono
parents:
diff changeset
1032 if (instance)
kono
parents:
diff changeset
1033 *instance = base_pointer;
kono
parents:
diff changeset
1034 return;
kono
parents:
diff changeset
1035 }
kono
parents:
diff changeset
1036 /* Non-PODs passed by value are really passed by invisible
kono
parents:
diff changeset
1037 reference. In this case we also know the type of the
kono
parents:
diff changeset
1038 object. */
kono
parents:
diff changeset
1039 if (DECL_BY_REFERENCE (SSA_NAME_VAR (base_pointer)))
kono
parents:
diff changeset
1040 {
kono
parents:
diff changeset
1041 outer_type
kono
parents:
diff changeset
1042 = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (base_pointer)));
kono
parents:
diff changeset
1043 /* Only type inconsistent programs can have otr_type that is
kono
parents:
diff changeset
1044 not part of outer type. */
kono
parents:
diff changeset
1045 if (otr_type && !contains_type_p (outer_type, offset,
kono
parents:
diff changeset
1046 otr_type))
kono
parents:
diff changeset
1047 {
kono
parents:
diff changeset
1048 invalid = true;
kono
parents:
diff changeset
1049 if (instance)
kono
parents:
diff changeset
1050 *instance = base_pointer;
kono
parents:
diff changeset
1051 return;
kono
parents:
diff changeset
1052 }
kono
parents:
diff changeset
1053 /* Non-polymorphic types have no interest for us. */
kono
parents:
diff changeset
1054 else if (!otr_type && !contains_polymorphic_type_p (outer_type))
kono
parents:
diff changeset
1055 {
kono
parents:
diff changeset
1056 outer_type = NULL;
kono
parents:
diff changeset
1057 if (instance)
kono
parents:
diff changeset
1058 *instance = base_pointer;
kono
parents:
diff changeset
1059 return;
kono
parents:
diff changeset
1060 }
kono
parents:
diff changeset
1061 maybe_derived_type = false;
kono
parents:
diff changeset
1062 maybe_in_construction = false;
kono
parents:
diff changeset
1063 if (instance)
kono
parents:
diff changeset
1064 *instance = base_pointer;
kono
parents:
diff changeset
1065 return;
kono
parents:
diff changeset
1066 }
kono
parents:
diff changeset
1067 }
kono
parents:
diff changeset
1068
kono
parents:
diff changeset
1069 tree base_type = TREE_TYPE (base_pointer);
kono
parents:
diff changeset
1070
kono
parents:
diff changeset
1071 if (TREE_CODE (base_pointer) == SSA_NAME
kono
parents:
diff changeset
1072 && SSA_NAME_IS_DEFAULT_DEF (base_pointer)
kono
parents:
diff changeset
1073 && !(TREE_CODE (SSA_NAME_VAR (base_pointer)) == PARM_DECL
kono
parents:
diff changeset
1074 || TREE_CODE (SSA_NAME_VAR (base_pointer)) == RESULT_DECL))
kono
parents:
diff changeset
1075 {
kono
parents:
diff changeset
1076 invalid = true;
kono
parents:
diff changeset
1077 if (instance)
kono
parents:
diff changeset
1078 *instance = base_pointer;
kono
parents:
diff changeset
1079 return;
kono
parents:
diff changeset
1080 }
kono
parents:
diff changeset
1081 if (TREE_CODE (base_pointer) == SSA_NAME
kono
parents:
diff changeset
1082 && SSA_NAME_DEF_STMT (base_pointer)
kono
parents:
diff changeset
1083 && gimple_assign_single_p (SSA_NAME_DEF_STMT (base_pointer)))
kono
parents:
diff changeset
1084 base_type = TREE_TYPE (gimple_assign_rhs1
kono
parents:
diff changeset
1085 (SSA_NAME_DEF_STMT (base_pointer)));
kono
parents:
diff changeset
1086
kono
parents:
diff changeset
1087 if (base_type && POINTER_TYPE_P (base_type))
kono
parents:
diff changeset
1088 combine_speculation_with (TYPE_MAIN_VARIANT (TREE_TYPE (base_type)),
kono
parents:
diff changeset
1089 offset,
kono
parents:
diff changeset
1090 true, NULL /* Do not change type here */);
kono
parents:
diff changeset
1091 /* TODO: There are multiple ways to derive a type. For instance
kono
parents:
diff changeset
1092 if BASE_POINTER is passed to an constructor call prior our refernece.
kono
parents:
diff changeset
1093 We do not make this type of flow sensitive analysis yet. */
kono
parents:
diff changeset
1094 if (instance)
kono
parents:
diff changeset
1095 *instance = base_pointer;
kono
parents:
diff changeset
1096 return;
kono
parents:
diff changeset
1097 }
kono
parents:
diff changeset
1098
kono
parents:
diff changeset
1099 /* Structure to be passed in between detect_type_change and
kono
parents:
diff changeset
1100 check_stmt_for_type_change. */
kono
parents:
diff changeset
1101
kono
parents:
diff changeset
1102 struct type_change_info
kono
parents:
diff changeset
1103 {
kono
parents:
diff changeset
1104 /* Offset into the object where there is the virtual method pointer we are
kono
parents:
diff changeset
1105 looking for. */
kono
parents:
diff changeset
1106 HOST_WIDE_INT offset;
kono
parents:
diff changeset
1107 /* The declaration or SSA_NAME pointer of the base that we are checking for
kono
parents:
diff changeset
1108 type change. */
kono
parents:
diff changeset
1109 tree instance;
kono
parents:
diff changeset
1110 /* The reference to virtual table pointer used. */
kono
parents:
diff changeset
1111 tree vtbl_ptr_ref;
kono
parents:
diff changeset
1112 tree otr_type;
kono
parents:
diff changeset
1113 /* If we actually can tell the type that the object has changed to, it is
kono
parents:
diff changeset
1114 stored in this field. Otherwise it remains NULL_TREE. */
kono
parents:
diff changeset
1115 tree known_current_type;
kono
parents:
diff changeset
1116 HOST_WIDE_INT known_current_offset;
kono
parents:
diff changeset
1117
kono
parents:
diff changeset
1118 /* Set to nonzero if we possibly missed some dynamic type changes and we
kono
parents:
diff changeset
1119 should consider the set to be speculative. */
kono
parents:
diff changeset
1120 unsigned speculative;
kono
parents:
diff changeset
1121
kono
parents:
diff changeset
1122 /* Set to true if dynamic type change has been detected. */
kono
parents:
diff changeset
1123 bool type_maybe_changed;
kono
parents:
diff changeset
1124 /* Set to true if multiple types have been encountered. known_current_type
kono
parents:
diff changeset
1125 must be disregarded in that case. */
kono
parents:
diff changeset
1126 bool multiple_types_encountered;
kono
parents:
diff changeset
1127 bool seen_unanalyzed_store;
kono
parents:
diff changeset
1128 };
kono
parents:
diff changeset
1129
kono
parents:
diff changeset
1130 /* Return true if STMT is not call and can modify a virtual method table pointer.
kono
parents:
diff changeset
1131 We take advantage of fact that vtable stores must appear within constructor
kono
parents:
diff changeset
1132 and destructor functions. */
kono
parents:
diff changeset
1133
kono
parents:
diff changeset
1134 static bool
kono
parents:
diff changeset
1135 noncall_stmt_may_be_vtbl_ptr_store (gimple *stmt)
kono
parents:
diff changeset
1136 {
kono
parents:
diff changeset
1137 if (is_gimple_assign (stmt))
kono
parents:
diff changeset
1138 {
kono
parents:
diff changeset
1139 tree lhs = gimple_assign_lhs (stmt);
kono
parents:
diff changeset
1140
kono
parents:
diff changeset
1141 if (gimple_clobber_p (stmt))
kono
parents:
diff changeset
1142 return false;
kono
parents:
diff changeset
1143 if (!AGGREGATE_TYPE_P (TREE_TYPE (lhs)))
kono
parents:
diff changeset
1144 {
kono
parents:
diff changeset
1145 if (flag_strict_aliasing
kono
parents:
diff changeset
1146 && !POINTER_TYPE_P (TREE_TYPE (lhs)))
kono
parents:
diff changeset
1147 return false;
kono
parents:
diff changeset
1148
kono
parents:
diff changeset
1149 if (TREE_CODE (lhs) == COMPONENT_REF
kono
parents:
diff changeset
1150 && !DECL_VIRTUAL_P (TREE_OPERAND (lhs, 1)))
kono
parents:
diff changeset
1151 return false;
kono
parents:
diff changeset
1152 /* In the future we might want to use get_base_ref_and_offset to find
kono
parents:
diff changeset
1153 if there is a field corresponding to the offset and if so, proceed
kono
parents:
diff changeset
1154 almost like if it was a component ref. */
kono
parents:
diff changeset
1155 }
kono
parents:
diff changeset
1156 }
kono
parents:
diff changeset
1157
kono
parents:
diff changeset
1158 /* Code unification may mess with inline stacks. */
kono
parents:
diff changeset
1159 if (cfun->after_inlining)
kono
parents:
diff changeset
1160 return true;
kono
parents:
diff changeset
1161
kono
parents:
diff changeset
1162 /* Walk the inline stack and watch out for ctors/dtors.
kono
parents:
diff changeset
1163 TODO: Maybe we can require the store to appear in toplevel
kono
parents:
diff changeset
1164 block of CTOR/DTOR. */
kono
parents:
diff changeset
1165 for (tree block = gimple_block (stmt); block && TREE_CODE (block) == BLOCK;
kono
parents:
diff changeset
1166 block = BLOCK_SUPERCONTEXT (block))
kono
parents:
diff changeset
1167 if (BLOCK_ABSTRACT_ORIGIN (block)
kono
parents:
diff changeset
1168 && TREE_CODE (block_ultimate_origin (block)) == FUNCTION_DECL)
kono
parents:
diff changeset
1169 return inlined_polymorphic_ctor_dtor_block_p (block, false);
kono
parents:
diff changeset
1170 return (TREE_CODE (TREE_TYPE (current_function_decl)) == METHOD_TYPE
kono
parents:
diff changeset
1171 && (DECL_CXX_CONSTRUCTOR_P (current_function_decl)
kono
parents:
diff changeset
1172 || DECL_CXX_DESTRUCTOR_P (current_function_decl)));
kono
parents:
diff changeset
1173 }
kono
parents:
diff changeset
1174
kono
parents:
diff changeset
1175 /* If STMT can be proved to be an assignment to the virtual method table
kono
parents:
diff changeset
1176 pointer of ANALYZED_OBJ and the type associated with the new table
kono
parents:
diff changeset
1177 identified, return the type. Otherwise return NULL_TREE if type changes
kono
parents:
diff changeset
1178 in unknown way or ERROR_MARK_NODE if type is unchanged. */
kono
parents:
diff changeset
1179
kono
parents:
diff changeset
1180 static tree
kono
parents:
diff changeset
1181 extr_type_from_vtbl_ptr_store (gimple *stmt, struct type_change_info *tci,
kono
parents:
diff changeset
1182 HOST_WIDE_INT *type_offset)
kono
parents:
diff changeset
1183 {
kono
parents:
diff changeset
1184 HOST_WIDE_INT offset, size, max_size;
kono
parents:
diff changeset
1185 tree lhs, rhs, base;
kono
parents:
diff changeset
1186 bool reverse;
kono
parents:
diff changeset
1187
kono
parents:
diff changeset
1188 if (!gimple_assign_single_p (stmt))
kono
parents:
diff changeset
1189 return NULL_TREE;
kono
parents:
diff changeset
1190
kono
parents:
diff changeset
1191 lhs = gimple_assign_lhs (stmt);
kono
parents:
diff changeset
1192 rhs = gimple_assign_rhs1 (stmt);
kono
parents:
diff changeset
1193 if (TREE_CODE (lhs) != COMPONENT_REF
kono
parents:
diff changeset
1194 || !DECL_VIRTUAL_P (TREE_OPERAND (lhs, 1)))
kono
parents:
diff changeset
1195 {
kono
parents:
diff changeset
1196 if (dump_file)
kono
parents:
diff changeset
1197 fprintf (dump_file, " LHS is not virtual table.\n");
kono
parents:
diff changeset
1198 return NULL_TREE;
kono
parents:
diff changeset
1199 }
kono
parents:
diff changeset
1200
kono
parents:
diff changeset
1201 if (tci->vtbl_ptr_ref && operand_equal_p (lhs, tci->vtbl_ptr_ref, 0))
kono
parents:
diff changeset
1202 ;
kono
parents:
diff changeset
1203 else
kono
parents:
diff changeset
1204 {
kono
parents:
diff changeset
1205 base = get_ref_base_and_extent (lhs, &offset, &size, &max_size, &reverse);
kono
parents:
diff changeset
1206 if (DECL_P (tci->instance))
kono
parents:
diff changeset
1207 {
kono
parents:
diff changeset
1208 if (base != tci->instance)
kono
parents:
diff changeset
1209 {
kono
parents:
diff changeset
1210 if (dump_file)
kono
parents:
diff changeset
1211 {
kono
parents:
diff changeset
1212 fprintf (dump_file, " base:");
kono
parents:
diff changeset
1213 print_generic_expr (dump_file, base, TDF_SLIM);
kono
parents:
diff changeset
1214 fprintf (dump_file, " does not match instance:");
kono
parents:
diff changeset
1215 print_generic_expr (dump_file, tci->instance, TDF_SLIM);
kono
parents:
diff changeset
1216 fprintf (dump_file, "\n");
kono
parents:
diff changeset
1217 }
kono
parents:
diff changeset
1218 return NULL_TREE;
kono
parents:
diff changeset
1219 }
kono
parents:
diff changeset
1220 }
kono
parents:
diff changeset
1221 else if (TREE_CODE (base) == MEM_REF)
kono
parents:
diff changeset
1222 {
kono
parents:
diff changeset
1223 if (!operand_equal_p (tci->instance, TREE_OPERAND (base, 0), 0))
kono
parents:
diff changeset
1224 {
kono
parents:
diff changeset
1225 if (dump_file)
kono
parents:
diff changeset
1226 {
kono
parents:
diff changeset
1227 fprintf (dump_file, " base mem ref:");
kono
parents:
diff changeset
1228 print_generic_expr (dump_file, base, TDF_SLIM);
kono
parents:
diff changeset
1229 fprintf (dump_file, " does not match instance:");
kono
parents:
diff changeset
1230 print_generic_expr (dump_file, tci->instance, TDF_SLIM);
kono
parents:
diff changeset
1231 fprintf (dump_file, "\n");
kono
parents:
diff changeset
1232 }
kono
parents:
diff changeset
1233 return NULL_TREE;
kono
parents:
diff changeset
1234 }
kono
parents:
diff changeset
1235 if (!integer_zerop (TREE_OPERAND (base, 1)))
kono
parents:
diff changeset
1236 {
kono
parents:
diff changeset
1237 if (!tree_fits_shwi_p (TREE_OPERAND (base, 1)))
kono
parents:
diff changeset
1238 {
kono
parents:
diff changeset
1239 if (dump_file)
kono
parents:
diff changeset
1240 {
kono
parents:
diff changeset
1241 fprintf (dump_file, " base mem ref:");
kono
parents:
diff changeset
1242 print_generic_expr (dump_file, base, TDF_SLIM);
kono
parents:
diff changeset
1243 fprintf (dump_file, " has non-representable offset:");
kono
parents:
diff changeset
1244 print_generic_expr (dump_file, tci->instance, TDF_SLIM);
kono
parents:
diff changeset
1245 fprintf (dump_file, "\n");
kono
parents:
diff changeset
1246 }
kono
parents:
diff changeset
1247 return NULL_TREE;
kono
parents:
diff changeset
1248 }
kono
parents:
diff changeset
1249 else
kono
parents:
diff changeset
1250 offset += tree_to_shwi (TREE_OPERAND (base, 1)) * BITS_PER_UNIT;
kono
parents:
diff changeset
1251 }
kono
parents:
diff changeset
1252 }
kono
parents:
diff changeset
1253 else if (!operand_equal_p (tci->instance, base, 0)
kono
parents:
diff changeset
1254 || tci->offset)
kono
parents:
diff changeset
1255 {
kono
parents:
diff changeset
1256 if (dump_file)
kono
parents:
diff changeset
1257 {
kono
parents:
diff changeset
1258 fprintf (dump_file, " base:");
kono
parents:
diff changeset
1259 print_generic_expr (dump_file, base, TDF_SLIM);
kono
parents:
diff changeset
1260 fprintf (dump_file, " does not match instance:");
kono
parents:
diff changeset
1261 print_generic_expr (dump_file, tci->instance, TDF_SLIM);
kono
parents:
diff changeset
1262 fprintf (dump_file, " with offset %i\n", (int)tci->offset);
kono
parents:
diff changeset
1263 }
kono
parents:
diff changeset
1264 return tci->offset > POINTER_SIZE ? error_mark_node : NULL_TREE;
kono
parents:
diff changeset
1265 }
kono
parents:
diff changeset
1266 if (offset != tci->offset
kono
parents:
diff changeset
1267 || size != POINTER_SIZE
kono
parents:
diff changeset
1268 || max_size != POINTER_SIZE)
kono
parents:
diff changeset
1269 {
kono
parents:
diff changeset
1270 if (dump_file)
kono
parents:
diff changeset
1271 fprintf (dump_file, " wrong offset %i!=%i or size %i\n",
kono
parents:
diff changeset
1272 (int)offset, (int)tci->offset, (int)size);
kono
parents:
diff changeset
1273 return offset + POINTER_SIZE <= tci->offset
kono
parents:
diff changeset
1274 || (max_size != -1
kono
parents:
diff changeset
1275 && tci->offset + POINTER_SIZE > offset + max_size)
kono
parents:
diff changeset
1276 ? error_mark_node : NULL;
kono
parents:
diff changeset
1277 }
kono
parents:
diff changeset
1278 }
kono
parents:
diff changeset
1279
kono
parents:
diff changeset
1280 tree vtable;
kono
parents:
diff changeset
1281 unsigned HOST_WIDE_INT offset2;
kono
parents:
diff changeset
1282
kono
parents:
diff changeset
1283 if (!vtable_pointer_value_to_vtable (rhs, &vtable, &offset2))
kono
parents:
diff changeset
1284 {
kono
parents:
diff changeset
1285 if (dump_file)
kono
parents:
diff changeset
1286 fprintf (dump_file, " Failed to lookup binfo\n");
kono
parents:
diff changeset
1287 return NULL;
kono
parents:
diff changeset
1288 }
kono
parents:
diff changeset
1289
kono
parents:
diff changeset
1290 tree binfo = subbinfo_with_vtable_at_offset (TYPE_BINFO (DECL_CONTEXT (vtable)),
kono
parents:
diff changeset
1291 offset2, vtable);
kono
parents:
diff changeset
1292 if (!binfo)
kono
parents:
diff changeset
1293 {
kono
parents:
diff changeset
1294 if (dump_file)
kono
parents:
diff changeset
1295 fprintf (dump_file, " Construction vtable used\n");
kono
parents:
diff changeset
1296 /* FIXME: We should suport construction contexts. */
kono
parents:
diff changeset
1297 return NULL;
kono
parents:
diff changeset
1298 }
kono
parents:
diff changeset
1299
kono
parents:
diff changeset
1300 *type_offset = tree_to_shwi (BINFO_OFFSET (binfo)) * BITS_PER_UNIT;
kono
parents:
diff changeset
1301 return DECL_CONTEXT (vtable);
kono
parents:
diff changeset
1302 }
kono
parents:
diff changeset
1303
kono
parents:
diff changeset
1304 /* Record dynamic type change of TCI to TYPE. */
kono
parents:
diff changeset
1305
kono
parents:
diff changeset
1306 static void
kono
parents:
diff changeset
1307 record_known_type (struct type_change_info *tci, tree type, HOST_WIDE_INT offset)
kono
parents:
diff changeset
1308 {
kono
parents:
diff changeset
1309 if (dump_file)
kono
parents:
diff changeset
1310 {
kono
parents:
diff changeset
1311 if (type)
kono
parents:
diff changeset
1312 {
kono
parents:
diff changeset
1313 fprintf (dump_file, " Recording type: ");
kono
parents:
diff changeset
1314 print_generic_expr (dump_file, type, TDF_SLIM);
kono
parents:
diff changeset
1315 fprintf (dump_file, " at offset %i\n", (int)offset);
kono
parents:
diff changeset
1316 }
kono
parents:
diff changeset
1317 else
kono
parents:
diff changeset
1318 fprintf (dump_file, " Recording unknown type\n");
kono
parents:
diff changeset
1319 }
kono
parents:
diff changeset
1320
kono
parents:
diff changeset
1321 /* If we found a constructor of type that is not polymorphic or
kono
parents:
diff changeset
1322 that may contain the type in question as a field (not as base),
kono
parents:
diff changeset
1323 restrict to the inner class first to make type matching bellow
kono
parents:
diff changeset
1324 happier. */
kono
parents:
diff changeset
1325 if (type
kono
parents:
diff changeset
1326 && (offset
kono
parents:
diff changeset
1327 || (TREE_CODE (type) != RECORD_TYPE
kono
parents:
diff changeset
1328 || !TYPE_BINFO (type)
kono
parents:
diff changeset
1329 || !polymorphic_type_binfo_p (TYPE_BINFO (type)))))
kono
parents:
diff changeset
1330 {
kono
parents:
diff changeset
1331 ipa_polymorphic_call_context context;
kono
parents:
diff changeset
1332
kono
parents:
diff changeset
1333 context.offset = offset;
kono
parents:
diff changeset
1334 context.outer_type = type;
kono
parents:
diff changeset
1335 context.maybe_in_construction = false;
kono
parents:
diff changeset
1336 context.maybe_derived_type = false;
kono
parents:
diff changeset
1337 context.dynamic = true;
kono
parents:
diff changeset
1338 /* If we failed to find the inner type, we know that the call
kono
parents:
diff changeset
1339 would be undefined for type produced here. */
kono
parents:
diff changeset
1340 if (!context.restrict_to_inner_class (tci->otr_type))
kono
parents:
diff changeset
1341 {
kono
parents:
diff changeset
1342 if (dump_file)
kono
parents:
diff changeset
1343 fprintf (dump_file, " Ignoring; does not contain otr_type\n");
kono
parents:
diff changeset
1344 return;
kono
parents:
diff changeset
1345 }
kono
parents:
diff changeset
1346 /* Watch for case we reached an POD type and anticipate placement
kono
parents:
diff changeset
1347 new. */
kono
parents:
diff changeset
1348 if (!context.maybe_derived_type)
kono
parents:
diff changeset
1349 {
kono
parents:
diff changeset
1350 type = context.outer_type;
kono
parents:
diff changeset
1351 offset = context.offset;
kono
parents:
diff changeset
1352 }
kono
parents:
diff changeset
1353 }
kono
parents:
diff changeset
1354 if (tci->type_maybe_changed
kono
parents:
diff changeset
1355 && (!types_same_for_odr (type, tci->known_current_type)
kono
parents:
diff changeset
1356 || offset != tci->known_current_offset))
kono
parents:
diff changeset
1357 tci->multiple_types_encountered = true;
kono
parents:
diff changeset
1358 tci->known_current_type = TYPE_MAIN_VARIANT (type);
kono
parents:
diff changeset
1359 tci->known_current_offset = offset;
kono
parents:
diff changeset
1360 tci->type_maybe_changed = true;
kono
parents:
diff changeset
1361 }
kono
parents:
diff changeset
1362
kono
parents:
diff changeset
1363
kono
parents:
diff changeset
1364 /* The maximum number of may-defs we visit when looking for a must-def
kono
parents:
diff changeset
1365 that changes the dynamic type in check_stmt_for_type_change. Tuned
kono
parents:
diff changeset
1366 after the PR12392 testcase which unlimited spends 40% time within
kono
parents:
diff changeset
1367 these alias walks and 8% with the following limit. */
kono
parents:
diff changeset
1368
kono
parents:
diff changeset
1369 static inline bool
kono
parents:
diff changeset
1370 csftc_abort_walking_p (unsigned speculative)
kono
parents:
diff changeset
1371 {
kono
parents:
diff changeset
1372 unsigned max = PARAM_VALUE (PARAM_MAX_SPECULATIVE_DEVIRT_MAYDEFS);
kono
parents:
diff changeset
1373 return speculative > max ? true : false;
kono
parents:
diff changeset
1374 }
kono
parents:
diff changeset
1375
kono
parents:
diff changeset
1376 /* Callback of walk_aliased_vdefs and a helper function for
kono
parents:
diff changeset
1377 detect_type_change to check whether a particular statement may modify
kono
parents:
diff changeset
1378 the virtual table pointer, and if possible also determine the new type of
kono
parents:
diff changeset
1379 the (sub-)object. It stores its result into DATA, which points to a
kono
parents:
diff changeset
1380 type_change_info structure. */
kono
parents:
diff changeset
1381
kono
parents:
diff changeset
1382 static bool
kono
parents:
diff changeset
1383 check_stmt_for_type_change (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef, void *data)
kono
parents:
diff changeset
1384 {
kono
parents:
diff changeset
1385 gimple *stmt = SSA_NAME_DEF_STMT (vdef);
kono
parents:
diff changeset
1386 struct type_change_info *tci = (struct type_change_info *) data;
kono
parents:
diff changeset
1387 tree fn;
kono
parents:
diff changeset
1388
kono
parents:
diff changeset
1389 /* If we already gave up, just terminate the rest of walk. */
kono
parents:
diff changeset
1390 if (tci->multiple_types_encountered)
kono
parents:
diff changeset
1391 return true;
kono
parents:
diff changeset
1392
kono
parents:
diff changeset
1393 if (is_gimple_call (stmt))
kono
parents:
diff changeset
1394 {
kono
parents:
diff changeset
1395 if (gimple_call_flags (stmt) & (ECF_CONST | ECF_PURE))
kono
parents:
diff changeset
1396 return false;
kono
parents:
diff changeset
1397
kono
parents:
diff changeset
1398 /* Check for a constructor call. */
kono
parents:
diff changeset
1399 if ((fn = gimple_call_fndecl (stmt)) != NULL_TREE
kono
parents:
diff changeset
1400 && DECL_CXX_CONSTRUCTOR_P (fn)
kono
parents:
diff changeset
1401 && TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE
kono
parents:
diff changeset
1402 && gimple_call_num_args (stmt))
kono
parents:
diff changeset
1403 {
kono
parents:
diff changeset
1404 tree op = walk_ssa_copies (gimple_call_arg (stmt, 0));
kono
parents:
diff changeset
1405 tree type = TYPE_METHOD_BASETYPE (TREE_TYPE (fn));
kono
parents:
diff changeset
1406 HOST_WIDE_INT offset = 0, size, max_size;
kono
parents:
diff changeset
1407 bool reverse;
kono
parents:
diff changeset
1408
kono
parents:
diff changeset
1409 if (dump_file)
kono
parents:
diff changeset
1410 {
kono
parents:
diff changeset
1411 fprintf (dump_file, " Checking constructor call: ");
kono
parents:
diff changeset
1412 print_gimple_stmt (dump_file, stmt, 0);
kono
parents:
diff changeset
1413 }
kono
parents:
diff changeset
1414
kono
parents:
diff changeset
1415 /* See if THIS parameter seems like instance pointer. */
kono
parents:
diff changeset
1416 if (TREE_CODE (op) == ADDR_EXPR)
kono
parents:
diff changeset
1417 {
kono
parents:
diff changeset
1418 op = get_ref_base_and_extent (TREE_OPERAND (op, 0), &offset,
kono
parents:
diff changeset
1419 &size, &max_size, &reverse);
kono
parents:
diff changeset
1420 if (size != max_size || max_size == -1)
kono
parents:
diff changeset
1421 {
kono
parents:
diff changeset
1422 tci->speculative++;
kono
parents:
diff changeset
1423 return csftc_abort_walking_p (tci->speculative);
kono
parents:
diff changeset
1424 }
kono
parents:
diff changeset
1425 if (op && TREE_CODE (op) == MEM_REF)
kono
parents:
diff changeset
1426 {
kono
parents:
diff changeset
1427 if (!tree_fits_shwi_p (TREE_OPERAND (op, 1)))
kono
parents:
diff changeset
1428 {
kono
parents:
diff changeset
1429 tci->speculative++;
kono
parents:
diff changeset
1430 return csftc_abort_walking_p (tci->speculative);
kono
parents:
diff changeset
1431 }
kono
parents:
diff changeset
1432 offset += tree_to_shwi (TREE_OPERAND (op, 1))
kono
parents:
diff changeset
1433 * BITS_PER_UNIT;
kono
parents:
diff changeset
1434 op = TREE_OPERAND (op, 0);
kono
parents:
diff changeset
1435 }
kono
parents:
diff changeset
1436 else if (DECL_P (op))
kono
parents:
diff changeset
1437 ;
kono
parents:
diff changeset
1438 else
kono
parents:
diff changeset
1439 {
kono
parents:
diff changeset
1440 tci->speculative++;
kono
parents:
diff changeset
1441 return csftc_abort_walking_p (tci->speculative);
kono
parents:
diff changeset
1442 }
kono
parents:
diff changeset
1443 op = walk_ssa_copies (op);
kono
parents:
diff changeset
1444 }
kono
parents:
diff changeset
1445 if (operand_equal_p (op, tci->instance, 0)
kono
parents:
diff changeset
1446 && TYPE_SIZE (type)
kono
parents:
diff changeset
1447 && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
kono
parents:
diff changeset
1448 && tree_fits_shwi_p (TYPE_SIZE (type))
kono
parents:
diff changeset
1449 && tree_to_shwi (TYPE_SIZE (type)) + offset > tci->offset
kono
parents:
diff changeset
1450 /* Some inlined constructors may look as follows:
kono
parents:
diff changeset
1451 _3 = operator new (16);
kono
parents:
diff changeset
1452 MEM[(struct &)_3] ={v} {CLOBBER};
kono
parents:
diff changeset
1453 MEM[(struct CompositeClass *)_3]._vptr.CompositeClass
kono
parents:
diff changeset
1454 = &MEM[(void *)&_ZTV14CompositeClass + 16B];
kono
parents:
diff changeset
1455 _7 = &MEM[(struct CompositeClass *)_3].object;
kono
parents:
diff changeset
1456 EmptyClass::EmptyClass (_7);
kono
parents:
diff changeset
1457
kono
parents:
diff changeset
1458 When determining dynamic type of _3 and because we stop at first
kono
parents:
diff changeset
1459 dynamic type found, we would stop on EmptyClass::EmptyClass (_7).
kono
parents:
diff changeset
1460 In this case the emptyclass is not even polymorphic and we miss
kono
parents:
diff changeset
1461 it is contained in an outer type that is polymorphic. */
kono
parents:
diff changeset
1462
kono
parents:
diff changeset
1463 && (tci->offset == offset || contains_polymorphic_type_p (type)))
kono
parents:
diff changeset
1464 {
kono
parents:
diff changeset
1465 record_known_type (tci, type, tci->offset - offset);
kono
parents:
diff changeset
1466 return true;
kono
parents:
diff changeset
1467 }
kono
parents:
diff changeset
1468 }
kono
parents:
diff changeset
1469 /* Calls may possibly change dynamic type by placement new. Assume
kono
parents:
diff changeset
1470 it will not happen, but make result speculative only. */
kono
parents:
diff changeset
1471 if (dump_file)
kono
parents:
diff changeset
1472 {
kono
parents:
diff changeset
1473 fprintf (dump_file, " Function call may change dynamic type:");
kono
parents:
diff changeset
1474 print_gimple_stmt (dump_file, stmt, 0);
kono
parents:
diff changeset
1475 }
kono
parents:
diff changeset
1476 tci->speculative++;
kono
parents:
diff changeset
1477 return csftc_abort_walking_p (tci->speculative);
kono
parents:
diff changeset
1478 }
kono
parents:
diff changeset
1479 /* Check for inlined virtual table store. */
kono
parents:
diff changeset
1480 else if (noncall_stmt_may_be_vtbl_ptr_store (stmt))
kono
parents:
diff changeset
1481 {
kono
parents:
diff changeset
1482 tree type;
kono
parents:
diff changeset
1483 HOST_WIDE_INT offset = 0;
kono
parents:
diff changeset
1484 if (dump_file)
kono
parents:
diff changeset
1485 {
kono
parents:
diff changeset
1486 fprintf (dump_file, " Checking vtbl store: ");
kono
parents:
diff changeset
1487 print_gimple_stmt (dump_file, stmt, 0);
kono
parents:
diff changeset
1488 }
kono
parents:
diff changeset
1489
kono
parents:
diff changeset
1490 type = extr_type_from_vtbl_ptr_store (stmt, tci, &offset);
kono
parents:
diff changeset
1491 if (type == error_mark_node)
kono
parents:
diff changeset
1492 return false;
kono
parents:
diff changeset
1493 gcc_assert (!type || TYPE_MAIN_VARIANT (type) == type);
kono
parents:
diff changeset
1494 if (!type)
kono
parents:
diff changeset
1495 {
kono
parents:
diff changeset
1496 if (dump_file)
kono
parents:
diff changeset
1497 fprintf (dump_file, " Unanalyzed store may change type.\n");
kono
parents:
diff changeset
1498 tci->seen_unanalyzed_store = true;
kono
parents:
diff changeset
1499 tci->speculative++;
kono
parents:
diff changeset
1500 }
kono
parents:
diff changeset
1501 else
kono
parents:
diff changeset
1502 record_known_type (tci, type, offset);
kono
parents:
diff changeset
1503 return true;
kono
parents:
diff changeset
1504 }
kono
parents:
diff changeset
1505 else
kono
parents:
diff changeset
1506 return false;
kono
parents:
diff changeset
1507 }
kono
parents:
diff changeset
1508
kono
parents:
diff changeset
1509 /* THIS is polymorphic call context obtained from get_polymorphic_context.
kono
parents:
diff changeset
1510 OTR_OBJECT is pointer to the instance returned by OBJ_TYPE_REF_OBJECT.
kono
parents:
diff changeset
1511 INSTANCE is pointer to the outer instance as returned by
kono
parents:
diff changeset
1512 get_polymorphic_context. To avoid creation of temporary expressions,
kono
parents:
diff changeset
1513 INSTANCE may also be an declaration of get_polymorphic_context found the
kono
parents:
diff changeset
1514 value to be in static storage.
kono
parents:
diff changeset
1515
kono
parents:
diff changeset
1516 If the type of instance is not fully determined
kono
parents:
diff changeset
1517 (either OUTER_TYPE is unknown or MAYBE_IN_CONSTRUCTION/INCLUDE_DERIVED_TYPES
kono
parents:
diff changeset
1518 is set), try to walk memory writes and find the actual construction of the
kono
parents:
diff changeset
1519 instance.
kono
parents:
diff changeset
1520
kono
parents:
diff changeset
1521 Return true if memory is unchanged from function entry.
kono
parents:
diff changeset
1522
kono
parents:
diff changeset
1523 We do not include this analysis in the context analysis itself, because
kono
parents:
diff changeset
1524 it needs memory SSA to be fully built and the walk may be expensive.
kono
parents:
diff changeset
1525 So it is not suitable for use withing fold_stmt and similar uses. */
kono
parents:
diff changeset
1526
kono
parents:
diff changeset
1527 bool
kono
parents:
diff changeset
1528 ipa_polymorphic_call_context::get_dynamic_type (tree instance,
kono
parents:
diff changeset
1529 tree otr_object,
kono
parents:
diff changeset
1530 tree otr_type,
kono
parents:
diff changeset
1531 gimple *call)
kono
parents:
diff changeset
1532 {
kono
parents:
diff changeset
1533 struct type_change_info tci;
kono
parents:
diff changeset
1534 ao_ref ao;
kono
parents:
diff changeset
1535 bool function_entry_reached = false;
kono
parents:
diff changeset
1536 tree instance_ref = NULL;
kono
parents:
diff changeset
1537 gimple *stmt = call;
kono
parents:
diff changeset
1538 /* Remember OFFSET before it is modified by restrict_to_inner_class.
kono
parents:
diff changeset
1539 This is because we do not update INSTANCE when walking inwards. */
kono
parents:
diff changeset
1540 HOST_WIDE_INT instance_offset = offset;
kono
parents:
diff changeset
1541 tree instance_outer_type = outer_type;
kono
parents:
diff changeset
1542
kono
parents:
diff changeset
1543 if (otr_type)
kono
parents:
diff changeset
1544 otr_type = TYPE_MAIN_VARIANT (otr_type);
kono
parents:
diff changeset
1545
kono
parents:
diff changeset
1546 /* Walk into inner type. This may clear maybe_derived_type and save us
kono
parents:
diff changeset
1547 from useless work. It also makes later comparsions with static type
kono
parents:
diff changeset
1548 easier. */
kono
parents:
diff changeset
1549 if (outer_type && otr_type)
kono
parents:
diff changeset
1550 {
kono
parents:
diff changeset
1551 if (!restrict_to_inner_class (otr_type))
kono
parents:
diff changeset
1552 return false;
kono
parents:
diff changeset
1553 }
kono
parents:
diff changeset
1554
kono
parents:
diff changeset
1555 if (!maybe_in_construction && !maybe_derived_type)
kono
parents:
diff changeset
1556 return false;
kono
parents:
diff changeset
1557
kono
parents:
diff changeset
1558 /* If we are in fact not looking at any object object or the instance is
kono
parents:
diff changeset
1559 some placement new into a random load, give up straight away. */
kono
parents:
diff changeset
1560 if (TREE_CODE (instance) == MEM_REF)
kono
parents:
diff changeset
1561 return false;
kono
parents:
diff changeset
1562
kono
parents:
diff changeset
1563 /* We need to obtain refernce to virtual table pointer. It is better
kono
parents:
diff changeset
1564 to look it up in the code rather than build our own. This require bit
kono
parents:
diff changeset
1565 of pattern matching, but we end up verifying that what we found is
kono
parents:
diff changeset
1566 correct.
kono
parents:
diff changeset
1567
kono
parents:
diff changeset
1568 What we pattern match is:
kono
parents:
diff changeset
1569
kono
parents:
diff changeset
1570 tmp = instance->_vptr.A; // vtbl ptr load
kono
parents:
diff changeset
1571 tmp2 = tmp[otr_token]; // vtable lookup
kono
parents:
diff changeset
1572 OBJ_TYPE_REF(tmp2;instance->0) (instance);
kono
parents:
diff changeset
1573
kono
parents:
diff changeset
1574 We want to start alias oracle walk from vtbl pointer load,
kono
parents:
diff changeset
1575 but we may not be able to identify it, for example, when PRE moved the
kono
parents:
diff changeset
1576 load around. */
kono
parents:
diff changeset
1577
kono
parents:
diff changeset
1578 if (gimple_code (call) == GIMPLE_CALL)
kono
parents:
diff changeset
1579 {
kono
parents:
diff changeset
1580 tree ref = gimple_call_fn (call);
kono
parents:
diff changeset
1581 HOST_WIDE_INT offset2, size, max_size;
kono
parents:
diff changeset
1582 bool reverse;
kono
parents:
diff changeset
1583
kono
parents:
diff changeset
1584 if (TREE_CODE (ref) == OBJ_TYPE_REF)
kono
parents:
diff changeset
1585 {
kono
parents:
diff changeset
1586 ref = OBJ_TYPE_REF_EXPR (ref);
kono
parents:
diff changeset
1587 ref = walk_ssa_copies (ref);
kono
parents:
diff changeset
1588
kono
parents:
diff changeset
1589 /* If call target is already known, no need to do the expensive
kono
parents:
diff changeset
1590 memory walk. */
kono
parents:
diff changeset
1591 if (is_gimple_min_invariant (ref))
kono
parents:
diff changeset
1592 return false;
kono
parents:
diff changeset
1593
kono
parents:
diff changeset
1594 /* Check if definition looks like vtable lookup. */
kono
parents:
diff changeset
1595 if (TREE_CODE (ref) == SSA_NAME
kono
parents:
diff changeset
1596 && !SSA_NAME_IS_DEFAULT_DEF (ref)
kono
parents:
diff changeset
1597 && gimple_assign_load_p (SSA_NAME_DEF_STMT (ref))
kono
parents:
diff changeset
1598 && TREE_CODE (gimple_assign_rhs1
kono
parents:
diff changeset
1599 (SSA_NAME_DEF_STMT (ref))) == MEM_REF)
kono
parents:
diff changeset
1600 {
kono
parents:
diff changeset
1601 ref = get_base_address
kono
parents:
diff changeset
1602 (TREE_OPERAND (gimple_assign_rhs1
kono
parents:
diff changeset
1603 (SSA_NAME_DEF_STMT (ref)), 0));
kono
parents:
diff changeset
1604 ref = walk_ssa_copies (ref);
kono
parents:
diff changeset
1605 /* Find base address of the lookup and see if it looks like
kono
parents:
diff changeset
1606 vptr load. */
kono
parents:
diff changeset
1607 if (TREE_CODE (ref) == SSA_NAME
kono
parents:
diff changeset
1608 && !SSA_NAME_IS_DEFAULT_DEF (ref)
kono
parents:
diff changeset
1609 && gimple_assign_load_p (SSA_NAME_DEF_STMT (ref)))
kono
parents:
diff changeset
1610 {
kono
parents:
diff changeset
1611 tree ref_exp = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (ref));
kono
parents:
diff changeset
1612 tree base_ref
kono
parents:
diff changeset
1613 = get_ref_base_and_extent (ref_exp, &offset2, &size,
kono
parents:
diff changeset
1614 &max_size, &reverse);
kono
parents:
diff changeset
1615
kono
parents:
diff changeset
1616 /* Finally verify that what we found looks like read from
kono
parents:
diff changeset
1617 OTR_OBJECT or from INSTANCE with offset OFFSET. */
kono
parents:
diff changeset
1618 if (base_ref
kono
parents:
diff changeset
1619 && ((TREE_CODE (base_ref) == MEM_REF
kono
parents:
diff changeset
1620 && ((offset2 == instance_offset
kono
parents:
diff changeset
1621 && TREE_OPERAND (base_ref, 0) == instance)
kono
parents:
diff changeset
1622 || (!offset2
kono
parents:
diff changeset
1623 && TREE_OPERAND (base_ref, 0)
kono
parents:
diff changeset
1624 == otr_object)))
kono
parents:
diff changeset
1625 || (DECL_P (instance) && base_ref == instance
kono
parents:
diff changeset
1626 && offset2 == instance_offset)))
kono
parents:
diff changeset
1627 {
kono
parents:
diff changeset
1628 stmt = SSA_NAME_DEF_STMT (ref);
kono
parents:
diff changeset
1629 instance_ref = ref_exp;
kono
parents:
diff changeset
1630 }
kono
parents:
diff changeset
1631 }
kono
parents:
diff changeset
1632 }
kono
parents:
diff changeset
1633 }
kono
parents:
diff changeset
1634 }
kono
parents:
diff changeset
1635
kono
parents:
diff changeset
1636 /* If we failed to look up the reference in code, build our own. */
kono
parents:
diff changeset
1637 if (!instance_ref)
kono
parents:
diff changeset
1638 {
kono
parents:
diff changeset
1639 /* If the statement in question does not use memory, we can't tell
kono
parents:
diff changeset
1640 anything. */
kono
parents:
diff changeset
1641 if (!gimple_vuse (stmt))
kono
parents:
diff changeset
1642 return false;
kono
parents:
diff changeset
1643 ao_ref_init_from_ptr_and_size (&ao, otr_object, NULL);
kono
parents:
diff changeset
1644 }
kono
parents:
diff changeset
1645 else
kono
parents:
diff changeset
1646 /* Otherwise use the real reference. */
kono
parents:
diff changeset
1647 ao_ref_init (&ao, instance_ref);
kono
parents:
diff changeset
1648
kono
parents:
diff changeset
1649 /* We look for vtbl pointer read. */
kono
parents:
diff changeset
1650 ao.size = POINTER_SIZE;
kono
parents:
diff changeset
1651 ao.max_size = ao.size;
kono
parents:
diff changeset
1652 /* We are looking for stores to vptr pointer within the instance of
kono
parents:
diff changeset
1653 outer type.
kono
parents:
diff changeset
1654 TODO: The vptr pointer type is globally known, we probably should
kono
parents:
diff changeset
1655 keep it and do that even when otr_type is unknown. */
kono
parents:
diff changeset
1656 if (otr_type)
kono
parents:
diff changeset
1657 {
kono
parents:
diff changeset
1658 ao.base_alias_set
kono
parents:
diff changeset
1659 = get_alias_set (outer_type ? outer_type : otr_type);
kono
parents:
diff changeset
1660 ao.ref_alias_set
kono
parents:
diff changeset
1661 = get_alias_set (TREE_TYPE (BINFO_VTABLE (TYPE_BINFO (otr_type))));
kono
parents:
diff changeset
1662 }
kono
parents:
diff changeset
1663
kono
parents:
diff changeset
1664 if (dump_file)
kono
parents:
diff changeset
1665 {
kono
parents:
diff changeset
1666 fprintf (dump_file, "Determining dynamic type for call: ");
kono
parents:
diff changeset
1667 print_gimple_stmt (dump_file, call, 0);
kono
parents:
diff changeset
1668 fprintf (dump_file, " Starting walk at: ");
kono
parents:
diff changeset
1669 print_gimple_stmt (dump_file, stmt, 0);
kono
parents:
diff changeset
1670 fprintf (dump_file, " instance pointer: ");
kono
parents:
diff changeset
1671 print_generic_expr (dump_file, otr_object, TDF_SLIM);
kono
parents:
diff changeset
1672 fprintf (dump_file, " Outer instance pointer: ");
kono
parents:
diff changeset
1673 print_generic_expr (dump_file, instance, TDF_SLIM);
kono
parents:
diff changeset
1674 fprintf (dump_file, " offset: %i (bits)", (int)instance_offset);
kono
parents:
diff changeset
1675 fprintf (dump_file, " vtbl reference: ");
kono
parents:
diff changeset
1676 print_generic_expr (dump_file, instance_ref, TDF_SLIM);
kono
parents:
diff changeset
1677 fprintf (dump_file, "\n");
kono
parents:
diff changeset
1678 }
kono
parents:
diff changeset
1679
kono
parents:
diff changeset
1680 tci.offset = instance_offset;
kono
parents:
diff changeset
1681 tci.instance = instance;
kono
parents:
diff changeset
1682 tci.vtbl_ptr_ref = instance_ref;
kono
parents:
diff changeset
1683 tci.known_current_type = NULL_TREE;
kono
parents:
diff changeset
1684 tci.known_current_offset = 0;
kono
parents:
diff changeset
1685 tci.otr_type = otr_type;
kono
parents:
diff changeset
1686 tci.type_maybe_changed = false;
kono
parents:
diff changeset
1687 tci.multiple_types_encountered = false;
kono
parents:
diff changeset
1688 tci.speculative = 0;
kono
parents:
diff changeset
1689 tci.seen_unanalyzed_store = false;
kono
parents:
diff changeset
1690
kono
parents:
diff changeset
1691 walk_aliased_vdefs (&ao, gimple_vuse (stmt), check_stmt_for_type_change,
kono
parents:
diff changeset
1692 &tci, NULL, &function_entry_reached);
kono
parents:
diff changeset
1693
kono
parents:
diff changeset
1694 /* If we did not find any type changing statements, we may still drop
kono
parents:
diff changeset
1695 maybe_in_construction flag if the context already have outer type.
kono
parents:
diff changeset
1696
kono
parents:
diff changeset
1697 Here we make special assumptions about both constructors and
kono
parents:
diff changeset
1698 destructors which are all the functions that are allowed to alter the
kono
parents:
diff changeset
1699 VMT pointers. It assumes that destructors begin with assignment into
kono
parents:
diff changeset
1700 all VMT pointers and that constructors essentially look in the
kono
parents:
diff changeset
1701 following way:
kono
parents:
diff changeset
1702
kono
parents:
diff changeset
1703 1) The very first thing they do is that they call constructors of
kono
parents:
diff changeset
1704 ancestor sub-objects that have them.
kono
parents:
diff changeset
1705
kono
parents:
diff changeset
1706 2) Then VMT pointers of this and all its ancestors is set to new
kono
parents:
diff changeset
1707 values corresponding to the type corresponding to the constructor.
kono
parents:
diff changeset
1708
kono
parents:
diff changeset
1709 3) Only afterwards, other stuff such as constructor of member
kono
parents:
diff changeset
1710 sub-objects and the code written by the user is run. Only this may
kono
parents:
diff changeset
1711 include calling virtual functions, directly or indirectly.
kono
parents:
diff changeset
1712
kono
parents:
diff changeset
1713 4) placement new can not be used to change type of non-POD statically
kono
parents:
diff changeset
1714 allocated variables.
kono
parents:
diff changeset
1715
kono
parents:
diff changeset
1716 There is no way to call a constructor of an ancestor sub-object in any
kono
parents:
diff changeset
1717 other way.
kono
parents:
diff changeset
1718
kono
parents:
diff changeset
1719 This means that we do not have to care whether constructors get the
kono
parents:
diff changeset
1720 correct type information because they will always change it (in fact,
kono
parents:
diff changeset
1721 if we define the type to be given by the VMT pointer, it is undefined).
kono
parents:
diff changeset
1722
kono
parents:
diff changeset
1723 The most important fact to derive from the above is that if, for some
kono
parents:
diff changeset
1724 statement in the section 3, we try to detect whether the dynamic type
kono
parents:
diff changeset
1725 has changed, we can safely ignore all calls as we examine the function
kono
parents:
diff changeset
1726 body backwards until we reach statements in section 2 because these
kono
parents:
diff changeset
1727 calls cannot be ancestor constructors or destructors (if the input is
kono
parents:
diff changeset
1728 not bogus) and so do not change the dynamic type (this holds true only
kono
parents:
diff changeset
1729 for automatically allocated objects but at the moment we devirtualize
kono
parents:
diff changeset
1730 only these). We then must detect that statements in section 2 change
kono
parents:
diff changeset
1731 the dynamic type and can try to derive the new type. That is enough
kono
parents:
diff changeset
1732 and we can stop, we will never see the calls into constructors of
kono
parents:
diff changeset
1733 sub-objects in this code.
kono
parents:
diff changeset
1734
kono
parents:
diff changeset
1735 Therefore if the static outer type was found (outer_type)
kono
parents:
diff changeset
1736 we can safely ignore tci.speculative that is set on calls and give up
kono
parents:
diff changeset
1737 only if there was dyanmic type store that may affect given variable
kono
parents:
diff changeset
1738 (seen_unanalyzed_store) */
kono
parents:
diff changeset
1739
kono
parents:
diff changeset
1740 if (!tci.type_maybe_changed
kono
parents:
diff changeset
1741 || (outer_type
kono
parents:
diff changeset
1742 && !dynamic
kono
parents:
diff changeset
1743 && !tci.seen_unanalyzed_store
kono
parents:
diff changeset
1744 && !tci.multiple_types_encountered
kono
parents:
diff changeset
1745 && ((offset == tci.offset
kono
parents:
diff changeset
1746 && types_same_for_odr (tci.known_current_type,
kono
parents:
diff changeset
1747 outer_type))
kono
parents:
diff changeset
1748 || (instance_offset == offset
kono
parents:
diff changeset
1749 && types_same_for_odr (tci.known_current_type,
kono
parents:
diff changeset
1750 instance_outer_type)))))
kono
parents:
diff changeset
1751 {
kono
parents:
diff changeset
1752 if (!outer_type || tci.seen_unanalyzed_store)
kono
parents:
diff changeset
1753 return false;
kono
parents:
diff changeset
1754 if (maybe_in_construction)
kono
parents:
diff changeset
1755 maybe_in_construction = false;
kono
parents:
diff changeset
1756 if (dump_file)
kono
parents:
diff changeset
1757 fprintf (dump_file, " No dynamic type change found.\n");
kono
parents:
diff changeset
1758 return true;
kono
parents:
diff changeset
1759 }
kono
parents:
diff changeset
1760
kono
parents:
diff changeset
1761 if (tci.known_current_type
kono
parents:
diff changeset
1762 && !function_entry_reached
kono
parents:
diff changeset
1763 && !tci.multiple_types_encountered)
kono
parents:
diff changeset
1764 {
kono
parents:
diff changeset
1765 if (!tci.speculative)
kono
parents:
diff changeset
1766 {
kono
parents:
diff changeset
1767 outer_type = TYPE_MAIN_VARIANT (tci.known_current_type);
kono
parents:
diff changeset
1768 offset = tci.known_current_offset;
kono
parents:
diff changeset
1769 dynamic = true;
kono
parents:
diff changeset
1770 maybe_in_construction = false;
kono
parents:
diff changeset
1771 maybe_derived_type = false;
kono
parents:
diff changeset
1772 if (dump_file)
kono
parents:
diff changeset
1773 fprintf (dump_file, " Determined dynamic type.\n");
kono
parents:
diff changeset
1774 }
kono
parents:
diff changeset
1775 else if (!speculative_outer_type
kono
parents:
diff changeset
1776 || speculative_maybe_derived_type)
kono
parents:
diff changeset
1777 {
kono
parents:
diff changeset
1778 speculative_outer_type = TYPE_MAIN_VARIANT (tci.known_current_type);
kono
parents:
diff changeset
1779 speculative_offset = tci.known_current_offset;
kono
parents:
diff changeset
1780 speculative_maybe_derived_type = false;
kono
parents:
diff changeset
1781 if (dump_file)
kono
parents:
diff changeset
1782 fprintf (dump_file, " Determined speculative dynamic type.\n");
kono
parents:
diff changeset
1783 }
kono
parents:
diff changeset
1784 }
kono
parents:
diff changeset
1785 else if (dump_file)
kono
parents:
diff changeset
1786 {
kono
parents:
diff changeset
1787 fprintf (dump_file, " Found multiple types%s%s\n",
kono
parents:
diff changeset
1788 function_entry_reached ? " (function entry reached)" : "",
kono
parents:
diff changeset
1789 function_entry_reached ? " (multiple types encountered)" : "");
kono
parents:
diff changeset
1790 }
kono
parents:
diff changeset
1791
kono
parents:
diff changeset
1792 return false;
kono
parents:
diff changeset
1793 }
kono
parents:
diff changeset
1794
kono
parents:
diff changeset
1795 /* See if speculation given by SPEC_OUTER_TYPE, SPEC_OFFSET and SPEC_MAYBE_DERIVED_TYPE
kono
parents:
diff changeset
1796 seems consistent (and useful) with what we already have in the non-speculative context. */
kono
parents:
diff changeset
1797
kono
parents:
diff changeset
1798 bool
kono
parents:
diff changeset
1799 ipa_polymorphic_call_context::speculation_consistent_p (tree spec_outer_type,
kono
parents:
diff changeset
1800 HOST_WIDE_INT spec_offset,
kono
parents:
diff changeset
1801 bool spec_maybe_derived_type,
kono
parents:
diff changeset
1802 tree otr_type) const
kono
parents:
diff changeset
1803 {
kono
parents:
diff changeset
1804 if (!flag_devirtualize_speculatively)
kono
parents:
diff changeset
1805 return false;
kono
parents:
diff changeset
1806
kono
parents:
diff changeset
1807 /* Non-polymorphic types are useless for deriving likely polymorphic
kono
parents:
diff changeset
1808 call targets. */
kono
parents:
diff changeset
1809 if (!spec_outer_type || !contains_polymorphic_type_p (spec_outer_type))
kono
parents:
diff changeset
1810 return false;
kono
parents:
diff changeset
1811
kono
parents:
diff changeset
1812 /* If we know nothing, speculation is always good. */
kono
parents:
diff changeset
1813 if (!outer_type)
kono
parents:
diff changeset
1814 return true;
kono
parents:
diff changeset
1815
kono
parents:
diff changeset
1816 /* Speculation is only useful to avoid derived types.
kono
parents:
diff changeset
1817 This is not 100% true for placement new, where the outer context may
kono
parents:
diff changeset
1818 turn out to be useless, but ignore these for now. */
kono
parents:
diff changeset
1819 if (!maybe_derived_type)
kono
parents:
diff changeset
1820 return false;
kono
parents:
diff changeset
1821
kono
parents:
diff changeset
1822 /* If types agrees, speculation is consistent, but it makes sense only
kono
parents:
diff changeset
1823 when it says something new. */
kono
parents:
diff changeset
1824 if (types_must_be_same_for_odr (spec_outer_type, outer_type))
kono
parents:
diff changeset
1825 return maybe_derived_type && !spec_maybe_derived_type;
kono
parents:
diff changeset
1826
kono
parents:
diff changeset
1827 /* If speculation does not contain the type in question, ignore it. */
kono
parents:
diff changeset
1828 if (otr_type
kono
parents:
diff changeset
1829 && !contains_type_p (spec_outer_type, spec_offset, otr_type, false, true))
kono
parents:
diff changeset
1830 return false;
kono
parents:
diff changeset
1831
kono
parents:
diff changeset
1832 /* If outer type already contains speculation as a filed,
kono
parents:
diff changeset
1833 it is useless. We already know from OUTER_TYPE
kono
parents:
diff changeset
1834 SPEC_TYPE and that it is not in the construction. */
kono
parents:
diff changeset
1835 if (contains_type_p (outer_type, offset - spec_offset,
kono
parents:
diff changeset
1836 spec_outer_type, false, false))
kono
parents:
diff changeset
1837 return false;
kono
parents:
diff changeset
1838
kono
parents:
diff changeset
1839 /* If speculative outer type is not more specified than outer
kono
parents:
diff changeset
1840 type, just give up.
kono
parents:
diff changeset
1841 We can only decide this safely if we can compare types with OUTER_TYPE.
kono
parents:
diff changeset
1842 */
kono
parents:
diff changeset
1843 if ((!in_lto_p || odr_type_p (outer_type))
kono
parents:
diff changeset
1844 && !contains_type_p (spec_outer_type,
kono
parents:
diff changeset
1845 spec_offset - offset,
kono
parents:
diff changeset
1846 outer_type, false))
kono
parents:
diff changeset
1847 return false;
kono
parents:
diff changeset
1848 return true;
kono
parents:
diff changeset
1849 }
kono
parents:
diff changeset
1850
kono
parents:
diff changeset
1851 /* Improve THIS with speculation described by NEW_OUTER_TYPE, NEW_OFFSET,
kono
parents:
diff changeset
1852 NEW_MAYBE_DERIVED_TYPE
kono
parents:
diff changeset
1853 If OTR_TYPE is set, assume the context is used with OTR_TYPE. */
kono
parents:
diff changeset
1854
kono
parents:
diff changeset
1855 bool
kono
parents:
diff changeset
1856 ipa_polymorphic_call_context::combine_speculation_with
kono
parents:
diff changeset
1857 (tree new_outer_type, HOST_WIDE_INT new_offset, bool new_maybe_derived_type,
kono
parents:
diff changeset
1858 tree otr_type)
kono
parents:
diff changeset
1859 {
kono
parents:
diff changeset
1860 if (!new_outer_type)
kono
parents:
diff changeset
1861 return false;
kono
parents:
diff changeset
1862
kono
parents:
diff changeset
1863 /* restrict_to_inner_class may eliminate wrong speculation making our job
kono
parents:
diff changeset
1864 easeier. */
kono
parents:
diff changeset
1865 if (otr_type)
kono
parents:
diff changeset
1866 restrict_to_inner_class (otr_type);
kono
parents:
diff changeset
1867
kono
parents:
diff changeset
1868 if (!speculation_consistent_p (new_outer_type, new_offset,
kono
parents:
diff changeset
1869 new_maybe_derived_type, otr_type))
kono
parents:
diff changeset
1870 return false;
kono
parents:
diff changeset
1871
kono
parents:
diff changeset
1872 /* New speculation is a win in case we have no speculation or new
kono
parents:
diff changeset
1873 speculation does not consider derivations. */
kono
parents:
diff changeset
1874 if (!speculative_outer_type
kono
parents:
diff changeset
1875 || (speculative_maybe_derived_type
kono
parents:
diff changeset
1876 && !new_maybe_derived_type))
kono
parents:
diff changeset
1877 {
kono
parents:
diff changeset
1878 speculative_outer_type = new_outer_type;
kono
parents:
diff changeset
1879 speculative_offset = new_offset;
kono
parents:
diff changeset
1880 speculative_maybe_derived_type = new_maybe_derived_type;
kono
parents:
diff changeset
1881 return true;
kono
parents:
diff changeset
1882 }
kono
parents:
diff changeset
1883 else if (types_must_be_same_for_odr (speculative_outer_type,
kono
parents:
diff changeset
1884 new_outer_type))
kono
parents:
diff changeset
1885 {
kono
parents:
diff changeset
1886 if (speculative_offset != new_offset)
kono
parents:
diff changeset
1887 {
kono
parents:
diff changeset
1888 /* OK we have two contexts that seems valid but they disagree,
kono
parents:
diff changeset
1889 just give up.
kono
parents:
diff changeset
1890
kono
parents:
diff changeset
1891 This is not a lattice operation, so we may want to drop it later. */
kono
parents:
diff changeset
1892 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
1893 fprintf (dump_file,
kono
parents:
diff changeset
1894 "Speculative outer types match, "
kono
parents:
diff changeset
1895 "offset mismatch -> invalid speculation\n");
kono
parents:
diff changeset
1896 clear_speculation ();
kono
parents:
diff changeset
1897 return true;
kono
parents:
diff changeset
1898 }
kono
parents:
diff changeset
1899 else
kono
parents:
diff changeset
1900 {
kono
parents:
diff changeset
1901 if (speculative_maybe_derived_type && !new_maybe_derived_type)
kono
parents:
diff changeset
1902 {
kono
parents:
diff changeset
1903 speculative_maybe_derived_type = false;
kono
parents:
diff changeset
1904 return true;
kono
parents:
diff changeset
1905 }
kono
parents:
diff changeset
1906 else
kono
parents:
diff changeset
1907 return false;
kono
parents:
diff changeset
1908 }
kono
parents:
diff changeset
1909 }
kono
parents:
diff changeset
1910 /* Choose type that contains the other. This one either contains the outer
kono
parents:
diff changeset
1911 as a field (thus giving exactly one target) or is deeper in the type
kono
parents:
diff changeset
1912 hiearchy. */
kono
parents:
diff changeset
1913 else if (speculative_outer_type
kono
parents:
diff changeset
1914 && speculative_maybe_derived_type
kono
parents:
diff changeset
1915 && (new_offset > speculative_offset
kono
parents:
diff changeset
1916 || (new_offset == speculative_offset
kono
parents:
diff changeset
1917 && contains_type_p (new_outer_type,
kono
parents:
diff changeset
1918 0, speculative_outer_type, false))))
kono
parents:
diff changeset
1919 {
kono
parents:
diff changeset
1920 tree old_outer_type = speculative_outer_type;
kono
parents:
diff changeset
1921 HOST_WIDE_INT old_offset = speculative_offset;
kono
parents:
diff changeset
1922 bool old_maybe_derived_type = speculative_maybe_derived_type;
kono
parents:
diff changeset
1923
kono
parents:
diff changeset
1924 speculative_outer_type = new_outer_type;
kono
parents:
diff changeset
1925 speculative_offset = new_offset;
kono
parents:
diff changeset
1926 speculative_maybe_derived_type = new_maybe_derived_type;
kono
parents:
diff changeset
1927
kono
parents:
diff changeset
1928 if (otr_type)
kono
parents:
diff changeset
1929 restrict_to_inner_class (otr_type);
kono
parents:
diff changeset
1930
kono
parents:
diff changeset
1931 /* If the speculation turned out to make no sense, revert to sensible
kono
parents:
diff changeset
1932 one. */
kono
parents:
diff changeset
1933 if (!speculative_outer_type)
kono
parents:
diff changeset
1934 {
kono
parents:
diff changeset
1935 speculative_outer_type = old_outer_type;
kono
parents:
diff changeset
1936 speculative_offset = old_offset;
kono
parents:
diff changeset
1937 speculative_maybe_derived_type = old_maybe_derived_type;
kono
parents:
diff changeset
1938 return false;
kono
parents:
diff changeset
1939 }
kono
parents:
diff changeset
1940 return (old_offset != speculative_offset
kono
parents:
diff changeset
1941 || old_maybe_derived_type != speculative_maybe_derived_type
kono
parents:
diff changeset
1942 || types_must_be_same_for_odr (speculative_outer_type,
kono
parents:
diff changeset
1943 new_outer_type));
kono
parents:
diff changeset
1944 }
kono
parents:
diff changeset
1945 return false;
kono
parents:
diff changeset
1946 }
kono
parents:
diff changeset
1947
kono
parents:
diff changeset
1948 /* Make speculation less specific so
kono
parents:
diff changeset
1949 NEW_OUTER_TYPE, NEW_OFFSET, NEW_MAYBE_DERIVED_TYPE is also included.
kono
parents:
diff changeset
1950 If OTR_TYPE is set, assume the context is used with OTR_TYPE. */
kono
parents:
diff changeset
1951
kono
parents:
diff changeset
1952 bool
kono
parents:
diff changeset
1953 ipa_polymorphic_call_context::meet_speculation_with
kono
parents:
diff changeset
1954 (tree new_outer_type, HOST_WIDE_INT new_offset, bool new_maybe_derived_type,
kono
parents:
diff changeset
1955 tree otr_type)
kono
parents:
diff changeset
1956 {
kono
parents:
diff changeset
1957 if (!new_outer_type && speculative_outer_type)
kono
parents:
diff changeset
1958 {
kono
parents:
diff changeset
1959 clear_speculation ();
kono
parents:
diff changeset
1960 return true;
kono
parents:
diff changeset
1961 }
kono
parents:
diff changeset
1962
kono
parents:
diff changeset
1963 /* restrict_to_inner_class may eliminate wrong speculation making our job
kono
parents:
diff changeset
1964 easeier. */
kono
parents:
diff changeset
1965 if (otr_type)
kono
parents:
diff changeset
1966 restrict_to_inner_class (otr_type);
kono
parents:
diff changeset
1967
kono
parents:
diff changeset
1968 if (!speculative_outer_type
kono
parents:
diff changeset
1969 || !speculation_consistent_p (speculative_outer_type,
kono
parents:
diff changeset
1970 speculative_offset,
kono
parents:
diff changeset
1971 speculative_maybe_derived_type,
kono
parents:
diff changeset
1972 otr_type))
kono
parents:
diff changeset
1973 return false;
kono
parents:
diff changeset
1974
kono
parents:
diff changeset
1975 if (!speculation_consistent_p (new_outer_type, new_offset,
kono
parents:
diff changeset
1976 new_maybe_derived_type, otr_type))
kono
parents:
diff changeset
1977 {
kono
parents:
diff changeset
1978 clear_speculation ();
kono
parents:
diff changeset
1979 return true;
kono
parents:
diff changeset
1980 }
kono
parents:
diff changeset
1981
kono
parents:
diff changeset
1982 else if (types_must_be_same_for_odr (speculative_outer_type,
kono
parents:
diff changeset
1983 new_outer_type))
kono
parents:
diff changeset
1984 {
kono
parents:
diff changeset
1985 if (speculative_offset != new_offset)
kono
parents:
diff changeset
1986 {
kono
parents:
diff changeset
1987 clear_speculation ();
kono
parents:
diff changeset
1988 return true;
kono
parents:
diff changeset
1989 }
kono
parents:
diff changeset
1990 else
kono
parents:
diff changeset
1991 {
kono
parents:
diff changeset
1992 if (!speculative_maybe_derived_type && new_maybe_derived_type)
kono
parents:
diff changeset
1993 {
kono
parents:
diff changeset
1994 speculative_maybe_derived_type = true;
kono
parents:
diff changeset
1995 return true;
kono
parents:
diff changeset
1996 }
kono
parents:
diff changeset
1997 else
kono
parents:
diff changeset
1998 return false;
kono
parents:
diff changeset
1999 }
kono
parents:
diff changeset
2000 }
kono
parents:
diff changeset
2001 /* See if one type contains the other as a field (not base). */
kono
parents:
diff changeset
2002 else if (contains_type_p (new_outer_type, new_offset - speculative_offset,
kono
parents:
diff changeset
2003 speculative_outer_type, false, false))
kono
parents:
diff changeset
2004 return false;
kono
parents:
diff changeset
2005 else if (contains_type_p (speculative_outer_type,
kono
parents:
diff changeset
2006 speculative_offset - new_offset,
kono
parents:
diff changeset
2007 new_outer_type, false, false))
kono
parents:
diff changeset
2008 {
kono
parents:
diff changeset
2009 speculative_outer_type = new_outer_type;
kono
parents:
diff changeset
2010 speculative_offset = new_offset;
kono
parents:
diff changeset
2011 speculative_maybe_derived_type = new_maybe_derived_type;
kono
parents:
diff changeset
2012 return true;
kono
parents:
diff changeset
2013 }
kono
parents:
diff changeset
2014 /* See if OUTER_TYPE is base of CTX.OUTER_TYPE. */
kono
parents:
diff changeset
2015 else if (contains_type_p (new_outer_type,
kono
parents:
diff changeset
2016 new_offset - speculative_offset,
kono
parents:
diff changeset
2017 speculative_outer_type, false, true))
kono
parents:
diff changeset
2018 {
kono
parents:
diff changeset
2019 if (!speculative_maybe_derived_type)
kono
parents:
diff changeset
2020 {
kono
parents:
diff changeset
2021 speculative_maybe_derived_type = true;
kono
parents:
diff changeset
2022 return true;
kono
parents:
diff changeset
2023 }
kono
parents:
diff changeset
2024 return false;
kono
parents:
diff changeset
2025 }
kono
parents:
diff changeset
2026 /* See if CTX.OUTER_TYPE is base of OUTER_TYPE. */
kono
parents:
diff changeset
2027 else if (contains_type_p (speculative_outer_type,
kono
parents:
diff changeset
2028 speculative_offset - new_offset, new_outer_type, false, true))
kono
parents:
diff changeset
2029 {
kono
parents:
diff changeset
2030 speculative_outer_type = new_outer_type;
kono
parents:
diff changeset
2031 speculative_offset = new_offset;
kono
parents:
diff changeset
2032 speculative_maybe_derived_type = true;
kono
parents:
diff changeset
2033 return true;
kono
parents:
diff changeset
2034 }
kono
parents:
diff changeset
2035 else
kono
parents:
diff changeset
2036 {
kono
parents:
diff changeset
2037 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
2038 fprintf (dump_file, "Giving up on speculative meet\n");
kono
parents:
diff changeset
2039 clear_speculation ();
kono
parents:
diff changeset
2040 return true;
kono
parents:
diff changeset
2041 }
kono
parents:
diff changeset
2042 }
kono
parents:
diff changeset
2043
kono
parents:
diff changeset
2044 /* Assume that both THIS and a given context is valid and strenghten THIS
kono
parents:
diff changeset
2045 if possible. Return true if any strenghtening was made.
kono
parents:
diff changeset
2046 If actual type the context is being used in is known, OTR_TYPE should be
kono
parents:
diff changeset
2047 set accordingly. This improves quality of combined result. */
kono
parents:
diff changeset
2048
kono
parents:
diff changeset
2049 bool
kono
parents:
diff changeset
2050 ipa_polymorphic_call_context::combine_with (ipa_polymorphic_call_context ctx,
kono
parents:
diff changeset
2051 tree otr_type)
kono
parents:
diff changeset
2052 {
kono
parents:
diff changeset
2053 bool updated = false;
kono
parents:
diff changeset
2054
kono
parents:
diff changeset
2055 if (ctx.useless_p () || invalid)
kono
parents:
diff changeset
2056 return false;
kono
parents:
diff changeset
2057
kono
parents:
diff changeset
2058 /* Restricting context to inner type makes merging easier, however do not
kono
parents:
diff changeset
2059 do that unless we know how the context is used (OTR_TYPE is non-NULL) */
kono
parents:
diff changeset
2060 if (otr_type && !invalid && !ctx.invalid)
kono
parents:
diff changeset
2061 {
kono
parents:
diff changeset
2062 restrict_to_inner_class (otr_type);
kono
parents:
diff changeset
2063 ctx.restrict_to_inner_class (otr_type);
kono
parents:
diff changeset
2064 if(invalid)
kono
parents:
diff changeset
2065 return false;
kono
parents:
diff changeset
2066 }
kono
parents:
diff changeset
2067
kono
parents:
diff changeset
2068 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
2069 {
kono
parents:
diff changeset
2070 fprintf (dump_file, "Polymorphic call context combine:");
kono
parents:
diff changeset
2071 dump (dump_file);
kono
parents:
diff changeset
2072 fprintf (dump_file, "With context: ");
kono
parents:
diff changeset
2073 ctx.dump (dump_file);
kono
parents:
diff changeset
2074 if (otr_type)
kono
parents:
diff changeset
2075 {
kono
parents:
diff changeset
2076 fprintf (dump_file, "To be used with type: ");
kono
parents:
diff changeset
2077 print_generic_expr (dump_file, otr_type, TDF_SLIM);
kono
parents:
diff changeset
2078 fprintf (dump_file, "\n");
kono
parents:
diff changeset
2079 }
kono
parents:
diff changeset
2080 }
kono
parents:
diff changeset
2081
kono
parents:
diff changeset
2082 /* If call is known to be invalid, we are done. */
kono
parents:
diff changeset
2083 if (ctx.invalid)
kono
parents:
diff changeset
2084 {
kono
parents:
diff changeset
2085 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
2086 fprintf (dump_file, "-> Invalid context\n");
kono
parents:
diff changeset
2087 goto invalidate;
kono
parents:
diff changeset
2088 }
kono
parents:
diff changeset
2089
kono
parents:
diff changeset
2090 if (!ctx.outer_type)
kono
parents:
diff changeset
2091 ;
kono
parents:
diff changeset
2092 else if (!outer_type)
kono
parents:
diff changeset
2093 {
kono
parents:
diff changeset
2094 outer_type = ctx.outer_type;
kono
parents:
diff changeset
2095 offset = ctx.offset;
kono
parents:
diff changeset
2096 dynamic = ctx.dynamic;
kono
parents:
diff changeset
2097 maybe_in_construction = ctx.maybe_in_construction;
kono
parents:
diff changeset
2098 maybe_derived_type = ctx.maybe_derived_type;
kono
parents:
diff changeset
2099 updated = true;
kono
parents:
diff changeset
2100 }
kono
parents:
diff changeset
2101 /* If types are known to be same, merging is quite easy. */
kono
parents:
diff changeset
2102 else if (types_must_be_same_for_odr (outer_type, ctx.outer_type))
kono
parents:
diff changeset
2103 {
kono
parents:
diff changeset
2104 if (offset != ctx.offset
kono
parents:
diff changeset
2105 && TYPE_SIZE (outer_type)
kono
parents:
diff changeset
2106 && TREE_CODE (TYPE_SIZE (outer_type)) == INTEGER_CST)
kono
parents:
diff changeset
2107 {
kono
parents:
diff changeset
2108 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
2109 fprintf (dump_file, "Outer types match, offset mismatch -> invalid\n");
kono
parents:
diff changeset
2110 clear_speculation ();
kono
parents:
diff changeset
2111 clear_outer_type ();
kono
parents:
diff changeset
2112 invalid = true;
kono
parents:
diff changeset
2113 return true;
kono
parents:
diff changeset
2114 }
kono
parents:
diff changeset
2115 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
2116 fprintf (dump_file, "Outer types match, merging flags\n");
kono
parents:
diff changeset
2117 if (maybe_in_construction && !ctx.maybe_in_construction)
kono
parents:
diff changeset
2118 {
kono
parents:
diff changeset
2119 updated = true;
kono
parents:
diff changeset
2120 maybe_in_construction = false;
kono
parents:
diff changeset
2121 }
kono
parents:
diff changeset
2122 if (maybe_derived_type && !ctx.maybe_derived_type)
kono
parents:
diff changeset
2123 {
kono
parents:
diff changeset
2124 updated = true;
kono
parents:
diff changeset
2125 maybe_derived_type = false;
kono
parents:
diff changeset
2126 }
kono
parents:
diff changeset
2127 if (dynamic && !ctx.dynamic)
kono
parents:
diff changeset
2128 {
kono
parents:
diff changeset
2129 updated = true;
kono
parents:
diff changeset
2130 dynamic = false;
kono
parents:
diff changeset
2131 }
kono
parents:
diff changeset
2132 }
kono
parents:
diff changeset
2133 /* If we know the type precisely, there is not much to improve. */
kono
parents:
diff changeset
2134 else if (!maybe_derived_type && !maybe_in_construction
kono
parents:
diff changeset
2135 && !ctx.maybe_derived_type && !ctx.maybe_in_construction)
kono
parents:
diff changeset
2136 {
kono
parents:
diff changeset
2137 /* It may be easy to check if second context permits the first
kono
parents:
diff changeset
2138 and set INVALID otherwise. This is not easy to do in general;
kono
parents:
diff changeset
2139 contains_type_p may return false negatives for non-comparable
kono
parents:
diff changeset
2140 types.
kono
parents:
diff changeset
2141
kono
parents:
diff changeset
2142 If OTR_TYPE is known, we however can expect that
kono
parents:
diff changeset
2143 restrict_to_inner_class should have discovered the same base
kono
parents:
diff changeset
2144 type. */
kono
parents:
diff changeset
2145 if (otr_type && !ctx.maybe_in_construction && !ctx.maybe_derived_type)
kono
parents:
diff changeset
2146 {
kono
parents:
diff changeset
2147 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
2148 fprintf (dump_file, "Contextes disagree -> invalid\n");
kono
parents:
diff changeset
2149 goto invalidate;
kono
parents:
diff changeset
2150 }
kono
parents:
diff changeset
2151 }
kono
parents:
diff changeset
2152 /* See if one type contains the other as a field (not base).
kono
parents:
diff changeset
2153 In this case we want to choose the wider type, because it contains
kono
parents:
diff changeset
2154 more information. */
kono
parents:
diff changeset
2155 else if (contains_type_p (ctx.outer_type, ctx.offset - offset,
kono
parents:
diff changeset
2156 outer_type, false, false))
kono
parents:
diff changeset
2157 {
kono
parents:
diff changeset
2158 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
2159 fprintf (dump_file, "Second type contain the first as a field\n");
kono
parents:
diff changeset
2160
kono
parents:
diff changeset
2161 if (maybe_derived_type)
kono
parents:
diff changeset
2162 {
kono
parents:
diff changeset
2163 outer_type = ctx.outer_type;
kono
parents:
diff changeset
2164 maybe_derived_type = ctx.maybe_derived_type;
kono
parents:
diff changeset
2165 offset = ctx.offset;
kono
parents:
diff changeset
2166 dynamic = ctx.dynamic;
kono
parents:
diff changeset
2167 updated = true;
kono
parents:
diff changeset
2168 }
kono
parents:
diff changeset
2169
kono
parents:
diff changeset
2170 /* If we do not know how the context is being used, we can
kono
parents:
diff changeset
2171 not clear MAYBE_IN_CONSTRUCTION because it may be offseted
kono
parents:
diff changeset
2172 to other component of OUTER_TYPE later and we know nothing
kono
parents:
diff changeset
2173 about it. */
kono
parents:
diff changeset
2174 if (otr_type && maybe_in_construction
kono
parents:
diff changeset
2175 && !ctx.maybe_in_construction)
kono
parents:
diff changeset
2176 {
kono
parents:
diff changeset
2177 maybe_in_construction = false;
kono
parents:
diff changeset
2178 updated = true;
kono
parents:
diff changeset
2179 }
kono
parents:
diff changeset
2180 }
kono
parents:
diff changeset
2181 else if (contains_type_p (outer_type, offset - ctx.offset,
kono
parents:
diff changeset
2182 ctx.outer_type, false, false))
kono
parents:
diff changeset
2183 {
kono
parents:
diff changeset
2184 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
2185 fprintf (dump_file, "First type contain the second as a field\n");
kono
parents:
diff changeset
2186
kono
parents:
diff changeset
2187 if (otr_type && maybe_in_construction
kono
parents:
diff changeset
2188 && !ctx.maybe_in_construction)
kono
parents:
diff changeset
2189 {
kono
parents:
diff changeset
2190 maybe_in_construction = false;
kono
parents:
diff changeset
2191 updated = true;
kono
parents:
diff changeset
2192 }
kono
parents:
diff changeset
2193 }
kono
parents:
diff changeset
2194 /* See if OUTER_TYPE is base of CTX.OUTER_TYPE. */
kono
parents:
diff changeset
2195 else if (contains_type_p (ctx.outer_type,
kono
parents:
diff changeset
2196 ctx.offset - offset, outer_type, false, true))
kono
parents:
diff changeset
2197 {
kono
parents:
diff changeset
2198 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
2199 fprintf (dump_file, "First type is base of second\n");
kono
parents:
diff changeset
2200 if (!maybe_derived_type)
kono
parents:
diff changeset
2201 {
kono
parents:
diff changeset
2202 if (!ctx.maybe_in_construction
kono
parents:
diff changeset
2203 && types_odr_comparable (outer_type, ctx.outer_type))
kono
parents:
diff changeset
2204 {
kono
parents:
diff changeset
2205 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
2206 fprintf (dump_file, "Second context does not permit base -> invalid\n");
kono
parents:
diff changeset
2207 goto invalidate;
kono
parents:
diff changeset
2208 }
kono
parents:
diff changeset
2209 }
kono
parents:
diff changeset
2210 /* Pick variant deeper in the hiearchy. */
kono
parents:
diff changeset
2211 else
kono
parents:
diff changeset
2212 {
kono
parents:
diff changeset
2213 outer_type = ctx.outer_type;
kono
parents:
diff changeset
2214 maybe_in_construction = ctx.maybe_in_construction;
kono
parents:
diff changeset
2215 maybe_derived_type = ctx.maybe_derived_type;
kono
parents:
diff changeset
2216 offset = ctx.offset;
kono
parents:
diff changeset
2217 dynamic = ctx.dynamic;
kono
parents:
diff changeset
2218 updated = true;
kono
parents:
diff changeset
2219 }
kono
parents:
diff changeset
2220 }
kono
parents:
diff changeset
2221 /* See if CTX.OUTER_TYPE is base of OUTER_TYPE. */
kono
parents:
diff changeset
2222 else if (contains_type_p (outer_type,
kono
parents:
diff changeset
2223 offset - ctx.offset, ctx.outer_type, false, true))
kono
parents:
diff changeset
2224 {
kono
parents:
diff changeset
2225 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
2226 fprintf (dump_file, "Second type is base of first\n");
kono
parents:
diff changeset
2227 if (!ctx.maybe_derived_type)
kono
parents:
diff changeset
2228 {
kono
parents:
diff changeset
2229 if (!maybe_in_construction
kono
parents:
diff changeset
2230 && types_odr_comparable (outer_type, ctx.outer_type))
kono
parents:
diff changeset
2231 {
kono
parents:
diff changeset
2232 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
2233 fprintf (dump_file, "First context does not permit base -> invalid\n");
kono
parents:
diff changeset
2234 goto invalidate;
kono
parents:
diff changeset
2235 }
kono
parents:
diff changeset
2236 /* Pick the base type. */
kono
parents:
diff changeset
2237 else if (maybe_in_construction)
kono
parents:
diff changeset
2238 {
kono
parents:
diff changeset
2239 outer_type = ctx.outer_type;
kono
parents:
diff changeset
2240 maybe_in_construction = ctx.maybe_in_construction;
kono
parents:
diff changeset
2241 maybe_derived_type = ctx.maybe_derived_type;
kono
parents:
diff changeset
2242 offset = ctx.offset;
kono
parents:
diff changeset
2243 dynamic = ctx.dynamic;
kono
parents:
diff changeset
2244 updated = true;
kono
parents:
diff changeset
2245 }
kono
parents:
diff changeset
2246 }
kono
parents:
diff changeset
2247 }
kono
parents:
diff changeset
2248 /* TODO handle merging using hiearchy. */
kono
parents:
diff changeset
2249 else if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
2250 fprintf (dump_file, "Giving up on merge\n");
kono
parents:
diff changeset
2251
kono
parents:
diff changeset
2252 updated |= combine_speculation_with (ctx.speculative_outer_type,
kono
parents:
diff changeset
2253 ctx.speculative_offset,
kono
parents:
diff changeset
2254 ctx.speculative_maybe_derived_type,
kono
parents:
diff changeset
2255 otr_type);
kono
parents:
diff changeset
2256
kono
parents:
diff changeset
2257 if (updated && dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
2258 {
kono
parents:
diff changeset
2259 fprintf (dump_file, "Updated as: ");
kono
parents:
diff changeset
2260 dump (dump_file);
kono
parents:
diff changeset
2261 fprintf (dump_file, "\n");
kono
parents:
diff changeset
2262 }
kono
parents:
diff changeset
2263 return updated;
kono
parents:
diff changeset
2264
kono
parents:
diff changeset
2265 invalidate:
kono
parents:
diff changeset
2266 invalid = true;
kono
parents:
diff changeset
2267 clear_speculation ();
kono
parents:
diff changeset
2268 clear_outer_type ();
kono
parents:
diff changeset
2269 return true;
kono
parents:
diff changeset
2270 }
kono
parents:
diff changeset
2271
kono
parents:
diff changeset
2272 /* Take non-speculative info, merge it with speculative and clear speculation.
kono
parents:
diff changeset
2273 Used when we no longer manage to keep track of actual outer type, but we
kono
parents:
diff changeset
2274 think it is still there.
kono
parents:
diff changeset
2275
kono
parents:
diff changeset
2276 If OTR_TYPE is set, the transformation can be done more effectively assuming
kono
parents:
diff changeset
2277 that context is going to be used only that way. */
kono
parents:
diff changeset
2278
kono
parents:
diff changeset
2279 void
kono
parents:
diff changeset
2280 ipa_polymorphic_call_context::make_speculative (tree otr_type)
kono
parents:
diff changeset
2281 {
kono
parents:
diff changeset
2282 tree spec_outer_type = outer_type;
kono
parents:
diff changeset
2283 HOST_WIDE_INT spec_offset = offset;
kono
parents:
diff changeset
2284 bool spec_maybe_derived_type = maybe_derived_type;
kono
parents:
diff changeset
2285
kono
parents:
diff changeset
2286 if (invalid)
kono
parents:
diff changeset
2287 {
kono
parents:
diff changeset
2288 invalid = false;
kono
parents:
diff changeset
2289 clear_outer_type ();
kono
parents:
diff changeset
2290 clear_speculation ();
kono
parents:
diff changeset
2291 return;
kono
parents:
diff changeset
2292 }
kono
parents:
diff changeset
2293 if (!outer_type)
kono
parents:
diff changeset
2294 return;
kono
parents:
diff changeset
2295 clear_outer_type ();
kono
parents:
diff changeset
2296 combine_speculation_with (spec_outer_type, spec_offset,
kono
parents:
diff changeset
2297 spec_maybe_derived_type,
kono
parents:
diff changeset
2298 otr_type);
kono
parents:
diff changeset
2299 }
kono
parents:
diff changeset
2300
kono
parents:
diff changeset
2301 /* Use when we can not track dynamic type change. This speculatively assume
kono
parents:
diff changeset
2302 type change is not happening. */
kono
parents:
diff changeset
2303
kono
parents:
diff changeset
2304 void
kono
parents:
diff changeset
2305 ipa_polymorphic_call_context::possible_dynamic_type_change (bool in_poly_cdtor,
kono
parents:
diff changeset
2306 tree otr_type)
kono
parents:
diff changeset
2307 {
kono
parents:
diff changeset
2308 if (dynamic)
kono
parents:
diff changeset
2309 make_speculative (otr_type);
kono
parents:
diff changeset
2310 else if (in_poly_cdtor)
kono
parents:
diff changeset
2311 maybe_in_construction = true;
kono
parents:
diff changeset
2312 }
kono
parents:
diff changeset
2313
kono
parents:
diff changeset
2314 /* Return TRUE if this context conveys the same information as OTHER. */
kono
parents:
diff changeset
2315
kono
parents:
diff changeset
2316 bool
kono
parents:
diff changeset
2317 ipa_polymorphic_call_context::equal_to
kono
parents:
diff changeset
2318 (const ipa_polymorphic_call_context &x) const
kono
parents:
diff changeset
2319 {
kono
parents:
diff changeset
2320 if (useless_p ())
kono
parents:
diff changeset
2321 return x.useless_p ();
kono
parents:
diff changeset
2322 if (invalid)
kono
parents:
diff changeset
2323 return x.invalid;
kono
parents:
diff changeset
2324 if (x.useless_p () || x.invalid)
kono
parents:
diff changeset
2325 return false;
kono
parents:
diff changeset
2326
kono
parents:
diff changeset
2327 if (outer_type)
kono
parents:
diff changeset
2328 {
kono
parents:
diff changeset
2329 if (!x.outer_type
kono
parents:
diff changeset
2330 || !types_odr_comparable (outer_type, x.outer_type)
kono
parents:
diff changeset
2331 || !types_same_for_odr (outer_type, x.outer_type)
kono
parents:
diff changeset
2332 || offset != x.offset
kono
parents:
diff changeset
2333 || maybe_in_construction != x.maybe_in_construction
kono
parents:
diff changeset
2334 || maybe_derived_type != x.maybe_derived_type
kono
parents:
diff changeset
2335 || dynamic != x.dynamic)
kono
parents:
diff changeset
2336 return false;
kono
parents:
diff changeset
2337 }
kono
parents:
diff changeset
2338 else if (x.outer_type)
kono
parents:
diff changeset
2339 return false;
kono
parents:
diff changeset
2340
kono
parents:
diff changeset
2341
kono
parents:
diff changeset
2342 if (speculative_outer_type
kono
parents:
diff changeset
2343 && speculation_consistent_p (speculative_outer_type, speculative_offset,
kono
parents:
diff changeset
2344 speculative_maybe_derived_type, NULL_TREE))
kono
parents:
diff changeset
2345 {
kono
parents:
diff changeset
2346 if (!x.speculative_outer_type)
kono
parents:
diff changeset
2347 return false;
kono
parents:
diff changeset
2348
kono
parents:
diff changeset
2349 if (!types_odr_comparable (speculative_outer_type,
kono
parents:
diff changeset
2350 x.speculative_outer_type)
kono
parents:
diff changeset
2351 || !types_same_for_odr (speculative_outer_type,
kono
parents:
diff changeset
2352 x.speculative_outer_type)
kono
parents:
diff changeset
2353 || speculative_offset != x.speculative_offset
kono
parents:
diff changeset
2354 || speculative_maybe_derived_type != x.speculative_maybe_derived_type)
kono
parents:
diff changeset
2355 return false;
kono
parents:
diff changeset
2356 }
kono
parents:
diff changeset
2357 else if (x.speculative_outer_type
kono
parents:
diff changeset
2358 && x.speculation_consistent_p (x.speculative_outer_type,
kono
parents:
diff changeset
2359 x.speculative_offset,
kono
parents:
diff changeset
2360 x.speculative_maybe_derived_type,
kono
parents:
diff changeset
2361 NULL))
kono
parents:
diff changeset
2362 return false;
kono
parents:
diff changeset
2363
kono
parents:
diff changeset
2364 return true;
kono
parents:
diff changeset
2365 }
kono
parents:
diff changeset
2366
kono
parents:
diff changeset
2367 /* Modify context to be strictly less restrictive than CTX. */
kono
parents:
diff changeset
2368
kono
parents:
diff changeset
2369 bool
kono
parents:
diff changeset
2370 ipa_polymorphic_call_context::meet_with (ipa_polymorphic_call_context ctx,
kono
parents:
diff changeset
2371 tree otr_type)
kono
parents:
diff changeset
2372 {
kono
parents:
diff changeset
2373 bool updated = false;
kono
parents:
diff changeset
2374
kono
parents:
diff changeset
2375 if (useless_p () || ctx.invalid)
kono
parents:
diff changeset
2376 return false;
kono
parents:
diff changeset
2377
kono
parents:
diff changeset
2378 /* Restricting context to inner type makes merging easier, however do not
kono
parents:
diff changeset
2379 do that unless we know how the context is used (OTR_TYPE is non-NULL) */
kono
parents:
diff changeset
2380 if (otr_type && !useless_p () && !ctx.useless_p ())
kono
parents:
diff changeset
2381 {
kono
parents:
diff changeset
2382 restrict_to_inner_class (otr_type);
kono
parents:
diff changeset
2383 ctx.restrict_to_inner_class (otr_type);
kono
parents:
diff changeset
2384 if(invalid)
kono
parents:
diff changeset
2385 return false;
kono
parents:
diff changeset
2386 }
kono
parents:
diff changeset
2387
kono
parents:
diff changeset
2388 if (equal_to (ctx))
kono
parents:
diff changeset
2389 return false;
kono
parents:
diff changeset
2390
kono
parents:
diff changeset
2391 if (ctx.useless_p () || invalid)
kono
parents:
diff changeset
2392 {
kono
parents:
diff changeset
2393 *this = ctx;
kono
parents:
diff changeset
2394 return true;
kono
parents:
diff changeset
2395 }
kono
parents:
diff changeset
2396
kono
parents:
diff changeset
2397 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
2398 {
kono
parents:
diff changeset
2399 fprintf (dump_file, "Polymorphic call context meet:");
kono
parents:
diff changeset
2400 dump (dump_file);
kono
parents:
diff changeset
2401 fprintf (dump_file, "With context: ");
kono
parents:
diff changeset
2402 ctx.dump (dump_file);
kono
parents:
diff changeset
2403 if (otr_type)
kono
parents:
diff changeset
2404 {
kono
parents:
diff changeset
2405 fprintf (dump_file, "To be used with type: ");
kono
parents:
diff changeset
2406 print_generic_expr (dump_file, otr_type, TDF_SLIM);
kono
parents:
diff changeset
2407 fprintf (dump_file, "\n");
kono
parents:
diff changeset
2408 }
kono
parents:
diff changeset
2409 }
kono
parents:
diff changeset
2410
kono
parents:
diff changeset
2411 if (!dynamic && ctx.dynamic)
kono
parents:
diff changeset
2412 {
kono
parents:
diff changeset
2413 dynamic = true;
kono
parents:
diff changeset
2414 updated = true;
kono
parents:
diff changeset
2415 }
kono
parents:
diff changeset
2416
kono
parents:
diff changeset
2417 /* If call is known to be invalid, we are done. */
kono
parents:
diff changeset
2418 if (!outer_type)
kono
parents:
diff changeset
2419 ;
kono
parents:
diff changeset
2420 else if (!ctx.outer_type)
kono
parents:
diff changeset
2421 {
kono
parents:
diff changeset
2422 clear_outer_type ();
kono
parents:
diff changeset
2423 updated = true;
kono
parents:
diff changeset
2424 }
kono
parents:
diff changeset
2425 /* If types are known to be same, merging is quite easy. */
kono
parents:
diff changeset
2426 else if (types_must_be_same_for_odr (outer_type, ctx.outer_type))
kono
parents:
diff changeset
2427 {
kono
parents:
diff changeset
2428 if (offset != ctx.offset
kono
parents:
diff changeset
2429 && TYPE_SIZE (outer_type)
kono
parents:
diff changeset
2430 && TREE_CODE (TYPE_SIZE (outer_type)) == INTEGER_CST)
kono
parents:
diff changeset
2431 {
kono
parents:
diff changeset
2432 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
2433 fprintf (dump_file, "Outer types match, offset mismatch -> clearing\n");
kono
parents:
diff changeset
2434 clear_outer_type ();
kono
parents:
diff changeset
2435 return true;
kono
parents:
diff changeset
2436 }
kono
parents:
diff changeset
2437 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
2438 fprintf (dump_file, "Outer types match, merging flags\n");
kono
parents:
diff changeset
2439 if (!maybe_in_construction && ctx.maybe_in_construction)
kono
parents:
diff changeset
2440 {
kono
parents:
diff changeset
2441 updated = true;
kono
parents:
diff changeset
2442 maybe_in_construction = true;
kono
parents:
diff changeset
2443 }
kono
parents:
diff changeset
2444 if (!maybe_derived_type && ctx.maybe_derived_type)
kono
parents:
diff changeset
2445 {
kono
parents:
diff changeset
2446 updated = true;
kono
parents:
diff changeset
2447 maybe_derived_type = true;
kono
parents:
diff changeset
2448 }
kono
parents:
diff changeset
2449 if (!dynamic && ctx.dynamic)
kono
parents:
diff changeset
2450 {
kono
parents:
diff changeset
2451 updated = true;
kono
parents:
diff changeset
2452 dynamic = true;
kono
parents:
diff changeset
2453 }
kono
parents:
diff changeset
2454 }
kono
parents:
diff changeset
2455 /* See if one type contains the other as a field (not base). */
kono
parents:
diff changeset
2456 else if (contains_type_p (ctx.outer_type, ctx.offset - offset,
kono
parents:
diff changeset
2457 outer_type, false, false))
kono
parents:
diff changeset
2458 {
kono
parents:
diff changeset
2459 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
2460 fprintf (dump_file, "Second type contain the first as a field\n");
kono
parents:
diff changeset
2461
kono
parents:
diff changeset
2462 /* The second type is more specified, so we keep the first.
kono
parents:
diff changeset
2463 We need to set DYNAMIC flag to avoid declaring context INVALID
kono
parents:
diff changeset
2464 of OFFSET ends up being out of range. */
kono
parents:
diff changeset
2465 if (!dynamic
kono
parents:
diff changeset
2466 && (ctx.dynamic
kono
parents:
diff changeset
2467 || (!otr_type
kono
parents:
diff changeset
2468 && (!TYPE_SIZE (ctx.outer_type)
kono
parents:
diff changeset
2469 || !TYPE_SIZE (outer_type)
kono
parents:
diff changeset
2470 || !operand_equal_p (TYPE_SIZE (ctx.outer_type),
kono
parents:
diff changeset
2471 TYPE_SIZE (outer_type), 0)))))
kono
parents:
diff changeset
2472 {
kono
parents:
diff changeset
2473 dynamic = true;
kono
parents:
diff changeset
2474 updated = true;
kono
parents:
diff changeset
2475 }
kono
parents:
diff changeset
2476 }
kono
parents:
diff changeset
2477 else if (contains_type_p (outer_type, offset - ctx.offset,
kono
parents:
diff changeset
2478 ctx.outer_type, false, false))
kono
parents:
diff changeset
2479 {
kono
parents:
diff changeset
2480 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
2481 fprintf (dump_file, "First type contain the second as a field\n");
kono
parents:
diff changeset
2482
kono
parents:
diff changeset
2483 if (!dynamic
kono
parents:
diff changeset
2484 && (ctx.dynamic
kono
parents:
diff changeset
2485 || (!otr_type
kono
parents:
diff changeset
2486 && (!TYPE_SIZE (ctx.outer_type)
kono
parents:
diff changeset
2487 || !TYPE_SIZE (outer_type)
kono
parents:
diff changeset
2488 || !operand_equal_p (TYPE_SIZE (ctx.outer_type),
kono
parents:
diff changeset
2489 TYPE_SIZE (outer_type), 0)))))
kono
parents:
diff changeset
2490 dynamic = true;
kono
parents:
diff changeset
2491 outer_type = ctx.outer_type;
kono
parents:
diff changeset
2492 offset = ctx.offset;
kono
parents:
diff changeset
2493 dynamic = ctx.dynamic;
kono
parents:
diff changeset
2494 maybe_in_construction = ctx.maybe_in_construction;
kono
parents:
diff changeset
2495 maybe_derived_type = ctx.maybe_derived_type;
kono
parents:
diff changeset
2496 updated = true;
kono
parents:
diff changeset
2497 }
kono
parents:
diff changeset
2498 /* See if OUTER_TYPE is base of CTX.OUTER_TYPE. */
kono
parents:
diff changeset
2499 else if (contains_type_p (ctx.outer_type,
kono
parents:
diff changeset
2500 ctx.offset - offset, outer_type, false, true))
kono
parents:
diff changeset
2501 {
kono
parents:
diff changeset
2502 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
2503 fprintf (dump_file, "First type is base of second\n");
kono
parents:
diff changeset
2504 if (!maybe_derived_type)
kono
parents:
diff changeset
2505 {
kono
parents:
diff changeset
2506 maybe_derived_type = true;
kono
parents:
diff changeset
2507 updated = true;
kono
parents:
diff changeset
2508 }
kono
parents:
diff changeset
2509 if (!maybe_in_construction && ctx.maybe_in_construction)
kono
parents:
diff changeset
2510 {
kono
parents:
diff changeset
2511 maybe_in_construction = true;
kono
parents:
diff changeset
2512 updated = true;
kono
parents:
diff changeset
2513 }
kono
parents:
diff changeset
2514 if (!dynamic && ctx.dynamic)
kono
parents:
diff changeset
2515 {
kono
parents:
diff changeset
2516 dynamic = true;
kono
parents:
diff changeset
2517 updated = true;
kono
parents:
diff changeset
2518 }
kono
parents:
diff changeset
2519 }
kono
parents:
diff changeset
2520 /* See if CTX.OUTER_TYPE is base of OUTER_TYPE. */
kono
parents:
diff changeset
2521 else if (contains_type_p (outer_type,
kono
parents:
diff changeset
2522 offset - ctx.offset, ctx.outer_type, false, true))
kono
parents:
diff changeset
2523 {
kono
parents:
diff changeset
2524 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
2525 fprintf (dump_file, "Second type is base of first\n");
kono
parents:
diff changeset
2526 outer_type = ctx.outer_type;
kono
parents:
diff changeset
2527 offset = ctx.offset;
kono
parents:
diff changeset
2528 updated = true;
kono
parents:
diff changeset
2529 if (!maybe_derived_type)
kono
parents:
diff changeset
2530 maybe_derived_type = true;
kono
parents:
diff changeset
2531 if (!maybe_in_construction && ctx.maybe_in_construction)
kono
parents:
diff changeset
2532 maybe_in_construction = true;
kono
parents:
diff changeset
2533 if (!dynamic && ctx.dynamic)
kono
parents:
diff changeset
2534 dynamic = true;
kono
parents:
diff changeset
2535 }
kono
parents:
diff changeset
2536 /* TODO handle merging using hiearchy. */
kono
parents:
diff changeset
2537 else
kono
parents:
diff changeset
2538 {
kono
parents:
diff changeset
2539 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
2540 fprintf (dump_file, "Giving up on meet\n");
kono
parents:
diff changeset
2541 clear_outer_type ();
kono
parents:
diff changeset
2542 updated = true;
kono
parents:
diff changeset
2543 }
kono
parents:
diff changeset
2544
kono
parents:
diff changeset
2545 updated |= meet_speculation_with (ctx.speculative_outer_type,
kono
parents:
diff changeset
2546 ctx.speculative_offset,
kono
parents:
diff changeset
2547 ctx.speculative_maybe_derived_type,
kono
parents:
diff changeset
2548 otr_type);
kono
parents:
diff changeset
2549
kono
parents:
diff changeset
2550 if (updated && dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
2551 {
kono
parents:
diff changeset
2552 fprintf (dump_file, "Updated as: ");
kono
parents:
diff changeset
2553 dump (dump_file);
kono
parents:
diff changeset
2554 fprintf (dump_file, "\n");
kono
parents:
diff changeset
2555 }
kono
parents:
diff changeset
2556 return updated;
kono
parents:
diff changeset
2557 }