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