Line data Source code
1 : // RTL SSA routines for changing instructions -*- C++ -*-
2 : // Copyright (C) 2020-2026 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 : #define INCLUDE_ALGORITHM
21 : #define INCLUDE_FUNCTIONAL
22 : #define INCLUDE_ARRAY
23 : #include "config.h"
24 : #include "system.h"
25 : #include "coretypes.h"
26 : #include "backend.h"
27 : #include "rtl.h"
28 : #include "df.h"
29 : #include "rtl-ssa.h"
30 : #include "rtl-ssa/internals.h"
31 : #include "rtl-ssa/internals.inl"
32 : #include "target.h"
33 : #include "predict.h"
34 : #include "memmodel.h" // Needed by emit-rtl.h
35 : #include "emit-rtl.h"
36 : #include "cfghooks.h"
37 : #include "cfgrtl.h"
38 : #include "sreal.h"
39 :
40 : using namespace rtl_ssa;
41 :
42 : // See the comment above the declaration.
43 : void
44 0 : insn_change::print (pretty_printer *pp) const
45 : {
46 0 : if (m_is_deletion)
47 : {
48 0 : pp_string (pp, "deletion of ");
49 0 : pp_insn (pp, m_insn);
50 : }
51 : else
52 : {
53 0 : pp_string (pp, "change to ");
54 0 : pp_insn (pp, m_insn);
55 0 : pp_newline_and_indent (pp, 2);
56 0 : pp_string (pp, "~~~~~~~");
57 :
58 0 : pp_newline_and_indent (pp, 0);
59 0 : pp_string (pp, "new cost: ");
60 0 : pp_decimal_int (pp, new_cost);
61 :
62 0 : pp_newline_and_indent (pp, 0);
63 0 : pp_string (pp, "new uses:");
64 0 : pp_newline_and_indent (pp, 2);
65 0 : pp_accesses (pp, new_uses);
66 0 : pp_indentation (pp) -= 2;
67 :
68 0 : pp_newline_and_indent (pp, 0);
69 0 : pp_string (pp, "new defs:");
70 0 : pp_newline_and_indent (pp, 2);
71 0 : pp_accesses (pp, new_defs);
72 0 : pp_indentation (pp) -= 2;
73 :
74 0 : pp_newline_and_indent (pp, 0);
75 0 : pp_string (pp, "first insert-after candidate: ");
76 0 : move_range.first->print_identifier_and_location (pp);
77 :
78 0 : pp_newline_and_indent (pp, 0);
79 0 : pp_string (pp, "last insert-after candidate: ");
80 0 : move_range.last->print_identifier_and_location (pp);
81 : }
82 0 : }
83 :
84 : // Return a copy of access_array ACCESSES, allocating it on the
85 : // temporary obstack.
86 : access_array
87 36952640 : function_info::temp_access_array (access_array accesses)
88 : {
89 36952640 : if (accesses.empty ())
90 10144349 : return accesses;
91 :
92 26808291 : gcc_assert (obstack_object_size (&m_temp_obstack) == 0);
93 26808291 : obstack_grow (&m_temp_obstack, accesses.begin (), accesses.size_bytes ());
94 26808291 : return { static_cast<access_info **> (obstack_finish (&m_temp_obstack)),
95 26808291 : accesses.size () };
96 : }
97 :
98 : // See the comment above the declaration.
99 : bool
100 2172089 : function_info::verify_insn_changes (array_slice<insn_change *const> changes)
101 : {
102 2172089 : HARD_REG_SET defined_hard_regs, clobbered_hard_regs;
103 8688356 : CLEAR_HARD_REG_SET (defined_hard_regs);
104 2172089 : CLEAR_HARD_REG_SET (clobbered_hard_regs);
105 :
106 2172089 : insn_info *min_insn = m_first_insn;
107 10105323 : for (insn_change *change : changes)
108 7937531 : if (!change->is_deletion ())
109 : {
110 : // Make sure that the changes can be kept in their current order
111 : // while honoring all of the move ranges.
112 5765442 : min_insn = later_insn (min_insn, change->move_range.first);
113 5765450 : while (min_insn && min_insn != change->insn () && !can_insert_after (min_insn))
114 8 : min_insn = min_insn->next_nondebug_insn ();
115 :
116 5765442 : if (!min_insn || *min_insn > *change->move_range.last)
117 : {
118 4238 : if (dump_file && (dump_flags & TDF_DETAILS))
119 0 : fprintf (dump_file, "no viable insn position assignment\n");
120 4238 : return false;
121 : }
122 :
123 : // If recog introduced new clobbers of a register as part of
124 : // the matching process, make sure that they don't conflict
125 : // with any other new definitions or uses of the register.
126 : // (We have already checked that they don't conflict with
127 : // unchanging definitions and uses.)
128 15619095 : for (use_info *use : change->new_uses)
129 : {
130 9857891 : unsigned int regno = use->regno ();
131 9857891 : if (HARD_REGISTER_NUM_P (regno)
132 9857891 : && TEST_HARD_REG_BIT (clobbered_hard_regs, regno))
133 : {
134 0 : if (dump_file && (dump_flags & TDF_DETAILS))
135 0 : fprintf (dump_file, "register %d would be clobbered"
136 : " while it is still live\n", regno);
137 0 : return false;
138 : }
139 : }
140 12151038 : for (def_info *def : change->new_defs)
141 : {
142 6389893 : unsigned int regno = def->regno ();
143 6389893 : if (HARD_REGISTER_NUM_P (regno))
144 : {
145 3037778 : if (def->m_is_temp)
146 : {
147 : // This is a clobber introduced by recog.
148 28961 : gcc_checking_assert (is_a<clobber_info *> (def));
149 28961 : if (TEST_HARD_REG_BIT (defined_hard_regs, regno))
150 : {
151 59 : if (dump_file && (dump_flags & TDF_DETAILS))
152 0 : fprintf (dump_file, "conflicting definitions of"
153 : " register %d\n", regno);
154 59 : return false;
155 : }
156 28902 : SET_HARD_REG_BIT (clobbered_hard_regs, regno);
157 : }
158 9398651 : else if (is_a<set_info *> (def))
159 : {
160 : // REGNO now has a defined value.
161 2467411 : SET_HARD_REG_BIT (defined_hard_regs, regno);
162 2467411 : CLEAR_HARD_REG_BIT (clobbered_hard_regs, regno);
163 : }
164 : }
165 : }
166 : }
167 : return true;
168 : }
169 :
170 : // See the comment above the declaration.
171 : bool
172 8572392 : rtl_ssa::changes_are_worthwhile (array_slice<insn_change *const> changes,
173 : bool strict_p)
174 : {
175 8572392 : unsigned int old_cost = 0;
176 8572392 : sreal weighted_old_cost = 0;
177 8572392 : auto entry_count = ENTRY_BLOCK_PTR_FOR_FN (cfun)->count;
178 8572392 : {
179 8572392 : undo_recog_changes undo (0);
180 23449262 : for (insn_change *change : changes)
181 : {
182 : // Count zero for the old cost if the old instruction was a no-op
183 : // move or had an unknown cost. This should reduce the chances of
184 : // making an unprofitable change.
185 14876870 : old_cost += change->old_cost ();
186 14876870 : basic_block cfg_bb = change->bb ()->cfg_bb ();
187 14876870 : if (optimize_bb_for_speed_p (cfg_bb))
188 13093806 : weighted_old_cost += (cfg_bb->count.to_sreal_scale (entry_count)
189 13093806 : * change->old_cost ());
190 :
191 : }
192 8572392 : }
193 8572392 : unsigned int new_cost = 0;
194 8572392 : sreal weighted_new_cost = 0;
195 23363332 : for (insn_change *change : changes)
196 : {
197 14819917 : basic_block cfg_bb = change->bb ()->cfg_bb ();
198 14819917 : bool for_speed = optimize_bb_for_speed_p (cfg_bb);
199 14819917 : if (!change->is_deletion ()
200 14819917 : && INSN_CODE (change->rtl ()) != NOOP_MOVE_INSN_CODE)
201 : {
202 12446706 : change->new_cost = insn_cost (change->rtl (), for_speed);
203 : /* If the cost is unknown, replacement is not worthwhile. */
204 12446706 : if (!change->new_cost)
205 : {
206 28977 : if (dump_file && (dump_flags & TDF_DETAILS))
207 0 : fprintf (dump_file,
208 : "Reject replacement due to unknown insn cost.\n");
209 28977 : return false;
210 : }
211 12417729 : new_cost += change->new_cost;
212 12417729 : if (for_speed)
213 32756286 : weighted_new_cost += (cfg_bb->count.to_sreal_scale (entry_count)
214 10918762 : * change->new_cost);
215 : }
216 : }
217 8543415 : bool ok_p;
218 8543415 : if (weighted_new_cost != weighted_old_cost)
219 3283954 : ok_p = weighted_new_cost < weighted_old_cost;
220 5259461 : else if (strict_p)
221 3642479 : ok_p = new_cost < old_cost;
222 : else
223 1616982 : ok_p = new_cost <= old_cost;
224 8543415 : if (dump_file && (dump_flags & TDF_DETAILS))
225 : {
226 0 : fprintf (dump_file, "original cost");
227 0 : char sep = '=';
228 0 : for (const insn_change *change : changes)
229 : {
230 0 : fprintf (dump_file, " %c %d", sep, change->old_cost ());
231 0 : sep = '+';
232 : }
233 0 : if (weighted_old_cost != 0)
234 0 : fprintf (dump_file, " (weighted: %f)", weighted_old_cost.to_double ());
235 0 : fprintf (dump_file, ", replacement cost");
236 0 : sep = '=';
237 0 : for (const insn_change *change : changes)
238 0 : if (!change->is_deletion ())
239 : {
240 0 : if (INSN_CODE (change->rtl ()) == NOOP_MOVE_INSN_CODE)
241 0 : fprintf (dump_file, " %c nop", sep);
242 : else
243 0 : fprintf (dump_file, " %c %d", sep, change->new_cost);
244 : sep = '+';
245 : }
246 0 : if (weighted_new_cost != 0)
247 0 : fprintf (dump_file, " (weighted: %f)", weighted_new_cost.to_double ());
248 0 : fprintf (dump_file, "; %s\n",
249 : ok_p ? "keeping replacement" : "rejecting replacement");
250 : }
251 8543415 : if (!ok_p)
252 : return false;
253 :
254 : return true;
255 : }
256 :
257 : // SET has been deleted. Clean up all remaining uses. Such uses are
258 : // either dead phis or now-redundant live-out uses.
259 : void
260 686116 : function_info::process_uses_of_deleted_def (set_info *set)
261 : {
262 : // Each member of the worklist is either SET or a dead phi.
263 686116 : auto_vec<set_info *, 16> worklist;
264 686116 : worklist.quick_push (set);
265 2716572 : while (!worklist.is_empty ())
266 : {
267 1344340 : auto *this_set = worklist.pop ();
268 1344340 : auto *use = this_set->first_use ();
269 1344340 : if (!use)
270 : {
271 26005 : if (this_set != set)
272 26005 : delete_phi (as_a<phi_info *> (this_set));
273 26005 : continue;
274 : }
275 1318335 : if (use->is_in_phi ())
276 : {
277 : // Removing all uses from the phi ensures that we'll only add
278 : // the phi to the worklist once.
279 26005 : auto *phi = use->phi ();
280 78015 : for (auto *input : phi->inputs ())
281 : {
282 26005 : remove_use (input);
283 26005 : input->set_def (nullptr);
284 : }
285 26005 : worklist.safe_push (phi);
286 : }
287 : else
288 : {
289 1292330 : gcc_assert (use->is_live_out_use ());
290 1292330 : remove_use (use);
291 : }
292 : // The phi handling above might have removed multiple uses of THIS_SET.
293 1318335 : if (this_set->has_any_uses ())
294 632219 : worklist.safe_push (this_set);
295 : }
296 686116 : }
297 :
298 : // Update the REG_NOTES of INSN, whose pattern has just been changed.
299 : static void
300 18476320 : update_notes (rtx_insn *insn)
301 : {
302 40547439 : for (rtx *note_ptr = ®_NOTES (insn); *note_ptr; )
303 : {
304 22071119 : rtx note = *note_ptr;
305 22071119 : bool keep_p = true;
306 22071119 : switch (REG_NOTE_KIND (note))
307 : {
308 233792 : case REG_EQUAL:
309 233792 : case REG_EQUIV:
310 233792 : case REG_NOALIAS:
311 233792 : keep_p = (single_set (insn) != nullptr);
312 233792 : break;
313 :
314 : case REG_UNUSED:
315 : case REG_DEAD:
316 : // These notes are stale. We'll recompute REG_UNUSED notes
317 : // after the update.
318 : keep_p = false;
319 : break;
320 :
321 : default:
322 : break;
323 : }
324 233792 : if (keep_p)
325 8154800 : note_ptr = &XEXP (*note_ptr, 1);
326 : else
327 : {
328 13916319 : *note_ptr = XEXP (*note_ptr, 1);
329 13916319 : free_EXPR_LIST_node (note);
330 : }
331 : }
332 18476320 : }
333 :
334 : // Pick a location for CHANGE's instruction and return the instruction
335 : // after which it should be placed.
336 : static insn_info *
337 18476320 : choose_insn_placement (insn_change &change)
338 : {
339 18476320 : gcc_checking_assert (change.move_range);
340 :
341 18476320 : insn_info *insn = change.insn ();
342 18476320 : insn_info *first = change.move_range.first;
343 18476320 : insn_info *last = change.move_range.last;
344 :
345 : // Quick(ish) exit if there is only one possible choice.
346 18476320 : if (first == last)
347 : return first;
348 588610 : if (first == insn->prev_nondebug_insn () && last == insn)
349 : return insn;
350 :
351 : // For now just use the closest valid choice to the original instruction.
352 : // If the register usage has changed significantly, it might instead be
353 : // better to try to take register pressure into account.
354 501464 : insn_info *closest = change.move_range.clamp_insn_to_range (insn);
355 1002928 : while (closest != insn && !can_insert_after (closest))
356 0 : closest = closest->next_nondebug_insn ();
357 : return closest;
358 : }
359 :
360 : // Record any changes related to CHANGE that need to be queued for later.
361 : void
362 20644112 : function_info::possibly_queue_changes (insn_change &change)
363 : {
364 20644112 : insn_info *insn = change.insn ();
365 20644112 : rtx_insn *rtl = insn->rtl ();
366 :
367 : // If the instruction could previously throw, we eventually need to call
368 : // purge_dead_edges to check whether things have changed.
369 20644112 : if (find_reg_note (rtl, REG_EH_REGION, nullptr))
370 49348 : bitmap_set_bit (m_need_to_purge_dead_edges, insn->bb ()->index ());
371 :
372 41288224 : auto needs_pending_update = [&]()
373 : {
374 : // If an instruction became a no-op without the pass explicitly
375 : // deleting it, queue the deletion for later. Removing the
376 : // instruction on the fly would require an update to all instructions
377 : // that use the result of the move, which would be a potential source
378 : // of quadraticness. Also, definitions shouldn't disappear under
379 : // the pass's feet.
380 20644112 : if (INSN_CODE (rtl) == NOOP_MOVE_INSN_CODE)
381 : return true;
382 :
383 : // If any jumps got turned into unconditional jumps or nops, we need
384 : // to update the CFG accordingly.
385 20638499 : if (JUMP_P (rtl)
386 7868684 : && (returnjump_p (rtl) || any_uncondjump_p (rtl))
387 20644147 : && !single_succ_p (insn->bb ()->cfg_bb ()))
388 : return true;
389 :
390 : // If a previously conditional trap now always fires, execution
391 : // terminates at that point.
392 20638464 : rtx pattern = PATTERN (rtl);
393 20638464 : if (GET_CODE (pattern) == TRAP_IF
394 0 : && XEXP (pattern, 0) == const1_rtx)
395 : return true;
396 :
397 : return false;
398 20644112 : };
399 :
400 20644112 : if (needs_pending_update ()
401 20644112 : && bitmap_set_bit (m_queued_insn_update_uids, insn->uid ()))
402 : {
403 5441 : gcc_assert (!change.is_deletion ());
404 5441 : m_queued_insn_updates.safe_push (insn);
405 : }
406 20644112 : }
407 :
408 : // Remove the instruction described by CHANGE from the underlying RTL
409 : // and from the insn_info list.
410 : static void
411 2167792 : delete_insn (insn_change &change)
412 : {
413 2167792 : insn_info *insn = change.insn ();
414 2167792 : rtx_insn *rtl = change.rtl ();
415 2167792 : if (dump_file && (dump_flags & TDF_DETAILS))
416 0 : fprintf (dump_file, "deleting insn %d\n", insn->uid ());
417 2167792 : set_insn_deleted (rtl);
418 2167792 : }
419 :
420 : // Move the RTL instruction associated with CHANGE so that it comes
421 : // immediately after AFTER.
422 : static void
423 25361 : move_insn (insn_change &change, insn_info *after)
424 : {
425 25361 : rtx_insn *rtl = change.rtl ();
426 25361 : rtx_insn *after_rtl = after->rtl ();
427 25361 : if (dump_file && (dump_flags & TDF_DETAILS))
428 0 : fprintf (dump_file, "moving insn %d after insn %d\n",
429 0 : INSN_UID (rtl), INSN_UID (after_rtl));
430 :
431 : // At the moment we don't support moving instructions between EBBs,
432 : // but this would be worth adding if it's useful.
433 25361 : insn_info *insn = change.insn ();
434 :
435 25361 : bb_info *bb = after->bb ();
436 25361 : basic_block cfg_bb = bb->cfg_bb ();
437 :
438 25361 : if (!insn->is_temporary ())
439 : {
440 25361 : gcc_assert (after->ebb () == insn->ebb ());
441 :
442 25361 : if (insn->bb () != bb)
443 : // Force DF to mark the old block as dirty.
444 18 : df_insn_delete (rtl);
445 25361 : ::remove_insn (rtl);
446 : }
447 :
448 25361 : ::add_insn_after (rtl, after_rtl, cfg_bb);
449 25361 : }
450 :
451 : // The instruction associated with CHANGE is being changed in-place.
452 : // Update the DF information for its new pattern.
453 : static void
454 18450959 : update_insn_in_place (insn_change &change)
455 : {
456 18450959 : insn_info *insn = change.insn ();
457 18450959 : if (dump_file && (dump_flags & TDF_DETAILS))
458 0 : fprintf (dump_file, "updating insn %d in-place\n", insn->uid ());
459 18450959 : df_insn_rescan (change.rtl ());
460 18450959 : }
461 :
462 : // Finalize the new list of definitions and uses in CHANGE, removing
463 : // any uses and definitions that are no longer needed, and converting
464 : // pending clobbers into actual definitions.
465 : //
466 : // POS gives the final position of INSN, which hasn't yet been moved into
467 : // place. Keep track of any newly-created set_infos being added with this
468 : // change by adding them to NEW_SETS.
469 : void
470 18476320 : function_info::finalize_new_accesses (insn_change &change, insn_info *pos,
471 : hash_set<def_info *> &new_sets)
472 : {
473 18476320 : insn_info *insn = change.insn ();
474 :
475 : // Get a list of all the things that the instruction now references.
476 18476320 : vec_rtx_properties properties;
477 18476320 : properties.add_insn (insn->rtl (), true);
478 :
479 : // Build up the new list of definitions.
480 52472006 : for (rtx_obj_reference ref : properties.refs ())
481 33995686 : if (ref.is_write ())
482 : {
483 9653870 : def_info *def = find_access (change.new_defs, ref.regno);
484 9653870 : gcc_assert (def);
485 :
486 9653870 : if (def->m_is_temp && is_a<set_info *> (def) && def->last_def ())
487 : {
488 : // For temporary sets being added with this change, we keep track of
489 : // the corresponding permanent def using the last_def link.
490 : //
491 : // So if we have one of these, follow it to get the permanent def.
492 0 : def = def->last_def ();
493 0 : gcc_assert (!def->m_is_temp && !def->m_has_been_superceded);
494 : }
495 :
496 9653870 : if (def->m_is_temp)
497 : {
498 29981 : if (is_a<clobber_info *> (def))
499 29981 : def = allocate<clobber_info> (change.insn (), ref.regno);
500 0 : else if (is_a<set_info *> (def))
501 : {
502 : // Install the permanent set in the last_def link of the
503 : // temporary def. This allows us to find the permanent def
504 : // later in case we see a second write to the same resource.
505 0 : def_info *perm_def = allocate<set_info> (change.insn (),
506 0 : def->resource ());
507 :
508 : // Keep track of the new set so we remember to add it to the
509 : // def chain later.
510 0 : if (new_sets.add (perm_def))
511 0 : gcc_unreachable (); // We shouldn't see duplicates here.
512 :
513 0 : def->set_last_def (perm_def);
514 0 : def = perm_def;
515 : }
516 : else
517 0 : gcc_unreachable ();
518 : }
519 9623889 : else if (!def->m_has_been_superceded)
520 : {
521 : // This is a second or subsequent definition.
522 : // See function_info::record_def for a discussion of when
523 : // this can happen.
524 688 : def->record_reference (ref, false);
525 688 : continue;
526 : }
527 : else
528 : {
529 9623201 : def->m_has_been_superceded = false;
530 :
531 : // Clobbers can move around, so remove them from their current
532 : // position and them back in their final position.
533 : //
534 : // At the moment, we don't allow sets to move relative to other
535 : // definitions of the same resource, so we can leave those where
536 : // they are. It might be useful to relax this in future.
537 : // The main complication is that removing a set would potentially
538 : // fuse two adjoining clobber_groups, and adding the set back
539 : // would require the group to be split again.
540 9623201 : if (is_a<clobber_info *> (def))
541 949270 : remove_def (def);
542 8673931 : else if (ref.is_reg ())
543 6559180 : def->set_mode (ref.mode);
544 9623201 : def->set_insn (insn);
545 : }
546 9653182 : def->record_reference (ref, true);
547 9653182 : m_temp_defs.safe_push (def);
548 : }
549 :
550 : // Also keep any explicitly-recorded call clobbers, which are deliberately
551 : // excluded from the vec_rtx_properties. Calls shouldn't move, so we can
552 : // keep the definitions in their current position.
553 : //
554 : // If the change describes a set of memory, but the pattern doesn't
555 : // reference memory, keep the set anyway. This can happen if the
556 : // old pattern was a parallel that contained a memory clobber, and if
557 : // the new pattern was recognized without that clobber. Keeping the
558 : // set avoids a linear-complexity update to the set's users.
559 : //
560 : // ??? We could queue an update so that these bogus clobbers are
561 : // removed later.
562 28167012 : for (def_info *def : change.new_defs)
563 9690692 : if (def->m_has_been_superceded
564 9690692 : && (def->is_call_clobber () || def->is_mem ()))
565 : {
566 0 : def->m_has_been_superceded = false;
567 0 : def->set_insn (insn);
568 0 : m_temp_defs.safe_push (def);
569 : }
570 :
571 : // Install the new list of definitions in CHANGE.
572 18476320 : sort_accesses (m_temp_defs);
573 36952640 : access_array accesses = temp_access_array (m_temp_defs);
574 18476320 : change.new_defs = def_array (accesses);
575 18476320 : m_temp_defs.truncate (0);
576 :
577 : // Create temporary copies of use_infos that are already attached to
578 : // other insns, which could happen if the uses come from unchanging
579 : // insns or if they have been used by earlier changes. Doing this
580 : // makes it easier to detect multiple reads below.
581 18476320 : auto *unshared_uses_base = XOBNEWVEC (&m_temp_obstack, access_info *,
582 : change.new_uses.size ());
583 18476320 : unsigned int i = 0;
584 45801398 : for (use_info *use : change.new_uses)
585 : {
586 27325078 : if (!use->m_has_been_superceded)
587 : {
588 7481875 : use = allocate_temp<use_info> (insn, use->resource (), use->def ());
589 7481875 : use->m_has_been_superceded = true;
590 7481875 : use->m_is_temp = true;
591 : }
592 27325078 : unshared_uses_base[i++] = use;
593 : }
594 18476320 : auto unshared_uses = use_array (unshared_uses_base, change.new_uses.size ());
595 :
596 : // Add (possibly temporary) uses to m_temp_uses for each resource.
597 : // If there are multiple references to the same resource, aggregate
598 : // information in the modes and flags.
599 18476320 : use_info *mem_use = nullptr;
600 52472006 : for (rtx_obj_reference ref : properties.refs ())
601 33995686 : if (ref.is_read ())
602 : {
603 24356771 : unsigned int regno = ref.regno;
604 24356771 : machine_mode mode = ref.is_reg () ? ref.mode : BLKmode;
605 24356771 : use_info *use = find_access (unshared_uses, ref.regno);
606 24356771 : if (!use)
607 : {
608 : // For now, we only support inferring uses of mem.
609 0 : gcc_assert (regno == MEM_REGNO);
610 :
611 0 : if (mem_use)
612 : {
613 0 : mem_use->record_reference (ref, false);
614 0 : continue;
615 : }
616 :
617 0 : resource_info resource { mode, regno };
618 0 : auto def = find_def (resource, pos).prev_def (pos);
619 0 : auto set = safe_dyn_cast <set_info *> (def);
620 0 : gcc_assert (set);
621 0 : mem_use = allocate<use_info> (insn, resource, set);
622 0 : mem_use->record_reference (ref, true);
623 0 : m_temp_uses.safe_push (mem_use);
624 0 : continue;
625 0 : }
626 :
627 24356771 : if (use->m_has_been_superceded)
628 : {
629 : // This is the first reference to the resource.
630 23891848 : bool is_temp = use->m_is_temp;
631 23891848 : *use = use_info (insn, resource_info { mode, regno }, use->def ());
632 23891848 : use->m_is_temp = is_temp;
633 23891848 : use->record_reference (ref, true);
634 23891848 : m_temp_uses.safe_push (use);
635 : }
636 : else
637 : {
638 : // Record the mode of the largest use. The choice is arbitrary if
639 : // the instruction (unusually) references the same register in two
640 : // different but equal-sized modes.
641 464923 : if (HARD_REGISTER_NUM_P (regno)
642 464923 : && partial_subreg_p (use->mode (), mode))
643 29 : use->set_mode (mode);
644 464923 : use->record_reference (ref, false);
645 : }
646 : }
647 :
648 : // Replace any temporary uses and definitions with real ones.
649 42368168 : for (unsigned int i = 0; i < m_temp_uses.length (); ++i)
650 : {
651 23891848 : auto *use = as_a<use_info *> (m_temp_uses[i]);
652 23891848 : if (use->m_is_temp)
653 : {
654 7393205 : m_temp_uses[i] = use = allocate<use_info> (*use);
655 7393205 : use->m_is_temp = false;
656 7393205 : set_info *def = use->def ();
657 7393205 : if (!def || !def->m_is_temp)
658 7379624 : continue;
659 :
660 13581 : if (auto phi = dyn_cast<phi_info *> (def))
661 : {
662 : // Handle cases in which the value was previously not used
663 : // within the block.
664 13581 : gcc_assert (phi->is_degenerate ());
665 13581 : phi = create_degenerate_phi (phi->ebb (), phi->input_value (0));
666 13581 : use->set_def (phi);
667 : }
668 : else
669 : {
670 : // The temporary def may also be a set added with this change, in
671 : // which case the permanent set is stored in the last_def link,
672 : // and we need to update the use to refer to the permanent set.
673 0 : gcc_assert (is_a<set_info *> (def));
674 0 : auto perm_set = as_a<set_info *> (def->last_def ());
675 0 : gcc_assert (!perm_set->is_temporary ());
676 0 : use->set_def (perm_set);
677 : }
678 : }
679 : }
680 :
681 : // Install the new list of uses in CHANGE.
682 18476320 : sort_accesses (m_temp_uses);
683 36952640 : change.new_uses = use_array (temp_access_array (m_temp_uses));
684 18476320 : m_temp_uses.truncate (0);
685 :
686 : // Record the new instruction-wide properties.
687 18476320 : insn->set_properties (properties);
688 18476320 : }
689 :
690 : // Copy information from CHANGE to its underlying insn_info, given that
691 : // the insn_info has already been placed appropriately. NEW_SETS contains the
692 : // new set_infos that are being added as part of this change (as opposed to
693 : // being moved or repurposed from existing instructions).
694 : void
695 20644112 : function_info::apply_changes_to_insn (insn_change &change,
696 : hash_set<def_info *> &new_sets)
697 : {
698 20644112 : insn_info *insn = change.insn ();
699 20644112 : if (change.is_deletion ())
700 : {
701 2167792 : insn->set_accesses (nullptr, 0, 0);
702 2167792 : return;
703 : }
704 :
705 : // Copy the cost.
706 18476320 : insn->set_cost (change.new_cost);
707 :
708 : // Add all clobbers and newly-created sets. Existing sets and call
709 : // clobbers never move relative to other definitions, so are OK as-is.
710 28129502 : for (def_info *def : change.new_defs)
711 9653182 : if ((is_a<clobber_info *> (def) && !def->is_call_clobber ())
712 10632433 : || (is_a<set_info *> (def) && new_sets.contains (def)))
713 979251 : add_def (def);
714 :
715 : // Add all uses, now that their position is final.
716 42368168 : for (use_info *use : change.new_uses)
717 : {
718 23891848 : if (use->def ())
719 23853181 : commit_make_use_available (use);
720 23891848 : add_use (use);
721 : }
722 :
723 : // Copy the uses and definitions.
724 18476320 : unsigned int num_defs = change.new_defs.size ();
725 18476320 : unsigned int num_uses = change.new_uses.size ();
726 18476320 : if (num_defs + num_uses <= insn->num_defs () + insn->num_uses ())
727 18187144 : insn->copy_accesses (change.new_defs, change.new_uses);
728 : else
729 : {
730 289176 : access_array_builder builder (&m_obstack);
731 289176 : builder.reserve (num_defs + num_uses);
732 :
733 640092 : for (def_info *def : change.new_defs)
734 350916 : builder.quick_push (def);
735 1025409 : for (use_info *use : change.new_uses)
736 736233 : builder.quick_push (use);
737 :
738 289176 : insn->set_accesses (builder.finish ().begin (), num_defs, num_uses);
739 289176 : }
740 :
741 18476320 : insn->m_is_temp = false;
742 : }
743 :
744 : // Add a temporary placeholder instruction after AFTER.
745 : insn_info *
746 25361 : function_info::add_placeholder_after (insn_info *after)
747 : {
748 25361 : insn_info *insn = allocate_temp<insn_info> (after->bb (), nullptr, -1);
749 25361 : add_insn_after (insn, after);
750 25361 : return insn;
751 : }
752 :
753 : // See the comment above the declaration.
754 : void
755 14896967 : function_info::change_insns (array_slice<insn_change *> changes)
756 : {
757 14896967 : auto watermark = temp_watermark ();
758 :
759 14896967 : insn_info *min_insn = m_first_insn;
760 35541079 : for (insn_change *change : changes)
761 : {
762 : // Tentatively mark all the old uses and definitions for deletion.
763 47930795 : for (use_info *use : change->old_uses ())
764 : {
765 27286683 : use->m_has_been_superceded = true;
766 27286683 : remove_use (use);
767 : }
768 32582908 : for (def_info *def : change->old_defs ())
769 11938796 : def->m_has_been_superceded = true;
770 :
771 20644112 : if (!change->is_deletion ())
772 : {
773 : // Remove any notes that are no longer relevant.
774 18476320 : if (!change->insn ()->m_is_temp)
775 18476320 : update_notes (change->rtl ());
776 :
777 : // Make sure that the placement of this instruction would still
778 : // leave room for previous instructions.
779 18476320 : change->move_range = move_later_than (change->move_range, min_insn);
780 18476320 : if (!canonicalize_move_range (change->move_range, change->insn ()))
781 : // verify_insn_changes is supposed to make sure that this holds.
782 0 : gcc_unreachable ();
783 18476320 : min_insn = later_insn (min_insn, change->move_range.first);
784 :
785 18476320 : if (change->insn ()->m_is_temp)
786 : {
787 0 : change->m_insn = allocate<insn_info> (change->insn ()->bb (),
788 : change->rtl (),
789 : change->insn_uid ());
790 :
791 : // Set the flag again so subsequent logic is aware.
792 : // It will be cleared later on.
793 0 : change->m_insn->m_is_temp = true;
794 : }
795 : }
796 : }
797 :
798 : // Walk backwards through the changes, allocating specific positions
799 : // to each one. Update the underlying RTL and its associated DF
800 : // information.
801 14896967 : insn_info *following_insn = nullptr;
802 14896967 : auto_vec<insn_info *, 16> placeholders;
803 14896967 : placeholders.safe_grow_cleared (changes.size ());
804 35541079 : for (unsigned int i = changes.size (); i-- > 0;)
805 : {
806 20644112 : insn_change &change = *changes[i];
807 20644112 : insn_info *placeholder = nullptr;
808 20644112 : possibly_queue_changes (change);
809 20644112 : if (change.is_deletion ())
810 2167792 : delete_insn (change);
811 : else
812 : {
813 : // Make sure that this instruction comes before later ones.
814 18476320 : if (following_insn)
815 : {
816 3615482 : change.move_range = move_earlier_than (change.move_range,
817 : following_insn);
818 3615482 : if (!canonicalize_move_range (change.move_range,
819 : change.insn ()))
820 : // verify_insn_changes is supposed to make sure that this
821 : // holds.
822 0 : gcc_unreachable ();
823 : }
824 :
825 : // Decide which instruction INSN should go after.
826 18476320 : insn_info *after = choose_insn_placement (change);
827 :
828 : // If INSN is moving, insert a placeholder insn_info at the
829 : // new location. We can't move INSN itself yet because it
830 : // might still be referenced by earlier move ranges.
831 18476320 : insn_info *insn = change.insn ();
832 18476320 : if (after == insn || after == insn->prev_nondebug_insn ())
833 : {
834 18450959 : update_insn_in_place (change);
835 18450959 : following_insn = insn;
836 : }
837 : else
838 : {
839 25361 : move_insn (change, after);
840 25361 : placeholder = add_placeholder_after (after);
841 25361 : following_insn = placeholder;
842 : }
843 : }
844 20644112 : placeholders[i] = placeholder;
845 : }
846 :
847 : // We need to keep track of newly-added sets as these need adding to
848 : // the def chain later.
849 14896967 : hash_set<def_info *> new_sets;
850 :
851 : // Finalize the new list of accesses for each change. Don't install them yet,
852 : // so that we still have access to the old lists below.
853 : //
854 : // Note that we do this forwards instead of in the backwards loop above so
855 : // that any new defs being inserted are processed before new uses of those
856 : // defs, so that the (initially) temporary uses referring to temporary defs
857 : // can be easily updated to become permanent uses referring to permanent defs.
858 35541079 : for (unsigned i = 0; i < changes.size (); i++)
859 : {
860 20644112 : insn_change &change = *changes[i];
861 20644112 : insn_info *placeholder = placeholders[i];
862 20644112 : if (!change.is_deletion ())
863 36927279 : finalize_new_accesses (change,
864 18450959 : placeholder ? placeholder : change.insn (),
865 : new_sets);
866 : }
867 :
868 : // Remove all definitions that are no longer needed. After the above,
869 : // the only uses of such definitions should be dead phis and now-redundant
870 : // live-out uses.
871 : //
872 : // In particular, this means that consumers must handle debug
873 : // instructions before removing a set.
874 35541079 : for (insn_change *change : changes)
875 32582908 : for (def_info *def : change->old_defs ())
876 11938796 : if (def->m_has_been_superceded)
877 : {
878 2315595 : auto *set = dyn_cast<set_info *> (def);
879 2155174 : if (set && set->has_any_uses ())
880 686116 : process_uses_of_deleted_def (set);
881 2315595 : remove_def (def);
882 : }
883 :
884 : // Move the insn_infos to their new locations.
885 35541079 : for (unsigned int i = 0; i < changes.size (); ++i)
886 : {
887 20644112 : insn_change &change = *changes[i];
888 20644112 : insn_info *insn = change.insn ();
889 20644112 : if (change.is_deletion ())
890 : {
891 2167792 : if (rtx_insn *rtl = insn->rtl ())
892 2167792 : ::remove_insn (rtl); // Remove the underlying RTL insn.
893 2167792 : remove_insn (insn);
894 : }
895 18476320 : else if (insn_info *placeholder = placeholders[i])
896 : {
897 : // Check if earlier movements turned a move into a no-op.
898 25361 : if (placeholder->prev_nondebug_insn () == insn
899 25361 : || placeholder->next_nondebug_insn () == insn)
900 : {
901 0 : remove_insn (placeholder);
902 0 : placeholders[i] = nullptr;
903 : }
904 : else
905 : {
906 25361 : insn_info *after = placeholder->prev_any_insn ();
907 25361 : if (!insn->is_temporary ())
908 25361 : remove_insn (insn);
909 25361 : replace_nondebug_insn (placeholder, insn);
910 25361 : insn->set_bb (after->bb ());
911 : }
912 : }
913 : }
914 :
915 : // Apply the changes to the underlying insn_infos.
916 35541079 : for (insn_change *change : changes)
917 20644112 : apply_changes_to_insn (*change, new_sets);
918 :
919 : // Now that the insns and accesses are up to date, add any REG_UNUSED notes.
920 35541079 : for (insn_change *change : changes)
921 20644112 : if (!change->is_deletion ())
922 18476320 : add_reg_unused_notes (change->insn ());
923 14896967 : }
924 :
925 : // See the comment above the declaration.
926 : void
927 11097675 : function_info::change_insn (insn_change &change)
928 : {
929 11097675 : insn_change *changes[] = { &change };
930 11097675 : return change_insns (changes);
931 : }
932 :
933 : // Try to adjust CHANGE so that its pattern can include clobber rtx CLOBBER.
934 : // Return true on success.
935 : //
936 : // ADD_REGNO_CLOBBER is a specialization of function_info::add_regno_clobber
937 : // for a specific caller-provided predicate.
938 : static bool
939 2625615 : add_clobber (insn_change &change, add_regno_clobber_fn add_regno_clobber,
940 : rtx clobber)
941 : {
942 2625615 : rtx pat = PATTERN (change.rtl ());
943 2625615 : gcc_assert (GET_CODE (clobber) == CLOBBER);
944 2625615 : rtx dest = XEXP (clobber, 0);
945 2625615 : if (GET_CODE (dest) == SCRATCH)
946 : {
947 105766 : if (reload_completed)
948 : {
949 37041 : if (dump_file && (dump_flags & TDF_DETAILS))
950 : {
951 : // ??? Maybe we could try to do some RA here?
952 0 : fprintf (dump_file, "instruction requires a scratch"
953 : " after reload:\n");
954 0 : print_rtl_single (dump_file, pat);
955 : }
956 37041 : return false;
957 : }
958 : return true;
959 : }
960 :
961 2519849 : gcc_assert (REG_P (dest));
962 5036396 : for (unsigned int regno = REGNO (dest); regno != END_REGNO (dest); ++regno)
963 2519849 : if (!add_regno_clobber (change, regno))
964 : {
965 3302 : if (dump_file && (dump_flags & TDF_DETAILS))
966 : {
967 0 : fprintf (dump_file, "cannot clobber live register %d in:\n",
968 : regno);
969 0 : print_rtl_single (dump_file, pat);
970 : }
971 3302 : return false;
972 : }
973 : return true;
974 : }
975 :
976 : // See if PARALLEL pattern PAT clobbers any of the registers in ACCESSES.
977 : // Return one such access if so, otherwise return null.
978 : static access_info *
979 4303721 : find_clobbered_access (access_array accesses, rtx pat)
980 : {
981 4303721 : rtx subpat;
982 13459521 : for (int i = 0; i < XVECLEN (pat, 0); ++i)
983 9169403 : if (GET_CODE (subpat = XVECEXP (pat, 0, i)) == CLOBBER)
984 : {
985 4718041 : rtx x = XEXP (subpat, 0);
986 4718041 : if (REG_P (x))
987 13717754 : for (auto *access : accesses)
988 9234814 : if (access->regno () >= REGNO (x)
989 9234814 : && access->regno () < END_REGNO (x))
990 : return access;
991 : }
992 : return nullptr;
993 : }
994 :
995 : // Try to recognize the new form of the insn associated with CHANGE,
996 : // adding any clobbers that are necessary to make the instruction match
997 : // an .md pattern. Return true on success.
998 : //
999 : // ADD_REGNO_CLOBBER is a specialization of function_info::add_regno_clobber
1000 : // for a specific caller-provided predicate.
1001 : static bool
1002 49858875 : recog_level2 (insn_change &change, add_regno_clobber_fn add_regno_clobber)
1003 : {
1004 49858875 : insn_change_watermark insn_watermark;
1005 49858875 : rtx_insn *rtl = change.rtl ();
1006 49858875 : rtx pat = PATTERN (rtl);
1007 49858875 : int num_clobbers = 0;
1008 49858875 : int icode = -1;
1009 49858875 : bool asm_p = asm_noperands (pat) >= 0;
1010 49858875 : if (asm_p)
1011 : {
1012 66477 : if (!check_asm_operands (pat))
1013 : {
1014 62734 : if (dump_file && (dump_flags & TDF_DETAILS))
1015 : {
1016 0 : fprintf (dump_file, "failed to match this asm instruction:\n");
1017 0 : print_rtl_single (dump_file, pat);
1018 : }
1019 62734 : return false;
1020 : }
1021 : }
1022 49792398 : else if (noop_move_p (rtl))
1023 : {
1024 9413 : INSN_CODE (rtl) = NOOP_MOVE_INSN_CODE;
1025 9413 : if (dump_file && (dump_flags & TDF_DETAILS))
1026 : {
1027 0 : fprintf (dump_file, "instruction becomes a no-op:\n");
1028 0 : print_rtl_single (dump_file, pat);
1029 : }
1030 9413 : insn_watermark.keep ();
1031 9413 : return true;
1032 : }
1033 : else
1034 : {
1035 49782985 : icode = ::recog (pat, rtl, &num_clobbers);
1036 49782985 : if (icode < 0)
1037 : {
1038 32482723 : if (dump_file && (dump_flags & TDF_DETAILS))
1039 : {
1040 0 : fprintf (dump_file, "failed to match this instruction:\n");
1041 0 : print_rtl_single (dump_file, pat);
1042 : }
1043 32482723 : return false;
1044 : }
1045 : }
1046 :
1047 17304005 : auto prev_new_defs = change.new_defs;
1048 17304005 : auto prev_move_range = change.move_range;
1049 17304005 : if (num_clobbers > 0)
1050 : {
1051 : // ??? It would be good to have a way of recycling the rtxes on failure,
1052 : // but any attempt to cache old PARALLELs would at best be a half
1053 : // measure, since add_clobbers would still generate fresh clobbers
1054 : // each time. It would be better to have a more general recycling
1055 : // mechanism that all rtx passes can use.
1056 2617935 : rtvec newvec;
1057 2617935 : int oldlen;
1058 2617935 : if (GET_CODE (pat) == PARALLEL)
1059 : {
1060 30119 : oldlen = XVECLEN (pat, 0);
1061 30119 : newvec = rtvec_alloc (num_clobbers + oldlen);
1062 90381 : for (int i = 0; i < oldlen; ++i)
1063 60262 : RTVEC_ELT (newvec, i) = XVECEXP (pat, 0, i);
1064 : }
1065 : else
1066 : {
1067 2587816 : oldlen = 1;
1068 2587816 : newvec = rtvec_alloc (num_clobbers + oldlen);
1069 2587816 : RTVEC_ELT (newvec, 0) = pat;
1070 : }
1071 2617935 : rtx newpat = gen_rtx_PARALLEL (VOIDmode, newvec);
1072 2617935 : add_clobbers (newpat, icode);
1073 2617935 : validate_change (rtl, &PATTERN (rtl), newpat, true);
1074 5203207 : for (int i = 0; i < num_clobbers; ++i)
1075 2625615 : if (!add_clobber (change, add_regno_clobber,
1076 2625615 : XVECEXP (newpat, 0, oldlen + i)))
1077 : {
1078 40343 : change.new_defs = prev_new_defs;
1079 40343 : change.move_range = prev_move_range;
1080 40343 : return false;
1081 : }
1082 :
1083 : pat = newpat;
1084 : }
1085 :
1086 17263662 : INSN_CODE (rtl) = icode;
1087 17263662 : if (recog_data.insn == rtl)
1088 0 : recog_data.insn = nullptr;
1089 :
1090 : // See if the pattern contains any hard-coded clobbers of registers
1091 : // that are also inputs to the instruction. The standard rtl semantics
1092 : // treat such clobbers as earlyclobbers, since there is no way of proving
1093 : // which clobbers conflict with the inputs and which don't.
1094 : //
1095 : // (Non-hard-coded clobbers are handled by constraint satisfaction instead.)
1096 17263662 : rtx subpat;
1097 17263662 : if (GET_CODE (pat) == PARALLEL)
1098 13431636 : for (int i = 0; i < XVECLEN (pat, 0); ++i)
1099 9050817 : if (GET_CODE (subpat = XVECEXP (pat, 0, i)) == CLOBBER
1100 9050817 : && REG_P (XEXP (subpat, 0)))
1101 : {
1102 : // Stub out all operands, so that we can tell which registers
1103 : // are hard-coded.
1104 4303721 : extract_insn (rtl);
1105 17400759 : for (int j = 0; j < recog_data.n_operands; ++j)
1106 13097038 : *recog_data.operand_loc[j] = pc_rtx;
1107 :
1108 4303721 : auto *use = find_clobbered_access (change.new_uses, pat);
1109 :
1110 : // Restore the operands.
1111 17400759 : for (int j = 0; j < recog_data.n_operands; ++j)
1112 13097038 : *recog_data.operand_loc[j] = recog_data.operand[j];
1113 :
1114 4303721 : if (use)
1115 : {
1116 13603 : if (dump_file && (dump_flags & TDF_DETAILS))
1117 : {
1118 0 : fprintf (dump_file, "register %d is both clobbered"
1119 : " and used as an input:\n", use->regno ());
1120 0 : print_rtl_single (dump_file, pat);
1121 : }
1122 13603 : return false;
1123 : }
1124 : }
1125 :
1126 : // Per rtl.texi, registers that are modified using RTX_AUTOINC operations
1127 : // cannot also appear outside an address.
1128 17250059 : vec_rtx_properties properties;
1129 17250059 : properties.add_pattern (pat);
1130 66248975 : for (rtx_obj_reference def : properties.refs ())
1131 49176335 : if (def.is_pre_post_modify ())
1132 177419 : for (rtx_obj_reference use : properties.refs ())
1133 177419 : if (def.regno == use.regno && !use.in_address ())
1134 : {
1135 177419 : if (dump_file && (dump_flags & TDF_DETAILS))
1136 : {
1137 0 : fprintf (dump_file, "register %d is both auto-modified"
1138 : " and used outside an address:\n", def.regno);
1139 0 : print_rtl_single (dump_file, pat);
1140 : }
1141 177419 : return false;
1142 : }
1143 :
1144 : // check_asm_operands checks the constraints after RA, so we don't
1145 : // need to do it again.
1146 17072640 : if (reload_completed && !asm_p)
1147 : {
1148 3634691 : extract_insn (rtl);
1149 3634691 : if (!constrain_operands (1, get_preferred_alternatives (rtl)))
1150 : {
1151 1963665 : if (dump_file && (dump_flags & TDF_DETAILS))
1152 : {
1153 0 : if (asm_p)
1154 : fprintf (dump_file, "asm does not match its constraints:\n");
1155 0 : else if (const char *name = get_insn_name (icode))
1156 0 : fprintf (dump_file, "instruction does not match the"
1157 : " constraints for %s:\n", name);
1158 : else
1159 0 : fprintf (dump_file, "instruction does not match its"
1160 : " constraints:\n");
1161 0 : print_rtl_single (dump_file, pat);
1162 : }
1163 1963665 : change.new_defs = prev_new_defs;
1164 1963665 : change.move_range = prev_move_range;
1165 1963665 : return false;
1166 : }
1167 : }
1168 :
1169 15108975 : if (dump_file && (dump_flags & TDF_DETAILS))
1170 : {
1171 0 : const char *name;
1172 0 : if (!asm_p && (name = get_insn_name (icode)))
1173 0 : fprintf (dump_file, "successfully matched this instruction "
1174 : "to %s:\n", name);
1175 : else
1176 0 : fprintf (dump_file, "successfully matched this instruction:\n");
1177 0 : print_rtl_single (dump_file, pat);
1178 : }
1179 :
1180 15108975 : insn_watermark.keep ();
1181 15108975 : return true;
1182 49858875 : }
1183 :
1184 : // Try to recognize the new form of the insn associated with CHANGE,
1185 : // adding and removing clobbers as necessary to make the instruction
1186 : // match an .md pattern. Return true on success, otherwise leave
1187 : // CHANGE as it was on entry.
1188 : //
1189 : // ADD_REGNO_CLOBBER is a specialization of function_info::add_regno_clobber
1190 : // for a specific caller-provided predicate.
1191 : bool
1192 43850025 : rtl_ssa::recog_internal (insn_change &change,
1193 : add_regno_clobber_fn add_regno_clobber)
1194 : {
1195 : // Accept all changes to debug instructions.
1196 43850025 : insn_info *insn = change.insn ();
1197 43850025 : if (insn->is_debug_insn ())
1198 : return true;
1199 :
1200 43440487 : rtx_insn *rtl = insn->rtl ();
1201 43440487 : rtx pat = PATTERN (rtl);
1202 43440487 : if (GET_CODE (pat) == PARALLEL && asm_noperands (pat) < 0)
1203 : {
1204 : // Try to remove trailing (clobber (scratch)) rtxes, since the new form
1205 : // of the instruction might not need those scratches. recog will add
1206 : // back any that are needed.
1207 11408027 : int len = XVECLEN (pat, 0);
1208 11408027 : int new_len = len;
1209 11408027 : while (new_len > 0
1210 11523592 : && GET_CODE (XVECEXP (pat, 0, new_len - 1)) == CLOBBER
1211 19057752 : && GET_CODE (XEXP (XVECEXP (pat, 0, new_len - 1), 0)) == SCRATCH)
1212 : new_len -= 1;
1213 :
1214 11408027 : int old_num_changes = num_validated_changes ();
1215 11408027 : validate_change_xveclen (rtl, &PATTERN (rtl), new_len, true);
1216 11408027 : if (recog_level2 (change, add_regno_clobber))
1217 : return true;
1218 10220166 : cancel_changes (old_num_changes);
1219 :
1220 : // Try to remove all trailing clobbers. For example, a pattern that
1221 : // used to clobber the flags might no longer need to do so.
1222 10220166 : int prev_len = new_len;
1223 10220166 : while (new_len > 0
1224 16810771 : && GET_CODE (XVECEXP (pat, 0, new_len - 1)) == CLOBBER)
1225 : new_len -= 1;
1226 10220166 : if (new_len != prev_len)
1227 : {
1228 6418388 : validate_change_xveclen (rtl, &PATTERN (rtl), new_len, true);
1229 6418388 : if (recog_level2 (change, add_regno_clobber))
1230 : return true;
1231 5741874 : cancel_changes (old_num_changes);
1232 : }
1233 9543652 : return false;
1234 : }
1235 :
1236 32032460 : return recog_level2 (change, add_regno_clobber);
1237 : }
1238 :
1239 : // See the comment above the declaration.
1240 : bool
1241 5942962 : function_info::perform_pending_updates ()
1242 : {
1243 5942962 : bool changed_cfg = false;
1244 5942962 : bool changed_jumps = false;
1245 5954441 : for (insn_info *insn : m_queued_insn_updates)
1246 : {
1247 5441 : rtx_insn *rtl = insn->rtl ();
1248 5441 : if (NOTE_P (rtl))
1249 : // The insn was later optimized away, typically to a NOTE_INSN_DELETED.
1250 : ;
1251 5235 : else if (JUMP_P (rtl))
1252 : {
1253 228 : if (INSN_CODE (rtl) == NOOP_MOVE_INSN_CODE)
1254 : {
1255 193 : ::delete_insn (rtl);
1256 193 : bitmap_set_bit (m_need_to_purge_dead_edges,
1257 193 : insn->bb ()->index ());
1258 : }
1259 35 : else if (returnjump_p (rtl) || any_uncondjump_p (rtl))
1260 : {
1261 35 : mark_jump_label (PATTERN (rtl), rtl, 0);
1262 35 : update_cfg_for_uncondjump (rtl);
1263 35 : changed_cfg = true;
1264 35 : changed_jumps = true;
1265 : }
1266 : }
1267 5007 : else if (INSN_CODE (rtl) == NOOP_MOVE_INSN_CODE)
1268 5004 : ::delete_insn (rtl);
1269 : else
1270 : {
1271 3 : rtx pattern = PATTERN (rtl);
1272 3 : if (GET_CODE (pattern) == TRAP_IF
1273 0 : && XEXP (pattern, 0) == const1_rtx)
1274 : {
1275 0 : remove_edge (split_block (BLOCK_FOR_INSN (rtl), rtl));
1276 0 : emit_barrier_after_bb (BLOCK_FOR_INSN (rtl));
1277 0 : changed_cfg = true;
1278 : }
1279 : }
1280 : }
1281 :
1282 5942962 : unsigned int index;
1283 5942962 : bitmap_iterator bi;
1284 5990881 : EXECUTE_IF_SET_IN_BITMAP (m_need_to_purge_dead_edges, 0, index, bi)
1285 47919 : if (purge_dead_edges (BASIC_BLOCK_FOR_FN (m_fn, index)))
1286 1921 : changed_cfg = true;
1287 :
1288 5942962 : if (changed_jumps)
1289 : // This uses its own timevar internally, so we don't need to push
1290 : // one ourselves.
1291 24 : rebuild_jump_labels (get_insns ());
1292 :
1293 5942962 : bitmap_clear (m_need_to_purge_dead_edges);
1294 5942962 : bitmap_clear (m_queued_insn_update_uids);
1295 5942962 : m_queued_insn_updates.truncate (0);
1296 :
1297 5942962 : if (changed_cfg)
1298 : {
1299 520 : free_dominance_info (CDI_DOMINATORS);
1300 520 : free_dominance_info (CDI_POST_DOMINATORS);
1301 : }
1302 :
1303 5942962 : return changed_cfg;
1304 : }
1305 :
1306 : insn_info *
1307 0 : function_info::create_insn (obstack_watermark &watermark,
1308 : rtx_code insn_code,
1309 : rtx pat)
1310 : {
1311 0 : rtx_insn *rti = nullptr;
1312 :
1313 : // TODO: extend, move in to emit-rtl.cc.
1314 0 : switch (insn_code)
1315 : {
1316 0 : case INSN:
1317 0 : rti = make_insn_raw (pat);
1318 0 : break;
1319 0 : default:
1320 0 : gcc_unreachable ();
1321 : }
1322 :
1323 0 : auto insn = change_alloc<insn_info> (watermark, nullptr, rti, INSN_UID (rti));
1324 0 : insn->m_is_temp = true;
1325 0 : return insn;
1326 : }
1327 :
1328 : // Print a description of CHANGE to PP.
1329 : void
1330 0 : rtl_ssa::pp_insn_change (pretty_printer *pp, const insn_change &change)
1331 : {
1332 0 : change.print (pp);
1333 0 : }
1334 :
1335 : // Print a description of CHANGE to FILE.
1336 : void
1337 0 : dump (FILE *file, const insn_change &change)
1338 : {
1339 0 : dump_using (file, pp_insn_change, change);
1340 0 : }
1341 :
1342 : // Debug interface to the dump routine above.
1343 0 : void debug (const insn_change &x) { dump (stderr, x); }
|