1/* Convert RTL to assembler code and output it, for GNU compiler.
2 Copyright (C) 1987-2026 Free Software Foundation, Inc.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free
8Software Foundation; either version 3, or (at your option) any later
9version.
10
11GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or
13FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14for more details.
15
16You should have received a copy of the GNU General Public License
17along with GCC; see the file COPYING3. If not see
18<http://www.gnu.org/licenses/>. */
19
20/* This is the final pass of the compiler.
21 It looks at the rtl code for a function and outputs assembler code.
22
23 Call `final_start_function' to output the assembler code for function entry,
24 `final' to output assembler code for some RTL code,
25 `final_end_function' to output assembler code for function exit.
26 If a function is compiled in several pieces, each piece is
27 output separately with `final'.
28
29 Some optimizations are also done at this level.
30 Move instructions that were made unnecessary by good register allocation
31 are detected and omitted from the output. (Though most of these
32 are removed by the last jump pass.)
33
34 Instructions to set the condition codes are omitted when it can be
35 seen that the condition codes already had the desired values.
36
37 In some cases it is sufficient if the inherited condition codes
38 have related values, but this may require the following insn
39 (the one that tests the condition codes) to be modified.
40
41 The code for the function prologue and epilogue are generated
42 directly in assembler by the target functions function_prologue and
43 function_epilogue. Those instructions never exist as rtl. */
44
45#include "config.h"
46#define INCLUDE_ALGORITHM /* reverse */
47#include "system.h"
48#include "coretypes.h"
49#include "backend.h"
50#include "target.h"
51#include "rtl.h"
52#include "tree.h"
53#include "cfghooks.h"
54#include "df.h"
55#include "memmodel.h"
56#include "tm_p.h"
57#include "insn-config.h"
58#include "regs.h"
59#include "emit-rtl.h"
60#include "recog.h"
61#include "cgraph.h"
62#include "tree-pretty-print.h" /* for dump_function_header */
63#include "varasm.h"
64#include "insn-attr.h"
65#include "conditions.h"
66#include "flags.h"
67#include "output.h"
68#include "except.h"
69#include "rtl-error.h"
70#include "toplev.h" /* exact_log2, floor_log2 */
71#include "reload.h"
72#include "intl.h"
73#include "cfgrtl.h"
74#include "debug.h"
75#include "tree-pass.h"
76#include "tree-ssa.h"
77#include "cfgloop.h"
78#include "stringpool.h"
79#include "attribs.h"
80#include "asan.h"
81#include "rtl-iter.h"
82#include "print-rtl.h"
83#include "function-abi.h"
84#include "common/common-target.h"
85#include "diagnostic.h"
86#include "diagnostics/file-cache.h"
87
88#include "dwarf2out.h"
89
90/* Most ports don't need to define CC_STATUS_INIT.
91 So define a null default for it to save conditionalization later. */
92#ifndef CC_STATUS_INIT
93#define CC_STATUS_INIT
94#endif
95
96/* Is the given character a logical line separator for the assembler? */
97#ifndef IS_ASM_LOGICAL_LINE_SEPARATOR
98#define IS_ASM_LOGICAL_LINE_SEPARATOR(C, STR) ((C) == ';')
99#endif
100
101#ifndef JUMP_TABLES_IN_TEXT_SECTION
102#define JUMP_TABLES_IN_TEXT_SECTION 0
103#endif
104
105/* Bitflags used by final_scan_insn. */
106#define SEEN_NOTE 1
107#define SEEN_EMITTED 2
108#define SEEN_NEXT_VIEW 4
109
110/* Last insn processed by final_scan_insn. */
111static rtx_insn *debug_insn;
112rtx_insn *current_output_insn;
113
114/* Line number of last NOTE. */
115static int last_linenum;
116
117/* Column number of last NOTE. */
118static int last_columnnum;
119
120/* Discriminator written to assembly. */
121static int last_discriminator;
122
123/* Compute discriminator to be written to assembly for current instruction.
124 Note: actual usage depends on loc_discriminator_kind setting. */
125static inline int compute_discriminator (location_t loc);
126
127/* Highest line number in current block. */
128static int high_block_linenum;
129
130/* Likewise for function. */
131static int high_function_linenum;
132
133/* Filename of last NOTE. */
134static const char *last_filename;
135
136/* Override filename, line and column number. */
137static const char *override_filename;
138static int override_linenum;
139static int override_columnnum;
140static int override_discriminator;
141
142/* Whether to force emission of a line note before the next insn. */
143static bool force_source_line = false;
144
145extern const int length_unit_log; /* This is defined in insn-attrtab.cc. */
146
147/* Nonzero while outputting an `asm' with operands.
148 This means that inconsistencies are the user's fault, so don't die.
149 The precise value is the insn being output, to pass to error_for_asm. */
150const rtx_insn *this_is_asm_operands;
151
152/* Number of operands of this insn, for an `asm' with operands. */
153unsigned int insn_noperands;
154
155/* Compare optimization flag. */
156
157static rtx last_ignored_compare = 0;
158
159/* Assign a unique number to each insn that is output.
160 This can be used to generate unique local labels. */
161
162static int insn_counter = 0;
163
164/* Number of unmatched NOTE_INSN_BLOCK_BEG notes we have seen. */
165
166static int block_depth;
167
168/* True if have enabled APP processing of our assembler output. */
169
170static bool app_on;
171
172/* If we are outputting an insn sequence, this contains the sequence rtx.
173 Zero otherwise. */
174
175rtx_sequence *final_sequence;
176
177#ifdef ASSEMBLER_DIALECT
178
179/* Number of the assembler dialect to use, starting at 0. */
180static int dialect_number;
181#endif
182
183/* Nonnull if the insn currently being emitted was a COND_EXEC pattern. */
184rtx current_insn_predicate;
185
186/* True if printing into -fdump-final-insns= dump. */
187bool final_insns_dump_p;
188
189/* True if profile_function should be called, but hasn't been called yet. */
190static bool need_profile_function;
191
192static int asm_insn_count (rtx);
193static void profile_function (FILE *);
194static void profile_after_prologue (FILE *);
195static bool notice_source_line (rtx_insn *, bool *);
196static rtx walk_alter_subreg (rtx *, bool *);
197static void output_asm_name (void);
198static void output_alternate_entry_point (FILE *, rtx_insn *);
199static tree get_mem_expr_from_op (rtx, int *);
200static void output_asm_operand_names (rtx *, int *, int);
201#ifdef LEAF_REGISTERS
202static void leaf_renumber_regs (rtx_insn *);
203#endif
204static int align_fuzz (rtx, rtx, int, unsigned);
205static void collect_fn_hard_reg_usage (void);
206
207/* Initialize data in final at the beginning of a compilation. */
208
209void
210init_final (const char *filename ATTRIBUTE_UNUSED)
211{
212 app_on = 0;
213 final_sequence = 0;
214
215#ifdef ASSEMBLER_DIALECT
216 dialect_number = ASSEMBLER_DIALECT;
217#endif
218}
219
220/* Default target function prologue and epilogue assembler output.
221
222 If not overridden for epilogue code, then the function body itself
223 contains return instructions wherever needed. */
224void
225default_function_pro_epilogue (FILE *)
226{
227}
228
229void
230default_function_switched_text_sections (FILE *file ATTRIBUTE_UNUSED,
231 tree decl ATTRIBUTE_UNUSED,
232 bool new_is_cold ATTRIBUTE_UNUSED)
233{
234}
235
236/* Default target hook that outputs nothing to a stream. */
237void
238no_asm_to_stream (FILE *file ATTRIBUTE_UNUSED)
239{
240}
241
242/* Enable APP processing of subsequent output.
243 Used before the output from an `asm' statement. */
244
245void
246app_enable (void)
247{
248 if (! app_on)
249 {
250 fputs (ASM_APP_ON, stream: asm_out_file);
251 app_on = 1;
252 }
253}
254
255/* Disable APP processing of subsequent output.
256 Called from varasm.cc before most kinds of output. */
257
258void
259app_disable (void)
260{
261 if (app_on)
262 {
263 fputs (ASM_APP_OFF, stream: asm_out_file);
264 app_on = 0;
265 }
266}
267
268/* Return the number of slots filled in the current
269 delayed branch sequence (we don't count the insn needing the
270 delay slot). Zero if not in a delayed branch sequence. */
271
272int
273dbr_sequence_length (void)
274{
275 if (final_sequence != 0)
276 return XVECLEN (final_sequence, 0) - 1;
277 else
278 return 0;
279}
280
281/* The next two pages contain routines used to compute the length of an insn
282 and to shorten branches. */
283
284/* Arrays for insn lengths, and addresses. The latter is referenced by
285 `insn_current_length'. */
286
287static int *insn_lengths;
288
289vec<int> insn_addresses_;
290
291/* Max uid for which the above arrays are valid. */
292static int insn_lengths_max_uid;
293
294/* Address of insn being processed. Used by `insn_current_length'. */
295int insn_current_address;
296
297/* Address of insn being processed in previous iteration. */
298int insn_last_address;
299
300/* known invariant alignment of insn being processed. */
301int insn_current_align;
302
303/* After shorten_branches, for any insn, uid_align[INSN_UID (insn)]
304 gives the next following alignment insn that increases the known
305 alignment, or NULL_RTX if there is no such insn.
306 For any alignment obtained this way, we can again index uid_align with
307 its uid to obtain the next following align that in turn increases the
308 alignment, till we reach NULL_RTX; the sequence obtained this way
309 for each insn we'll call the alignment chain of this insn in the following
310 comments. */
311
312static rtx *uid_align;
313static int *uid_shuid;
314static vec<align_flags> label_align;
315
316/* Indicate that branch shortening hasn't yet been done. */
317
318void
319init_insn_lengths (void)
320{
321 if (uid_shuid)
322 {
323 free (ptr: uid_shuid);
324 uid_shuid = 0;
325 }
326 if (insn_lengths)
327 {
328 free (ptr: insn_lengths);
329 insn_lengths = 0;
330 insn_lengths_max_uid = 0;
331 }
332 if (HAVE_ATTR_length)
333 INSN_ADDRESSES_FREE ();
334 if (uid_align)
335 {
336 free (ptr: uid_align);
337 uid_align = 0;
338 }
339}
340
341/* Obtain the current length of an insn. If branch shortening has been done,
342 get its actual length. Otherwise, use FALLBACK_FN to calculate the
343 length. */
344static int
345get_attr_length_1 (rtx_insn *insn, int (*fallback_fn) (rtx_insn *))
346{
347 rtx body;
348 int i;
349 int length = 0;
350
351 if (!HAVE_ATTR_length)
352 return 0;
353
354 if (insn_lengths_max_uid > INSN_UID (insn))
355 return insn_lengths[INSN_UID (insn)];
356 else
357 switch (GET_CODE (insn))
358 {
359 case NOTE:
360 case BARRIER:
361 case CODE_LABEL:
362 case DEBUG_INSN:
363 return 0;
364
365 case CALL_INSN:
366 case JUMP_INSN:
367 body = PATTERN (insn);
368 if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0)
369 length = asm_insn_count (body) * fallback_fn (insn);
370 else
371 length = fallback_fn (insn);
372 break;
373
374 case INSN:
375 body = PATTERN (insn);
376 if (GET_CODE (body) == USE || GET_CODE (body) == CLOBBER)
377 return 0;
378
379 else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0)
380 length = asm_insn_count (body) * fallback_fn (insn);
381 else if (rtx_sequence *seq = dyn_cast <rtx_sequence *> (p: body))
382 for (i = 0; i < seq->len (); i++)
383 length += get_attr_length_1 (insn: seq->insn (index: i), fallback_fn);
384 else
385 length = fallback_fn (insn);
386 break;
387
388 default:
389 break;
390 }
391
392#ifdef ADJUST_INSN_LENGTH
393 ADJUST_INSN_LENGTH (insn, length);
394#endif
395 return length;
396}
397
398/* Obtain the current length of an insn. If branch shortening has been done,
399 get its actual length. Otherwise, get its maximum length. */
400int
401get_attr_length (rtx_insn *insn)
402{
403 return get_attr_length_1 (insn, fallback_fn: insn_default_length);
404}
405
406/* Obtain the current length of an insn. If branch shortening has been done,
407 get its actual length. Otherwise, get its minimum length. */
408int
409get_attr_min_length (rtx_insn *insn)
410{
411 return get_attr_length_1 (insn, fallback_fn: insn_min_length);
412}
413
414/* Code to handle alignment inside shorten_branches. */
415
416/* Here is an explanation how the algorithm in align_fuzz can give
417 proper results:
418
419 Call a sequence of instructions beginning with alignment point X
420 and continuing until the next alignment point `block X'. When `X'
421 is used in an expression, it means the alignment value of the
422 alignment point.
423
424 Call the distance between the start of the first insn of block X, and
425 the end of the last insn of block X `IX', for the `inner size of X'.
426 This is clearly the sum of the instruction lengths.
427
428 Likewise with the next alignment-delimited block following X, which we
429 shall call block Y.
430
431 Call the distance between the start of the first insn of block X, and
432 the start of the first insn of block Y `OX', for the `outer size of X'.
433
434 The estimated padding is then OX - IX.
435
436 OX can be safely estimated as
437
438 if (X >= Y)
439 OX = round_up(IX, Y)
440 else
441 OX = round_up(IX, X) + Y - X
442
443 Clearly est(IX) >= real(IX), because that only depends on the
444 instruction lengths, and those being overestimated is a given.
445
446 Clearly round_up(foo, Z) >= round_up(bar, Z) if foo >= bar, so
447 we needn't worry about that when thinking about OX.
448
449 When X >= Y, the alignment provided by Y adds no uncertainty factor
450 for branch ranges starting before X, so we can just round what we have.
451 But when X < Y, we don't know anything about the, so to speak,
452 `middle bits', so we have to assume the worst when aligning up from an
453 address mod X to one mod Y, which is Y - X. */
454
455#ifndef LABEL_ALIGN
456#define LABEL_ALIGN(LABEL) align_labels
457#endif
458
459#ifndef LOOP_ALIGN
460#define LOOP_ALIGN(LABEL) align_loops
461#endif
462
463#ifndef LABEL_ALIGN_AFTER_BARRIER
464#define LABEL_ALIGN_AFTER_BARRIER(LABEL) 0
465#endif
466
467#ifndef JUMP_ALIGN
468#define JUMP_ALIGN(LABEL) align_jumps
469#endif
470
471#ifndef ADDR_VEC_ALIGN
472static int
473final_addr_vec_align (rtx_jump_table_data *addr_vec)
474{
475 int align = GET_MODE_SIZE (mode: addr_vec->get_data_mode ());
476
477 if (align > BIGGEST_ALIGNMENT / BITS_PER_UNIT)
478 align = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
479 return exact_log2 (x: align);
480
481}
482
483#define ADDR_VEC_ALIGN(ADDR_VEC) final_addr_vec_align (ADDR_VEC)
484#endif
485
486#ifndef INSN_LENGTH_ALIGNMENT
487#define INSN_LENGTH_ALIGNMENT(INSN) length_unit_log
488#endif
489
490#define INSN_SHUID(INSN) (uid_shuid[INSN_UID (INSN)])
491
492static int min_labelno, max_labelno;
493
494#define LABEL_TO_ALIGNMENT(LABEL) \
495 (label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno])
496
497/* For the benefit of port specific code do this also as a function. */
498
499align_flags
500label_to_alignment (rtx label)
501{
502 if (CODE_LABEL_NUMBER (label) <= max_labelno)
503 return LABEL_TO_ALIGNMENT (label);
504 return align_flags ();
505}
506
507/* The differences in addresses
508 between a branch and its target might grow or shrink depending on
509 the alignment the start insn of the range (the branch for a forward
510 branch or the label for a backward branch) starts out on; if these
511 differences are used naively, they can even oscillate infinitely.
512 We therefore want to compute a 'worst case' address difference that
513 is independent of the alignment the start insn of the range end
514 up on, and that is at least as large as the actual difference.
515 The function align_fuzz calculates the amount we have to add to the
516 naively computed difference, by traversing the part of the alignment
517 chain of the start insn of the range that is in front of the end insn
518 of the range, and considering for each alignment the maximum amount
519 that it might contribute to a size increase.
520
521 For casesi tables, we also want to know worst case minimum amounts of
522 address difference, in case a machine description wants to introduce
523 some common offset that is added to all offsets in a table.
524 For this purpose, align_fuzz with a growth argument of 0 computes the
525 appropriate adjustment. */
526
527/* Compute the maximum delta by which the difference of the addresses of
528 START and END might grow / shrink due to a different address for start
529 which changes the size of alignment insns between START and END.
530 KNOWN_ALIGN_LOG is the alignment known for START.
531 GROWTH should be ~0 if the objective is to compute potential code size
532 increase, and 0 if the objective is to compute potential shrink.
533 The return value is undefined for any other value of GROWTH. */
534
535static int
536align_fuzz (rtx start, rtx end, int known_align_log, unsigned int growth)
537{
538 int uid = INSN_UID (insn: start);
539 rtx align_label;
540 int known_align = 1 << known_align_log;
541 int end_shuid = INSN_SHUID (end);
542 int fuzz = 0;
543
544 for (align_label = uid_align[uid]; align_label; align_label = uid_align[uid])
545 {
546 int align_addr, new_align;
547
548 uid = INSN_UID (insn: align_label);
549 align_addr = INSN_ADDRESSES (uid) - insn_lengths[uid];
550 if (uid_shuid[uid] > end_shuid)
551 break;
552 align_flags alignment = LABEL_TO_ALIGNMENT (align_label);
553 new_align = 1 << alignment.levels[0].log;
554 if (new_align < known_align)
555 continue;
556 fuzz += (-align_addr ^ growth) & (new_align - known_align);
557 known_align = new_align;
558 }
559 return fuzz;
560}
561
562/* Compute a worst-case reference address of a branch so that it
563 can be safely used in the presence of aligned labels. Since the
564 size of the branch itself is unknown, the size of the branch is
565 not included in the range. I.e. for a forward branch, the reference
566 address is the end address of the branch as known from the previous
567 branch shortening pass, minus a value to account for possible size
568 increase due to alignment. For a backward branch, it is the start
569 address of the branch as known from the current pass, plus a value
570 to account for possible size increase due to alignment.
571 NB.: Therefore, the maximum offset allowed for backward branches needs
572 to exclude the branch size. */
573
574int
575insn_current_reference_address (rtx_insn *branch)
576{
577 rtx dest;
578 int seq_uid;
579
580 if (! INSN_ADDRESSES_SET_P ())
581 return 0;
582
583 rtx_insn *seq = NEXT_INSN (insn: PREV_INSN (insn: branch));
584 seq_uid = INSN_UID (insn: seq);
585 if (!jump_to_label_p (branch))
586 /* This can happen for example on the PA; the objective is to know the
587 offset to address something in front of the start of the function.
588 Thus, we can treat it like a backward branch.
589 We assume here that FUNCTION_BOUNDARY / BITS_PER_UNIT is larger than
590 any alignment we'd encounter, so we skip the call to align_fuzz. */
591 return insn_current_address;
592 dest = JUMP_LABEL (branch);
593
594 /* BRANCH has no proper alignment chain set, so use SEQ.
595 BRANCH also has no INSN_SHUID. */
596 if (INSN_SHUID (seq) < INSN_SHUID (dest))
597 {
598 /* Forward branch. */
599 return (insn_last_address + insn_lengths[seq_uid]
600 - align_fuzz (start: seq, end: dest, known_align_log: length_unit_log, growth: ~0));
601 }
602 else
603 {
604 /* Backward branch. */
605 return (insn_current_address
606 + align_fuzz (start: dest, end: seq, known_align_log: length_unit_log, growth: ~0));
607 }
608}
609
610/* Compute branch alignments based on CFG profile. */
611
612void
613compute_alignments (void)
614{
615 basic_block bb;
616 align_flags max_alignment;
617
618 label_align.truncate (size: 0);
619
620 max_labelno = max_label_num ();
621 min_labelno = get_first_label_num ();
622 label_align.safe_grow_cleared (len: max_labelno - min_labelno + 1, exact: true);
623
624 /* If not optimizing or optimizing for size, don't assign any alignments. */
625 if (! optimize || optimize_function_for_size_p (cfun))
626 return;
627
628 if (dump_file)
629 {
630 dump_reg_info (dump_file);
631 dump_flow_info (dump_file, TDF_DETAILS);
632 flow_loops_dump (dump_file, NULL, 1);
633 }
634 loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
635 profile_count count_threshold = cfun->cfg->count_max / param_align_threshold;
636
637 if (dump_file)
638 {
639 fprintf (stream: dump_file, format: "count_max: ");
640 cfun->cfg->count_max.dump (f: dump_file);
641 fprintf (stream: dump_file, format: "\n");
642 }
643 FOR_EACH_BB_FN (bb, cfun)
644 {
645 rtx_insn *label = BB_HEAD (bb);
646 bool has_fallthru = 0;
647 edge e;
648 edge_iterator ei;
649
650 if (!LABEL_P (label)
651 || optimize_bb_for_size_p (bb))
652 {
653 if (dump_file)
654 fprintf (stream: dump_file,
655 format: "BB %4i loop %2i loop_depth %2i skipped.\n",
656 bb->index,
657 bb->loop_father->num,
658 bb_loop_depth (bb));
659 continue;
660 }
661 max_alignment = LABEL_ALIGN (label);
662 profile_count fallthru_count = profile_count::zero ();
663 profile_count branch_count = profile_count::zero ();
664
665 FOR_EACH_EDGE (e, ei, bb->preds)
666 {
667 if (e->flags & EDGE_FALLTHRU)
668 has_fallthru = 1, fallthru_count += e->count ();
669 else
670 branch_count += e->count ();
671 }
672 if (dump_file)
673 {
674 fprintf (stream: dump_file, format: "BB %4i loop %2i loop_depth"
675 " %2i fall ",
676 bb->index, bb->loop_father->num,
677 bb_loop_depth (bb));
678 fallthru_count.dump (f: dump_file);
679 fprintf (stream: dump_file, format: " branch ");
680 branch_count.dump (f: dump_file);
681 if (!bb->loop_father->inner && bb->loop_father->num)
682 fprintf (stream: dump_file, format: " inner_loop");
683 if (bb->loop_father->header == bb)
684 fprintf (stream: dump_file, format: " loop_header");
685 fprintf (stream: dump_file, format: "\n");
686 }
687 if (!fallthru_count.initialized_p () || !branch_count.initialized_p ())
688 continue;
689
690 /* There are two purposes to align block with no fallthru incoming edge:
691 1) to avoid fetch stalls when branch destination is near cache boundary
692 2) to improve cache efficiency in case the previous block is not executed
693 (so it does not need to be in the cache).
694
695 We to catch first case, we align frequently executed blocks.
696 To catch the second, we align blocks that are executed more frequently
697 than the predecessor and the predecessor is likely to not be executed
698 when function is called. */
699
700 if (!has_fallthru
701 && (branch_count > count_threshold
702 || (bb->count > bb->prev_bb->count * 10
703 && (bb->prev_bb->count
704 <= ENTRY_BLOCK_PTR_FOR_FN (cfun)->count / 2))))
705 {
706 align_flags alignment = JUMP_ALIGN (label);
707 if (dump_file)
708 fprintf (stream: dump_file, format: " jump alignment added.\n");
709 max_alignment = align_flags::max (f0: max_alignment, f1: alignment);
710 }
711 /* In case block is frequent and reached mostly by non-fallthru edge,
712 align it. It is most likely a first block of loop. */
713 if (has_fallthru
714 && !(single_succ_p (bb)
715 && single_succ (bb) == EXIT_BLOCK_PTR_FOR_FN (cfun))
716 && optimize_bb_for_speed_p (bb)
717 && branch_count + fallthru_count > count_threshold
718 && (branch_count > fallthru_count * param_align_loop_iterations))
719 {
720 align_flags alignment = LOOP_ALIGN (label);
721 if (dump_file)
722 fprintf (stream: dump_file, format: " internal loop alignment added.\n");
723 max_alignment = align_flags::max (f0: max_alignment, f1: alignment);
724 }
725 LABEL_TO_ALIGNMENT (label) = max_alignment;
726 }
727
728 loop_optimizer_finalize ();
729 free_dominance_info (CDI_DOMINATORS);
730}
731
732/* Grow the LABEL_ALIGN array after new labels are created. */
733
734static void
735grow_label_align (void)
736{
737 int old = max_labelno;
738 int n_labels;
739 int n_old_labels;
740
741 max_labelno = max_label_num ();
742
743 n_labels = max_labelno - min_labelno + 1;
744 n_old_labels = old - min_labelno + 1;
745
746 label_align.safe_grow_cleared (len: n_labels, exact: true);
747
748 /* Range of labels grows monotonically in the function. Failing here
749 means that the initialization of array got lost. */
750 gcc_assert (n_old_labels <= n_labels);
751}
752
753/* Update the already computed alignment information. LABEL_PAIRS is a vector
754 made up of pairs of labels for which the alignment information of the first
755 element will be copied from that of the second element. */
756
757void
758update_alignments (vec<rtx> &label_pairs)
759{
760 unsigned int i = 0;
761 rtx iter, label = NULL_RTX;
762
763 if (max_labelno != max_label_num ())
764 grow_label_align ();
765
766 FOR_EACH_VEC_ELT (label_pairs, i, iter)
767 if (i & 1)
768 LABEL_TO_ALIGNMENT (label) = LABEL_TO_ALIGNMENT (iter);
769 else
770 label = iter;
771}
772
773namespace {
774
775const pass_data pass_data_compute_alignments =
776{
777 .type: RTL_PASS, /* type */
778 .name: "alignments", /* name */
779 .optinfo_flags: OPTGROUP_NONE, /* optinfo_flags */
780 .tv_id: TV_NONE, /* tv_id */
781 .properties_required: 0, /* properties_required */
782 .properties_provided: 0, /* properties_provided */
783 .properties_destroyed: 0, /* properties_destroyed */
784 .todo_flags_start: 0, /* todo_flags_start */
785 .todo_flags_finish: 0, /* todo_flags_finish */
786};
787
788class pass_compute_alignments : public rtl_opt_pass
789{
790public:
791 pass_compute_alignments (gcc::context *ctxt)
792 : rtl_opt_pass (pass_data_compute_alignments, ctxt)
793 {}
794
795 /* opt_pass methods: */
796 unsigned int execute (function *) final override
797 {
798 compute_alignments ();
799 return 0;
800 }
801
802}; // class pass_compute_alignments
803
804} // anon namespace
805
806rtl_opt_pass *
807make_pass_compute_alignments (gcc::context *ctxt)
808{
809 return new pass_compute_alignments (ctxt);
810}
811
812
813/* Make a pass over all insns and compute their actual lengths by shortening
814 any branches of variable length if possible. */
815
816/* shorten_branches might be called multiple times: for example, the SH
817 port splits out-of-range conditional branches in MACHINE_DEPENDENT_REORG.
818 In order to do this, it needs proper length information, which it obtains
819 by calling shorten_branches. This cannot be collapsed with
820 shorten_branches itself into a single pass unless we also want to integrate
821 reorg.cc, since the branch splitting exposes new instructions with delay
822 slots. */
823
824void
825shorten_branches (rtx_insn *first)
826{
827 rtx_insn *insn;
828 int max_uid;
829 int i;
830 rtx_insn *seq;
831 bool something_changed = true;
832 char *varying_length;
833 rtx body;
834 int uid;
835 rtx align_tab[MAX_CODE_ALIGN + 1];
836
837 /* Compute maximum UID and allocate label_align / uid_shuid. */
838 max_uid = get_max_uid ();
839
840 /* Free uid_shuid before reallocating it. */
841 free (ptr: uid_shuid);
842
843 uid_shuid = XNEWVEC (int, max_uid);
844
845 if (max_labelno != max_label_num ())
846 grow_label_align ();
847
848 /* Initialize label_align and set up uid_shuid to be strictly
849 monotonically rising with insn order. */
850 /* We use alignment here to keep track of the maximum alignment we want to
851 impose on the next CODE_LABEL (or the current one if we are processing
852 the CODE_LABEL itself). */
853
854 align_flags max_alignment;
855
856 for (insn = get_insns (), i = 1; insn; insn = NEXT_INSN (insn))
857 {
858 INSN_SHUID (insn) = i++;
859 if (INSN_P (insn))
860 continue;
861
862 if (rtx_code_label *label = dyn_cast <rtx_code_label *> (p: insn))
863 {
864 /* Merge in alignments computed by compute_alignments. */
865 align_flags alignment = LABEL_TO_ALIGNMENT (label);
866 max_alignment = align_flags::max (f0: max_alignment, f1: alignment);
867
868 rtx_jump_table_data *table = jump_table_for_label (label);
869 if (!table)
870 {
871 align_flags alignment = LABEL_ALIGN (label);
872 max_alignment = align_flags::max (f0: max_alignment, f1: alignment);
873 }
874 /* ADDR_VECs only take room if read-only data goes into the text
875 section. */
876 if ((JUMP_TABLES_IN_TEXT_SECTION
877 || readonly_data_section == text_section)
878 && table)
879 {
880 align_flags alignment = align_flags (ADDR_VEC_ALIGN (table));
881 max_alignment = align_flags::max (f0: max_alignment, f1: alignment);
882 }
883 LABEL_TO_ALIGNMENT (label) = max_alignment;
884 max_alignment = align_flags ();
885 }
886 else if (BARRIER_P (insn))
887 {
888 rtx_insn *label;
889
890 for (label = insn; label && ! INSN_P (label);
891 label = NEXT_INSN (insn: label))
892 if (LABEL_P (label))
893 {
894 align_flags alignment
895 = align_flags (LABEL_ALIGN_AFTER_BARRIER (insn));
896 max_alignment = align_flags::max (f0: max_alignment, f1: alignment);
897 break;
898 }
899 }
900 }
901 if (!HAVE_ATTR_length)
902 return;
903
904 /* Allocate the rest of the arrays. */
905 insn_lengths = XNEWVEC (int, max_uid);
906 insn_lengths_max_uid = max_uid;
907 /* Syntax errors can lead to labels being outside of the main insn stream.
908 Initialize insn_addresses, so that we get reproducible results. */
909 INSN_ADDRESSES_ALLOC (max_uid);
910
911 varying_length = XCNEWVEC (char, max_uid);
912
913 /* Initialize uid_align. We scan instructions
914 from end to start, and keep in align_tab[n] the last seen insn
915 that does an alignment of at least n+1, i.e. the successor
916 in the alignment chain for an insn that does / has a known
917 alignment of n. */
918 uid_align = XCNEWVEC (rtx, max_uid);
919
920 for (i = MAX_CODE_ALIGN + 1; --i >= 0;)
921 align_tab[i] = NULL_RTX;
922 seq = get_last_insn ();
923 for (; seq; seq = PREV_INSN (insn: seq))
924 {
925 int uid = INSN_UID (insn: seq);
926 int log;
927 log = (LABEL_P (seq) ? LABEL_TO_ALIGNMENT (seq).levels[0].log : 0);
928 uid_align[uid] = align_tab[0];
929 if (log)
930 {
931 /* Found an alignment label. */
932 gcc_checking_assert (log < MAX_CODE_ALIGN + 1);
933 uid_align[uid] = align_tab[log];
934 for (i = log - 1; i >= 0; i--)
935 align_tab[i] = seq;
936 }
937 }
938
939 /* When optimizing, we start assuming minimum length, and keep increasing
940 lengths as we find the need for this, till nothing changes.
941 When not optimizing, we start assuming maximum lengths, and
942 do a single pass to update the lengths. */
943 bool increasing = optimize != 0;
944
945#ifdef CASE_VECTOR_SHORTEN_MODE
946 if (optimize)
947 {
948 /* Look for ADDR_DIFF_VECs, and initialize their minimum and maximum
949 label fields. */
950
951 int min_shuid = INSN_SHUID (get_insns ()) - 1;
952 int max_shuid = INSN_SHUID (get_last_insn ()) + 1;
953 int rel;
954
955 for (insn = first; insn != 0; insn = NEXT_INSN (insn))
956 {
957 rtx min_lab = NULL_RTX, max_lab = NULL_RTX, pat;
958 int len, i, min, max, insn_shuid;
959 int min_align;
960 addr_diff_vec_flags flags;
961
962 if (! JUMP_TABLE_DATA_P (insn)
963 || GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC)
964 continue;
965 pat = PATTERN (insn);
966 len = XVECLEN (pat, 1);
967 gcc_assert (len > 0);
968 min_align = MAX_CODE_ALIGN;
969 for (min = max_shuid, max = min_shuid, i = len - 1; i >= 0; i--)
970 {
971 rtx lab = XEXP (XVECEXP (pat, 1, i), 0);
972 int shuid = INSN_SHUID (lab);
973 if (shuid < min)
974 {
975 min = shuid;
976 min_lab = lab;
977 }
978 if (shuid > max)
979 {
980 max = shuid;
981 max_lab = lab;
982 }
983
984 int label_alignment = LABEL_TO_ALIGNMENT (lab).levels[0].log;
985 if (min_align > label_alignment)
986 min_align = label_alignment;
987 }
988 XEXP (pat, 2) = gen_rtx_LABEL_REF (Pmode, min_lab);
989 XEXP (pat, 3) = gen_rtx_LABEL_REF (Pmode, max_lab);
990 insn_shuid = INSN_SHUID (insn);
991 rel = INSN_SHUID (XEXP (XEXP (pat, 0), 0));
992 memset (&flags, 0, sizeof (flags));
993 flags.min_align = min_align;
994 flags.base_after_vec = rel > insn_shuid;
995 flags.min_after_vec = min > insn_shuid;
996 flags.max_after_vec = max > insn_shuid;
997 flags.min_after_base = min > rel;
998 flags.max_after_base = max > rel;
999 ADDR_DIFF_VEC_FLAGS (pat) = flags;
1000
1001 if (increasing)
1002 PUT_MODE (pat, CASE_VECTOR_SHORTEN_MODE (0, 0, pat));
1003 }
1004 }
1005#endif /* CASE_VECTOR_SHORTEN_MODE */
1006
1007 /* Compute initial lengths, addresses, and varying flags for each insn. */
1008 int (*length_fun) (rtx_insn *) = increasing ? insn_min_length : insn_default_length;
1009
1010 for (insn_current_address = 0, insn = first;
1011 insn != 0;
1012 insn_current_address += insn_lengths[uid], insn = NEXT_INSN (insn))
1013 {
1014 uid = INSN_UID (insn);
1015
1016 insn_lengths[uid] = 0;
1017
1018 if (LABEL_P (insn))
1019 {
1020 int log = LABEL_TO_ALIGNMENT (insn).levels[0].log;
1021 if (log)
1022 {
1023 int align = 1 << log;
1024 int new_address = (insn_current_address + align - 1) & -align;
1025 insn_lengths[uid] = new_address - insn_current_address;
1026 }
1027 }
1028
1029 INSN_ADDRESSES (uid) = insn_current_address + insn_lengths[uid];
1030
1031 if (NOTE_P (insn) || BARRIER_P (insn)
1032 || LABEL_P (insn) || DEBUG_INSN_P (insn))
1033 continue;
1034 if (insn->deleted ())
1035 continue;
1036
1037 body = PATTERN (insn);
1038 if (rtx_jump_table_data *table = dyn_cast <rtx_jump_table_data *> (p: insn))
1039 {
1040 /* This only takes room if read-only data goes into the text
1041 section. */
1042 if (JUMP_TABLES_IN_TEXT_SECTION
1043 || readonly_data_section == text_section)
1044 insn_lengths[uid] = (XVECLEN (body,
1045 GET_CODE (body) == ADDR_DIFF_VEC)
1046 * GET_MODE_SIZE (mode: table->get_data_mode ()));
1047 /* Alignment is handled by ADDR_VEC_ALIGN. */
1048 }
1049 else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0)
1050 insn_lengths[uid] = asm_insn_count (body) * insn_default_length (insn);
1051 else if (rtx_sequence *body_seq = dyn_cast <rtx_sequence *> (p: body))
1052 {
1053 int i;
1054 int const_delay_slots;
1055 if (DELAY_SLOTS)
1056 const_delay_slots = const_num_delay_slots (body_seq->insn (index: 0));
1057 else
1058 const_delay_slots = 0;
1059
1060 int (*inner_length_fun) (rtx_insn *)
1061 = const_delay_slots ? length_fun : insn_default_length;
1062 /* Inside a delay slot sequence, we do not do any branch shortening
1063 if the shortening could change the number of delay slots
1064 of the branch. */
1065 for (i = 0; i < body_seq->len (); i++)
1066 {
1067 rtx_insn *inner_insn = body_seq->insn (index: i);
1068 int inner_uid = INSN_UID (insn: inner_insn);
1069 int inner_length;
1070
1071 if (GET_CODE (PATTERN (inner_insn)) == ASM_INPUT
1072 || asm_noperands (PATTERN (insn: inner_insn)) >= 0)
1073 inner_length = (asm_insn_count (PATTERN (insn: inner_insn))
1074 * insn_default_length (inner_insn));
1075 else
1076 inner_length = inner_length_fun (inner_insn);
1077
1078 insn_lengths[inner_uid] = inner_length;
1079 if (const_delay_slots)
1080 {
1081 if ((varying_length[inner_uid]
1082 = insn_variable_length_p (inner_insn)) != 0)
1083 varying_length[uid] = 1;
1084 INSN_ADDRESSES (inner_uid) = (insn_current_address
1085 + insn_lengths[uid]);
1086 }
1087 else
1088 varying_length[inner_uid] = 0;
1089 insn_lengths[uid] += inner_length;
1090 }
1091 }
1092 else if (GET_CODE (body) != USE && GET_CODE (body) != CLOBBER)
1093 {
1094 insn_lengths[uid] = length_fun (insn);
1095 varying_length[uid] = insn_variable_length_p (insn);
1096 }
1097
1098 /* If needed, do any adjustment. */
1099#ifdef ADJUST_INSN_LENGTH
1100 ADJUST_INSN_LENGTH (insn, insn_lengths[uid]);
1101 if (insn_lengths[uid] < 0)
1102 fatal_insn ("negative insn length", insn);
1103#endif
1104 }
1105
1106 /* Now loop over all the insns finding varying length insns. For each,
1107 get the current insn length. If it has changed, reflect the change.
1108 When nothing changes for a full pass, we are done. */
1109
1110 while (something_changed)
1111 {
1112 something_changed = false;
1113 insn_current_align = MAX_CODE_ALIGN - 1;
1114 for (insn_current_address = 0, insn = first;
1115 insn != 0;
1116 insn = NEXT_INSN (insn))
1117 {
1118 int new_length;
1119#ifdef ADJUST_INSN_LENGTH
1120 int tmp_length;
1121#endif
1122 int length_align;
1123
1124 uid = INSN_UID (insn);
1125
1126 if (rtx_code_label *label = dyn_cast <rtx_code_label *> (p: insn))
1127 {
1128 int log = LABEL_TO_ALIGNMENT (label).levels[0].log;
1129
1130#ifdef CASE_VECTOR_SHORTEN_MODE
1131 /* If the mode of a following jump table was changed, we
1132 may need to update the alignment of this label. */
1133
1134 if (JUMP_TABLES_IN_TEXT_SECTION
1135 || readonly_data_section == text_section)
1136 {
1137 rtx_jump_table_data *table = jump_table_for_label (label);
1138 if (table)
1139 {
1140 int newlog = ADDR_VEC_ALIGN (table);
1141 if (newlog != log)
1142 {
1143 log = newlog;
1144 LABEL_TO_ALIGNMENT (insn) = log;
1145 something_changed = true;
1146 }
1147 }
1148 }
1149#endif
1150
1151 if (log > insn_current_align)
1152 {
1153 int align = 1 << log;
1154 int new_address= (insn_current_address + align - 1) & -align;
1155 insn_lengths[uid] = new_address - insn_current_address;
1156 insn_current_align = log;
1157 insn_current_address = new_address;
1158 }
1159 else
1160 insn_lengths[uid] = 0;
1161 INSN_ADDRESSES (uid) = insn_current_address;
1162 continue;
1163 }
1164
1165 length_align = INSN_LENGTH_ALIGNMENT (insn);
1166 if (length_align < insn_current_align)
1167 insn_current_align = length_align;
1168
1169 insn_last_address = INSN_ADDRESSES (uid);
1170 INSN_ADDRESSES (uid) = insn_current_address;
1171
1172#ifdef CASE_VECTOR_SHORTEN_MODE
1173 if (optimize
1174 && JUMP_TABLE_DATA_P (insn)
1175 && GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
1176 {
1177 rtx_jump_table_data *table = as_a <rtx_jump_table_data *> (insn);
1178 rtx body = PATTERN (insn);
1179 int old_length = insn_lengths[uid];
1180 rtx_insn *rel_lab =
1181 safe_as_a <rtx_insn *> (XEXP (XEXP (body, 0), 0));
1182 rtx min_lab = XEXP (XEXP (body, 2), 0);
1183 rtx max_lab = XEXP (XEXP (body, 3), 0);
1184 int rel_addr = INSN_ADDRESSES (INSN_UID (rel_lab));
1185 int min_addr = INSN_ADDRESSES (INSN_UID (min_lab));
1186 int max_addr = INSN_ADDRESSES (INSN_UID (max_lab));
1187 rtx_insn *prev;
1188 int rel_align = 0;
1189 addr_diff_vec_flags flags;
1190 scalar_int_mode vec_mode;
1191
1192 /* Avoid automatic aggregate initialization. */
1193 flags = ADDR_DIFF_VEC_FLAGS (body);
1194
1195 /* Try to find a known alignment for rel_lab. */
1196 for (prev = rel_lab;
1197 prev
1198 && ! insn_lengths[INSN_UID (prev)]
1199 && ! (varying_length[INSN_UID (prev)] & 1);
1200 prev = PREV_INSN (prev))
1201 if (varying_length[INSN_UID (prev)] & 2)
1202 {
1203 rel_align = LABEL_TO_ALIGNMENT (prev).levels[0].log;
1204 break;
1205 }
1206
1207 /* See the comment on addr_diff_vec_flags in rtl.h for the
1208 meaning of the flags values. base: REL_LAB vec: INSN */
1209 /* Anything after INSN has still addresses from the last
1210 pass; adjust these so that they reflect our current
1211 estimate for this pass. */
1212 if (flags.base_after_vec)
1213 rel_addr += insn_current_address - insn_last_address;
1214 if (flags.min_after_vec)
1215 min_addr += insn_current_address - insn_last_address;
1216 if (flags.max_after_vec)
1217 max_addr += insn_current_address - insn_last_address;
1218 /* We want to know the worst case, i.e. lowest possible value
1219 for the offset of MIN_LAB. If MIN_LAB is after REL_LAB,
1220 its offset is positive, and we have to be wary of code shrink;
1221 otherwise, it is negative, and we have to be vary of code
1222 size increase. */
1223 if (flags.min_after_base)
1224 {
1225 /* If INSN is between REL_LAB and MIN_LAB, the size
1226 changes we are about to make can change the alignment
1227 within the observed offset, therefore we have to break
1228 it up into two parts that are independent. */
1229 if (! flags.base_after_vec && flags.min_after_vec)
1230 {
1231 min_addr -= align_fuzz (rel_lab, insn, rel_align, 0);
1232 min_addr -= align_fuzz (insn, min_lab, 0, 0);
1233 }
1234 else
1235 min_addr -= align_fuzz (rel_lab, min_lab, rel_align, 0);
1236 }
1237 else
1238 {
1239 if (flags.base_after_vec && ! flags.min_after_vec)
1240 {
1241 min_addr -= align_fuzz (min_lab, insn, 0, ~0);
1242 min_addr -= align_fuzz (insn, rel_lab, 0, ~0);
1243 }
1244 else
1245 min_addr -= align_fuzz (min_lab, rel_lab, 0, ~0);
1246 }
1247 /* Likewise, determine the highest lowest possible value
1248 for the offset of MAX_LAB. */
1249 if (flags.max_after_base)
1250 {
1251 if (! flags.base_after_vec && flags.max_after_vec)
1252 {
1253 max_addr += align_fuzz (rel_lab, insn, rel_align, ~0);
1254 max_addr += align_fuzz (insn, max_lab, 0, ~0);
1255 }
1256 else
1257 max_addr += align_fuzz (rel_lab, max_lab, rel_align, ~0);
1258 }
1259 else
1260 {
1261 if (flags.base_after_vec && ! flags.max_after_vec)
1262 {
1263 max_addr += align_fuzz (max_lab, insn, 0, 0);
1264 max_addr += align_fuzz (insn, rel_lab, 0, 0);
1265 }
1266 else
1267 max_addr += align_fuzz (max_lab, rel_lab, 0, 0);
1268 }
1269 vec_mode = CASE_VECTOR_SHORTEN_MODE (min_addr - rel_addr,
1270 max_addr - rel_addr, body);
1271 if (!increasing
1272 || (GET_MODE_SIZE (vec_mode)
1273 >= GET_MODE_SIZE (table->get_data_mode ())))
1274 PUT_MODE (body, vec_mode);
1275 if (JUMP_TABLES_IN_TEXT_SECTION
1276 || readonly_data_section == text_section)
1277 {
1278 insn_lengths[uid]
1279 = (XVECLEN (body, 1)
1280 * GET_MODE_SIZE (table->get_data_mode ()));
1281 insn_current_address += insn_lengths[uid];
1282 if (insn_lengths[uid] != old_length)
1283 something_changed = true;
1284 }
1285
1286 continue;
1287 }
1288#endif /* CASE_VECTOR_SHORTEN_MODE */
1289
1290 if (! (varying_length[uid]))
1291 {
1292 if (NONJUMP_INSN_P (insn)
1293 && GET_CODE (PATTERN (insn)) == SEQUENCE)
1294 {
1295 int i;
1296
1297 body = PATTERN (insn);
1298 for (i = 0; i < XVECLEN (body, 0); i++)
1299 {
1300 rtx inner_insn = XVECEXP (body, 0, i);
1301 int inner_uid = INSN_UID (insn: inner_insn);
1302
1303 INSN_ADDRESSES (inner_uid) = insn_current_address;
1304
1305 insn_current_address += insn_lengths[inner_uid];
1306 }
1307 }
1308 else
1309 insn_current_address += insn_lengths[uid];
1310
1311 continue;
1312 }
1313
1314 if (NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE)
1315 {
1316 rtx_sequence *seqn = as_a <rtx_sequence *> (p: PATTERN (insn));
1317 int i;
1318
1319 body = PATTERN (insn);
1320 new_length = 0;
1321 for (i = 0; i < seqn->len (); i++)
1322 {
1323 rtx_insn *inner_insn = seqn->insn (index: i);
1324 int inner_uid = INSN_UID (insn: inner_insn);
1325 int inner_length;
1326
1327 INSN_ADDRESSES (inner_uid) = insn_current_address;
1328
1329 /* insn_current_length returns 0 for insns with a
1330 non-varying length. */
1331 if (! varying_length[inner_uid])
1332 inner_length = insn_lengths[inner_uid];
1333 else
1334 inner_length = insn_current_length (inner_insn);
1335
1336 if (inner_length != insn_lengths[inner_uid])
1337 {
1338 if (!increasing || inner_length > insn_lengths[inner_uid])
1339 {
1340 insn_lengths[inner_uid] = inner_length;
1341 something_changed = true;
1342 }
1343 else
1344 inner_length = insn_lengths[inner_uid];
1345 }
1346 insn_current_address += inner_length;
1347 new_length += inner_length;
1348 }
1349 }
1350 else
1351 {
1352 new_length = insn_current_length (insn);
1353 insn_current_address += new_length;
1354 }
1355
1356#ifdef ADJUST_INSN_LENGTH
1357 /* If needed, do any adjustment. */
1358 tmp_length = new_length;
1359 ADJUST_INSN_LENGTH (insn, new_length);
1360 insn_current_address += (new_length - tmp_length);
1361#endif
1362
1363 if (new_length != insn_lengths[uid]
1364 && (!increasing || new_length > insn_lengths[uid]))
1365 {
1366 insn_lengths[uid] = new_length;
1367 something_changed = true;
1368 }
1369 else
1370 insn_current_address += insn_lengths[uid] - new_length;
1371 }
1372 /* For a non-optimizing compile, do only a single pass. */
1373 if (!increasing)
1374 break;
1375 }
1376 crtl->max_insn_address = insn_current_address;
1377 free (ptr: varying_length);
1378}
1379
1380/* Given the body of an INSN known to be generated by an ASM statement, return
1381 the number of machine instructions likely to be generated for this insn.
1382 This is used to compute its length. */
1383
1384static int
1385asm_insn_count (rtx body)
1386{
1387 const char *templ;
1388
1389 if (GET_CODE (body) == ASM_INPUT)
1390 templ = XSTR (body, 0);
1391 else
1392 templ = decode_asm_operands (body, NULL, NULL, NULL, NULL, NULL);
1393
1394 return asm_str_count (templ);
1395}
1396
1397/* Return the number of machine instructions likely to be generated for the
1398 inline-asm template. */
1399int
1400asm_str_count (const char *templ)
1401{
1402 int count = 1;
1403
1404 if (!*templ)
1405 return 0;
1406
1407 for (; *templ; templ++)
1408 if (IS_ASM_LOGICAL_LINE_SEPARATOR (*templ, templ)
1409 || *templ == '\n')
1410 count++;
1411
1412 return count;
1413}
1414
1415/* Return true if DWARF2 debug info can be emitted for DECL. */
1416
1417static bool
1418dwarf2_debug_info_emitted_p (tree decl)
1419{
1420 /* When DWARF2 debug info is not generated internally. */
1421 if (!dwarf_debuginfo_p () && !dwarf_based_debuginfo_p ())
1422 return false;
1423
1424 if (DECL_IGNORED_P (decl))
1425 return false;
1426
1427 return true;
1428}
1429
1430/* Return scope resulting from combination of S1 and S2. */
1431static tree
1432choose_inner_scope (tree s1, tree s2)
1433{
1434 if (!s1)
1435 return s2;
1436 if (!s2)
1437 return s1;
1438 if (BLOCK_NUMBER (s1) > BLOCK_NUMBER (s2))
1439 return s1;
1440 return s2;
1441}
1442
1443/* Emit lexical block notes needed to change scope from S1 to S2. */
1444
1445static void
1446change_scope (rtx_insn *orig_insn, tree s1, tree s2)
1447{
1448 rtx_insn *insn = orig_insn;
1449 tree com = NULL_TREE;
1450 tree ts1 = s1, ts2 = s2;
1451 tree s;
1452
1453 while (ts1 != ts2)
1454 {
1455 gcc_assert (ts1 && ts2);
1456 if (BLOCK_NUMBER (ts1) > BLOCK_NUMBER (ts2))
1457 ts1 = BLOCK_SUPERCONTEXT (ts1);
1458 else if (BLOCK_NUMBER (ts1) < BLOCK_NUMBER (ts2))
1459 ts2 = BLOCK_SUPERCONTEXT (ts2);
1460 else
1461 {
1462 ts1 = BLOCK_SUPERCONTEXT (ts1);
1463 ts2 = BLOCK_SUPERCONTEXT (ts2);
1464 }
1465 }
1466 com = ts1;
1467
1468 /* Close scopes. */
1469 s = s1;
1470 while (s != com)
1471 {
1472 rtx_note *note = emit_note_before (NOTE_INSN_BLOCK_END, insn);
1473 NOTE_BLOCK (note) = s;
1474 s = BLOCK_SUPERCONTEXT (s);
1475 }
1476
1477 /* Open scopes. */
1478 s = s2;
1479 while (s != com)
1480 {
1481 insn = emit_note_before (NOTE_INSN_BLOCK_BEG, insn);
1482 NOTE_BLOCK (insn) = s;
1483 s = BLOCK_SUPERCONTEXT (s);
1484 }
1485}
1486
1487/* Rebuild all the NOTE_INSN_BLOCK_BEG and NOTE_INSN_BLOCK_END notes based
1488 on the scope tree and the newly reordered instructions. */
1489
1490static void
1491reemit_insn_block_notes (void)
1492{
1493 tree cur_block = DECL_INITIAL (cfun->decl);
1494 rtx_insn *insn;
1495
1496 insn = get_insns ();
1497 for (; insn; insn = NEXT_INSN (insn))
1498 {
1499 tree this_block;
1500
1501 /* Prevent lexical blocks from straddling section boundaries. */
1502 if (NOTE_P (insn))
1503 switch (NOTE_KIND (insn))
1504 {
1505 case NOTE_INSN_SWITCH_TEXT_SECTIONS:
1506 {
1507 for (tree s = cur_block; s != DECL_INITIAL (cfun->decl);
1508 s = BLOCK_SUPERCONTEXT (s))
1509 {
1510 rtx_note *note = emit_note_before (NOTE_INSN_BLOCK_END, insn);
1511 NOTE_BLOCK (note) = s;
1512 note = emit_note_after (NOTE_INSN_BLOCK_BEG, insn);
1513 NOTE_BLOCK (note) = s;
1514 }
1515 }
1516 break;
1517
1518 case NOTE_INSN_BEGIN_STMT:
1519 case NOTE_INSN_INLINE_ENTRY:
1520 this_block = LOCATION_BLOCK (NOTE_MARKER_LOCATION (insn));
1521 if (!this_block)
1522 continue;
1523 goto set_cur_block_to_this_block;
1524
1525 default:
1526 continue;
1527 }
1528
1529 if (!active_insn_p (insn))
1530 continue;
1531
1532 /* Avoid putting scope notes between jump table and its label. */
1533 if (JUMP_TABLE_DATA_P (insn))
1534 continue;
1535
1536 this_block = insn_scope (insn);
1537 /* For sequences compute scope resulting from merging all scopes
1538 of instructions nested inside. */
1539 if (rtx_sequence *body = dyn_cast <rtx_sequence *> (p: PATTERN (insn)))
1540 {
1541 int i;
1542
1543 this_block = NULL;
1544 for (i = 0; i < body->len (); i++)
1545 this_block = choose_inner_scope (s1: this_block,
1546 s2: insn_scope (body->insn (index: i)));
1547 }
1548 if (! this_block)
1549 {
1550 if (INSN_LOCATION (insn) == UNKNOWN_LOCATION)
1551 continue;
1552 else
1553 this_block = DECL_INITIAL (cfun->decl);
1554 }
1555
1556 set_cur_block_to_this_block:
1557 if (this_block != cur_block)
1558 {
1559 change_scope (orig_insn: insn, s1: cur_block, s2: this_block);
1560 cur_block = this_block;
1561 }
1562 }
1563
1564 /* change_scope emits before the insn, not after. */
1565 rtx_note *note = emit_note (NOTE_INSN_DELETED);
1566 change_scope (orig_insn: note, s1: cur_block, DECL_INITIAL (cfun->decl));
1567 delete_insn (note);
1568
1569 reorder_blocks ();
1570}
1571
1572static const char *some_local_dynamic_name;
1573
1574/* Locate some local-dynamic symbol still in use by this function
1575 so that we can print its name in local-dynamic base patterns.
1576 Return null if there are no local-dynamic references. */
1577
1578const char *
1579get_some_local_dynamic_name ()
1580{
1581 subrtx_iterator::array_type array;
1582 rtx_insn *insn;
1583
1584 if (some_local_dynamic_name)
1585 return some_local_dynamic_name;
1586
1587 for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
1588 if (NONDEBUG_INSN_P (insn))
1589 FOR_EACH_SUBRTX (iter, array, PATTERN (insn), ALL)
1590 {
1591 const_rtx x = *iter;
1592 if (GET_CODE (x) == SYMBOL_REF)
1593 {
1594 if (SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_LOCAL_DYNAMIC)
1595 return some_local_dynamic_name = XSTR (x, 0);
1596 if (CONSTANT_POOL_ADDRESS_P (x))
1597 iter.substitute (x: get_pool_constant (x));
1598 }
1599 }
1600
1601 return 0;
1602}
1603
1604/* Arrange for us to emit a source location note before any further
1605 real insns or section changes, by setting the SEEN_NEXT_VIEW bit in
1606 *SEEN, as long as we are keeping track of location views. The bit
1607 indicates we have referenced the next view at the current PC, so we
1608 have to emit it. This should be called next to the var_location
1609 debug hook. */
1610
1611static inline void
1612set_next_view_needed (int *seen)
1613{
1614 if (debug_variable_location_views)
1615 *seen |= SEEN_NEXT_VIEW;
1616}
1617
1618/* Clear the flag in *SEEN indicating we need to emit the next view.
1619 This should be called next to the source_line debug hook. */
1620
1621static inline void
1622clear_next_view_needed (int *seen)
1623{
1624 *seen &= ~SEEN_NEXT_VIEW;
1625}
1626
1627/* Test whether we have a pending request to emit the next view in
1628 *SEEN, and emit it if needed, clearing the request bit. */
1629
1630static inline void
1631maybe_output_next_view (int *seen)
1632{
1633 if ((*seen & SEEN_NEXT_VIEW) != 0)
1634 {
1635 clear_next_view_needed (seen);
1636 (*debug_hooks->source_line) (last_linenum, last_columnnum,
1637 last_filename, last_discriminator,
1638 false);
1639 }
1640}
1641
1642/* We want to emit param bindings (before the first begin_stmt) in the
1643 initial view, if we are emitting views. To that end, we may
1644 consume initial notes in the function, processing them in
1645 final_start_function, before signaling the beginning of the
1646 prologue, rather than in final.
1647
1648 We don't test whether the DECLs are PARM_DECLs: the assumption is
1649 that there will be a NOTE_INSN_BEGIN_STMT marker before any
1650 non-parameter NOTE_INSN_VAR_LOCATION. It's ok if the marker is not
1651 there, we'll just have more variable locations bound in the initial
1652 view, which is consistent with their being bound without any code
1653 that would give them a value. */
1654
1655static inline bool
1656in_initial_view_p (rtx_insn *insn)
1657{
1658 return (!DECL_IGNORED_P (current_function_decl)
1659 && debug_variable_location_views
1660 && insn && GET_CODE (insn) == NOTE
1661 && (NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION
1662 || NOTE_KIND (insn) == NOTE_INSN_DELETED));
1663}
1664
1665/* Output assembler code for the start of a function,
1666 and initialize some of the variables in this file
1667 for the new function. The label for the function and associated
1668 assembler pseudo-ops have already been output in `assemble_start_function'.
1669
1670 FIRST is the first insn of the rtl for the function being compiled.
1671 FILE is the file to write assembler code to.
1672 SEEN should be initially set to zero, and it may be updated to
1673 indicate we have references to the next location view, that would
1674 require us to emit it at the current PC.
1675 OPTIMIZE_P is nonzero if we should eliminate redundant
1676 test and compare insns. */
1677
1678static void
1679final_start_function_1 (rtx_insn **firstp, FILE *file, int *seen,
1680 int optimize_p ATTRIBUTE_UNUSED)
1681{
1682 block_depth = 0;
1683
1684 this_is_asm_operands = 0;
1685
1686 need_profile_function = false;
1687
1688 last_filename = LOCATION_FILE (prologue_location);
1689 last_linenum = LOCATION_LINE (prologue_location);
1690 last_columnnum = LOCATION_COLUMN (prologue_location);
1691 last_discriminator = 0;
1692 force_source_line = false;
1693
1694 high_block_linenum = high_function_linenum = last_linenum;
1695
1696 rtx_insn *first = *firstp;
1697 if (in_initial_view_p (insn: first))
1698 {
1699 do
1700 {
1701 final_scan_insn (first, file, 0, 0, seen);
1702 first = NEXT_INSN (insn: first);
1703 }
1704 while (in_initial_view_p (insn: first));
1705 *firstp = first;
1706 }
1707
1708 if (!DECL_IGNORED_P (current_function_decl))
1709 debug_hooks->begin_prologue (last_linenum, last_columnnum,
1710 last_filename);
1711
1712 if (!dwarf2_debug_info_emitted_p (decl: current_function_decl))
1713 dwarf2out_begin_prologue (0, 0, NULL);
1714
1715 if (DECL_IGNORED_P (current_function_decl) && last_linenum && last_filename)
1716 debug_hooks->set_ignored_loc (last_linenum, last_columnnum, last_filename);
1717
1718#ifdef LEAF_REG_REMAP
1719 if (crtl->uses_only_leaf_regs)
1720 leaf_renumber_regs (first);
1721#endif
1722
1723 /* The Sun386i and perhaps other machines don't work right
1724 if the profiling code comes after the prologue. */
1725 if (targetm.profile_before_prologue () && crtl->profile)
1726 {
1727 if (targetm.asm_out.function_prologue == default_function_pro_epilogue
1728 && targetm.have_prologue ())
1729 {
1730 rtx_insn *insn;
1731 for (insn = first; insn; insn = NEXT_INSN (insn))
1732 if (!NOTE_P (insn))
1733 {
1734 insn = NULL;
1735 break;
1736 }
1737 else if (NOTE_KIND (insn) == NOTE_INSN_BASIC_BLOCK
1738 || NOTE_KIND (insn) == NOTE_INSN_FUNCTION_BEG)
1739 break;
1740 else if (NOTE_KIND (insn) == NOTE_INSN_DELETED
1741 || NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION)
1742 continue;
1743 else
1744 {
1745 insn = NULL;
1746 break;
1747 }
1748
1749 if (insn)
1750 need_profile_function = true;
1751 else
1752 profile_function (file);
1753 }
1754 else
1755 profile_function (file);
1756 }
1757
1758 /* If debugging, assign block numbers to all of the blocks in this
1759 function. */
1760 if (write_symbols)
1761 {
1762 reemit_insn_block_notes ();
1763 number_blocks (current_function_decl);
1764 /* We never actually put out begin/end notes for the top-level
1765 block in the function. But, conceptually, that block is
1766 always needed. */
1767 TREE_ASM_WRITTEN (DECL_INITIAL (current_function_decl)) = 1;
1768 }
1769
1770 unsigned HOST_WIDE_INT min_frame_size
1771 = constant_lower_bound (a: get_frame_size ());
1772 if (min_frame_size > (unsigned HOST_WIDE_INT) warn_frame_larger_than_size)
1773 {
1774 /* Issue a warning */
1775 warning (OPT_Wframe_larger_than_,
1776 "the frame size of %wu bytes is larger than %wu bytes",
1777 min_frame_size, warn_frame_larger_than_size);
1778 }
1779
1780 /* First output the function prologue: code to set up the stack frame. */
1781 targetm.asm_out.function_prologue (file);
1782
1783 /* If the machine represents the prologue as RTL, the profiling code must
1784 be emitted when NOTE_INSN_PROLOGUE_END is scanned. */
1785 if (! targetm.have_prologue ())
1786 profile_after_prologue (file);
1787}
1788
1789/* This is an exported final_start_function_1, callable without SEEN. */
1790
1791void
1792final_start_function (rtx_insn *first, FILE *file,
1793 int optimize_p ATTRIBUTE_UNUSED)
1794{
1795 int seen = 0;
1796 final_start_function_1 (firstp: &first, file, seen: &seen, optimize_p);
1797 gcc_assert (seen == 0);
1798}
1799
1800static void
1801profile_after_prologue (FILE *file ATTRIBUTE_UNUSED)
1802{
1803 if (!targetm.profile_before_prologue () && crtl->profile)
1804 profile_function (file);
1805}
1806
1807static void
1808profile_function (FILE *file ATTRIBUTE_UNUSED)
1809{
1810#ifndef NO_PROFILE_COUNTERS
1811# define NO_PROFILE_COUNTERS 0
1812#endif
1813#ifdef ASM_OUTPUT_REG_PUSH
1814 rtx sval = NULL, chain = NULL;
1815
1816 if (cfun->returns_struct)
1817 sval = targetm.calls.struct_value_rtx (TREE_TYPE (current_function_decl),
1818 true);
1819 if (cfun->static_chain_decl)
1820 chain = targetm.calls.static_chain (current_function_decl, true);
1821#endif /* ASM_OUTPUT_REG_PUSH */
1822
1823 if (! NO_PROFILE_COUNTERS)
1824 {
1825 int align = MIN (BIGGEST_ALIGNMENT, LONG_TYPE_SIZE);
1826 switch_to_section (data_section);
1827 ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
1828 targetm.asm_out.internal_label (file, "LP", current_function_funcdef_no);
1829 assemble_integer (const0_rtx, LONG_TYPE_SIZE / BITS_PER_UNIT, align, 1);
1830 }
1831
1832 switch_to_section (current_function_section ());
1833
1834#ifdef ASM_OUTPUT_REG_PUSH
1835 if (sval && REG_P (sval))
1836 ASM_OUTPUT_REG_PUSH (file, REGNO (sval));
1837 if (chain && REG_P (chain))
1838 ASM_OUTPUT_REG_PUSH (file, REGNO (chain));
1839#endif
1840
1841 FUNCTION_PROFILER (file, current_function_funcdef_no);
1842
1843#ifdef ASM_OUTPUT_REG_PUSH
1844 if (chain && REG_P (chain))
1845 ASM_OUTPUT_REG_POP (file, REGNO (chain));
1846 if (sval && REG_P (sval))
1847 ASM_OUTPUT_REG_POP (file, REGNO (sval));
1848#endif
1849}
1850
1851/* Output assembler code for the end of a function.
1852 For clarity, args are same as those of `final_start_function'
1853 even though not all of them are needed. */
1854
1855void
1856final_end_function (void)
1857{
1858 app_disable ();
1859
1860 if (!DECL_IGNORED_P (current_function_decl))
1861 debug_hooks->end_function (high_function_linenum);
1862
1863 /* Finally, output the function epilogue:
1864 code to restore the stack frame and return to the caller. */
1865 targetm.asm_out.function_epilogue (asm_out_file);
1866
1867 /* And debug output. */
1868 if (!DECL_IGNORED_P (current_function_decl))
1869 debug_hooks->end_epilogue (last_linenum, last_filename);
1870
1871 if (!dwarf2_debug_info_emitted_p (decl: current_function_decl)
1872 && dwarf2out_do_frame ())
1873 dwarf2out_end_epilogue (last_linenum, last_filename);
1874
1875 some_local_dynamic_name = 0;
1876}
1877
1878
1879/* Dumper helper for basic block information. FILE is the assembly
1880 output file, and INSN is the instruction being emitted. */
1881
1882static void
1883dump_basic_block_info (FILE *file, rtx_insn *insn, basic_block *start_to_bb,
1884 basic_block *end_to_bb, int bb_map_size, int *bb_seqn)
1885{
1886 basic_block bb;
1887
1888 if (!flag_debug_asm)
1889 return;
1890
1891 if (INSN_UID (insn) < bb_map_size
1892 && (bb = start_to_bb[INSN_UID (insn)]) != NULL)
1893 {
1894 edge e;
1895 edge_iterator ei;
1896
1897 fprintf (stream: file, format: "%s BLOCK %d", ASM_COMMENT_START, bb->index);
1898 if (bb->count.initialized_p ())
1899 {
1900 fprintf (stream: file, format: ", count:");
1901 bb->count.dump (f: file);
1902 }
1903 fprintf (stream: file, format: " seq:%d", (*bb_seqn)++);
1904 fprintf (stream: file, format: "\n%s PRED:", ASM_COMMENT_START);
1905 FOR_EACH_EDGE (e, ei, bb->preds)
1906 {
1907 dump_edge_info (file, e, TDF_DETAILS, 0);
1908 }
1909 fprintf (stream: file, format: "\n");
1910 }
1911 if (INSN_UID (insn) < bb_map_size
1912 && (bb = end_to_bb[INSN_UID (insn)]) != NULL)
1913 {
1914 edge e;
1915 edge_iterator ei;
1916
1917 fprintf (stream: asm_out_file, format: "%s SUCC:", ASM_COMMENT_START);
1918 FOR_EACH_EDGE (e, ei, bb->succs)
1919 {
1920 dump_edge_info (asm_out_file, e, TDF_DETAILS, 1);
1921 }
1922 fprintf (stream: file, format: "\n");
1923 }
1924}
1925
1926/* Output assembler code for some insns: all or part of a function.
1927 For description of args, see `final_start_function', above. */
1928
1929static void
1930final_1 (rtx_insn *first, FILE *file, int seen, int optimize_p)
1931{
1932 rtx_insn *insn, *next;
1933
1934 /* Used for -dA dump. */
1935 basic_block *start_to_bb = NULL;
1936 basic_block *end_to_bb = NULL;
1937 int bb_map_size = 0;
1938 int bb_seqn = 0;
1939
1940 last_ignored_compare = 0;
1941
1942 init_recog ();
1943
1944 CC_STATUS_INIT;
1945
1946 if (flag_debug_asm)
1947 {
1948 basic_block bb;
1949
1950 bb_map_size = get_max_uid () + 1;
1951 start_to_bb = XCNEWVEC (basic_block, bb_map_size);
1952 end_to_bb = XCNEWVEC (basic_block, bb_map_size);
1953
1954 /* There is no cfg for a thunk. */
1955 if (!cfun->is_thunk)
1956 FOR_EACH_BB_REVERSE_FN (bb, cfun)
1957 {
1958 start_to_bb[INSN_UID (BB_HEAD (bb))] = bb;
1959 end_to_bb[INSN_UID (BB_END (bb))] = bb;
1960 }
1961 }
1962
1963 /* Output the insns. */
1964 for (insn = first; insn;)
1965 {
1966 if (HAVE_ATTR_length)
1967 {
1968 if ((unsigned) INSN_UID (insn) >= INSN_ADDRESSES_SIZE ())
1969 {
1970 /* This can be triggered by bugs elsewhere in the compiler if
1971 new insns are created after init_insn_lengths is called. */
1972 gcc_assert (NOTE_P (insn));
1973 insn_current_address = -1;
1974 }
1975 else
1976 insn_current_address = INSN_ADDRESSES (INSN_UID (insn));
1977 /* final can be seen as an iteration of shorten_branches that
1978 does nothing (since a fixed point has already been reached). */
1979 insn_last_address = insn_current_address;
1980 }
1981
1982 dump_basic_block_info (file, insn, start_to_bb, end_to_bb,
1983 bb_map_size, bb_seqn: &bb_seqn);
1984 insn = final_scan_insn (insn, file, optimize_p, 0, &seen);
1985 }
1986
1987 maybe_output_next_view (seen: &seen);
1988
1989 if (flag_debug_asm)
1990 {
1991 free (ptr: start_to_bb);
1992 free (ptr: end_to_bb);
1993 }
1994
1995 /* Remove CFI notes, to avoid compare-debug failures. */
1996 for (insn = first; insn; insn = next)
1997 {
1998 next = NEXT_INSN (insn);
1999 if (NOTE_P (insn)
2000 && (NOTE_KIND (insn) == NOTE_INSN_CFI
2001 || NOTE_KIND (insn) == NOTE_INSN_CFI_LABEL))
2002 delete_insn (insn);
2003 }
2004}
2005
2006/* This is an exported final_1, callable without SEEN. */
2007
2008void
2009final (rtx_insn *first, FILE *file, int optimize_p)
2010{
2011 /* Those that use the internal final_start_function_1/final_1 API
2012 skip initial debug bind notes in final_start_function_1, and pass
2013 the modified FIRST to final_1. But those that use the public
2014 final_start_function/final APIs, final_start_function can't move
2015 FIRST because it's not passed by reference, so if they were
2016 skipped there, skip them again here. */
2017 while (in_initial_view_p (insn: first))
2018 first = NEXT_INSN (insn: first);
2019
2020 final_1 (first, file, seen: 0, optimize_p);
2021}
2022
2023const char *
2024get_insn_template (int code, rtx_insn *insn)
2025{
2026 switch (insn_data[code].output_format)
2027 {
2028 case INSN_OUTPUT_FORMAT_SINGLE:
2029 return insn_data[code].output.single;
2030 case INSN_OUTPUT_FORMAT_MULTI:
2031 return insn_data[code].output.multi[which_alternative];
2032 case INSN_OUTPUT_FORMAT_FUNCTION:
2033 gcc_assert (insn);
2034 return (*insn_data[code].output.function) (recog_data.operand, insn);
2035
2036 default:
2037 gcc_unreachable ();
2038 }
2039}
2040
2041/* Emit the appropriate declaration for an alternate-entry-point
2042 symbol represented by INSN, to FILE. INSN is a CODE_LABEL with
2043 LABEL_KIND != LABEL_NORMAL.
2044
2045 The case fall-through in this function is intentional. */
2046static void
2047output_alternate_entry_point (FILE *file, rtx_insn *insn)
2048{
2049 const char *name = LABEL_NAME (insn);
2050
2051 switch (LABEL_KIND (insn))
2052 {
2053 case LABEL_WEAK_ENTRY:
2054#ifdef ASM_WEAKEN_LABEL
2055 ASM_WEAKEN_LABEL (file, name);
2056 gcc_fallthrough ();
2057#endif
2058 case LABEL_GLOBAL_ENTRY:
2059 targetm.asm_out.globalize_label (file, name);
2060 gcc_fallthrough ();
2061 case LABEL_STATIC_ENTRY:
2062#ifdef ASM_OUTPUT_TYPE_DIRECTIVE
2063 ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
2064#endif
2065 ASM_OUTPUT_LABEL (file, name);
2066 break;
2067
2068 case LABEL_NORMAL:
2069 default:
2070 gcc_unreachable ();
2071 }
2072}
2073
2074/* Given a CALL_INSN, find and return the nested CALL. */
2075static rtx
2076call_from_call_insn (const rtx_call_insn *insn)
2077{
2078 rtx x;
2079 gcc_assert (CALL_P (insn));
2080 x = PATTERN (insn);
2081
2082 while (GET_CODE (x) != CALL)
2083 {
2084 switch (GET_CODE (x))
2085 {
2086 default:
2087 gcc_unreachable ();
2088 case COND_EXEC:
2089 x = COND_EXEC_CODE (x);
2090 break;
2091 case PARALLEL:
2092 x = XVECEXP (x, 0, 0);
2093 break;
2094 case SET:
2095 x = XEXP (x, 1);
2096 break;
2097 }
2098 }
2099 return x;
2100}
2101
2102/* Return the CALL in X if there is one. */
2103
2104rtx
2105get_call_rtx_from (const rtx_insn *insn)
2106{
2107 const rtx_call_insn *call_insn = as_a<const rtx_call_insn *> (p: insn);
2108 return call_from_call_insn (insn: call_insn);
2109}
2110
2111/* Print a comment into the asm showing FILENAME, LINENUM, and the
2112 corresponding source line, if available. */
2113
2114static void
2115asm_show_source (const char *filename, int linenum)
2116{
2117 if (!filename)
2118 return;
2119
2120 diagnostics::char_span line
2121 = global_dc->get_file_cache ().get_source_line (file_path: filename, line: linenum);
2122 if (!line)
2123 return;
2124
2125 fprintf (stream: asm_out_file, format: "%s %s:%i: ", ASM_COMMENT_START, filename, linenum);
2126 /* "line" is not 0-terminated, so we must use its length. */
2127 fwrite (ptr: line.get_buffer (), size: 1, n: line.length (), s: asm_out_file);
2128 fputc (c: '\n', stream: asm_out_file);
2129}
2130
2131/* Judge if an absolute jump table is relocatable. */
2132
2133bool
2134jumptable_relocatable (void)
2135{
2136 bool relocatable = false;
2137
2138 if (!CASE_VECTOR_PC_RELATIVE
2139 && !targetm.asm_out.generate_pic_addr_diff_vec ()
2140 && targetm_common.have_named_sections)
2141 relocatable = targetm.asm_out.reloc_rw_mask ();
2142
2143 return relocatable;
2144}
2145
2146/* The final scan for one insn, INSN.
2147 Args are same as in `final', except that INSN
2148 is the insn being scanned.
2149 Value returned is the next insn to be scanned.
2150
2151 NOPEEPHOLES is the flag to disallow peephole processing (currently
2152 used for within delayed branch sequence output).
2153
2154 SEEN is used to track the end of the prologue, for emitting
2155 debug information. We force the emission of a line note after
2156 both NOTE_INSN_PROLOGUE_END and NOTE_INSN_FUNCTION_BEG. */
2157
2158static rtx_insn *
2159final_scan_insn_1 (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
2160 int nopeepholes ATTRIBUTE_UNUSED, int *seen)
2161{
2162 rtx_insn *next;
2163 rtx_jump_table_data *table;
2164
2165 insn_counter++;
2166
2167 /* Ignore deleted insns. These can occur when we split insns (due to a
2168 template of "#") while not optimizing. */
2169 if (insn->deleted ())
2170 return NEXT_INSN (insn);
2171
2172 switch (GET_CODE (insn))
2173 {
2174 case NOTE:
2175 switch (NOTE_KIND (insn))
2176 {
2177 case NOTE_INSN_DELETED:
2178 case NOTE_INSN_UPDATE_SJLJ_CONTEXT:
2179 break;
2180
2181 case NOTE_INSN_SWITCH_TEXT_SECTIONS:
2182 maybe_output_next_view (seen);
2183
2184 output_function_exception_table (0);
2185
2186 if (targetm.asm_out.unwind_emit)
2187 targetm.asm_out.unwind_emit (asm_out_file, insn);
2188
2189 in_cold_section_p = !in_cold_section_p;
2190
2191 gcc_checking_assert (in_cold_section_p);
2192 if (in_cold_section_p)
2193 cold_function_name
2194 = clone_function_name (decl: current_function_decl, suffix: "cold");
2195
2196 if (dwarf2out_do_frame ())
2197 {
2198 dwarf2out_switch_text_section ();
2199 if (!dwarf2_debug_info_emitted_p (decl: current_function_decl)
2200 && !DECL_IGNORED_P (current_function_decl))
2201 debug_hooks->switch_text_section ();
2202 }
2203 else if (!DECL_IGNORED_P (current_function_decl))
2204 debug_hooks->switch_text_section ();
2205 if (DECL_IGNORED_P (current_function_decl) && last_linenum
2206 && last_filename)
2207 debug_hooks->set_ignored_loc (last_linenum, last_columnnum,
2208 last_filename);
2209
2210 switch_to_section (current_function_section ());
2211 targetm.asm_out.function_switched_text_sections (asm_out_file,
2212 current_function_decl,
2213 in_cold_section_p);
2214 /* Emit a label for the split cold section. Form label name by
2215 suffixing "cold" to the original function's name. */
2216 if (in_cold_section_p)
2217 {
2218#ifdef ASM_DECLARE_COLD_FUNCTION_NAME
2219 ASM_DECLARE_COLD_FUNCTION_NAME (asm_out_file,
2220 IDENTIFIER_POINTER
2221 (cold_function_name),
2222 current_function_decl);
2223#else
2224 ASM_OUTPUT_LABEL (asm_out_file,
2225 IDENTIFIER_POINTER (cold_function_name));
2226#endif
2227 if (dwarf2out_do_frame ()
2228 && cfun->fde->dw_fde_second_begin != NULL)
2229 ASM_OUTPUT_LABEL (asm_out_file, cfun->fde->dw_fde_second_begin);
2230 }
2231 break;
2232
2233 case NOTE_INSN_BASIC_BLOCK:
2234 if (need_profile_function)
2235 {
2236 profile_function (file: asm_out_file);
2237 need_profile_function = false;
2238 }
2239
2240 if (targetm.asm_out.unwind_emit)
2241 targetm.asm_out.unwind_emit (asm_out_file, insn);
2242
2243 break;
2244
2245 case NOTE_INSN_EH_REGION_BEG:
2246 ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LEHB",
2247 NOTE_EH_HANDLER (insn));
2248 break;
2249
2250 case NOTE_INSN_EH_REGION_END:
2251 ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LEHE",
2252 NOTE_EH_HANDLER (insn));
2253 break;
2254
2255 case NOTE_INSN_PROLOGUE_END:
2256 targetm.asm_out.function_end_prologue (file);
2257 profile_after_prologue (file);
2258
2259 if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE)
2260 {
2261 *seen |= SEEN_EMITTED;
2262 force_source_line = true;
2263 }
2264 else
2265 *seen |= SEEN_NOTE;
2266
2267 break;
2268
2269 case NOTE_INSN_EPILOGUE_BEG:
2270 if (!DECL_IGNORED_P (current_function_decl))
2271 (*debug_hooks->begin_epilogue) (last_linenum, last_filename);
2272 targetm.asm_out.function_begin_epilogue (file);
2273 break;
2274
2275 case NOTE_INSN_CFI:
2276 dwarf2out_emit_cfi (NOTE_CFI (insn));
2277 break;
2278
2279 case NOTE_INSN_CFI_LABEL:
2280 ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LCFI",
2281 NOTE_LABEL_NUMBER (insn));
2282 break;
2283
2284 case NOTE_INSN_FUNCTION_BEG:
2285 if (need_profile_function)
2286 {
2287 profile_function (file: asm_out_file);
2288 need_profile_function = false;
2289 }
2290
2291 app_disable ();
2292 if (!DECL_IGNORED_P (current_function_decl))
2293 debug_hooks->end_prologue (last_linenum, last_filename);
2294
2295 if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE)
2296 {
2297 *seen |= SEEN_EMITTED;
2298 force_source_line = true;
2299 }
2300 else
2301 *seen |= SEEN_NOTE;
2302
2303 break;
2304
2305 case NOTE_INSN_BLOCK_BEG:
2306 if (debug_info_level >= DINFO_LEVEL_NORMAL
2307 || dwarf_debuginfo_p ()
2308 || write_symbols == VMS_DEBUG)
2309 {
2310 int n = BLOCK_NUMBER (NOTE_BLOCK (insn));
2311
2312 app_disable ();
2313 ++block_depth;
2314 high_block_linenum = last_linenum;
2315
2316 /* Output debugging info about the symbol-block beginning. */
2317 if (!DECL_IGNORED_P (current_function_decl))
2318 debug_hooks->begin_block (last_linenum, n, NOTE_BLOCK (insn));
2319
2320 /* Mark this block as output. */
2321 TREE_ASM_WRITTEN (NOTE_BLOCK (insn)) = 1;
2322 BLOCK_IN_COLD_SECTION_P (NOTE_BLOCK (insn)) = in_cold_section_p;
2323 }
2324 break;
2325
2326 case NOTE_INSN_BLOCK_END:
2327 maybe_output_next_view (seen);
2328
2329 if (debug_info_level >= DINFO_LEVEL_NORMAL
2330 || dwarf_debuginfo_p ()
2331 || write_symbols == VMS_DEBUG)
2332 {
2333 int n = BLOCK_NUMBER (NOTE_BLOCK (insn));
2334
2335 app_disable ();
2336
2337 /* End of a symbol-block. */
2338 --block_depth;
2339 gcc_assert (block_depth >= 0);
2340
2341 if (!DECL_IGNORED_P (current_function_decl))
2342 debug_hooks->end_block (high_block_linenum, n);
2343 gcc_assert (BLOCK_IN_COLD_SECTION_P (NOTE_BLOCK (insn))
2344 == in_cold_section_p);
2345 }
2346 break;
2347
2348 case NOTE_INSN_DELETED_LABEL:
2349 /* Emit the label. We may have deleted the CODE_LABEL because
2350 the label could be proved to be unreachable, though still
2351 referenced (in the form of having its address taken. */
2352 ASM_OUTPUT_DEBUG_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
2353 break;
2354
2355 case NOTE_INSN_DELETED_DEBUG_LABEL:
2356 /* Similarly, but need to use different namespace for it. */
2357 if (CODE_LABEL_NUMBER (insn) != -1)
2358 ASM_OUTPUT_DEBUG_LABEL (file, "LDL", CODE_LABEL_NUMBER (insn));
2359 break;
2360
2361 case NOTE_INSN_VAR_LOCATION:
2362 if (!DECL_IGNORED_P (current_function_decl))
2363 {
2364 debug_hooks->var_location (insn);
2365 set_next_view_needed (seen);
2366 }
2367 break;
2368
2369 case NOTE_INSN_BEGIN_STMT:
2370 gcc_checking_assert (cfun->debug_nonbind_markers);
2371 if (!DECL_IGNORED_P (current_function_decl)
2372 && notice_source_line (insn, NULL))
2373 {
2374 output_source_line:
2375 (*debug_hooks->source_line) (last_linenum, last_columnnum,
2376 last_filename, last_discriminator,
2377 true);
2378 clear_next_view_needed (seen);
2379 }
2380 break;
2381
2382 case NOTE_INSN_INLINE_ENTRY:
2383 gcc_checking_assert (cfun->debug_nonbind_markers);
2384 if (!DECL_IGNORED_P (current_function_decl)
2385 && notice_source_line (insn, NULL))
2386 {
2387 (*debug_hooks->inline_entry) (LOCATION_BLOCK
2388 (NOTE_MARKER_LOCATION (insn)));
2389 goto output_source_line;
2390 }
2391 break;
2392
2393 default:
2394 gcc_unreachable ();
2395 break;
2396 }
2397 break;
2398
2399 case BARRIER:
2400 break;
2401
2402 case CODE_LABEL:
2403 /* The target port might emit labels in the output function for
2404 some insn, e.g. sh.cc output_branchy_insn. */
2405 if (CODE_LABEL_NUMBER (insn) <= max_labelno)
2406 {
2407 align_flags alignment = LABEL_TO_ALIGNMENT (insn);
2408 if (alignment.levels[0].log && NEXT_INSN (insn))
2409 {
2410#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
2411 /* Output both primary and secondary alignment. */
2412 ASM_OUTPUT_MAX_SKIP_ALIGN (file, alignment.levels[0].log,
2413 alignment.levels[0].maxskip);
2414 ASM_OUTPUT_MAX_SKIP_ALIGN (file, alignment.levels[1].log,
2415 alignment.levels[1].maxskip);
2416#else
2417#ifdef ASM_OUTPUT_ALIGN_WITH_NOP
2418 ASM_OUTPUT_ALIGN_WITH_NOP (file, alignment.levels[0].log);
2419#else
2420 ASM_OUTPUT_ALIGN (file, alignment.levels[0].log);
2421#endif
2422#endif
2423 }
2424 }
2425 CC_STATUS_INIT;
2426
2427 if (!DECL_IGNORED_P (current_function_decl) && LABEL_NAME (insn))
2428 debug_hooks->label (as_a <rtx_code_label *> (p: insn));
2429
2430 app_disable ();
2431
2432 /* If this label is followed by a jump-table, make sure we put
2433 the label in the read-only section. Also possibly write the
2434 label and jump table together. */
2435 table = jump_table_for_label (label: as_a <rtx_code_label *> (p: insn));
2436 if (table)
2437 {
2438#if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)
2439 /* In this case, the case vector is being moved by the
2440 target, so don't output the label at all. Leave that
2441 to the back end macros. */
2442#else
2443 if (! JUMP_TABLES_IN_TEXT_SECTION)
2444 {
2445 int log_align;
2446
2447 switch_to_section (targetm.asm_out.function_rodata_section
2448 (current_function_decl,
2449 jumptable_relocatable ()));
2450
2451#ifdef ADDR_VEC_ALIGN
2452 log_align = ADDR_VEC_ALIGN (table);
2453#else
2454 log_align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
2455#endif
2456 ASM_OUTPUT_ALIGN (file, log_align);
2457 }
2458 else
2459 switch_to_section (current_function_section ());
2460
2461#ifdef ASM_OUTPUT_CASE_LABEL
2462 ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn), table);
2463#else
2464 targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (insn));
2465#endif
2466#endif
2467 break;
2468 }
2469 if (LABEL_ALT_ENTRY_P (insn))
2470 output_alternate_entry_point (file, insn);
2471 else
2472 targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (insn));
2473 break;
2474
2475 default:
2476 {
2477 rtx body = PATTERN (insn);
2478 int insn_code_number;
2479 const char *templ;
2480 bool is_stmt, *is_stmt_p;
2481
2482 if (MAY_HAVE_DEBUG_MARKER_INSNS && cfun->debug_nonbind_markers)
2483 {
2484 is_stmt = false;
2485 is_stmt_p = NULL;
2486 }
2487 else
2488 is_stmt_p = &is_stmt;
2489
2490 /* Reset this early so it is correct for ASM statements. */
2491 current_insn_predicate = NULL_RTX;
2492
2493 /* An INSN, JUMP_INSN or CALL_INSN.
2494 First check for special kinds that recog doesn't recognize. */
2495
2496 if (GET_CODE (body) == USE /* These are just declarations. */
2497 || GET_CODE (body) == CLOBBER)
2498 break;
2499
2500 /* Detect insns that are really jump-tables
2501 and output them as such. */
2502
2503 if (JUMP_TABLE_DATA_P (insn))
2504 {
2505#if !(defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC))
2506 int vlen, idx;
2507#endif
2508
2509 if (! JUMP_TABLES_IN_TEXT_SECTION)
2510 switch_to_section (targetm.asm_out.function_rodata_section
2511 (current_function_decl,
2512 jumptable_relocatable ()));
2513 else
2514 switch_to_section (current_function_section ());
2515
2516 app_disable ();
2517
2518#if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)
2519 if (GET_CODE (body) == ADDR_VEC)
2520 {
2521#ifdef ASM_OUTPUT_ADDR_VEC
2522 ASM_OUTPUT_ADDR_VEC (PREV_INSN (insn), body);
2523#else
2524 gcc_unreachable ();
2525#endif
2526 }
2527 else
2528 {
2529#ifdef ASM_OUTPUT_ADDR_DIFF_VEC
2530 ASM_OUTPUT_ADDR_DIFF_VEC (PREV_INSN (insn), body);
2531#else
2532 gcc_unreachable ();
2533#endif
2534 }
2535#else
2536 vlen = XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC);
2537 for (idx = 0; idx < vlen; idx++)
2538 {
2539 if (GET_CODE (body) == ADDR_VEC)
2540 {
2541#ifdef ASM_OUTPUT_ADDR_VEC_ELT
2542 ASM_OUTPUT_ADDR_VEC_ELT
2543 (file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0)));
2544#else
2545 gcc_unreachable ();
2546#endif
2547 }
2548 else
2549 {
2550#ifdef ASM_OUTPUT_ADDR_DIFF_ELT
2551 ASM_OUTPUT_ADDR_DIFF_ELT
2552 (file,
2553 body,
2554 CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)),
2555 CODE_LABEL_NUMBER (XEXP (XEXP (body, 0), 0)));
2556#else
2557 gcc_unreachable ();
2558#endif
2559 }
2560 }
2561#ifdef ASM_OUTPUT_CASE_END
2562 ASM_OUTPUT_CASE_END (file,
2563 CODE_LABEL_NUMBER (PREV_INSN (insn)),
2564 insn);
2565#endif
2566#endif
2567
2568 switch_to_section (current_function_section ());
2569
2570 if (debug_variable_location_views
2571 && !DECL_IGNORED_P (current_function_decl))
2572 debug_hooks->var_location (insn);
2573
2574 break;
2575 }
2576 /* Output this line note if it is the first or the last line
2577 note in a row. */
2578 if (!DECL_IGNORED_P (current_function_decl)
2579 && notice_source_line (insn, is_stmt_p))
2580 {
2581 if (flag_verbose_asm)
2582 asm_show_source (filename: last_filename, linenum: last_linenum);
2583 (*debug_hooks->source_line) (last_linenum, last_columnnum,
2584 last_filename, last_discriminator,
2585 is_stmt);
2586 clear_next_view_needed (seen);
2587 }
2588 else
2589 maybe_output_next_view (seen);
2590
2591 gcc_checking_assert (!DEBUG_INSN_P (insn));
2592
2593 if (GET_CODE (body) == PARALLEL
2594 && GET_CODE (XVECEXP (body, 0, 0)) == ASM_INPUT)
2595 body = XVECEXP (body, 0, 0);
2596
2597 if (GET_CODE (body) == ASM_INPUT)
2598 {
2599 const char *string = XSTR (body, 0);
2600
2601 /* There's no telling what that did to the condition codes. */
2602 CC_STATUS_INIT;
2603
2604 if (string[0])
2605 {
2606 expanded_location loc;
2607
2608 app_enable ();
2609 loc = expand_location (ASM_INPUT_SOURCE_LOCATION (body));
2610 if (*loc.file && loc.line)
2611 fprintf (stream: asm_out_file, format: "%s %i \"%s\" 1\n",
2612 ASM_COMMENT_START, loc.line, loc.file);
2613 fprintf (stream: asm_out_file, format: "\t%s\n", string);
2614#if HAVE_AS_LINE_ZERO
2615 if (*loc.file && loc.line)
2616 fprintf (stream: asm_out_file, format: "%s 0 \"\" 2\n", ASM_COMMENT_START);
2617#endif
2618 }
2619 break;
2620 }
2621
2622 /* Detect `asm' construct with operands. */
2623 if (asm_noperands (body) >= 0)
2624 {
2625 unsigned int noperands = asm_noperands (body);
2626 rtx *ops = XALLOCAVEC (rtx, noperands);
2627 const char *string;
2628 location_t loc;
2629 expanded_location expanded;
2630
2631 /* There's no telling what that did to the condition codes. */
2632 CC_STATUS_INIT;
2633
2634 /* Get out the operand values. */
2635 string = decode_asm_operands (body, ops, NULL, NULL, NULL, &loc);
2636 /* Inhibit dying on what would otherwise be compiler bugs. */
2637 insn_noperands = noperands;
2638 this_is_asm_operands = insn;
2639 expanded = expand_location (loc);
2640
2641#ifdef FINAL_PRESCAN_INSN
2642 FINAL_PRESCAN_INSN (insn, ops, insn_noperands);
2643#endif
2644
2645 /* Output the insn using them. */
2646 if (string[0])
2647 {
2648 app_enable ();
2649 if (expanded.file && expanded.line)
2650 fprintf (stream: asm_out_file, format: "%s %i \"%s\" 1\n",
2651 ASM_COMMENT_START, expanded.line, expanded.file);
2652 output_asm_insn (string, ops);
2653#if HAVE_AS_LINE_ZERO
2654 if (expanded.file && expanded.line)
2655 fprintf (stream: asm_out_file, format: "%s 0 \"\" 2\n", ASM_COMMENT_START);
2656#endif
2657 }
2658
2659 if (targetm.asm_out.final_postscan_insn)
2660 targetm.asm_out.final_postscan_insn (file, insn, ops,
2661 insn_noperands);
2662
2663 this_is_asm_operands = 0;
2664 break;
2665 }
2666
2667 app_disable ();
2668
2669 if (rtx_sequence *seq = dyn_cast <rtx_sequence *> (p: body))
2670 {
2671 /* A delayed-branch sequence */
2672 int i;
2673
2674 final_sequence = seq;
2675
2676 /* The first insn in this SEQUENCE might be a JUMP_INSN that will
2677 force the restoration of a comparison that was previously
2678 thought unnecessary. If that happens, cancel this sequence
2679 and cause that insn to be restored. */
2680
2681 next = final_scan_insn (seq->insn (index: 0), file, 0, 1, seen);
2682 if (next != seq->insn (index: 1))
2683 {
2684 final_sequence = 0;
2685 return next;
2686 }
2687
2688 for (i = 1; i < seq->len (); i++)
2689 {
2690 rtx_insn *insn = seq->insn (index: i);
2691 rtx_insn *next = NEXT_INSN (insn);
2692 /* We loop in case any instruction in a delay slot gets
2693 split. */
2694 do
2695 insn = final_scan_insn (insn, file, 0, 1, seen);
2696 while (insn != next);
2697 }
2698#ifdef DBR_OUTPUT_SEQEND
2699 DBR_OUTPUT_SEQEND (file);
2700#endif
2701 final_sequence = 0;
2702
2703 /* If the insn requiring the delay slot was a CALL_INSN, the
2704 insns in the delay slot are actually executed before the
2705 called function. Hence we don't preserve any CC-setting
2706 actions in these insns and the CC must be marked as being
2707 clobbered by the function. */
2708 if (CALL_P (seq->insn (0)))
2709 {
2710 CC_STATUS_INIT;
2711 }
2712 break;
2713 }
2714
2715 /* We have a real machine instruction as rtl. */
2716
2717 body = PATTERN (insn);
2718
2719 /* Do machine-specific peephole optimizations if desired. */
2720
2721 if (HAVE_peephole && optimize_p && !flag_no_peephole && !nopeepholes)
2722 {
2723 rtx_insn *next = peephole (insn);
2724 /* When peepholing, if there were notes within the peephole,
2725 emit them before the peephole. */
2726 if (next != 0 && next != NEXT_INSN (insn))
2727 {
2728 rtx_insn *note, *prev = PREV_INSN (insn);
2729
2730 for (note = NEXT_INSN (insn); note != next;
2731 note = NEXT_INSN (insn: note))
2732 final_scan_insn (note, file, optimize_p, nopeepholes, seen);
2733
2734 /* Put the notes in the proper position for a later
2735 rescan. For example, the SH target can do this
2736 when generating a far jump in a delayed branch
2737 sequence. */
2738 note = NEXT_INSN (insn);
2739 SET_PREV_INSN (note) = prev;
2740 SET_NEXT_INSN (prev) = note;
2741 SET_NEXT_INSN (PREV_INSN (insn: next)) = insn;
2742 SET_PREV_INSN (insn) = PREV_INSN (insn: next);
2743 SET_NEXT_INSN (insn) = next;
2744 SET_PREV_INSN (next) = insn;
2745 }
2746
2747 /* PEEPHOLE might have changed this. */
2748 body = PATTERN (insn);
2749 }
2750
2751 /* Try to recognize the instruction.
2752 If successful, verify that the operands satisfy the
2753 constraints for the instruction. Crash if they don't,
2754 since `reload' should have changed them so that they do. */
2755
2756 insn_code_number = recog_memoized (insn);
2757 cleanup_subreg_operands (insn);
2758
2759 /* Dump the insn in the assembly for debugging (-dAP).
2760 If the final dump is requested as slim RTL, dump slim
2761 RTL to the assembly file also. */
2762 if (flag_dump_rtl_in_asm)
2763 {
2764 print_rtx_head = ASM_COMMENT_START;
2765 if (! (dump_flags & TDF_SLIM))
2766 print_rtl_single (asm_out_file, insn);
2767 else
2768 dump_insn_slim (asm_out_file, insn);
2769 print_rtx_head = "";
2770 }
2771
2772 if (! constrain_operands_cached (insn, 1))
2773 fatal_insn_not_found (insn);
2774
2775 /* Some target machines need to prescan each insn before
2776 it is output. */
2777
2778#ifdef FINAL_PRESCAN_INSN
2779 FINAL_PRESCAN_INSN (insn, recog_data.operand, recog_data.n_operands);
2780#endif
2781
2782 if (targetm.have_conditional_execution ()
2783 && GET_CODE (PATTERN (insn)) == COND_EXEC)
2784 current_insn_predicate = COND_EXEC_TEST (PATTERN (insn));
2785
2786 current_output_insn = debug_insn = insn;
2787
2788 /* Find the proper template for this insn. */
2789 templ = get_insn_template (code: insn_code_number, insn);
2790
2791 /* If the C code returns 0, it means that it is a jump insn
2792 which follows a deleted test insn, and that test insn
2793 needs to be reinserted. */
2794 if (templ == 0)
2795 {
2796 rtx_insn *prev;
2797
2798 gcc_assert (prev_nonnote_insn (insn) == last_ignored_compare);
2799
2800 /* We have already processed the notes between the setter and
2801 the user. Make sure we don't process them again, this is
2802 particularly important if one of the notes is a block
2803 scope note or an EH note. */
2804 for (prev = insn;
2805 prev != last_ignored_compare;
2806 prev = PREV_INSN (insn: prev))
2807 {
2808 if (NOTE_P (prev))
2809 delete_insn (prev); /* Use delete_note. */
2810 }
2811
2812 return prev;
2813 }
2814
2815 /* If the template is the string "#", it means that this insn must
2816 be split. */
2817 if (templ[0] == '#' && templ[1] == '\0')
2818 {
2819 rtx_insn *new_rtx = try_split (body, insn, 0);
2820
2821 /* If we didn't split the insn, go away. */
2822 if (new_rtx == insn && PATTERN (insn: new_rtx) == body)
2823 fatal_insn ("could not split insn", insn);
2824
2825 /* If we have a length attribute, this instruction should have
2826 been split in shorten_branches, to ensure that we would have
2827 valid length info for the splitees. */
2828 gcc_assert (!HAVE_ATTR_length);
2829
2830 return new_rtx;
2831 }
2832
2833 /* ??? This will put the directives in the wrong place if
2834 get_insn_template outputs assembly directly. However calling it
2835 before get_insn_template breaks if the insns is split. */
2836 if (targetm.asm_out.unwind_emit_before_insn
2837 && targetm.asm_out.unwind_emit)
2838 targetm.asm_out.unwind_emit (asm_out_file, insn);
2839
2840 rtx_call_insn *call_insn = dyn_cast <rtx_call_insn *> (p: insn);
2841 if (call_insn != NULL)
2842 {
2843 rtx x = call_from_call_insn (insn: call_insn);
2844 x = XEXP (x, 0);
2845 if (x && MEM_P (x) && GET_CODE (XEXP (x, 0)) == SYMBOL_REF)
2846 {
2847 tree t;
2848 x = XEXP (x, 0);
2849 t = SYMBOL_REF_DECL (x);
2850 if (t)
2851 assemble_external (t);
2852 }
2853 }
2854
2855 /* Output assembler code from the template. */
2856 output_asm_insn (templ, recog_data.operand);
2857
2858 /* Some target machines need to postscan each insn after
2859 it is output. */
2860 if (targetm.asm_out.final_postscan_insn)
2861 targetm.asm_out.final_postscan_insn (file, insn, recog_data.operand,
2862 recog_data.n_operands);
2863
2864 if (!targetm.asm_out.unwind_emit_before_insn
2865 && targetm.asm_out.unwind_emit)
2866 targetm.asm_out.unwind_emit (asm_out_file, insn);
2867
2868 /* Let the debug info back-end know about this call. We do this only
2869 after the instruction has been emitted because labels that may be
2870 created to reference the call instruction must appear after it. */
2871 if ((debug_variable_location_views || call_insn != NULL)
2872 && !DECL_IGNORED_P (current_function_decl))
2873 debug_hooks->var_location (insn);
2874
2875 current_output_insn = debug_insn = 0;
2876 }
2877 }
2878 return NEXT_INSN (insn);
2879}
2880
2881/* This is a wrapper around final_scan_insn_1 that allows ports to
2882 call it recursively without a known value for SEEN. The value is
2883 saved at the outermost call, and recovered for recursive calls.
2884 Recursive calls MUST pass NULL, or the same pointer if they can
2885 otherwise get to it. */
2886
2887rtx_insn *
2888final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p,
2889 int nopeepholes, int *seen)
2890{
2891 static int *enclosing_seen;
2892 static int recursion_counter;
2893
2894 gcc_assert (seen || recursion_counter);
2895 gcc_assert (!recursion_counter || !seen || seen == enclosing_seen);
2896
2897 if (!recursion_counter++)
2898 enclosing_seen = seen;
2899 else if (!seen)
2900 seen = enclosing_seen;
2901
2902 rtx_insn *ret = final_scan_insn_1 (insn, file, optimize_p, nopeepholes, seen);
2903
2904 if (!--recursion_counter)
2905 enclosing_seen = NULL;
2906
2907 return ret;
2908}
2909
2910
2911
2912/* Map DECLs to instance discriminators. This is allocated and
2913 defined in ada/gcc-interfaces/trans.cc, when compiling with -gnateS.
2914 Mappings from this table are saved and restored for LTO, so
2915 link-time compilation will have this map set, at least in
2916 partitions containing at least one DECL with an associated instance
2917 discriminator. */
2918
2919decl_to_instance_map_t *decl_to_instance_map;
2920
2921/* Return the instance number assigned to DECL. */
2922
2923static inline int
2924map_decl_to_instance (const_tree decl)
2925{
2926 int *inst;
2927
2928 if (!decl_to_instance_map || !decl || !DECL_P (decl))
2929 return 0;
2930
2931 inst = decl_to_instance_map->get (k: decl);
2932
2933 if (!inst)
2934 return 0;
2935
2936 return *inst;
2937}
2938
2939/* Set DISCRIMINATOR to the appropriate value, possibly derived from LOC. */
2940
2941static inline int
2942compute_discriminator (location_t loc)
2943{
2944 int discriminator;
2945
2946 if (!decl_to_instance_map)
2947 discriminator = get_discriminator_from_loc (loc);
2948 else
2949 {
2950 tree block = LOCATION_BLOCK (loc);
2951
2952 while (block && TREE_CODE (block) == BLOCK
2953 && !inlined_function_outer_scope_p (block))
2954 block = BLOCK_SUPERCONTEXT (block);
2955
2956 tree decl;
2957
2958 if (!block)
2959 decl = current_function_decl;
2960 else if (DECL_P (block))
2961 decl = block;
2962 else
2963 decl = block_ultimate_origin (block);
2964
2965 discriminator = map_decl_to_instance (decl);
2966 }
2967
2968 return discriminator;
2969}
2970
2971/* Return discriminator of the statement that produced this insn. */
2972int
2973insn_discriminator (const rtx_insn *insn)
2974{
2975 return compute_discriminator (loc: INSN_LOCATION (insn));
2976}
2977
2978/* Return whether a source line note needs to be emitted before INSN.
2979 Sets IS_STMT to TRUE if the line should be marked as a possible
2980 breakpoint location. */
2981
2982static bool
2983notice_source_line (rtx_insn *insn, bool *is_stmt)
2984{
2985 const char *filename;
2986 int linenum, columnnum;
2987 int discriminator;
2988
2989 if (NOTE_MARKER_P (insn))
2990 {
2991 location_t loc = NOTE_MARKER_LOCATION (insn);
2992 expanded_location xloc = expand_location (loc);
2993 if (xloc.line == 0
2994 && (LOCATION_LOCUS (loc) == UNKNOWN_LOCATION
2995 || LOCATION_LOCUS (loc) == BUILTINS_LOCATION))
2996 return false;
2997
2998 filename = xloc.file;
2999 linenum = xloc.line;
3000 columnnum = xloc.column;
3001 discriminator = compute_discriminator (loc);
3002 force_source_line = true;
3003 }
3004 else if (override_filename)
3005 {
3006 filename = override_filename;
3007 linenum = override_linenum;
3008 columnnum = override_columnnum;
3009 discriminator = override_discriminator;
3010 }
3011 else if (INSN_HAS_LOCATION (insn))
3012 {
3013 expanded_location xloc = insn_location (insn);
3014 filename = xloc.file;
3015 linenum = xloc.line;
3016 columnnum = xloc.column;
3017 discriminator = insn_discriminator (insn);
3018 }
3019 else
3020 {
3021 filename = NULL;
3022 linenum = 0;
3023 columnnum = 0;
3024 discriminator = 0;
3025 }
3026
3027 if (filename == NULL)
3028 return false;
3029
3030 if (force_source_line
3031 || filename != last_filename
3032 || last_linenum != linenum
3033 || (debug_column_info && last_columnnum != columnnum))
3034 {
3035 force_source_line = false;
3036 last_filename = filename;
3037 last_linenum = linenum;
3038 last_columnnum = columnnum;
3039 last_discriminator = discriminator;
3040 if (is_stmt)
3041 *is_stmt = true;
3042 high_block_linenum = MAX (last_linenum, high_block_linenum);
3043 high_function_linenum = MAX (last_linenum, high_function_linenum);
3044 return true;
3045 }
3046
3047 if (SUPPORTS_DISCRIMINATOR && last_discriminator != discriminator)
3048 {
3049 /* If the discriminator changed, but the line number did not,
3050 output the line table entry with is_stmt false so the
3051 debugger does not treat this as a breakpoint location. */
3052 last_discriminator = discriminator;
3053 if (is_stmt)
3054 *is_stmt = false;
3055 return true;
3056 }
3057
3058 return false;
3059}
3060
3061/* For each operand in INSN, simplify (subreg (reg)) so that it refers
3062 directly to the desired hard register. */
3063
3064void
3065cleanup_subreg_operands (rtx_insn *insn)
3066{
3067 int i;
3068 bool changed = false;
3069 extract_insn_cached (insn);
3070 for (i = 0; i < recog_data.n_operands; i++)
3071 {
3072 /* The following test cannot use recog_data.operand when testing
3073 for a SUBREG: the underlying object might have been changed
3074 already if we are inside a match_operator expression that
3075 matches the else clause. Instead we test the underlying
3076 expression directly. */
3077 if (GET_CODE (*recog_data.operand_loc[i]) == SUBREG)
3078 {
3079 recog_data.operand[i] = alter_subreg (recog_data.operand_loc[i], true);
3080 changed = true;
3081 }
3082 else if (GET_CODE (recog_data.operand[i]) == PLUS
3083 || GET_CODE (recog_data.operand[i]) == MULT
3084 || MEM_P (recog_data.operand[i]))
3085 recog_data.operand[i] = walk_alter_subreg (recog_data.operand_loc[i], &changed);
3086 }
3087
3088 for (i = 0; i < recog_data.n_dups; i++)
3089 {
3090 if (GET_CODE (*recog_data.dup_loc[i]) == SUBREG)
3091 {
3092 *recog_data.dup_loc[i] = alter_subreg (recog_data.dup_loc[i], true);
3093 changed = true;
3094 }
3095 else if (GET_CODE (*recog_data.dup_loc[i]) == PLUS
3096 || GET_CODE (*recog_data.dup_loc[i]) == MULT
3097 || MEM_P (*recog_data.dup_loc[i]))
3098 *recog_data.dup_loc[i] = walk_alter_subreg (recog_data.dup_loc[i], &changed);
3099 }
3100 if (changed)
3101 df_insn_rescan (insn);
3102}
3103
3104/* If X is a SUBREG, try to replace it with a REG or a MEM, based on
3105 the thing it is a subreg of. Do it anyway if FINAL_P. */
3106
3107rtx
3108alter_subreg (rtx *xp, bool final_p)
3109{
3110 rtx x = *xp;
3111 rtx y = SUBREG_REG (x);
3112
3113 /* simplify_subreg does not remove subreg from volatile references.
3114 We are required to. */
3115 if (MEM_P (y))
3116 {
3117 poly_int64 offset = SUBREG_BYTE (x);
3118
3119 /* For paradoxical subregs on big-endian machines, SUBREG_BYTE
3120 contains 0 instead of the proper offset. See simplify_subreg. */
3121 if (paradoxical_subreg_p (x))
3122 offset = byte_lowpart_offset (GET_MODE (x), GET_MODE (y));
3123
3124 if (final_p)
3125 *xp = adjust_address (y, GET_MODE (x), offset);
3126 else
3127 *xp = adjust_address_nv (y, GET_MODE (x), offset);
3128 }
3129 else if (REG_P (y) && HARD_REGISTER_P (y))
3130 {
3131 rtx new_rtx = simplify_subreg (GET_MODE (x), op: y, GET_MODE (y),
3132 SUBREG_BYTE (x));
3133
3134 if (new_rtx != 0)
3135 *xp = new_rtx;
3136 else if (final_p && REG_P (y))
3137 {
3138 /* Simplify_subreg can't handle some REG cases, but we have to. */
3139 unsigned int regno;
3140 poly_int64 offset;
3141
3142 regno = subreg_regno (x);
3143 if (subreg_lowpart_p (x))
3144 offset = byte_lowpart_offset (GET_MODE (x), GET_MODE (y));
3145 else
3146 offset = SUBREG_BYTE (x);
3147 *xp = gen_rtx_REG_offset (y, GET_MODE (x), regno, offset);
3148 }
3149 }
3150
3151 return *xp;
3152}
3153
3154/* Do alter_subreg on all the SUBREGs contained in X. */
3155
3156static rtx
3157walk_alter_subreg (rtx *xp, bool *changed)
3158{
3159 rtx x = *xp;
3160 switch (GET_CODE (x))
3161 {
3162 case PLUS:
3163 case MULT:
3164 case AND:
3165 case ASHIFT:
3166 XEXP (x, 0) = walk_alter_subreg (xp: &XEXP (x, 0), changed);
3167 XEXP (x, 1) = walk_alter_subreg (xp: &XEXP (x, 1), changed);
3168 break;
3169
3170 case MEM:
3171 case ZERO_EXTEND:
3172 XEXP (x, 0) = walk_alter_subreg (xp: &XEXP (x, 0), changed);
3173 break;
3174
3175 case SUBREG:
3176 *changed = true;
3177 return alter_subreg (xp, final_p: true);
3178
3179 default:
3180 break;
3181 }
3182
3183 return *xp;
3184}
3185
3186/* Report inconsistency between the assembler template and the operands.
3187 In an `asm', it's the user's fault; otherwise, the compiler's fault. */
3188
3189void
3190output_operand_lossage (const char *cmsgid, ...)
3191{
3192 char *fmt_string;
3193 char *new_message;
3194 const char *pfx_str;
3195 va_list ap;
3196
3197 va_start (ap, cmsgid);
3198
3199 pfx_str = this_is_asm_operands ? _("invalid 'asm': ") : "output_operand: ";
3200 fmt_string = xasprintf ("%s%s", pfx_str, _(cmsgid));
3201 new_message = xvasprintf (fmt_string, ap);
3202
3203 if (this_is_asm_operands)
3204 error_for_asm (this_is_asm_operands, "%s", new_message);
3205 else
3206 internal_error ("%s", new_message);
3207
3208 free (ptr: fmt_string);
3209 free (ptr: new_message);
3210 va_end (ap);
3211}
3212
3213/* Output of assembler code from a template, and its subroutines. */
3214
3215/* Annotate the assembly with a comment describing the pattern and
3216 alternative used. */
3217
3218static void
3219output_asm_name (void)
3220{
3221 if (debug_insn)
3222 {
3223 fprintf (stream: asm_out_file, format: "\t%s %d\t",
3224 ASM_COMMENT_START, INSN_UID (insn: debug_insn));
3225
3226 fprintf (stream: asm_out_file, format: "[c=%d",
3227 insn_cost (debug_insn, optimize_insn_for_speed_p ()));
3228 if (HAVE_ATTR_length)
3229 fprintf (stream: asm_out_file, format: " l=%d",
3230 get_attr_length (insn: debug_insn));
3231 fprintf (stream: asm_out_file, format: "] ");
3232
3233 int num = INSN_CODE (debug_insn);
3234 fprintf (stream: asm_out_file, format: "%s", insn_data[num].name);
3235 if (insn_data[num].n_alternatives > 1)
3236 fprintf (stream: asm_out_file, format: "/%d", which_alternative);
3237
3238 /* Clear this so only the first assembler insn
3239 of any rtl insn will get the special comment for -dp. */
3240 debug_insn = 0;
3241 }
3242}
3243
3244/* If OP is a REG or MEM and we can find a MEM_EXPR corresponding to it
3245 or its address, return that expr . Set *PADDRESSP to 1 if the expr
3246 corresponds to the address of the object and 0 if to the object. */
3247
3248static tree
3249get_mem_expr_from_op (rtx op, int *paddressp)
3250{
3251 tree expr;
3252 int inner_addressp;
3253
3254 *paddressp = 0;
3255
3256 if (REG_P (op))
3257 return REG_EXPR (op);
3258 else if (!MEM_P (op))
3259 return 0;
3260
3261 if (MEM_EXPR (op) != 0)
3262 return MEM_EXPR (op);
3263
3264 /* Otherwise we have an address, so indicate it and look at the address. */
3265 *paddressp = 1;
3266 op = XEXP (op, 0);
3267
3268 /* First check if we have a decl for the address, then look at the right side
3269 if it is a PLUS. Otherwise, strip off arithmetic and keep looking.
3270 But don't allow the address to itself be indirect. */
3271 if ((expr = get_mem_expr_from_op (op, paddressp: &inner_addressp)) && ! inner_addressp)
3272 return expr;
3273 else if (GET_CODE (op) == PLUS
3274 && (expr = get_mem_expr_from_op (XEXP (op, 1), paddressp: &inner_addressp)))
3275 return expr;
3276
3277 while (UNARY_P (op)
3278 || GET_RTX_CLASS (GET_CODE (op)) == RTX_BIN_ARITH)
3279 op = XEXP (op, 0);
3280
3281 expr = get_mem_expr_from_op (op, paddressp: &inner_addressp);
3282 return inner_addressp ? 0 : expr;
3283}
3284
3285/* Output operand names for assembler instructions. OPERANDS is the
3286 operand vector, OPORDER is the order to write the operands, and NOPS
3287 is the number of operands to write. */
3288
3289static void
3290output_asm_operand_names (rtx *operands, int *oporder, int nops)
3291{
3292 int wrote = 0;
3293 int i;
3294
3295 for (i = 0; i < nops; i++)
3296 {
3297 int addressp;
3298 int opnum = oporder[i];
3299 /* Skip invalid ops. */
3300 if (opnum == MAX_RECOG_OPERANDS)
3301 continue;
3302 rtx op = operands[opnum];
3303 tree expr = get_mem_expr_from_op (op, paddressp: &addressp);
3304
3305 fprintf (stream: asm_out_file, format: "%c%s",
3306 wrote ? ',' : '\t', wrote ? "" : ASM_COMMENT_START);
3307 wrote = 1;
3308 if (expr)
3309 {
3310 fprintf (stream: asm_out_file, format: "%s",
3311 addressp ? "*" : "");
3312 print_mem_expr (asm_out_file, expr);
3313 wrote = 1;
3314 }
3315 else if (REG_P (op) && ORIGINAL_REGNO (op)
3316 && ORIGINAL_REGNO (op) != REGNO (op))
3317 fprintf (stream: asm_out_file, format: " tmp%i", ORIGINAL_REGNO (op));
3318 }
3319}
3320
3321#ifdef ASSEMBLER_DIALECT
3322/* Helper function to parse assembler dialects in the asm string.
3323 This is called from output_asm_insn and asm_fprintf. */
3324static const char *
3325do_assembler_dialects (const char *p, int *dialect)
3326{
3327 char c = *(p - 1);
3328
3329 switch (c)
3330 {
3331 case '{':
3332 {
3333 int i;
3334
3335 if (*dialect)
3336 output_operand_lossage (cmsgid: "nested assembly dialect alternatives");
3337 else
3338 *dialect = 1;
3339
3340 /* If we want the first dialect, do nothing. Otherwise, skip
3341 DIALECT_NUMBER of strings ending with '|'. */
3342 for (i = 0; i < dialect_number; i++)
3343 {
3344 while (*p && *p != '}')
3345 {
3346 if (*p == '|')
3347 {
3348 p++;
3349 break;
3350 }
3351
3352 /* Skip over any character after a percent sign. */
3353 if (*p == '%')
3354 p++;
3355 if (*p)
3356 p++;
3357 }
3358
3359 if (*p == '}')
3360 break;
3361 }
3362
3363 if (*p == '\0')
3364 output_operand_lossage (cmsgid: "unterminated assembly dialect alternative");
3365 }
3366 break;
3367
3368 case '|':
3369 if (*dialect)
3370 {
3371 /* Skip to close brace. */
3372 do
3373 {
3374 if (*p == '\0')
3375 {
3376 output_operand_lossage (cmsgid: "unterminated assembly dialect alternative");
3377 break;
3378 }
3379
3380 /* Skip over any character after a percent sign. */
3381 if (*p == '%' && p[1])
3382 {
3383 p += 2;
3384 continue;
3385 }
3386
3387 if (*p++ == '}')
3388 break;
3389 }
3390 while (1);
3391
3392 *dialect = 0;
3393 }
3394 else
3395 putc (c: c, stream: asm_out_file);
3396 break;
3397
3398 case '}':
3399 if (! *dialect)
3400 putc (c: c, stream: asm_out_file);
3401 *dialect = 0;
3402 break;
3403 default:
3404 gcc_unreachable ();
3405 }
3406
3407 return p;
3408}
3409#endif
3410
3411/* Output text from TEMPLATE to the assembler output file,
3412 obeying %-directions to substitute operands taken from
3413 the vector OPERANDS.
3414
3415 %N (for N a digit) means print operand N in usual manner.
3416 %lN means require operand N to be a CODE_LABEL or LABEL_REF
3417 and print the label name with no punctuation.
3418 %cN means require operand N to be a constant
3419 and print the constant expression with no punctuation.
3420 %aN means expect operand N to be a memory address
3421 (not a memory reference!) and print a reference
3422 to that address.
3423 %nN means expect operand N to be a constant
3424 and print a constant expression for minus the value
3425 of the operand, with no other punctuation. */
3426
3427void
3428output_asm_insn (const char *templ, rtx *operands)
3429{
3430 const char *p;
3431 int c;
3432#ifdef ASSEMBLER_DIALECT
3433 int dialect = 0;
3434#endif
3435 int oporder[MAX_RECOG_OPERANDS+1];
3436 char opoutput[MAX_RECOG_OPERANDS+1];
3437 int ops = 0;
3438
3439 /* An insn may return a null string template
3440 in a case where no assembler code is needed. */
3441 if (*templ == 0)
3442 return;
3443
3444 memset (s: opoutput, c: 0, n: sizeof opoutput);
3445 p = templ;
3446 putc (c: '\t', stream: asm_out_file);
3447
3448#ifdef ASM_OUTPUT_OPCODE
3449 ASM_OUTPUT_OPCODE (asm_out_file, p);
3450#endif
3451
3452 while ((c = *p++))
3453 switch (c)
3454 {
3455 case '\n':
3456 if (flag_verbose_asm)
3457 output_asm_operand_names (operands, oporder, nops: ops);
3458 if (flag_print_asm_name)
3459 output_asm_name ();
3460
3461 ops = 0;
3462 memset (s: opoutput, c: 0, n: sizeof opoutput);
3463
3464 putc (c: c, stream: asm_out_file);
3465#ifdef ASM_OUTPUT_OPCODE
3466 while ((c = *p) == '\t')
3467 {
3468 putc (c: c, stream: asm_out_file);
3469 p++;
3470 }
3471 ASM_OUTPUT_OPCODE (asm_out_file, p);
3472#endif
3473 break;
3474
3475#ifdef ASSEMBLER_DIALECT
3476 case '{':
3477 case '}':
3478 case '|':
3479 p = do_assembler_dialects (p, dialect: &dialect);
3480 break;
3481#endif
3482
3483 case '%':
3484 /* %% outputs a single %. %{, %} and %| print {, } and | respectively
3485 if ASSEMBLER_DIALECT defined and these characters have a special
3486 meaning as dialect delimiters.*/
3487 if (*p == '%'
3488#ifdef ASSEMBLER_DIALECT
3489 || *p == '{' || *p == '}' || *p == '|'
3490#endif
3491 )
3492 {
3493 putc (c: *p, stream: asm_out_file);
3494 p++;
3495 }
3496 /* %= outputs a number which is unique to each insn in the entire
3497 compilation. This is useful for making local labels that are
3498 referred to more than once in a given insn. */
3499 else if (*p == '=')
3500 {
3501 p++;
3502 fprintf (stream: asm_out_file, format: "%d", insn_counter);
3503 }
3504 /* % followed by a letter and some digits
3505 outputs an operand in a special way depending on the letter.
3506 Letters `acln' are implemented directly.
3507 Other letters are passed to `output_operand' so that
3508 the TARGET_PRINT_OPERAND hook can define them. */
3509 else if (ISALPHA (*p))
3510 {
3511 int letter = *p++;
3512 unsigned long opnum;
3513 char *endptr;
3514 int letter2 = 0;
3515
3516 if (letter == 'c' && *p == 'c')
3517 letter2 = *p++;
3518 opnum = strtoul (nptr: p, endptr: &endptr, base: 10);
3519
3520 if (endptr == p)
3521 output_operand_lossage (cmsgid: "operand number missing "
3522 "after %%-letter");
3523 else if (this_is_asm_operands && opnum >= insn_noperands)
3524 {
3525 /* Force the opnum in bounds to a bogus location. */
3526 opnum = MAX_RECOG_OPERANDS;
3527 output_operand_lossage (cmsgid: "operand number out of range");
3528 }
3529 else if (letter == 'l')
3530 output_asm_label (operands[opnum]);
3531 else if (letter == 'a')
3532 output_address (VOIDmode, operands[opnum]);
3533 else if (letter == 'c')
3534 {
3535 if (letter2 == 'c' || CONSTANT_ADDRESS_P (operands[opnum]))
3536 output_addr_const (asm_out_file, operands[opnum]);
3537 else
3538 output_operand (operands[opnum], 'c');
3539 }
3540 else if (letter == 'n')
3541 {
3542 if (CONST_INT_P (operands[opnum]))
3543 fprintf (stream: asm_out_file, HOST_WIDE_INT_PRINT_DEC,
3544 - INTVAL (operands[opnum]));
3545 else
3546 {
3547 putc (c: '-', stream: asm_out_file);
3548 output_addr_const (asm_out_file, operands[opnum]);
3549 }
3550 }
3551 else
3552 output_operand (operands[opnum], letter);
3553
3554 if (!opoutput[opnum])
3555 oporder[ops++] = opnum;
3556 opoutput[opnum] = 1;
3557
3558 p = endptr;
3559 c = *p;
3560 }
3561 /* % followed by a digit outputs an operand the default way. */
3562 else if (ISDIGIT (*p))
3563 {
3564 unsigned long opnum;
3565 char *endptr;
3566
3567 opnum = strtoul (nptr: p, endptr: &endptr, base: 10);
3568 if (this_is_asm_operands && opnum >= insn_noperands)
3569 {
3570 /* Force the opnum in bounds to a bogus location. */
3571 opnum = MAX_RECOG_OPERANDS;
3572 output_operand_lossage (cmsgid: "operand number out of range");
3573 }
3574 else
3575 output_operand (operands[opnum], 0);
3576
3577 if (!opoutput[opnum])
3578 oporder[ops++] = opnum;
3579 opoutput[opnum] = 1;
3580
3581 p = endptr;
3582 c = *p;
3583 }
3584 /* % followed by punctuation: output something for that
3585 punctuation character alone, with no operand. The
3586 TARGET_PRINT_OPERAND hook decides what is actually done. */
3587 else if (targetm.asm_out.print_operand_punct_valid_p ((unsigned char) *p))
3588 output_operand (NULL_RTX, *p++);
3589 else
3590 output_operand_lossage (cmsgid: "invalid %%-code");
3591 break;
3592
3593 default:
3594 putc (c: c, stream: asm_out_file);
3595 }
3596
3597 /* Try to keep the asm a bit more readable. */
3598 if ((flag_verbose_asm || flag_print_asm_name) && strlen (s: templ) < 9)
3599 putc (c: '\t', stream: asm_out_file);
3600
3601 /* Write out the variable names for operands, if we know them. */
3602 if (flag_verbose_asm)
3603 output_asm_operand_names (operands, oporder, nops: ops);
3604 if (flag_print_asm_name)
3605 output_asm_name ();
3606
3607 putc (c: '\n', stream: asm_out_file);
3608}
3609
3610/* Output a LABEL_REF, or a bare CODE_LABEL, as an assembler symbol. */
3611
3612void
3613output_asm_label (rtx x)
3614{
3615 char buf[256];
3616
3617 if (GET_CODE (x) == LABEL_REF)
3618 x = label_ref_label (ref: x);
3619 if (LABEL_P (x)
3620 || (NOTE_P (x)
3621 && NOTE_KIND (x) == NOTE_INSN_DELETED_LABEL))
3622 ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
3623 else
3624 output_operand_lossage (cmsgid: "'%%l' operand isn't a label");
3625
3626 assemble_name (asm_out_file, buf);
3627}
3628
3629/* Marks SYMBOL_REFs in x as referenced through use of assemble_external. */
3630
3631void
3632mark_symbol_refs_as_used (rtx x)
3633{
3634 subrtx_iterator::array_type array;
3635 FOR_EACH_SUBRTX (iter, array, x, ALL)
3636 {
3637 const_rtx x = *iter;
3638 if (GET_CODE (x) == SYMBOL_REF)
3639 if (tree t = SYMBOL_REF_DECL (x))
3640 assemble_external (t);
3641 }
3642}
3643
3644/* Print operand X using machine-dependent assembler syntax.
3645 CODE is a non-digit that preceded the operand-number in the % spec,
3646 such as 'z' if the spec was `%z3'. CODE is 0 if there was no char
3647 between the % and the digits.
3648 When CODE is a non-letter, X is 0.
3649
3650 The meanings of the letters are machine-dependent and controlled
3651 by TARGET_PRINT_OPERAND. */
3652
3653void
3654output_operand (rtx x, int code ATTRIBUTE_UNUSED)
3655{
3656 if (x && GET_CODE (x) == SUBREG)
3657 x = alter_subreg (xp: &x, final_p: true);
3658
3659 /* X must not be a pseudo reg. */
3660 if (!targetm.no_register_allocation)
3661 gcc_assert (!x || !REG_P (x) || REGNO (x) < FIRST_PSEUDO_REGISTER);
3662
3663 targetm.asm_out.print_operand (asm_out_file, x, code);
3664
3665 if (x == NULL_RTX)
3666 return;
3667
3668 mark_symbol_refs_as_used (x);
3669}
3670
3671/* Print a memory reference operand for address X using
3672 machine-dependent assembler syntax. */
3673
3674void
3675output_address (machine_mode mode, rtx x)
3676{
3677 bool changed = false;
3678 walk_alter_subreg (xp: &x, changed: &changed);
3679 targetm.asm_out.print_operand_address (asm_out_file, mode, x);
3680}
3681
3682/* Print an integer constant expression in assembler syntax.
3683 Addition and subtraction are the only arithmetic
3684 that may appear in these expressions. */
3685
3686void
3687output_addr_const (FILE *file, rtx x)
3688{
3689 char buf[256];
3690
3691 restart:
3692 switch (GET_CODE (x))
3693 {
3694 case PC:
3695 putc (c: '.', stream: file);
3696 break;
3697
3698 case SYMBOL_REF:
3699 if (SYMBOL_REF_DECL (x))
3700 assemble_external (SYMBOL_REF_DECL (x));
3701#ifdef ASM_OUTPUT_SYMBOL_REF
3702 ASM_OUTPUT_SYMBOL_REF (file, x);
3703#else
3704 assemble_name (file, XSTR (x, 0));
3705#endif
3706 break;
3707
3708 case LABEL_REF:
3709 x = label_ref_label (ref: x);
3710 /* Fall through. */
3711 case CODE_LABEL:
3712 ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
3713#ifdef ASM_OUTPUT_LABEL_REF
3714 ASM_OUTPUT_LABEL_REF (file, buf);
3715#else
3716 assemble_name (file, buf);
3717#endif
3718 break;
3719
3720 case CONST_INT:
3721 fprintf (stream: file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
3722 break;
3723
3724 case CONST:
3725 /* This used to output parentheses around the expression,
3726 but that does not work on the 386 (either ATT or BSD assembler). */
3727 output_addr_const (file, XEXP (x, 0));
3728 break;
3729
3730 case CONST_WIDE_INT:
3731 /* We do not know the mode here so we have to use a round about
3732 way to build a wide-int to get it printed properly. */
3733 {
3734 wide_int w = wide_int::from_array (val: &CONST_WIDE_INT_ELT (x, 0),
3735 CONST_WIDE_INT_NUNITS (x),
3736 CONST_WIDE_INT_NUNITS (x)
3737 * HOST_BITS_PER_WIDE_INT,
3738 need_canon_p: false);
3739 print_decs (wi: w, file);
3740 }
3741 break;
3742
3743 case CONST_DOUBLE:
3744 if (CONST_DOUBLE_AS_INT_P (x))
3745 {
3746 /* We can use %d if the number is one word and positive. */
3747 if (CONST_DOUBLE_HIGH (x))
3748 fprintf (stream: file, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
3749 (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (x),
3750 (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (x));
3751 else if (CONST_DOUBLE_LOW (x) < 0)
3752 fprintf (stream: file, HOST_WIDE_INT_PRINT_HEX,
3753 (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (x));
3754 else
3755 fprintf (stream: file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x));
3756 }
3757 else
3758 /* We can't handle floating point constants;
3759 PRINT_OPERAND must handle them. */
3760 output_operand_lossage (cmsgid: "floating constant misused");
3761 break;
3762
3763 case CONST_FIXED:
3764 fprintf (stream: file, HOST_WIDE_INT_PRINT_DEC, CONST_FIXED_VALUE_LOW (x));
3765 break;
3766
3767 case PLUS:
3768 /* Some assemblers need integer constants to appear last (eg masm). */
3769 if (CONST_INT_P (XEXP (x, 0)))
3770 {
3771 output_addr_const (file, XEXP (x, 1));
3772 if (INTVAL (XEXP (x, 0)) >= 0)
3773 fprintf (stream: file, format: "+");
3774 output_addr_const (file, XEXP (x, 0));
3775 }
3776 else
3777 {
3778 output_addr_const (file, XEXP (x, 0));
3779 if (!CONST_INT_P (XEXP (x, 1))
3780 || INTVAL (XEXP (x, 1)) >= 0)
3781 fprintf (stream: file, format: "+");
3782 output_addr_const (file, XEXP (x, 1));
3783 }
3784 break;
3785
3786 case MINUS:
3787 /* Avoid outputting things like x-x or x+5-x,
3788 since some assemblers can't handle that. */
3789 x = simplify_subtraction (x);
3790 if (GET_CODE (x) != MINUS)
3791 goto restart;
3792
3793 output_addr_const (file, XEXP (x, 0));
3794 fprintf (stream: file, format: "-");
3795 if ((CONST_INT_P (XEXP (x, 1)) && INTVAL (XEXP (x, 1)) >= 0)
3796 || GET_CODE (XEXP (x, 1)) == PC
3797 || GET_CODE (XEXP (x, 1)) == SYMBOL_REF)
3798 output_addr_const (file, XEXP (x, 1));
3799 else
3800 {
3801 fputs (s: targetm.asm_out.open_paren, stream: file);
3802 output_addr_const (file, XEXP (x, 1));
3803 fputs (s: targetm.asm_out.close_paren, stream: file);
3804 }
3805 break;
3806
3807 case ZERO_EXTEND:
3808 case SIGN_EXTEND:
3809 case SUBREG:
3810 case TRUNCATE:
3811 output_addr_const (file, XEXP (x, 0));
3812 break;
3813
3814 default:
3815 if (targetm.asm_out.output_addr_const_extra (file, x))
3816 break;
3817
3818 output_operand_lossage (cmsgid: "invalid expression as operand");
3819 }
3820}
3821
3822/* Output a quoted string. */
3823
3824void
3825output_quoted_string (FILE *asm_file, const char *string)
3826{
3827#ifdef OUTPUT_QUOTED_STRING
3828 OUTPUT_QUOTED_STRING (asm_file, string);
3829#else
3830 char c;
3831
3832 putc (c: '\"', stream: asm_file);
3833 while ((c = *string++) != 0)
3834 {
3835 if (ISPRINT (c))
3836 {
3837 if (c == '\"' || c == '\\')
3838 putc (c: '\\', stream: asm_file);
3839 putc (c: c, stream: asm_file);
3840 }
3841 else
3842 fprintf (stream: asm_file, format: "\\%03o", (unsigned char) c);
3843 }
3844 putc (c: '\"', stream: asm_file);
3845#endif
3846}
3847
3848/* Write a HOST_WIDE_INT number in hex form 0x1234, fast. */
3849
3850void
3851fprint_whex (FILE *f, unsigned HOST_WIDE_INT value)
3852{
3853 char buf[2 + CHAR_BIT * sizeof (value) / 4];
3854 if (value == 0)
3855 putc (c: '0', stream: f);
3856 else
3857 {
3858 char *p = buf + sizeof (buf);
3859 do
3860 *--p = "0123456789abcdef"[value % 16];
3861 while ((value /= 16) != 0);
3862 *--p = 'x';
3863 *--p = '0';
3864 fwrite (ptr: p, size: 1, n: buf + sizeof (buf) - p, s: f);
3865 }
3866}
3867
3868/* Internal function that prints an unsigned long in decimal in reverse.
3869 The output string IS NOT null-terminated. */
3870
3871static int
3872sprint_ul_rev (char *s, unsigned long value)
3873{
3874 int i = 0;
3875 do
3876 {
3877 s[i] = "0123456789"[value % 10];
3878 value /= 10;
3879 i++;
3880 /* alternate version, without modulo */
3881 /* oldval = value; */
3882 /* value /= 10; */
3883 /* s[i] = "0123456789" [oldval - 10*value]; */
3884 /* i++ */
3885 }
3886 while (value != 0);
3887 return i;
3888}
3889
3890/* Write an unsigned long as decimal to a file, fast. */
3891
3892void
3893fprint_ul (FILE *f, unsigned long value)
3894{
3895 /* python says: len(str(2**64)) == 20 */
3896 char s[20];
3897 int i;
3898
3899 i = sprint_ul_rev (s, value);
3900
3901 /* It's probably too small to bother with string reversal and fputs. */
3902 do
3903 {
3904 i--;
3905 putc (c: s[i], stream: f);
3906 }
3907 while (i != 0);
3908}
3909
3910/* Write an unsigned long as decimal to a string, fast.
3911 s must be wide enough to not overflow, at least 21 chars.
3912 Returns the length of the string (without terminating '\0'). */
3913
3914int
3915sprint_ul (char *s, unsigned long value)
3916{
3917 int len = sprint_ul_rev (s, value);
3918 s[len] = '\0';
3919
3920 std::reverse (first: s, last: s + len);
3921 return len;
3922}
3923
3924/* A poor man's fprintf, with the added features of %I, %R, %L, and %U.
3925 %R prints the value of REGISTER_PREFIX.
3926 %L prints the value of LOCAL_LABEL_PREFIX.
3927 %U prints the value of USER_LABEL_PREFIX.
3928 %I prints the value of IMMEDIATE_PREFIX.
3929 %O runs ASM_OUTPUT_OPCODE to transform what follows in the string.
3930 Also supported are %d, %i, %u, %x, %X, %o, %c, %s and %%.
3931
3932 We handle alternate assembler dialects here, just like output_asm_insn. */
3933
3934void
3935asm_fprintf (FILE *file, const char *p, ...)
3936{
3937 char buf[10];
3938 char *q, c;
3939#ifdef ASSEMBLER_DIALECT
3940 int dialect = 0;
3941#endif
3942 va_list argptr;
3943
3944 va_start (argptr, p);
3945
3946 buf[0] = '%';
3947
3948 while ((c = *p++))
3949 switch (c)
3950 {
3951#ifdef ASSEMBLER_DIALECT
3952 case '{':
3953 case '}':
3954 case '|':
3955 p = do_assembler_dialects (p, dialect: &dialect);
3956 break;
3957#endif
3958
3959 case '%':
3960 c = *p++;
3961 q = &buf[1];
3962 while (strchr (s: "-+ #0", c: c))
3963 {
3964 *q++ = c;
3965 c = *p++;
3966 }
3967 while (ISDIGIT (c) || c == '.')
3968 {
3969 *q++ = c;
3970 c = *p++;
3971 }
3972 switch (c)
3973 {
3974 case '%':
3975 putc (c: '%', stream: file);
3976 break;
3977
3978 case 'd': case 'i': case 'u':
3979 case 'x': case 'X': case 'o':
3980 case 'c':
3981 *q++ = c;
3982 *q = 0;
3983 fprintf (stream: file, format: buf, va_arg (argptr, int));
3984 break;
3985
3986 case 'w':
3987 /* This is a prefix to the 'd', 'i', 'u', 'x', 'X', and
3988 'o' cases, but we do not check for those cases. It
3989 means that the value is a HOST_WIDE_INT, which may be
3990 either `long' or `long long'. */
3991 memcpy (dest: q, HOST_WIDE_INT_PRINT, n: strlen (HOST_WIDE_INT_PRINT));
3992 q += strlen (HOST_WIDE_INT_PRINT);
3993 *q++ = *p++;
3994 *q = 0;
3995 fprintf (stream: file, format: buf, va_arg (argptr, HOST_WIDE_INT));
3996 break;
3997
3998 case 'l':
3999 *q++ = c;
4000#ifdef HAVE_LONG_LONG
4001 if (*p == 'l')
4002 {
4003 *q++ = *p++;
4004 *q++ = *p++;
4005 *q = 0;
4006 fprintf (stream: file, format: buf, va_arg (argptr, long long));
4007 }
4008 else
4009#endif
4010 {
4011 *q++ = *p++;
4012 *q = 0;
4013 fprintf (stream: file, format: buf, va_arg (argptr, long));
4014 }
4015
4016 break;
4017
4018 case 's':
4019 *q++ = c;
4020 *q = 0;
4021 fprintf (stream: file, format: buf, va_arg (argptr, char *));
4022 break;
4023
4024 case 'O':
4025#ifdef ASM_OUTPUT_OPCODE
4026 ASM_OUTPUT_OPCODE (asm_out_file, p);
4027#endif
4028 break;
4029
4030 case 'R':
4031#ifdef REGISTER_PREFIX
4032 fprintf (file, "%s", REGISTER_PREFIX);
4033#endif
4034 break;
4035
4036 case 'I':
4037#ifdef IMMEDIATE_PREFIX
4038 fprintf (file, "%s", IMMEDIATE_PREFIX);
4039#endif
4040 break;
4041
4042 case 'L':
4043#ifdef LOCAL_LABEL_PREFIX
4044 fprintf (stream: file, format: "%s", LOCAL_LABEL_PREFIX);
4045#endif
4046 break;
4047
4048 case 'U':
4049 fputs (s: user_label_prefix, stream: file);
4050 break;
4051
4052#ifdef ASM_FPRINTF_EXTENSIONS
4053 /* Uppercase letters are reserved for general use by asm_fprintf
4054 and so are not available to target specific code. In order to
4055 prevent the ASM_FPRINTF_EXTENSIONS macro from using them then,
4056 they are defined here. As they get turned into real extensions
4057 to asm_fprintf they should be removed from this list. */
4058 case 'A': case 'B': case 'C': case 'D': case 'E':
4059 case 'F': case 'G': case 'H': case 'J': case 'K':
4060 case 'M': case 'N': case 'P': case 'Q': case 'S':
4061 case 'T': case 'V': case 'W': case 'Y': case 'Z':
4062 break;
4063
4064 ASM_FPRINTF_EXTENSIONS (file, argptr, p)
4065#endif
4066 default:
4067 gcc_unreachable ();
4068 }
4069 break;
4070
4071 default:
4072 putc (c: c, stream: file);
4073 }
4074 va_end (argptr);
4075}
4076
4077/* Return true if this function has no function calls. */
4078
4079bool
4080leaf_function_p (void)
4081{
4082 rtx_insn *insn;
4083
4084 /* Ensure we walk the entire function body. */
4085 gcc_assert (!in_sequence_p ());
4086
4087 /* Some back-ends (e.g. s390) want leaf functions to stay leaf
4088 functions even if they call mcount. */
4089 if (crtl->profile && !targetm.keep_leaf_when_profiled ())
4090 return false;
4091
4092 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
4093 {
4094 if (CALL_P (insn)
4095 && ! SIBLING_CALL_P (insn)
4096 && ! FAKE_CALL_P (insn))
4097 return false;
4098 if (NONJUMP_INSN_P (insn)
4099 && GET_CODE (PATTERN (insn)) == SEQUENCE
4100 && CALL_P (XVECEXP (PATTERN (insn), 0, 0))
4101 && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0)))
4102 return false;
4103 }
4104
4105 return true;
4106}
4107
4108/* Return true if branch is a forward branch.
4109 Uses insn_shuid array, so it works only in the final pass. May be used by
4110 output templates to customary add branch prediction hints.
4111 */
4112bool
4113final_forward_branch_p (rtx_insn *insn)
4114{
4115 int insn_id, label_id;
4116
4117 gcc_assert (uid_shuid);
4118 insn_id = INSN_SHUID (insn);
4119 label_id = INSN_SHUID (JUMP_LABEL (insn));
4120 /* We've hit some insns that does not have id information available. */
4121 gcc_assert (insn_id && label_id);
4122 return insn_id < label_id;
4123}
4124
4125/* On some machines, a function with no call insns
4126 can run faster if it doesn't create its own register window.
4127 When output, the leaf function should use only the "output"
4128 registers. Ordinarily, the function would be compiled to use
4129 the "input" registers to find its arguments; it is a candidate
4130 for leaf treatment if it uses only the "input" registers.
4131 Leaf function treatment means renumbering so the function
4132 uses the "output" registers instead. */
4133
4134#ifdef LEAF_REGISTERS
4135
4136/* Return bool if this function uses only the registers that can be
4137 safely renumbered. */
4138
4139bool
4140only_leaf_regs_used (void)
4141{
4142 int i;
4143 const char *const permitted_reg_in_leaf_functions = LEAF_REGISTERS;
4144
4145 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
4146 if ((df_regs_ever_live_p (i) || global_regs[i])
4147 && ! permitted_reg_in_leaf_functions[i])
4148 return false;
4149
4150 if (crtl->uses_pic_offset_table
4151 && pic_offset_table_rtx != 0
4152 && REG_P (pic_offset_table_rtx)
4153 && ! permitted_reg_in_leaf_functions[REGNO (pic_offset_table_rtx)])
4154 return false;
4155
4156 return true;
4157}
4158
4159/* Scan all instructions and renumber all registers into those
4160 available in leaf functions. */
4161
4162static void
4163leaf_renumber_regs (rtx_insn *first)
4164{
4165 rtx_insn *insn;
4166
4167 /* Renumber only the actual patterns.
4168 The reg-notes can contain frame pointer refs,
4169 and renumbering them could crash, and should not be needed. */
4170 for (insn = first; insn; insn = NEXT_INSN (insn))
4171 if (INSN_P (insn))
4172 leaf_renumber_regs_insn (PATTERN (insn));
4173}
4174
4175/* Scan IN_RTX and its subexpressions, and renumber all regs into those
4176 available in leaf functions. */
4177
4178void
4179leaf_renumber_regs_insn (rtx in_rtx)
4180{
4181 int i, j;
4182 const char *format_ptr;
4183
4184 if (in_rtx == 0)
4185 return;
4186
4187 /* Renumber all input-registers into output-registers.
4188 renumbered_regs would be 1 for an output-register;
4189 they */
4190
4191 if (REG_P (in_rtx))
4192 {
4193 int newreg;
4194
4195 /* Don't renumber the same reg twice. */
4196 if (in_rtx->used)
4197 return;
4198
4199 newreg = REGNO (in_rtx);
4200 /* Don't try to renumber pseudo regs. It is possible for a pseudo reg
4201 to reach here as part of a REG_NOTE. */
4202 if (newreg >= FIRST_PSEUDO_REGISTER)
4203 {
4204 in_rtx->used = 1;
4205 return;
4206 }
4207 newreg = LEAF_REG_REMAP (newreg);
4208 gcc_assert (newreg >= 0);
4209 df_set_regs_ever_live (REGNO (in_rtx), false);
4210 df_set_regs_ever_live (newreg, true);
4211 SET_REGNO (in_rtx, newreg);
4212 in_rtx->used = 1;
4213 return;
4214 }
4215
4216 if (INSN_P (in_rtx))
4217 {
4218 /* Inside a SEQUENCE, we find insns.
4219 Renumber just the patterns of these insns,
4220 just as we do for the top-level insns. */
4221 leaf_renumber_regs_insn (PATTERN (in_rtx));
4222 return;
4223 }
4224
4225 format_ptr = GET_RTX_FORMAT (GET_CODE (in_rtx));
4226
4227 for (i = 0; i < GET_RTX_LENGTH (GET_CODE (in_rtx)); i++)
4228 switch (*format_ptr++)
4229 {
4230 case 'e':
4231 leaf_renumber_regs_insn (XEXP (in_rtx, i));
4232 break;
4233
4234 case 'E':
4235 if (XVEC (in_rtx, i) != NULL)
4236 for (j = 0; j < XVECLEN (in_rtx, i); j++)
4237 leaf_renumber_regs_insn (XVECEXP (in_rtx, i, j));
4238 break;
4239
4240 case 'S':
4241 case 's':
4242 case '0':
4243 case 'i':
4244 case 'L':
4245 case 'w':
4246 case 'p':
4247 case 'n':
4248 case 'u':
4249 break;
4250
4251 default:
4252 gcc_unreachable ();
4253 }
4254}
4255#endif
4256
4257/* Turn the RTL into assembly. */
4258static unsigned int
4259rest_of_handle_final (void)
4260{
4261 const char *fnname = get_fnname_from_decl (current_function_decl);
4262
4263 /* Turn debug markers into notes if the var-tracking pass has not
4264 been invoked. */
4265 if (!flag_var_tracking && MAY_HAVE_DEBUG_MARKER_INSNS)
4266 delete_vta_debug_insns (false);
4267
4268 assemble_start_function (current_function_decl, fnname);
4269 rtx_insn *first = get_insns ();
4270 int seen = 0;
4271 final_start_function_1 (firstp: &first, file: asm_out_file, seen: &seen, optimize);
4272 final_1 (first, file: asm_out_file, seen, optimize);
4273 if (flag_ipa_ra
4274 && !lookup_attribute (attr_name: "noipa", DECL_ATTRIBUTES (current_function_decl))
4275 /* Functions with naked attributes are supported only with basic asm
4276 statements in the body, thus for supported use cases the information
4277 on clobbered registers is not available. */
4278 && !lookup_attribute (attr_name: "naked", DECL_ATTRIBUTES (current_function_decl)))
4279 collect_fn_hard_reg_usage ();
4280 final_end_function ();
4281
4282 /* The IA-64 ".handlerdata" directive must be issued before the ".endp"
4283 directive that closes the procedure descriptor. Similarly, for x64 SEH.
4284 Otherwise it's not strictly necessary, but it doesn't hurt either. */
4285 output_function_exception_table (crtl->has_bb_partition ? 1 : 0);
4286
4287 assemble_end_function (current_function_decl, fnname);
4288
4289 /* Free up reg info memory. */
4290 free_reg_info ();
4291
4292 if (! quiet_flag)
4293 fflush (stream: asm_out_file);
4294
4295 /* Note that for those inline functions where we don't initially
4296 know for certain that we will be generating an out-of-line copy,
4297 the first invocation of this routine (rest_of_compilation) will
4298 skip over this code by doing a `goto exit_rest_of_compilation;'.
4299 Later on, wrapup_global_declarations will (indirectly) call
4300 rest_of_compilation again for those inline functions that need
4301 to have out-of-line copies generated. During that call, we
4302 *will* be routed past here. */
4303
4304 timevar_push (tv: TV_SYMOUT);
4305 if (!DECL_IGNORED_P (current_function_decl))
4306 debug_hooks->function_decl (current_function_decl);
4307 timevar_pop (tv: TV_SYMOUT);
4308
4309 /* Release the blocks that are linked to DECL_INITIAL() to free the memory. */
4310 DECL_INITIAL (current_function_decl) = error_mark_node;
4311
4312 if (DECL_STATIC_CONSTRUCTOR (current_function_decl)
4313 && targetm.have_ctors_dtors)
4314 targetm.asm_out.constructor (XEXP (DECL_RTL (current_function_decl), 0),
4315 decl_init_priority_lookup
4316 (current_function_decl));
4317 if (DECL_STATIC_DESTRUCTOR (current_function_decl)
4318 && targetm.have_ctors_dtors)
4319 targetm.asm_out.destructor (XEXP (DECL_RTL (current_function_decl), 0),
4320 decl_fini_priority_lookup
4321 (current_function_decl));
4322 return 0;
4323}
4324
4325namespace {
4326
4327const pass_data pass_data_final =
4328{
4329 .type: RTL_PASS, /* type */
4330 .name: "final", /* name */
4331 .optinfo_flags: OPTGROUP_NONE, /* optinfo_flags */
4332 .tv_id: TV_FINAL, /* tv_id */
4333 .properties_required: 0, /* properties_required */
4334 .properties_provided: 0, /* properties_provided */
4335 .properties_destroyed: 0, /* properties_destroyed */
4336 .todo_flags_start: 0, /* todo_flags_start */
4337 .todo_flags_finish: 0, /* todo_flags_finish */
4338};
4339
4340class pass_final : public rtl_opt_pass
4341{
4342public:
4343 pass_final (gcc::context *ctxt)
4344 : rtl_opt_pass (pass_data_final, ctxt)
4345 {}
4346
4347 /* opt_pass methods: */
4348 unsigned int execute (function *) final override
4349 {
4350 return rest_of_handle_final ();
4351 }
4352
4353}; // class pass_final
4354
4355} // anon namespace
4356
4357rtl_opt_pass *
4358make_pass_final (gcc::context *ctxt)
4359{
4360 return new pass_final (ctxt);
4361}
4362
4363
4364static unsigned int
4365rest_of_handle_shorten_branches (void)
4366{
4367 /* Shorten branches. */
4368 shorten_branches (first: get_insns ());
4369 return 0;
4370}
4371
4372namespace {
4373
4374const pass_data pass_data_shorten_branches =
4375{
4376 .type: RTL_PASS, /* type */
4377 .name: "shorten", /* name */
4378 .optinfo_flags: OPTGROUP_NONE, /* optinfo_flags */
4379 .tv_id: TV_SHORTEN_BRANCH, /* tv_id */
4380 .properties_required: 0, /* properties_required */
4381 .properties_provided: 0, /* properties_provided */
4382 .properties_destroyed: 0, /* properties_destroyed */
4383 .todo_flags_start: 0, /* todo_flags_start */
4384 .todo_flags_finish: 0, /* todo_flags_finish */
4385};
4386
4387class pass_shorten_branches : public rtl_opt_pass
4388{
4389public:
4390 pass_shorten_branches (gcc::context *ctxt)
4391 : rtl_opt_pass (pass_data_shorten_branches, ctxt)
4392 {}
4393
4394 /* opt_pass methods: */
4395 unsigned int execute (function *) final override
4396 {
4397 return rest_of_handle_shorten_branches ();
4398 }
4399
4400}; // class pass_shorten_branches
4401
4402} // anon namespace
4403
4404rtl_opt_pass *
4405make_pass_shorten_branches (gcc::context *ctxt)
4406{
4407 return new pass_shorten_branches (ctxt);
4408}
4409
4410
4411static unsigned int
4412rest_of_clean_state (void)
4413{
4414 rtx_insn *insn, *next;
4415 FILE *final_output = NULL;
4416 int save_unnumbered = flag_dump_unnumbered;
4417 int save_noaddr = flag_dump_noaddr;
4418
4419 if (flag_dump_final_insns)
4420 {
4421 final_output = fopen (flag_dump_final_insns, modes: "a");
4422 if (!final_output)
4423 {
4424 error ("could not open final insn dump file %qs: %m",
4425 flag_dump_final_insns);
4426 flag_dump_final_insns = NULL;
4427 }
4428 else
4429 {
4430 flag_dump_noaddr = flag_dump_unnumbered = 1;
4431 if (flag_compare_debug_opt || flag_compare_debug)
4432 dump_flags |= TDF_NOUID | TDF_COMPARE_DEBUG;
4433 dump_function_header (final_output, current_function_decl,
4434 dump_flags);
4435 final_insns_dump_p = true;
4436
4437 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
4438 if (LABEL_P (insn))
4439 INSN_UID (insn) = CODE_LABEL_NUMBER (insn);
4440 else
4441 {
4442 if (NOTE_P (insn))
4443 set_block_for_insn (insn, NULL);
4444 INSN_UID (insn) = 0;
4445 }
4446 }
4447 }
4448
4449 /* It is very important to decompose the RTL instruction chain here:
4450 debug information keeps pointing into CODE_LABEL insns inside the function
4451 body. If these remain pointing to the other insns, we end up preserving
4452 whole RTL chain and attached detailed debug info in memory. */
4453 for (insn = get_insns (); insn; insn = next)
4454 {
4455 next = NEXT_INSN (insn);
4456 SET_NEXT_INSN (insn) = NULL;
4457 SET_PREV_INSN (insn) = NULL;
4458
4459 rtx_insn *call_insn = insn;
4460 if (NONJUMP_INSN_P (call_insn)
4461 && GET_CODE (PATTERN (call_insn)) == SEQUENCE)
4462 {
4463 rtx_sequence *seq = as_a <rtx_sequence *> (p: PATTERN (insn: call_insn));
4464 call_insn = seq->insn (index: 0);
4465 }
4466 if (CALL_P (call_insn))
4467 {
4468 rtx note
4469 = find_reg_note (call_insn, REG_CALL_ARG_LOCATION, NULL_RTX);
4470 if (note)
4471 remove_note (call_insn, note);
4472 }
4473
4474 if (final_output
4475 && (!NOTE_P (insn)
4476 || (NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION
4477 && NOTE_KIND (insn) != NOTE_INSN_BEGIN_STMT
4478 && NOTE_KIND (insn) != NOTE_INSN_INLINE_ENTRY
4479 && NOTE_KIND (insn) != NOTE_INSN_BLOCK_BEG
4480 && NOTE_KIND (insn) != NOTE_INSN_BLOCK_END
4481 && NOTE_KIND (insn) != NOTE_INSN_DELETED_DEBUG_LABEL)))
4482 print_rtl_single (final_output, insn);
4483 }
4484
4485 if (final_output)
4486 {
4487 flag_dump_noaddr = save_noaddr;
4488 flag_dump_unnumbered = save_unnumbered;
4489 final_insns_dump_p = false;
4490
4491 if (fclose (stream: final_output))
4492 {
4493 error ("could not close final insn dump file %qs: %m",
4494 flag_dump_final_insns);
4495 flag_dump_final_insns = NULL;
4496 }
4497 }
4498
4499 flag_rerun_cse_after_global_opts = 0;
4500 reload_completed = 0;
4501 epilogue_completed = 0;
4502#ifdef STACK_REGS
4503 regstack_completed = 0;
4504#endif
4505
4506 /* Clear out the insn_length contents now that they are no
4507 longer valid. */
4508 init_insn_lengths ();
4509
4510 /* Show no temporary slots allocated. */
4511 init_temp_slots ();
4512
4513 free_bb_for_insn ();
4514
4515 if (cfun->gimple_df)
4516 delete_tree_ssa (cfun);
4517
4518 /* We can reduce stack alignment on call site only when we are sure that
4519 the function body just produced will be actually used in the final
4520 executable. */
4521 if (flag_ipa_stack_alignment
4522 && decl_binds_to_current_def_p (current_function_decl))
4523 {
4524 unsigned int pref = crtl->preferred_stack_boundary;
4525 if (crtl->stack_alignment_needed > crtl->preferred_stack_boundary)
4526 pref = crtl->stack_alignment_needed;
4527 cgraph_node::rtl_info (current_function_decl)
4528 ->preferred_incoming_stack_boundary = pref;
4529 }
4530
4531 /* Make sure volatile mem refs aren't considered valid operands for
4532 arithmetic insns. We must call this here if this is a nested inline
4533 function, since the above code leaves us in the init_recog state,
4534 and the function context push/pop code does not save/restore volatile_ok.
4535
4536 ??? Maybe it isn't necessary for expand_start_function to call this
4537 anymore if we do it here? */
4538
4539 init_recog_no_volatile ();
4540
4541 /* We're done with this function. Free up memory if we can. */
4542 free_after_parsing (cfun);
4543 free_after_compilation (cfun);
4544 return 0;
4545}
4546
4547namespace {
4548
4549const pass_data pass_data_clean_state =
4550{
4551 .type: RTL_PASS, /* type */
4552 .name: "*clean_state", /* name */
4553 .optinfo_flags: OPTGROUP_NONE, /* optinfo_flags */
4554 .tv_id: TV_FINAL, /* tv_id */
4555 .properties_required: 0, /* properties_required */
4556 .properties_provided: 0, /* properties_provided */
4557 PROP_rtl, /* properties_destroyed */
4558 .todo_flags_start: 0, /* todo_flags_start */
4559 .todo_flags_finish: 0, /* todo_flags_finish */
4560};
4561
4562class pass_clean_state : public rtl_opt_pass
4563{
4564public:
4565 pass_clean_state (gcc::context *ctxt)
4566 : rtl_opt_pass (pass_data_clean_state, ctxt)
4567 {}
4568
4569 /* opt_pass methods: */
4570 unsigned int execute (function *) final override
4571 {
4572 return rest_of_clean_state ();
4573 }
4574
4575}; // class pass_clean_state
4576
4577} // anon namespace
4578
4579rtl_opt_pass *
4580make_pass_clean_state (gcc::context *ctxt)
4581{
4582 return new pass_clean_state (ctxt);
4583}
4584
4585/* Return true if INSN is a call to the current function. */
4586
4587static bool
4588self_recursive_call_p (rtx_insn *insn)
4589{
4590 tree fndecl = get_call_fndecl (insn);
4591 return (fndecl == current_function_decl
4592 && decl_binds_to_current_def_p (fndecl));
4593}
4594
4595/* Collect hard register usage for the current function. */
4596
4597static void
4598collect_fn_hard_reg_usage (void)
4599{
4600 rtx_insn *insn;
4601#ifdef STACK_REGS
4602 int i;
4603#endif
4604 struct cgraph_rtl_info *node;
4605 HARD_REG_SET function_used_regs;
4606
4607 /* ??? To be removed when all the ports have been fixed. */
4608 if (!targetm.call_fusage_contains_non_callee_clobbers)
4609 return;
4610
4611 /* Be conservative - mark fixed and global registers as used. */
4612 function_used_regs = fixed_reg_set;
4613
4614#ifdef STACK_REGS
4615 /* Handle STACK_REGS conservatively, since the df-framework does not
4616 provide accurate information for them. */
4617
4618 for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
4619 SET_HARD_REG_BIT (set&: function_used_regs, bit: i);
4620#endif
4621
4622 for (insn = get_insns (); insn != NULL_RTX; insn = next_insn (insn))
4623 {
4624 HARD_REG_SET insn_used_regs;
4625
4626 if (!NONDEBUG_INSN_P (insn))
4627 continue;
4628
4629 if (CALL_P (insn)
4630 && !self_recursive_call_p (insn))
4631 function_used_regs
4632 |= insn_callee_abi (insn).full_and_partial_reg_clobbers ();
4633
4634 find_all_hard_reg_sets (insn, &insn_used_regs, false);
4635 function_used_regs |= insn_used_regs;
4636
4637 if (hard_reg_set_subset_p (crtl->abi->full_and_partial_reg_clobbers (),
4638 y: function_used_regs))
4639 return;
4640 }
4641
4642 /* Mask out fully-saved registers, so that they don't affect equality
4643 comparisons between function_abis. */
4644 function_used_regs &= crtl->abi->full_and_partial_reg_clobbers ();
4645
4646 node = cgraph_node::rtl_info (current_function_decl);
4647 gcc_assert (node != NULL);
4648
4649 node->function_used_regs = function_used_regs;
4650}
4651

source code of gcc/final.cc