1 | // Implementation of private inline member functions for RTL SSA -*- C++ -*- |
2 | // Copyright (C) 2020-2024 Free Software Foundation, Inc. |
3 | // |
4 | // This file is part of GCC. |
5 | // |
6 | // GCC is free software; you can redistribute it and/or modify it under |
7 | // the terms of the GNU General Public License as published by the Free |
8 | // Software Foundation; either version 3, or (at your option) any later |
9 | // version. |
10 | // |
11 | // GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
12 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or |
13 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
14 | // for more details. |
15 | // |
16 | // You should have received a copy of the GNU General Public License |
17 | // along with GCC; see the file COPYING3. If not see |
18 | // <http://www.gnu.org/licenses/>. |
19 | |
20 | namespace rtl_ssa { |
21 | |
22 | // Construct a new access with the given resource () and kind () values. |
23 | inline access_info::access_info (resource_info resource, access_kind kind) |
24 | : m_regno (resource.regno), |
25 | m_mode (resource.mode), |
26 | m_kind (kind), |
27 | m_is_artificial (false), |
28 | m_is_set_with_nondebug_insn_uses (false), |
29 | m_is_pre_post_modify (false), |
30 | m_is_call_clobber (false), |
31 | m_is_live_out_use (false), |
32 | m_includes_address_uses (false), |
33 | m_includes_read_writes (false), |
34 | m_includes_subregs (false), |
35 | m_includes_multiregs (false), |
36 | m_only_occurs_in_notes (false), |
37 | m_is_last_nondebug_insn_use (false), |
38 | m_is_in_debug_insn_or_phi (false), |
39 | m_has_been_superceded (false), |
40 | m_is_temp (false) |
41 | { |
42 | } |
43 | |
44 | // Construct a use of RESOURCE in LOCATION. The resource's value is provided |
45 | // by DEF, or is completely undefined if DEF is null. |
46 | inline use_info::use_info (insn_or_phi location, resource_info resource, |
47 | set_info *definition) |
48 | : access_info (resource, access_kind::USE), |
49 | m_insn_or_phi (location), |
50 | m_last_use_or_prev_use (nullptr), |
51 | m_last_nondebug_insn_use_or_next_use (nullptr), |
52 | m_def (definition) |
53 | { |
54 | if (m_insn_or_phi.is_second ()) |
55 | { |
56 | m_is_in_debug_insn_or_phi = true; |
57 | m_is_artificial = true; |
58 | } |
59 | else |
60 | { |
61 | insn_info *insn = m_insn_or_phi.known_first (); |
62 | m_is_in_debug_insn_or_phi = insn->is_debug_insn (); |
63 | m_is_artificial = insn->is_artificial (); |
64 | } |
65 | } |
66 | |
67 | // Return the correct (uncached) value of m_is_last_nondebug_insn_use. |
68 | inline bool |
69 | use_info::calculate_is_last_nondebug_insn_use () const |
70 | { |
71 | use_info *next = next_use (); |
72 | return is_in_nondebug_insn () && (!next || next->is_in_debug_insn_or_phi ()); |
73 | } |
74 | |
75 | // Accumulate any properties about REF that are also stored in use_infos. |
76 | // IS_FIRST is true if REF is the first access to resource () that we have |
77 | // recorded in this way, false if we have already recorded previous |
78 | // references. |
79 | inline void |
80 | use_info::record_reference (rtx_obj_reference ref, bool is_first) |
81 | { |
82 | if (is_first) |
83 | { |
84 | m_includes_address_uses = ref.in_address (); |
85 | m_includes_read_writes = ref.is_write (); |
86 | m_includes_subregs = ref.in_subreg (); |
87 | m_includes_multiregs = ref.is_multireg (); |
88 | m_only_occurs_in_notes = ref.in_note (); |
89 | } |
90 | else |
91 | { |
92 | m_includes_address_uses |= ref.in_address (); |
93 | m_includes_read_writes |= ref.is_write (); |
94 | m_includes_subregs |= ref.in_subreg (); |
95 | m_includes_multiregs |= ref.is_multireg (); |
96 | m_only_occurs_in_notes &= ref.in_note (); |
97 | } |
98 | } |
99 | |
100 | // Change the value of insn () to INSN. |
101 | inline void |
102 | use_info::set_insn (insn_info *insn) |
103 | { |
104 | m_insn_or_phi = insn; |
105 | m_is_artificial = insn->is_artificial (); |
106 | } |
107 | |
108 | // Copy the overloaded prev link from OTHER. |
109 | inline void |
110 | use_info::copy_prev_from (use_info *other) |
111 | { |
112 | m_last_use_or_prev_use = other->m_last_use_or_prev_use; |
113 | } |
114 | |
115 | // Copy the overloaded next link from OTHER. |
116 | inline void |
117 | use_info::copy_next_from (use_info *other) |
118 | { |
119 | m_last_nondebug_insn_use_or_next_use |
120 | = other->m_last_nondebug_insn_use_or_next_use; |
121 | m_is_last_nondebug_insn_use = calculate_is_last_nondebug_insn_use (); |
122 | } |
123 | |
124 | // Record that this use is the first in the list and that the last use is LAST. |
125 | inline void |
126 | use_info::set_last_use (use_info *last_use) |
127 | { |
128 | m_last_use_or_prev_use.set_first (last_use); |
129 | } |
130 | |
131 | // Record that this use is not the first in the list and that the previous |
132 | // use is PREV. |
133 | inline void |
134 | use_info::set_prev_use (use_info *prev_use) |
135 | { |
136 | m_last_use_or_prev_use.set_second (prev_use); |
137 | } |
138 | |
139 | // Record that this use is the last use in the list. If USE is nonnull, |
140 | // record that USE is the last use in the list by a nondebug instruction, |
141 | // otherwise record that there are no uses by nondebug instructions |
142 | // in the list. |
143 | inline void |
144 | use_info::set_last_nondebug_insn_use (use_info *use) |
145 | { |
146 | m_last_nondebug_insn_use_or_next_use.set_first (use); |
147 | m_is_last_nondebug_insn_use = (use == this); |
148 | } |
149 | |
150 | // Record that this use is not the last in the list and that the next |
151 | // use is NEXT_USE. |
152 | inline void |
153 | use_info::set_next_use (use_info *next_use) |
154 | { |
155 | m_last_nondebug_insn_use_or_next_use.set_second (next_use); |
156 | m_is_last_nondebug_insn_use = calculate_is_last_nondebug_insn_use (); |
157 | } |
158 | |
159 | // Clear any information relating to the position of the use in its |
160 | // definition's list. |
161 | inline void |
162 | use_info::clear_use_links () |
163 | { |
164 | m_last_use_or_prev_use = nullptr; |
165 | m_last_nondebug_insn_use_or_next_use = nullptr; |
166 | m_is_last_nondebug_insn_use = false; |
167 | } |
168 | |
169 | // Return true if the use has any links to other uses. This is mostly |
170 | // for assert checking. |
171 | inline bool |
172 | use_info::has_use_links () |
173 | { |
174 | return (m_last_use_or_prev_use |
175 | || m_last_nondebug_insn_use_or_next_use |
176 | || m_is_last_nondebug_insn_use); |
177 | } |
178 | |
179 | // Construct a definition of RESOURCE in INSN, giving it kind KIND. |
180 | inline def_info::def_info (insn_info *insn, resource_info resource, |
181 | access_kind kind) |
182 | : access_info (resource, kind), |
183 | m_insn (insn), |
184 | m_last_def_or_prev_def (nullptr), |
185 | m_splay_root_or_next_def (nullptr) |
186 | { |
187 | m_is_artificial = insn->is_artificial (); |
188 | } |
189 | |
190 | // Record any properties about REF that are also stored in def_infos. |
191 | // IS_FIRST is true if REF is the first access to resource () that we have |
192 | // recorded in this way, false if we have already recorded previous |
193 | // references. |
194 | inline void |
195 | def_info::record_reference (rtx_obj_reference ref, bool is_first) |
196 | { |
197 | if (is_first) |
198 | { |
199 | m_is_pre_post_modify = ref.is_pre_post_modify (); |
200 | m_includes_read_writes = ref.is_read (); |
201 | m_includes_subregs = ref.in_subreg (); |
202 | m_includes_multiregs = ref.is_multireg (); |
203 | } |
204 | else |
205 | { |
206 | m_is_pre_post_modify |= ref.is_pre_post_modify (); |
207 | m_includes_read_writes |= ref.is_read (); |
208 | m_includes_subregs |= ref.in_subreg (); |
209 | m_includes_multiregs |= ref.is_multireg (); |
210 | } |
211 | } |
212 | |
213 | // Return the last definition in the list. Only valid when is_first () |
214 | // is true. |
215 | inline def_info * |
216 | def_info::last_def () const |
217 | { |
218 | return m_last_def_or_prev_def.known_first (); |
219 | } |
220 | |
221 | // Return the root of the splay tree of definitions of resource (), |
222 | // or null if no splay tree has been created for this resource. |
223 | // Only valid when is_last () is true. |
224 | inline def_node * |
225 | def_info::splay_root () const |
226 | { |
227 | return m_splay_root_or_next_def.known_first (); |
228 | } |
229 | |
230 | // Copy the overloaded prev link from OTHER. |
231 | inline void |
232 | def_info::copy_prev_from (def_info *other) |
233 | { |
234 | m_last_def_or_prev_def |
235 | = other->m_last_def_or_prev_def; |
236 | } |
237 | |
238 | // Copy the overloaded next link from OTHER. |
239 | inline void |
240 | def_info::copy_next_from (def_info *other) |
241 | { |
242 | m_splay_root_or_next_def = other->m_splay_root_or_next_def; |
243 | } |
244 | |
245 | // Record that this definition is the first in the list and that the last |
246 | // definition is LAST. |
247 | inline void |
248 | def_info::set_last_def (def_info *last_def) |
249 | { |
250 | m_last_def_or_prev_def.set_first (last_def); |
251 | } |
252 | |
253 | // Record that this definition is not the first in the list and that the |
254 | // previous definition is PREV. |
255 | inline void |
256 | def_info::set_prev_def (def_info *prev_def) |
257 | { |
258 | m_last_def_or_prev_def.set_second (prev_def); |
259 | } |
260 | |
261 | // Record that this definition is the last in the list and that the root |
262 | // of the splay tree associated with resource () is ROOT. |
263 | inline void |
264 | def_info::set_splay_root (def_node *root) |
265 | { |
266 | m_splay_root_or_next_def = root; |
267 | } |
268 | |
269 | // Record that this definition is not the last in the list and that the |
270 | // next definition is NEXT. |
271 | inline void |
272 | def_info::set_next_def (def_info *next_def) |
273 | { |
274 | m_splay_root_or_next_def = next_def; |
275 | } |
276 | |
277 | // Clear the prev and next links |
278 | inline void |
279 | def_info::clear_def_links () |
280 | { |
281 | m_last_def_or_prev_def = nullptr; |
282 | m_splay_root_or_next_def = nullptr; |
283 | } |
284 | |
285 | // Return true if the definition has any links to other definitions. |
286 | // This is mostly for assert checking. |
287 | inline bool |
288 | def_info::has_def_links () |
289 | { |
290 | return m_last_def_or_prev_def || m_splay_root_or_next_def; |
291 | } |
292 | |
293 | // Construct a clobber of register REGNO in insn INSN. |
294 | inline clobber_info::clobber_info (insn_info *insn, unsigned int regno) |
295 | : def_info (insn, { .mode: E_BLKmode, .regno: regno }, access_kind::CLOBBER), |
296 | m_children (), |
297 | m_parent (nullptr), |
298 | m_group (nullptr) |
299 | { |
300 | } |
301 | |
302 | // Set the containing group to GROUP, if it isn't already. The main |
303 | // use of this function is to update the new root of GROUP's splay tree. |
304 | inline void |
305 | clobber_info::update_group (clobber_group *group) |
306 | { |
307 | if (UNLIKELY (m_group != group)) |
308 | m_group = group; |
309 | } |
310 | |
311 | // Cconstruct a set_info for a store to RESOURCE in INSN, giving it |
312 | // kind KIND. |
313 | inline set_info::set_info (insn_info *insn, resource_info resource, |
314 | access_kind kind) |
315 | : def_info (insn, resource, kind), |
316 | m_first_use (nullptr) |
317 | { |
318 | } |
319 | |
320 | // Cconstruct a set_info for a store to RESOURCE in INSN. |
321 | inline set_info::set_info (insn_info *insn, resource_info resource) |
322 | : set_info (insn, resource, access_kind::SET) |
323 | { |
324 | } |
325 | |
326 | // Record that USE is the first use of this definition. |
327 | inline void |
328 | set_info::set_first_use (use_info *first_use) |
329 | { |
330 | m_first_use = first_use; |
331 | m_is_set_with_nondebug_insn_uses |
332 | = (first_use && first_use->is_in_nondebug_insn ()); |
333 | } |
334 | |
335 | // Construct a phi for RESOURCE in INSN, giving it identifier UID. |
336 | inline phi_info::phi_info (insn_info *insn, resource_info resource, |
337 | unsigned int uid) |
338 | : set_info (insn, resource, access_kind::PHI), |
339 | m_uid (uid), |
340 | m_num_inputs (0), |
341 | m_prev_phi (nullptr), |
342 | m_next_phi (nullptr) |
343 | { |
344 | } |
345 | |
346 | // Turn the phi into a degenerate phi, with INPUT representing the |
347 | // value of the resource on all incoming edges. |
348 | inline void |
349 | phi_info::make_degenerate (use_info *input) |
350 | { |
351 | m_num_inputs = 1; |
352 | m_single_input = input; |
353 | } |
354 | |
355 | // Set the inputs of the phi to INPUTS. |
356 | inline void |
357 | phi_info::set_inputs (use_array inputs) |
358 | { |
359 | m_num_inputs = inputs.size (); |
360 | if (inputs.size () == 1) |
361 | m_single_input = inputs[0]; |
362 | else |
363 | m_inputs = access_array (inputs).begin (); |
364 | } |
365 | |
366 | // Construct a definition splay tree node for FIRST_DEF, which is either |
367 | // the first clobber_info in a group or a standalone set_info. |
368 | inline def_node::def_node (clobber_or_set first_def) |
369 | : m_clobber_or_set (first_def), |
370 | m_children () |
371 | { |
372 | } |
373 | |
374 | // Construct a new group of clobber_infos that initially contains just CLOBBER. |
375 | inline clobber_group::clobber_group (clobber_info *clobber) |
376 | : def_node (clobber), |
377 | m_last_clobber (clobber), |
378 | m_clobber_tree (clobber) |
379 | { |
380 | clobber->m_group = this; |
381 | } |
382 | |
383 | // Construct a node for the instruction with uid UID. |
384 | inline insn_info::order_node::order_node (int uid) |
385 | : insn_note (kind), |
386 | m_children (), |
387 | m_parent (nullptr) |
388 | { |
389 | m_data32 = uid; |
390 | } |
391 | |
392 | // Construct a note for instruction INSN, giving it abi_id () value ABI_ID. |
393 | inline insn_call_clobbers_note::insn_call_clobbers_note (unsigned int abi_id, |
394 | insn_info *insn) |
395 | : insn_note (kind), |
396 | m_children (), |
397 | m_insn (insn) |
398 | { |
399 | m_data32 = abi_id; |
400 | } |
401 | |
402 | // Construct an instruction with the given bb () and rtl () values. |
403 | // If the instruction is real, COST_OR_UID is the value of cost (), |
404 | // otherwise it is the value of uid (). |
405 | inline insn_info::insn_info (bb_info *bb, rtx_insn *rtl, int cost_or_uid) |
406 | : m_prev_insn_or_last_debug_insn (nullptr), |
407 | m_next_nondebug_or_debug_insn (nullptr), |
408 | m_bb (bb), |
409 | m_rtl (rtl), |
410 | m_accesses (nullptr), |
411 | m_num_uses (0), |
412 | m_num_defs (0), |
413 | m_is_debug_insn (rtl && DEBUG_INSN_P (rtl)), |
414 | m_can_be_optimized (false), |
415 | m_is_asm (false), |
416 | m_has_pre_post_modify (false), |
417 | m_has_volatile_refs (false), |
418 | m_is_temp (false), |
419 | m_spare (0), |
420 | m_point (0), |
421 | m_cost_or_uid (cost_or_uid), |
422 | m_first_note (nullptr) |
423 | { |
424 | } |
425 | |
426 | // Copy any insn properties from PROPERTIES that are also stored in an |
427 | // insn_info. |
428 | inline void |
429 | insn_info::set_properties (const rtx_properties &properties) |
430 | { |
431 | m_is_asm = properties.has_asm; |
432 | m_has_pre_post_modify = properties.has_pre_post_modify; |
433 | m_has_volatile_refs = properties.has_volatile_refs; |
434 | // Not strictly related to the properties we've been given, but it's |
435 | // a convenient location to do this. |
436 | m_can_be_optimized = (NONDEBUG_INSN_P (m_rtl) |
437 | & (GET_CODE (PATTERN (m_rtl)) != USE) |
438 | & (GET_CODE (PATTERN (m_rtl)) != CLOBBER)); |
439 | } |
440 | |
441 | // Change the list of instruction accesses to ACCESSES, which contains |
442 | // NUM_DEFS definitions followed by NUM_USES uses. |
443 | inline void |
444 | insn_info::set_accesses (access_info **accesses, |
445 | unsigned int num_defs, unsigned int num_uses) |
446 | { |
447 | m_accesses = accesses; |
448 | m_num_defs = num_defs; |
449 | gcc_assert (num_defs == m_num_defs); |
450 | m_num_uses = num_uses; |
451 | } |
452 | |
453 | // Change defs () and uses () to DEFS and USES respectively, given that |
454 | // the existing m_accesses array has enough room for them. |
455 | inline void |
456 | insn_info::copy_accesses (access_array defs, access_array uses) |
457 | { |
458 | gcc_assert (defs.size () + uses.size () <= m_num_defs + m_num_uses); |
459 | memcpy (dest: m_accesses, src: defs.begin (), n: defs.size_bytes ()); |
460 | memcpy (dest: m_accesses + defs.size (), src: uses.begin (), n: uses.size_bytes ()); |
461 | m_num_defs = defs.size (); |
462 | gcc_assert (m_num_defs == defs.size ()); |
463 | m_num_uses = uses.size (); |
464 | } |
465 | |
466 | // If the instruction has an insn_info::order_node, return the node, |
467 | // otherwise return null. |
468 | inline insn_info::order_node * |
469 | insn_info::get_order_node () const |
470 | { |
471 | // The order_node always comes first. |
472 | if (insn_note *note = first_note ()) |
473 | return note->dyn_cast<insn_info::order_node *> (); |
474 | return nullptr; |
475 | } |
476 | |
477 | // Like get_order_node (), but the node is known to exist. |
478 | inline insn_info::order_node * |
479 | insn_info::get_known_order_node () const |
480 | { |
481 | // The order_node always comes first. |
482 | return first_note ()->as_a<insn_info::order_node *> (); |
483 | } |
484 | |
485 | // Copy the overloaded prev link from OTHER. |
486 | inline void |
487 | insn_info::copy_prev_from (insn_info *other) |
488 | { |
489 | m_prev_insn_or_last_debug_insn = other->m_prev_insn_or_last_debug_insn; |
490 | } |
491 | |
492 | // Copy the overloaded next link from OTHER. |
493 | inline void |
494 | insn_info::copy_next_from (insn_info *other) |
495 | { |
496 | m_next_nondebug_or_debug_insn = other->m_next_nondebug_or_debug_insn; |
497 | } |
498 | |
499 | // If this is a nondebug instruction, record that the previous nondebug |
500 | // instruction is PREV. (There might be intervening debug instructions.) |
501 | // |
502 | // If this is a debug instruction, record that the previous instruction |
503 | // is debug instruction PREV. |
504 | inline void |
505 | insn_info::set_prev_sametype_insn (insn_info *prev) |
506 | { |
507 | m_prev_insn_or_last_debug_insn.set_first (prev); |
508 | } |
509 | |
510 | // Only valid for debug instructions. Record that this instruction starts |
511 | // a subsequence of debug instructions that ends with LAST. |
512 | inline void |
513 | insn_info::set_last_debug_insn (insn_info *last) |
514 | { |
515 | m_prev_insn_or_last_debug_insn.set_second (last); |
516 | } |
517 | |
518 | // Record that the next instruction of any kind is NEXT. |
519 | inline void |
520 | insn_info::set_next_any_insn (insn_info *next) |
521 | { |
522 | if (next && next->is_debug_insn ()) |
523 | m_next_nondebug_or_debug_insn.set_second (next); |
524 | else |
525 | m_next_nondebug_or_debug_insn.set_first (next); |
526 | } |
527 | |
528 | // Clear the list links and point number for this instruction. |
529 | inline void |
530 | insn_info::clear_insn_links () |
531 | { |
532 | m_prev_insn_or_last_debug_insn = nullptr; |
533 | m_next_nondebug_or_debug_insn = nullptr; |
534 | m_point = 0; |
535 | } |
536 | |
537 | // Return true if the instruction contains any list information. |
538 | // This is used by assert checking. |
539 | inline bool |
540 | insn_info::has_insn_links () |
541 | { |
542 | return (m_prev_insn_or_last_debug_insn |
543 | || m_next_nondebug_or_debug_insn |
544 | || m_point); |
545 | } |
546 | |
547 | // Construct a representation of basic block CFG_BB. |
548 | inline bb_info::bb_info (basic_block cfg_bb) |
549 | : m_prev_bb (nullptr), |
550 | m_next_bb (nullptr), |
551 | m_cfg_bb (cfg_bb), |
552 | m_ebb (nullptr), |
553 | m_head_insn (nullptr), |
554 | m_end_insn (nullptr) |
555 | { |
556 | } |
557 | |
558 | // Construct a tree of call clobbers for the given ABI. |
559 | inline ebb_call_clobbers_info:: |
560 | ebb_call_clobbers_info (const predefined_function_abi *abi) |
561 | : m_next (nullptr), |
562 | m_abi (abi) |
563 | { |
564 | } |
565 | |
566 | // Construct an EBB whose first block is FIRST_BB and whose last block |
567 | // is LAST_BB. |
568 | inline ebb_info::ebb_info (bb_info *first_bb, bb_info *last_bb) |
569 | : m_first_phi (nullptr), |
570 | m_phi_insn (nullptr), |
571 | m_first_bb (first_bb), |
572 | m_last_bb (last_bb), |
573 | m_first_call_clobbers (nullptr) |
574 | { |
575 | } |
576 | |
577 | // Record register definition DEF in last_access, pushing a definition |
578 | // to def_stack where appropriate. |
579 | inline void |
580 | function_info::build_info::record_reg_def (def_info *def) |
581 | { |
582 | unsigned int regno = def->regno (); |
583 | auto *prev_dominating_def = safe_as_a<def_info *> (p: last_access[regno + 1]); |
584 | if (!prev_dominating_def) |
585 | // Indicate that DEF is the first dominating definition of REGNO. |
586 | def_stack.safe_push (obj: def); |
587 | else if (prev_dominating_def->bb () != def->bb ()) |
588 | // Record that PREV_DOMINATING_DEF was the dominating definition |
589 | // of REGNO on entry to the current block. |
590 | def_stack.safe_push (obj: prev_dominating_def); |
591 | last_access[regno + 1] = def; |
592 | } |
593 | |
594 | // Set the contents of last_access for memory to DEF. |
595 | inline void |
596 | function_info::build_info::record_mem_def (def_info *def) |
597 | { |
598 | last_access[0] = def; |
599 | } |
600 | |
601 | // Return the current value of live register REGNO, or null if the register's |
602 | // value is completedly undefined. |
603 | inline set_info * |
604 | function_info::build_info::current_reg_value (unsigned int regno) const |
605 | { |
606 | return safe_dyn_cast<set_info *> (p: last_access[regno + 1]); |
607 | } |
608 | |
609 | // Return the current value of memory. |
610 | inline set_info * |
611 | function_info::build_info::current_mem_value () const |
612 | { |
613 | return as_a<set_info *> (p: last_access[0]); |
614 | } |
615 | |
616 | // Allocate a T on the function's main obstack, passing ARGS |
617 | // to its constructor. |
618 | template<typename T, typename... Ts> |
619 | inline T * |
620 | function_info::allocate (Ts... args) |
621 | { |
622 | static_assert (std::is_trivially_destructible<T>::value, |
623 | "destructor won't be called" ); |
624 | static_assert (alignof (T) <= obstack_alignment, |
625 | "too much alignment required" ); |
626 | void *addr = obstack_alloc (&m_obstack, sizeof (T)); |
627 | return new (addr) T (std::forward<Ts> (args)...); |
628 | } |
629 | |
630 | // Allocate a T on the function's temporary obstack, passing ARGS |
631 | // to its constructor. |
632 | template<typename T, typename... Ts> |
633 | inline T * |
634 | function_info::allocate_temp (Ts... args) |
635 | { |
636 | static_assert (std::is_trivially_destructible<T>::value, |
637 | "destructor won't be called" ); |
638 | static_assert (alignof (T) <= obstack_alignment, |
639 | "too much alignment required" ); |
640 | void *addr = obstack_alloc (&m_temp_obstack, sizeof (T)); |
641 | return new (addr) T (std::forward<Ts> (args)...); |
642 | } |
643 | |
644 | // Add INSN to the end of the function's list of instructions. |
645 | inline void |
646 | function_info::append_insn (insn_info *insn) |
647 | { |
648 | gcc_checking_assert (!insn->has_insn_links ()); |
649 | if (insn_info *after = m_last_insn) |
650 | add_insn_after (insn, after); |
651 | else |
652 | // The first instruction is for the entry block and is always a nondebug |
653 | // insn |
654 | m_first_insn = m_last_insn = m_last_nondebug_insn = insn; |
655 | } |
656 | |
657 | // Start building a new list of uses and definitions for an instruction. |
658 | inline void |
659 | function_info::start_insn_accesses () |
660 | { |
661 | gcc_checking_assert (m_temp_defs.is_empty () |
662 | && m_temp_uses.is_empty ()); |
663 | } |
664 | |
665 | // Return a mode that encapsulates two distinct references to a register, |
666 | // one with mode MODE1 and one with mode MODE2. Treat BLKmode as a |
667 | // "don't know" wildcard. |
668 | inline machine_mode |
669 | combine_modes (machine_mode mode1, machine_mode mode2) |
670 | { |
671 | if (mode1 == E_BLKmode) |
672 | return mode2; |
673 | |
674 | if (mode2 == E_BLKmode) |
675 | return mode1; |
676 | |
677 | if (!ordered_p (a: GET_MODE_SIZE (mode: mode1), b: GET_MODE_SIZE (mode: mode2))) |
678 | return BLKmode; |
679 | |
680 | return wider_subreg_mode (outermode: mode1, innermode: mode2); |
681 | } |
682 | |
683 | // PRINTER (PP, ARGS...) prints ARGS... to a pretty_printer PP. Use it |
684 | // to print ARGS... to FILE. |
685 | template<typename Printer, typename... Args> |
686 | inline void |
687 | dump_using (FILE *file, Printer printer, Args... args) |
688 | { |
689 | pretty_printer pp; |
690 | printer (&pp, args...); |
691 | pp_newline (&pp); |
692 | fprintf (stream: file, format: "%s" , pp_formatted_text (&pp)); |
693 | } |
694 | |
695 | } |
696 | |