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